Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 29 Jul 2016 20:23:18 +0000 (13:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 29 Jul 2016 20:23:18 +0000 (13:23 -0700)
Pull sparc updates from David Miller:

 1) Double spin lock bug in sunhv serial driver, from Dan Carpenter.

 2) Use correct RSS estimate when determining whether to grow the huge
    TSB or not, from Mike Kravetz.

 3) Don't use full three level page tables for hugepages, PMD level is
    sufficient.  From Nitin Gupta.

 4) Mask out extraneous bits from TSB_TAG_ACCESS register, we only want
    the address bits.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
  sparc64: Trim page tables for 8M hugepages
  sparc64 mm: Fix base TSB sizing when hugetlb pages are used
  sparc: serial: sunhv: fix a double lock bug
  sparc32: off by ones in BUG_ON()
  sparc: Don't leak context bits into thread->fault_address

560 files changed:
Documentation/block/biodoc.txt
Documentation/cgroup-v1/memcg_test.txt
Documentation/cgroup-v1/memory.txt
Documentation/devicetree/bindings/dma/mv-xor-v2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt [deleted file]
Documentation/devicetree/bindings/dma/xilinx/zynqmp_dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_oxnas.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/brcm,iproc-gpio.txt
Documentation/devicetree/bindings/pinctrl/brcm,nsp-pinmux.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/oxnas,pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/pinctrl-max77620.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt
Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt [new file with mode: 0644]
Documentation/filesystems/Locking
Documentation/filesystems/vfs.txt
Documentation/hid/hid-alps.txt [new file with mode: 0644]
Documentation/nvdimm/btt.txt
Documentation/pinctrl.txt
Documentation/trace/kprobetrace.txt
Documentation/trace/uprobetracer.txt
MAINTAINERS
Makefile
arch/arc/include/asm/pgtable.h
arch/arc/kernel/setup.c
arch/arc/mm/dma.c
arch/arc/mm/ioremap.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/Makefile
arch/arm/include/asm/assembler.h
arch/arm/include/asm/barrier.h
arch/arm/include/asm/delay.h
arch/arm/include/asm/floppy.h
arch/arm/include/asm/io.h
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/uaccess.h
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/cpuidle.c
arch/arm/kernel/devtree.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/entry-header.S
arch/arm/kernel/entry-v7m.S
arch/arm/kernel/process.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp_tlb.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/Makefile
arch/arm/lib/delay-loop.S
arch/arm/mm/Kconfig
arch/arm/mm/dma-mapping.c
arch/arm/mm/proc-v7.S
arch/arm64/mm/init.c
arch/avr32/include/uapi/asm/unistd.h
arch/avr32/kernel/syscall-stubs.S
arch/avr32/kernel/syscall_table.S
arch/avr32/mach-at32ap/pio.c
arch/powerpc/sysdev/axonram.c
arch/s390/appldata/appldata_mem.c
arch/tile/mm/pgtable.c
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/pmem.h
arch/x86/include/asm/special_insns.h
arch/x86/include/asm/vmx.h
arch/x86/include/uapi/asm/vmx.h
arch/x86/kvm/cpuid.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/vmx.c
arch/x86/lib/x86-opcode-map.txt
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/nfit.c [deleted file]
drivers/acpi/nfit.h [deleted file]
drivers/acpi/nfit/Kconfig [new file with mode: 0644]
drivers/acpi/nfit/Makefile [new file with mode: 0644]
drivers/acpi/nfit/core.c [new file with mode: 0644]
drivers/acpi/nfit/mce.c [new file with mode: 0644]
drivers/acpi/nfit/nfit.h [new file with mode: 0644]
drivers/base/node.c
drivers/block/brd.c
drivers/block/drbd/drbd_debugfs.c
drivers/char/random.c
drivers/dax/dax.c
drivers/dax/pmem.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/amba-pl08x.c
drivers/dma/at_xdmac.c
drivers/dma/bcm2835-dma.c
drivers/dma/bestcomm/bestcomm.c
drivers/dma/coh901318.c
drivers/dma/cppi41.c
drivers/dma/dma-axi-dmac.c
drivers/dma/dma-jz4740.c
drivers/dma/dmatest.c
drivers/dma/edma.c
drivers/dma/fsl-edma.c
drivers/dma/fsl_raid.c
drivers/dma/fsldma.c
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/ioat/init.c
drivers/dma/k3dma.c
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/moxart-dma.c
drivers/dma/mpc512x_dma.c
drivers/dma/mv_xor.c
drivers/dma/mv_xor_v2.c [new file with mode: 0644]
drivers/dma/nbpfaxi.c
drivers/dma/omap-dma.c
drivers/dma/pl330.c
drivers/dma/ppc4xx/adma.c
drivers/dma/pxa_dma.c
drivers/dma/qcom/bam_dma.c
drivers/dma/qcom/hidma.c
drivers/dma/qcom/hidma_ll.c
drivers/dma/qcom/hidma_mgmt.c
drivers/dma/s3c24xx-dma.c
drivers/dma/sh/rcar-dmac.c
drivers/dma/sh/shdmac.c
drivers/dma/sh/sudmac.c
drivers/dma/sirf-dma.c
drivers/dma/ste_dma40.c
drivers/dma/ste_dma40_ll.c
drivers/dma/sun6i-dma.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/ti-dma-crossbar.c
drivers/dma/timb_dma.c
drivers/dma/txx9dmac.c
drivers/dma/xilinx/Makefile
drivers/dma/xilinx/xilinx_dma.c [new file with mode: 0644]
drivers/dma/xilinx/xilinx_vdma.c [deleted file]
drivers/dma/xilinx/zynqmp_dma.c [new file with mode: 0644]
drivers/gpu/drm/armada/armada_gem.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/etnaviv/etnaviv_gem.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-alps.c [new file with mode: 0644]
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-led.c [new file with mode: 0644]
drivers/hid/hid-thingm.c [deleted file]
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/uhid.c
drivers/hwspinlock/qcom_hwspinlock.c
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c
drivers/md/dm-linear.c
drivers/md/dm-snap.c
drivers/md/dm-stripe.c
drivers/md/dm-target.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/md.h
drivers/md/multipath.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid10.h
drivers/md/raid5.c
drivers/nvdimm/Kconfig
drivers/nvdimm/blk.c
drivers/nvdimm/btt_devs.c
drivers/nvdimm/bus.c
drivers/nvdimm/claim.c
drivers/nvdimm/core.c
drivers/nvdimm/dimm_devs.c
drivers/nvdimm/e820.c
drivers/nvdimm/nd-core.h
drivers/nvdimm/nd.h
drivers/nvdimm/pmem.c
drivers/nvdimm/pmem.h [new file with mode: 0644]
drivers/nvdimm/region.c
drivers/nvdimm/region_devs.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/bcm/Kconfig
drivers/pinctrl/bcm/Makefile
drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
drivers/pinctrl/bcm/pinctrl-ns2-mux.c
drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
drivers/pinctrl/bcm/pinctrl-nsp-mux.c [new file with mode: 0644]
drivers/pinctrl/core.c
drivers/pinctrl/core.h
drivers/pinctrl/devicetree.c
drivers/pinctrl/freescale/pinctrl-imx.c
drivers/pinctrl/freescale/pinctrl-imx1-core.c
drivers/pinctrl/freescale/pinctrl-imx1.c
drivers/pinctrl/freescale/pinctrl-imx21.c
drivers/pinctrl/freescale/pinctrl-imx23.c
drivers/pinctrl/freescale/pinctrl-imx25.c
drivers/pinctrl/freescale/pinctrl-imx27.c
drivers/pinctrl/freescale/pinctrl-imx28.c
drivers/pinctrl/freescale/pinctrl-imx35.c
drivers/pinctrl/freescale/pinctrl-imx50.c
drivers/pinctrl/freescale/pinctrl-imx51.c
drivers/pinctrl/freescale/pinctrl-imx53.c
drivers/pinctrl/freescale/pinctrl-imx6dl.c
drivers/pinctrl/freescale/pinctrl-imx6q.c
drivers/pinctrl/freescale/pinctrl-imx6sl.c
drivers/pinctrl/freescale/pinctrl-imx6sx.c
drivers/pinctrl/freescale/pinctrl-imx6ul.c
drivers/pinctrl/freescale/pinctrl-imx7d.c
drivers/pinctrl/freescale/pinctrl-mxs.c
drivers/pinctrl/freescale/pinctrl-mxs.h
drivers/pinctrl/freescale/pinctrl-vf610.c
drivers/pinctrl/intel/Kconfig
drivers/pinctrl/intel/Makefile
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-broxton.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/intel/pinctrl-merrifield.c [new file with mode: 0644]
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/meson/pinctrl-meson-gxbb.c
drivers/pinctrl/mvebu/pinctrl-kirkwood.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/pinconf-generic.c
drivers/pinctrl/pinconf.c
drivers/pinctrl/pinctrl-at91-pio4.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-digicolor.c
drivers/pinctrl/pinctrl-lpc18xx.c
drivers/pinctrl/pinctrl-max77620.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-oxnas.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-st.c
drivers/pinctrl/pinctrl-u300.c
drivers/pinctrl/pinctrl-xway.c
drivers/pinctrl/pinctrl-zynq.c
drivers/pinctrl/pinmux.c
drivers/pinctrl/qcom/Kconfig
drivers/pinctrl/qcom/Makefile
drivers/pinctrl/qcom/pinctrl-mdm9615.c [new file with mode: 0644]
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-msm8660.c
drivers/pinctrl/qcom/pinctrl-msm8x74.c
drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
drivers/pinctrl/samsung/pinctrl-exynos5440.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/sh-pfc/core.c
drivers/pinctrl/sh-pfc/core.h
drivers/pinctrl/sh-pfc/gpio.c
drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
drivers/pinctrl/sh-pfc/pfc-r8a7740.c
drivers/pinctrl/sh-pfc/pfc-r8a7778.c
drivers/pinctrl/sh-pfc/pfc-r8a7790.c
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pinctrl/sh-pfc/pfc-r8a7795.c
drivers/pinctrl/sh-pfc/pfc-sh7757.c
drivers/pinctrl/sh-pfc/pinctrl.c
drivers/pinctrl/sh-pfc/sh_pfc.h
drivers/pinctrl/sirf/pinctrl-atlas7.c
drivers/pinctrl/stm32/Kconfig
drivers/pinctrl/stm32/Makefile
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/pinctrl/stm32/pinctrl-stm32f746.c [new file with mode: 0644]
drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
drivers/pinctrl/tegra/pinctrl-tegra.c
drivers/pinctrl/tegra/pinctrl-tegra.h
drivers/pinctrl/tegra/pinctrl-tegra114.c
drivers/pinctrl/tegra/pinctrl-tegra124.c
drivers/pinctrl/tegra/pinctrl-tegra20.c
drivers/pinctrl/tegra/pinctrl-tegra210.c
drivers/pinctrl/tegra/pinctrl-tegra30.c
drivers/pinctrl/uniphier/Kconfig
drivers/pinctrl/uniphier/Makefile
drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c [new file with mode: 0644]
drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c [new file with mode: 0644]
drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c
drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c
drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c
drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c
drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c
drivers/pinctrl/uniphier/pinctrl-uniphier.h
drivers/remoteproc/Kconfig
drivers/remoteproc/Makefile
drivers/remoteproc/qcom_mdt_loader.c [new file with mode: 0644]
drivers/remoteproc/qcom_mdt_loader.h [new file with mode: 0644]
drivers/remoteproc/qcom_q6v5_pil.c [new file with mode: 0644]
drivers/remoteproc/remoteproc_core.c
drivers/s390/block/dcssblk.c
drivers/scsi/qla2xxx/qla_nx.h
drivers/staging/android/lowmemorykiller.c
drivers/staging/lustre/lustre/llite/statahead.c
drivers/staging/lustre/lustre/osc/osc_cache.c
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/usbled.c [deleted file]
drivers/vfio/pci/vfio_pci.c
drivers/vfio/pci/vfio_pci_private.h
drivers/vfio/platform/vfio_amba.c
drivers/vfio/platform/vfio_platform.c
drivers/vfio/platform/vfio_platform_common.c
drivers/vfio/platform/vfio_platform_private.h
drivers/vfio/vfio.c
fs/9p/fid.h
fs/9p/vfs_addr.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/adfs/dir.c
fs/affs/namei.c
fs/autofs4/waitq.c
fs/binfmt_misc.c
fs/block_dev.c
fs/cachefiles/proc.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/inode.c
fs/cifs/smb2ops.c
fs/coda/pioctl.c
fs/configfs/file.c
fs/dax.c
fs/dcache.c
fs/debugfs/inode.c
fs/efivarfs/super.c
fs/ext4/mballoc.c
fs/ext4/sysfs.c
fs/f2fs/super.c
fs/fat/inode.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/freevxfs/Kconfig
fs/freevxfs/vxfs.h
fs/freevxfs/vxfs_bmap.c
fs/freevxfs/vxfs_dir.h
fs/freevxfs/vxfs_extern.h
fs/freevxfs/vxfs_fshead.c
fs/freevxfs/vxfs_fshead.h
fs/freevxfs/vxfs_inode.c
fs/freevxfs/vxfs_inode.h
fs/freevxfs/vxfs_lookup.c
fs/freevxfs/vxfs_olt.c
fs/freevxfs/vxfs_olt.h
fs/freevxfs/vxfs_super.c
fs/fs-writeback.c
fs/fscache/histogram.c
fs/fscache/object-list.c
fs/fscache/stats.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/hfs/inode.c
fs/hfs/string.c
fs/hfsplus/inode.c
fs/hfsplus/unicode.c
fs/hpfs/dentry.c
fs/ioctl.c
fs/isofs/compress.c
fs/isofs/inode.c
fs/jffs2/dir.c
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/summary.c
fs/jffs2/write.c
fs/jfs/jfs_debug.c
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_metapage.c
fs/jfs/jfs_txnmgr.c
fs/jfs/jfs_xtree.c
fs/jfs/namei.c
fs/kernfs/dir.c
fs/lockd/procfs.c
fs/logfs/dir.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/internal.h
fs/nfs/nfs4trace.h
fs/nfs/nfstrace.h
fs/nfs/write.c
fs/nfsd/nfsctl.c
fs/nfsd/stats.c
fs/ntfs/inode.c
fs/ntfs/namei.c
fs/ocfs2/aops.c
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/quota_global.c
fs/ocfs2/xattr.c
fs/open.c
fs/orangefs/inode.c
fs/orangefs/namei.c
fs/orangefs/orangefs-kernel.h
fs/orangefs/symlink.c
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c
fs/proc/base.c
fs/proc/meminfo.c
fs/proc/proc_sysctl.c
fs/quota/dquot.c
fs/sysv/namei.c
fs/tracefs/inode.c
fs/ufs/dir.c
fs/xfs/xfs_stats.c
include/dt-bindings/pinctrl/stm32f746-pinfunc.h [new file with mode: 0644]
include/linux/backing-dev.h
include/linux/blkdev.h
include/linux/compaction.h
include/linux/compiler.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/fsnotify_backend.h
include/linux/ftrace.h
include/linux/gfp.h
include/linux/huge_mm.h
include/linux/kasan.h
include/linux/kdb.h
include/linux/libnvdimm.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/memremap.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/mm_types.h
include/linux/mmzone.h
include/linux/namei.h
include/linux/nd.h
include/linux/oom.h
include/linux/pfn_t.h
include/linux/pinctrl/pinconf-generic.h
include/linux/pmem.h
include/linux/quota.h
include/linux/sched.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/stringhash.h
include/linux/sunrpc/svcauth.h
include/linux/swap.h
include/linux/topology.h
include/linux/vm_event_item.h
include/linux/vmstat.h
include/linux/wait.h
include/linux/writeback.h
include/ras/ras_event.h
include/trace/events/compaction.h
include/trace/events/mmflags.h
include/trace/events/printk.h
include/trace/events/vmscan.h
include/trace/events/writeback.h
include/trace/perf.h
include/trace/trace_events.h
include/uapi/linux/ndctl.h
init/Kconfig
kernel/cpuset.c
kernel/fork.c
kernel/freezer.c
kernel/memremap.c
kernel/power/snapshot.c
kernel/printk/printk.c
kernel/sysctl.c
kernel/trace/Kconfig
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_entries.h
kernel/trace/trace_events.c
kernel/trace/trace_functions.c
kernel/trace/trace_functions_graph.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_mmiotrace.c
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
lib/Kconfig.kasan
lib/iov_iter.c
lib/stackdepot.c
lib/test_hash.c
mm/Kconfig
mm/backing-dev.c
mm/compaction.c
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/internal.h
mm/kasan/Makefile
mm/kasan/kasan.c
mm/kasan/kasan.h
mm/kasan/report.c
mm/khugepaged.c
mm/kmemleak.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/mempool.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_idle.c
mm/page_io.c
mm/rmap.c
mm/shmem.c
mm/slab.h
mm/slub.c
mm/sparse.c
mm/swap.c
mm/swap_state.c
mm/util.c
mm/vmscan.c
mm/vmstat.c
mm/workingset.c
mm/zsmalloc.c
net/core/dev.c
samples/Kconfig
samples/Makefile
samples/trace_printk/Makefile [new file with mode: 0644]
samples/trace_printk/trace-printk.c [new file with mode: 0644]
scripts/checkpatch.pl
security/inode.c
security/smack/smack_access.c
security/tomoyo/memory.c
security/tomoyo/util.c
sound/soc/codecs/max9877.h
tools/objtool/arch/x86/insn/x86-opcode-map.txt
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/builtin-kmem.c
tools/perf/util/intel-pt-decoder/x86-opcode-map.txt
tools/testing/nvdimm/Kbuild
tools/testing/nvdimm/config_check.c
tools/testing/nvdimm/pmem-dax.c [new file with mode: 0644]
tools/testing/nvdimm/test/Kbuild
tools/testing/nvdimm/test/iomap.c
tools/testing/nvdimm/test/nfit.c
tools/testing/nvdimm/test/nfit_test.h

index 5be8a7f4cc7f0e0e181143ed0af847a489045de3..026d13362acaaf3fd620fdbfed1dd880ab10cb56 100644 (file)
@@ -1024,8 +1024,7 @@ could be on demand. For example wait_on_buffer sets the unplugging going
 through sync_buffer() running blk_run_address_space(mapping). Or the caller
 can do it explicity through blk_unplug(bdev). So in the read case,
 the queue gets explicitly unplugged as part of waiting for completion on that
-buffer. For page driven IO, the address space ->sync_page() takes care of
-doing the blk_run_address_space().
+buffer.
 
 Aside:
   This is kind of controversial territory, as it's not clear if plugging is
index 8870b02121502430a420e129b61e7d887ee0c762..78a8c2963b38816b152cb07c0f6b82a953b32eaa 100644 (file)
@@ -107,9 +107,9 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
 
 8. LRU
         Each memcg has its own private LRU. Now, its handling is under global
-       VM's control (means that it's handled under global zone->lru_lock).
+       VM's control (means that it's handled under global zone_lru_lock).
        Almost all routines around memcg's LRU is called by global LRU's
-       list management functions under zone->lru_lock().
+       list management functions under zone_lru_lock().
 
        A special function is mem_cgroup_isolate_pages(). This scans
        memcg's private LRU and call __isolate_lru_page() to extract a page
index b14abf217239e892e19cd9f8c6366e3646ee640f..946e69103cdd78134d2071483aa12b22c699e670 100644 (file)
@@ -267,11 +267,11 @@ When oom event notifier is registered, event will be delivered.
    Other lock order is following:
    PG_locked.
    mm->page_table_lock
-       zone->lru_lock
+       zone_lru_lock
          lock_page_cgroup.
   In many cases, just lock_page_cgroup() is called.
   per-zone-per-cgroup LRU (cgroup's private LRU) is just guarded by
-  zone->lru_lock, it has no lock of its own.
+  zone_lru_lock, it has no lock of its own.
 
 2.7 Kernel Memory Extension (CONFIG_MEMCG_KMEM)
 
diff --git a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt
new file mode 100644 (file)
index 0000000..217a90e
--- /dev/null
@@ -0,0 +1,24 @@
+* Marvell XOR v2 engines
+
+Required properties:
+- compatible: one of the following values:
+    "marvell,armada-7k-xor"
+    "marvell,xor-v2"
+- reg: Should contain registers location and length (two sets)
+    the first set is the DMA registers
+    the second set is the global registers
+- msi-parent: Phandle to the MSI-capable interrupt controller used for
+  interrupts.
+
+Optional properties:
+- clocks: Optional reference to the clock used by the XOR engine.
+
+Example:
+
+       xor0@400000 {
+               compatible = "marvell,xor-v2";
+               reg = <0x400000 0x1000>,
+                     <0x410000 0x1000>;
+               msi-parent = <&gic_v2m0>;
+               dma-coherent;
+       };
index 3cf0072d3141962342f56df2f251ffbeb094879d..a2b8bfaec43cc12654175f22494e3ddbd8f818cf 100644 (file)
@@ -1,46 +1,96 @@
+Xilinx AXI VDMA engine, it does transfers between memory and video devices.
+It can be configured to have one channel or two channels. If configured
+as two channels, one is to transmit to the video device and another is
+to receive from the video device.
+
 Xilinx AXI DMA engine, it does transfers between memory and AXI4 stream
 target devices. It can be configured to have one channel or two channels.
 If configured as two channels, one is to transmit to the device and another
 is to receive from the device.
 
+Xilinx AXI CDMA engine, it does transfers between memory-mapped source
+address and a memory-mapped destination address.
+
 Required properties:
-- compatible: Should be "xlnx,axi-dma-1.00.a"
+- compatible: Should be "xlnx,axi-vdma-1.00.a" or "xlnx,axi-dma-1.00.a" or
+             "xlnx,axi-cdma-1.00.a""
 - #dma-cells: Should be <1>, see "dmas" property below
-- reg: Should contain DMA registers location and length.
+- reg: Should contain VDMA registers location and length.
+- xlnx,addrwidth: Should be the vdma addressing size in bits(ex: 32 bits).
+- dma-ranges: Should be as the following <dma_addr cpu_addr max_len>.
 - dma-channel child node: Should have at least one channel and can have up to
        two channels per device. This node specifies the properties of each
        DMA channel (see child node properties below).
+- clocks: Input clock specifier. Refer to common clock bindings.
+- clock-names: List of input clocks
+       For VDMA:
+       Required elements: "s_axi_lite_aclk"
+       Optional elements: "m_axi_mm2s_aclk" "m_axi_s2mm_aclk",
+                          "m_axis_mm2s_aclk", "s_axis_s2mm_aclk"
+       For CDMA:
+       Required elements: "s_axi_lite_aclk", "m_axi_aclk"
+       FOR AXIDMA:
+       Required elements: "s_axi_lite_aclk"
+       Optional elements: "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
+                          "m_axi_sg_aclk"
+
+Required properties for VDMA:
+- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w.
 
 Optional properties:
-- xlnx,include-sg: Tells whether configured for Scatter-mode in
+- xlnx,include-sg: Tells configured for Scatter-mode in
        the hardware.
+Optional properties for AXI DMA:
+- 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:
+       {1}, flush both channels
+       {2}, flush mm2s channel
+       {3}, flush s2mm channel
 
 Required child node properties:
-- compatible: It should be either "xlnx,axi-dma-mm2s-channel" or
+- compatible:
+       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".
-- interrupts: Should contain per channel DMA interrupts.
+- interrupts: Should contain per channel VDMA interrupts.
 - xlnx,datawidth: Should contain the stream data width, take values
        {32,64...1024}.
 
-Option child node properties:
-- xlnx,include-dre: Tells whether hardware is configured for Data
+Optional child node properties:
+- xlnx,include-dre: Tells hardware is configured for Data
        Realignment Engine.
+Optional child node properties for VDMA:
+- xlnx,genlock-mode: Tells Genlock synchronization is
+       enabled/disabled in hardware.
+Optional child node properties for AXI DMA:
+-dma-channels: Number of dma channels in child node.
 
 Example:
 ++++++++
 
-axi_dma_0: axidma@40400000 {
-       compatible = "xlnx,axi-dma-1.00.a";
+axi_vdma_0: axivdma@40030000 {
+       compatible = "xlnx,axi-vdma-1.00.a";
        #dma_cells = <1>;
-       reg = < 0x40400000 0x10000 >;
-       dma-channel@40400000 {
-               compatible = "xlnx,axi-dma-mm2s-channel";
-               interrupts = < 0 59 4 >;
+       reg = < 0x40030000 0x10000 >;
+       dma-ranges = <0x00000000 0x00000000 0x40000000>;
+       xlnx,num-fstores = <0x8>;
+       xlnx,flush-fsync = <0x1>;
+       xlnx,addrwidth = <0x20>;
+       clocks = <&clk 0>, <&clk 1>, <&clk 2>, <&clk 3>, <&clk 4>;
+       clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
+                     "m_axis_mm2s_aclk", "s_axis_s2mm_aclk";
+       dma-channel@40030000 {
+               compatible = "xlnx,axi-vdma-mm2s-channel";
+               interrupts = < 0 54 4 >;
                xlnx,datawidth = <0x40>;
        } ;
-       dma-channel@40400030 {
-               compatible = "xlnx,axi-dma-s2mm-channel";
-               interrupts = < 0 58 4 >;
+       dma-channel@40030030 {
+               compatible = "xlnx,axi-vdma-s2mm-channel";
+               interrupts = < 0 53 4 >;
                xlnx,datawidth = <0x40>;
        } ;
 } ;
@@ -49,7 +99,7 @@ axi_dma_0: axidma@40400000 {
 * DMA client
 
 Required properties:
-- dmas: a list of <[DMA device phandle] [Channel ID]> pairs,
+- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs,
        where Channel ID is '0' for write/tx and '1' for read/rx
        channel.
 - dma-names: a list of DMA channel names, one per "dmas" entry
@@ -57,9 +107,9 @@ Required properties:
 Example:
 ++++++++
 
-dmatest_0: dmatest@0 {
-       compatible ="xlnx,axi-dma-test-1.00.a";
-       dmas = <&axi_dma_0 0
-               &axi_dma_0 1>;
-       dma-names = "dma0", "dma1";
+vdmatest_0: vdmatest@0 {
+       compatible ="xlnx,axi-vdma-test-1.00.a";
+       dmas = <&axi_vdma_0 0
+               &axi_vdma_0 1>;
+       dma-names = "vdma0", "vdma1";
 } ;
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
deleted file mode 100644 (file)
index a1f2683..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-Xilinx AXI VDMA engine, it does transfers between memory and video devices.
-It can be configured to have one channel or two channels. If configured
-as two channels, one is to transmit to the video device and another is
-to receive from the video device.
-
-Xilinx AXI DMA engine, it does transfers between memory and AXI4 stream
-target devices. It can be configured to have one channel or two channels.
-If configured as two channels, one is to transmit to the device and another
-is to receive from the device.
-
-Xilinx AXI CDMA engine, it does transfers between memory-mapped source
-address and a memory-mapped destination address.
-
-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""
-- #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).
-- dma-ranges: Should be as the following <dma_addr cpu_addr max_len>.
-- dma-channel child node: Should have at least one channel and can have up to
-       two channels per device. This node specifies the properties of each
-       DMA channel (see child node properties below).
-- clocks: Input clock specifier. Refer to common clock bindings.
-- clock-names: List of input clocks
-       For VDMA:
-       Required elements: "s_axi_lite_aclk"
-       Optional elements: "m_axi_mm2s_aclk" "m_axi_s2mm_aclk",
-                          "m_axis_mm2s_aclk", "s_axis_s2mm_aclk"
-       For CDMA:
-       Required elements: "s_axi_lite_aclk", "m_axi_aclk"
-       FOR AXIDMA:
-       Required elements: "s_axi_lite_aclk"
-       Optional elements: "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
-                          "m_axi_sg_aclk"
-
-Required properties for VDMA:
-- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w.
-
-Optional properties:
-- xlnx,include-sg: Tells configured for Scatter-mode in
-       the hardware.
-Optional properties for VDMA:
-- xlnx,flush-fsync: Tells which channel to Flush on Frame sync.
-       It takes following values:
-       {1}, flush both channels
-       {2}, flush mm2s channel
-       {3}, flush s2mm channel
-
-Required child node properties:
-- compatible: It should be either "xlnx,axi-vdma-mm2s-channel" or
-       "xlnx,axi-vdma-s2mm-channel".
-- interrupts: Should contain per channel VDMA interrupts.
-- xlnx,datawidth: Should contain the stream data width, take values
-       {32,64...1024}.
-
-Optional child node properties:
-- xlnx,include-dre: Tells hardware is configured for Data
-       Realignment Engine.
-Optional child node properties for VDMA:
-- xlnx,genlock-mode: Tells Genlock synchronization is
-       enabled/disabled in hardware.
-
-Example:
-++++++++
-
-axi_vdma_0: axivdma@40030000 {
-       compatible = "xlnx,axi-vdma-1.00.a";
-       #dma_cells = <1>;
-       reg = < 0x40030000 0x10000 >;
-       dma-ranges = <0x00000000 0x00000000 0x40000000>;
-       xlnx,num-fstores = <0x8>;
-       xlnx,flush-fsync = <0x1>;
-       xlnx,addrwidth = <0x20>;
-       clocks = <&clk 0>, <&clk 1>, <&clk 2>, <&clk 3>, <&clk 4>;
-       clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
-                     "m_axis_mm2s_aclk", "s_axis_s2mm_aclk";
-       dma-channel@40030000 {
-               compatible = "xlnx,axi-vdma-mm2s-channel";
-               interrupts = < 0 54 4 >;
-               xlnx,datawidth = <0x40>;
-       } ;
-       dma-channel@40030030 {
-               compatible = "xlnx,axi-vdma-s2mm-channel";
-               interrupts = < 0 53 4 >;
-               xlnx,datawidth = <0x40>;
-       } ;
-} ;
-
-
-* DMA client
-
-Required properties:
-- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs,
-       where Channel ID is '0' for write/tx and '1' for read/rx
-       channel.
-- dma-names: a list of DMA channel names, one per "dmas" entry
-
-Example:
-++++++++
-
-vdmatest_0: vdmatest@0 {
-       compatible ="xlnx,axi-vdma-test-1.00.a";
-       dmas = <&axi_vdma_0 0
-               &axi_vdma_0 1>;
-       dma-names = "vdma0", "vdma1";
-} ;
diff --git a/Documentation/devicetree/bindings/dma/xilinx/zynqmp_dma.txt b/Documentation/devicetree/bindings/dma/xilinx/zynqmp_dma.txt
new file mode 100644 (file)
index 0000000..a784cdd
--- /dev/null
@@ -0,0 +1,27 @@
+Xilinx ZynqMP DMA engine, it does support memory to memory transfers,
+memory to device and device to memory transfers. It also has flow
+control and rate control support for slave/peripheral dma access.
+
+Required properties:
+- compatible           : Should be "xlnx,zynqmp-dma-1.0"
+- reg                  : Memory map for gdma/adma module access.
+- interrupt-parent     : Interrupt controller the interrupt is routed through
+- interrupts           : Should contain DMA channel interrupt.
+- xlnx,bus-width       : Axi buswidth in bits. Should contain 128 or 64
+- clock-names          : List of input clocks "clk_main", "clk_apb"
+                         (see clock bindings for details)
+
+Optional properties:
+- dma-coherent         : Present if dma operations are coherent.
+
+Example:
+++++++++
+fpd_dma_chan1: dma@fd500000 {
+       compatible = "xlnx,zynqmp-dma-1.0";
+       reg = <0x0 0xFD500000 0x1000>;
+       interrupt-parent = <&gic>;
+       interrupts = <0 117 4>;
+       clock-names = "clk_main", "clk_apb";
+       xlnx,bus-width = <128>;
+       dma-coherent;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_oxnas.txt b/Documentation/devicetree/bindings/gpio/gpio_oxnas.txt
new file mode 100644 (file)
index 0000000..928ed4f
--- /dev/null
@@ -0,0 +1,47 @@
+* Oxford Semiconductor OXNAS SoC GPIO Controller
+
+Please refer to gpio.txt for generic information regarding GPIO bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox810se-gpio"
+ - reg: Base address and length for the device.
+ - interrupts: The port interrupt shared by all pins.
+ - gpio-controller: Marks the port as GPIO controller.
+ - #gpio-cells: Two. The first cell is the pin number and
+   the second cell is used to specify the gpio polarity as defined in
+   defined in <dt-bindings/gpio/gpio.h>:
+      0 = GPIO_ACTIVE_HIGH
+      1 = GPIO_ACTIVE_LOW
+ - interrupt-controller: Marks the device node as an interrupt controller.
+ - #interrupt-cells: Two. The first cell is the GPIO number and second cell
+   is used to specify the trigger type as defined in
+   <dt-bindings/interrupt-controller/irq.h>:
+      IRQ_TYPE_EDGE_RISING
+      IRQ_TYPE_EDGE_FALLING
+      IRQ_TYPE_EDGE_BOTH
+ - gpio-ranges: Interaction with the PINCTRL subsystem, it also specifies the
+   gpio base and count, should be in the format of numeric-gpio-range as
+   specified in the gpio.txt file.
+
+Example:
+
+gpio0: gpio@0 {
+       compatible = "oxsemi,ox810se-gpio";
+       reg = <0x000000 0x100000>;
+       interrupts = <21>;
+       #gpio-cells = <2>;
+       gpio-controller;
+       interrupt-controller;
+       #interrupt-cells = <2>;
+       gpio-ranges = <&pinctrl 0 0 32>;
+};
+
+keys {
+       ...
+
+       button-esc {
+               label = "ESC";
+               linux,code = <1>;
+               gpios = <&gpio0 12 0>;
+       };
+};
index e4277921f3e30a6dd8e883434eb733d59d4e34dc..a73cbeb0f309dea99c3823bc1d79898f89285bcd 100644 (file)
@@ -3,8 +3,22 @@ Broadcom iProc GPIO/PINCONF Controller
 Required properties:
 
 - compatible:
-    Must be "brcm,cygnus-ccm-gpio", "brcm,cygnus-asiu-gpio",
-    "brcm,cygnus-crmu-gpio" or "brcm,iproc-gpio"
+    "brcm,iproc-gpio" for the generic iProc based GPIO controller IP that
+    supports full-featured pinctrl and GPIO functions used in various iProc
+    based SoCs
+
+    May contain an SoC-specific compatibility string to accommodate any
+    SoC-specific features
+
+    "brcm,cygnus-ccm-gpio", "brcm,cygnus-asiu-gpio", or
+    "brcm,cygnus-crmu-gpio" for Cygnus SoCs
+
+    "brcm,iproc-nsp-gpio" for the iProc NSP SoC that has drive strength support
+    disabled
+
+    "brcm,iproc-stingray-gpio" for the iProc Stingray SoC that has the general
+    pinctrl support completely disabled in this IP block. In Stingray, a
+    different IP block is used to handle pinctrl related functions
 
 - reg:
     Define the base and range of the I/O address space that contains SoC
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,nsp-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/brcm,nsp-pinmux.txt
new file mode 100644 (file)
index 0000000..603564e
--- /dev/null
@@ -0,0 +1,79 @@
+Broadcom NSP (Northstar plus) IOMUX Controller
+
+The NSP IOMUX controller supports group based mux configuration. In
+addition, certain pins can be muxed to GPIO function individually.
+
+Required properties:
+- compatible:
+    Must be "brcm,nsp-pinmux"
+
+- reg:
+    Should contain the register physical address and length for each of
+    GPIO_CONTROL0, GP_AUX_SEL and IPROC_CONFIG IOMUX registers
+
+Properties in subnodes:
+- function:
+    The mux function to select
+
+- groups:
+    The list of groups to select with a given function
+
+For more details, refer to
+Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+For example:
+
+       pinmux: pinmux@1803f1c0 {
+               compatible = "brcm,nsp-pinmux";
+               reg = <0x1803f1c0 0x04>,
+                     <0x18030028 0x04>,
+                     <0x1803f408 0x04>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm &gpio_b &nand_sel>;
+
+               pwm: pwm {
+                       function = "pwm";
+                       groups = "pwm0_grp", "pwm1_grp";
+               };
+
+               gpio_b: gpio_b {
+                       function = "gpio_b";
+                       groups = "gpio_b_0_grp", "gpio_b_1_grp";
+               };
+
+               nand_sel: nand_sel {
+                       function = "nand";
+                       groups = "nand_grp";
+               };
+       };
+
+List of supported functions and groups in Northstar Plus:
+
+"spi": "spi_grp"
+
+"i2c": "i2c_grp"
+
+"mdio": "mdio_grp"
+
+"pwm": "pwm0_grp", "pwm1_grp", "pwm2_grp", "pwm3_grp"
+
+"gpio_b": "gpio_b_0_grp", "gpio_b_1_grp", "gpio_b_2_grp", "gpio_b_3_grp"
+
+"uart1": "uart1_grp"
+
+"uart2": "uart2_grp"
+
+"synce": "synce_grp"
+
+"sata_led_grps": "sata0_led_grp", "sata1_led_grp"
+
+"xtal_out": "xtal_out_grp"
+
+"sdio": "sdio_pwr_grp", "sdio_1p8v_grp"
+
+"switch_led": "switch_p05_led0_grp", "switch_p05_led1_grp"
+
+"nand": "nand_grp"
+
+"emmc": "emmc_grp"
diff --git a/Documentation/devicetree/bindings/pinctrl/oxnas,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/oxnas,pinctrl.txt
new file mode 100644 (file)
index 0000000..d607432
--- /dev/null
@@ -0,0 +1,57 @@
+* Oxford Semiconductor OXNAS SoC Family Pin Controller
+
+Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and
+../interrupt-controller/interrupts.txt for generic information regarding
+pin controller, GPIO, and interrupt bindings.
+
+OXNAS 'pin configuration node' is a node of a group of pins which can be
+used for a specific device or function. This node represents configurations of
+pins, optional function, and optional mux related configuration.
+
+Required properties for pin controller node:
+ - compatible: "oxsemi,ox810se-pinctrl"
+ - oxsemi,sys-ctrl: a phandle to the system controller syscon node
+
+Required properties for pin configuration sub-nodes:
+ - pins: List of pins to which the configuration applies.
+
+Optional properties for pin configuration sub-nodes:
+----------------------------------------------------
+ - function: Mux function for the specified pins.
+ - bias-pull-up: Enable weak pull-up.
+
+Example:
+
+pinctrl: pinctrl {
+       compatible = "oxsemi,ox810se-pinctrl";
+
+       /* Regmap for sys registers */
+       oxsemi,sys-ctrl = <&sys>;
+
+       pinctrl_uart2: pinctrl_uart2 {
+               uart2a {
+                       pins = "gpio31";
+                       function = "fct3";
+               };
+               uart2b {
+                       pins = "gpio32";
+                       function = "fct3";
+               };
+       };
+};
+
+uart2: serial@900000 {
+       compatible = "ns16550a";
+       reg = <0x900000 0x100000>;
+       clocks = <&sysclk>;
+       interrupts = <29>;
+       reg-shift = <0>;
+       fifo-size = <16>;
+       reg-io-width = <1>;
+       current-speed = <115200>;
+       no-loopback-test;
+       status = "disabled";
+       resets = <&reset 22>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-max77620.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-max77620.txt
new file mode 100644 (file)
index 0000000..ad4fce3
--- /dev/null
@@ -0,0 +1,127 @@
+Pincontrol driver for MAX77620 Power management IC from Maxim Semiconductor.
+
+Device has 8 GPIO pins which can be configured as GPIO as well as the
+special IO functions.
+
+Please refer file <devicetree/bindings/pinctrl/pinctrl-bindings.txt>
+for details of the common pinctrl bindings used by client devices,
+including the meaning of the phrase "pin configuration node".
+
+Optional Pinmux properties:
+--------------------------
+Following properties are required if default setting of pins are required
+at boot.
+- pinctrl-names: A pinctrl state named per <pinctrl-binding.txt>.
+- pinctrl[0...n]: Properties to contain the phandle for pinctrl states per
+               <pinctrl-binding.txt>.
+
+The pin configurations are defined as child of the pinctrl states node. Each
+sub-node have following properties:
+
+Required properties:
+------------------
+- pins: List of pins. Valid values of pins properties are:
+                     gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, gpio6, gpio7.
+
+Optional properties:
+-------------------
+Following are optional properties defined as pinmux DT binding document
+<pinctrl-bindings.txt>. Absence of properties will leave the configuration
+on default.
+       function,
+       drive-push-pull,
+       drive-open-drain,
+       bias-pull-up,
+       bias-pull-down.
+
+Valid values for function properties are:
+       gpio, lpm-control-in, fps-out, 32k-out, sd0-dvs-in, sd1-dvs-in,
+       reference-out
+
+Theres is also customised properties for the GPIO1, GPIO2 and GPIO3. These
+customised properties are required to configure FPS configuration parameters
+of these GPIOs. Please refer <devicetree/bindings/mfd/max77620.txt> for more
+detail of Flexible Power Sequence (FPS).
+
+- maxim,active-fps-source:             FPS source for the GPIOs to get
+                                       enabled/disabled when system is in
+                                       active state.  Valid values are:
+                                       - MAX77620_FPS_SRC_0,
+                                               FPS source is FPS0.
+                                       - MAX77620_FPS_SRC_1,
+                                               FPS source is FPS1
+                                       - MAX77620_FPS_SRC_2 and
+                                               FPS source is FPS2
+                                       - MAX77620_FPS_SRC_NONE.
+                                               GPIO is not controlled
+                                               by FPS events and it gets
+                                               enabled/disabled by register
+                                               access.
+                                       Absence of this property will leave
+                                       the FPS configuration register for that
+                                       GPIO to default configuration.
+
+- maxim,active-fps-power-up-slot:      Sequencing event slot number on which
+                                       the GPIO get enabled when
+                                       master FPS input event set to HIGH.
+                                       Valid values are 0 to 7.
+                                       This is applicable if FPS source is
+                                       selected as FPS0, FPS1 or FPS2.
+
+- maxim,active-fps-power-down-slot:    Sequencing event slot number on which
+                                       the GPIO get disabled when master
+                                       FPS input event set to LOW.
+                                       Valid values are 0 to 7.
+                                       This is applicable if FPS source is
+                                       selected as FPS0, FPS1 or FPS2.
+
+- maxim,suspend-fps-source:            This is same as property
+                                       "maxim,active-fps-source" but value
+                                       get configured when system enters in
+                                       to suspend state.
+
+- maxim,suspend-fps-power-up-slot:     This is same as property
+                                       "maxim,active-fps-power-up-slot" but
+                                       this value get configured into FPS
+                                       configuration register when system
+                                       enters into suspend.
+                                       This is applicable if suspend state
+                                       FPS source is selected as FPS0, FPS1 or
+
+- maxim,suspend-fps-power-down-slot:   This is same as property
+                                       "maxim,active-fps-power-down-slot" but
+                                       this value get configured into FPS
+                                       configuration register when system
+                                       enters into suspend.
+                                       This is applicable if suspend state
+                                       FPS source is selected as FPS0, FPS1 or
+                                       FPS2.
+
+Example:
+--------
+#include <dt-bindings/mfd/max77620.h>
+...
+max77620@3c {
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&spmic_default>;
+
+       spmic_default: pinmux@0 {
+               pin_gpio0 {
+                       pins = "gpio0";
+                       function = "gpio";
+               };
+
+               pin_gpio1 {
+                       pins = "gpio1";
+                       function = "fps-out";
+                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+               };
+
+               pin_gpio2 {
+                       pins = "gpio2";
+                       function = "fps-out";
+                       maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.txt
new file mode 100644 (file)
index 0000000..1b52f01
--- /dev/null
@@ -0,0 +1,152 @@
+Qualcomm MDM9615 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MDM9615 platform.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be "qcom,mdm9615-pinctrl"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+       Usage: required
+       Value type: <none>
+       Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 2. Specifying the pin number and flags, as defined
+                   in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+       Usage: required
+       Value type: <none>
+       Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 2. Specifying the pin number and flags, as defined
+                   in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+       Usage: required
+       Value type: <string-array>
+       Definition: List of gpio pins affected by the properties specified in
+                   this subnode.  Valid pins are:
+                   gpio0-gpio87
+
+- function:
+       Usage: required
+       Value type: <string>
+       Definition: Specify the alternative function to be configured for the
+                   specified pins.
+                   Valid values are:
+                   gpio, gsbi2_i2c, gsbi3, gsbi4, gsbi5_i2c, gsbi5_uart,
+                   sdc2, ebi2_lcdc, ps_hold, prim_audio, sec_audio,
+                   cdc_mclk
+
+- bias-disable:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as pull up.
+
+- output-high:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins are configured in output mode, driven
+                   high.
+
+- output-low:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins are configured in output mode, driven
+                   low.
+
+- drive-strength:
+       Usage: optional
+       Value type: <u32>
+       Definition: Selects the drive strength for the specified pins, in mA.
+                   Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+       msmgpio: pinctrl@800000 {
+               compatible = "qcom,mdm9615-pinctrl";
+               reg = <0x800000 0x4000>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               interrupts = <0 16 0x4>;
+
+               gsbi8_uart: gsbi8-uart {
+                       mux {
+                               pins = "gpio34", "gpio35";
+                               function = "gsbi8";
+                       };
+
+                       tx {
+                               pins = "gpio34";
+                               drive-strength = <4>;
+                               bias-disable;
+                       };
+
+                       rx {
+                               pins = "gpio35";
+                               drive-strength = <2>;
+                               bias-pull-up;
+                       };
+               };
+       };
index 77aa117901638c2831ff412453d752d2aff12e18..df9a838ec5f90c7500e5347a779699b9ba1d2f22 100644 (file)
@@ -52,7 +52,7 @@ Valid values for function are:
   gsbi2_spi_cs3_n, gsbi3, gsbi3_spi_cs1_n, gsbi3_spi_cs2_n, gsbi3_spi_cs3_n,
   gsbi4, gsbi5, gsbi6, gsbi7, gsbi8, gsbi9, gsbi10, gsbi11, gsbi12, hdmi, i2s,
   lcdc, mdp_vsync, mi2s, pcm, ps_hold, sdc1, sdc2, sdc5, tsif1, tsif2, usb_fs1,
-  usb_fs1_oe_n, usb_fs2, usb_fs2_oe_n, vfe, vsens_alarm,
+  usb_fs1_oe_n, usb_fs2, usb_fs2_oe_n, vfe, vsens_alarm, ebi2, ebi2cs
 
 Example:
 
index e4d6a9d20f7d0d82c684356f03397f95872ffe26..453bd7c76d6babe5e17b4696fb018dbdfae35c92 100644 (file)
@@ -49,6 +49,9 @@ Valid values for pins are:
   sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data
     Supports bias and drive-strength
 
+  hsic_data, hsic_strobe
+    Supports only mux
+
 Valid values for function are:
   cci_i2c0, cci_i2c1, uim1, uim2, uim_batt_alarm,
   blsp_uim1, blsp_uart1, blsp_i2c1, blsp_spi1,
@@ -70,7 +73,7 @@ Valid values for function are:
   cam_mckl0, cam_mclk1, cam_mclk2, cam_mclk3, mdp_vsync, hdmi_cec, hdmi_ddc,
   hdmi_hpd, edp_hpd, gp_pdm0, gp_pdm1, gp_pdm2, gp_pdm3, gp0_clk, gp1_clk,
   gp_mn, tsif1, tsif2, hsic, grfc, audio_ref_clk, qua_mi2s, pri_mi2s, spkr_mi2s,
-  ter_mi2s, sec_mi2s, bt, fm, wlan, slimbus, gpio
+  ter_mi2s, sec_mi2s, bt, fm, wlan, slimbus, hsic_ctl, gpio
 
   (Note that this is not yet the complete list of functions)
 
index d74e631e10da1eb35252c97660d7044e1c502941..b484ba1af78c28b6d3224fde46fc81a2fea70934 100644 (file)
@@ -9,6 +9,7 @@ of PMIC's from Qualcomm.
        Definition: Should contain one of:
                    "qcom,pm8018-mpp",
                    "qcom,pm8038-mpp",
+                   "qcom,pm8058-mpp",
                    "qcom,pm8821-mpp",
                    "qcom,pm8841-mpp",
                    "qcom,pm8916-mpp",
index 74e6ec0339d6fb6e3f37d158def03df27f53b863..e4cf022c992ed1892e44ccc5d659ea72434360b3 100644 (file)
@@ -72,7 +72,7 @@ Pin Configuration Node Properties:
 
 The pin configuration parameters use the generic pinconf bindings defined in
 pinctrl-bindings.txt in this directory. The supported parameters are
-bias-disable, bias-pull-up, bias-pull-down, drive strength and power-source. For
+bias-disable, bias-pull-up, bias-pull-down, drive-strength and power-source. For
 pins that have a configurable I/O voltage, the power-source value should be the
 nominal I/O voltage in millivolts.
 
index 7b4800cc251e9b493a77ed5ddb3a13839a292db6..587bffb9cbc668ce5a6821f01b0bed788aaa3c7b 100644 (file)
@@ -9,6 +9,7 @@ Pin controller node:
 Required properies:
  - compatible: value should be one of the following:
    (a) "st,stm32f429-pinctrl"
+   (b) "st,stm32f746-pinctrl"
  - #address-cells: The value of this property must be 1
  - #size-cells : The value of this property must be 1
  - ranges      : defines mapping between pin controller node (parent) to
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
new file mode 100644 (file)
index 0000000..57cb49e
--- /dev/null
@@ -0,0 +1,137 @@
+Qualcomm Hexagon Peripheral Image Loader
+
+This document defines the binding for a component that loads and boots firmware
+on the Qualcomm Hexagon core.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be one of:
+                   "qcom,q6v5-pil"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: must specify the base address and size of the qdsp6 and
+                   rmb register blocks
+
+- reg-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "q6dsp" and "rmb"
+
+- interrupts-extended:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: must list the watchdog, fatal IRQs ready, handover and
+                   stop-ack IRQs
+
+- interrupt-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack"
+
+- clocks:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the iface, bus and mem clocks to be held on
+                   behalf of the booting of the Hexagon core
+
+- clock-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "iface", "bus", "mem"
+
+- resets:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the reset-controller for the modem sub-system
+
+- reset-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "mss_restart"
+
+- cx-supply:
+- mss-supply:
+- mx-supply:
+- pll-supply:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the regulators to be held on behalf of the
+                   booting of the Hexagon core
+
+- qcom,smem-states:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the smem state for requesting the Hexagon to
+                   shut down
+
+- qcom,smem-state-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "stop"
+
+- qcom,halt-regs:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: a phandle reference to a syscon representing TCSR followed
+                   by the three offsets within syscon for q6, modem and nc
+                   halt registers.
+
+= SUBNODES:
+The Hexagon node must contain two subnodes, named "mba" and "mpss" representing
+the memory regions used by the Hexagon firmware. Each sub-node must contain:
+
+- memory-region:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the reserved-memory for the region
+
+= EXAMPLE
+The following example describes the resources needed to boot control the
+Hexagon, as it is found on MSM8974 boards.
+
+       modem-rproc@fc880000 {
+               compatible = "qcom,q6v5-pil";
+               reg = <0xfc880000 0x100>,
+                     <0xfc820000 0x020>;
+               reg-names = "qdsp6", "rmb";
+
+               interrupts-extended = <&intc 0 24 1>,
+                                     <&modem_smp2p_in 0 0>,
+                                     <&modem_smp2p_in 1 0>,
+                                     <&modem_smp2p_in 2 0>,
+                                     <&modem_smp2p_in 3 0>;
+               interrupt-names = "wdog",
+                                 "fatal",
+                                 "ready",
+                                 "handover",
+                                 "stop-ack";
+
+               clocks = <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>,
+                        <&gcc GCC_MSS_CFG_AHB_CLK>,
+                        <&gcc GCC_BOOT_ROM_AHB_CLK>;
+               clock-names = "iface", "bus", "mem";
+
+               qcom,halt-regs = <&tcsr_mutex_block 0x1180 0x1200 0x1280>;
+
+               resets = <&gcc GCC_MSS_RESTART>;
+               reset-names = "mss_restart";
+
+               cx-supply = <&pm8841_s2>;
+               mss-supply = <&pm8841_s3>;
+               mx-supply = <&pm8841_s1>;
+               pll-supply = <&pm8941_l12>;
+
+               qcom,smem-states = <&modem_smp2p_out 0>;
+               qcom,smem-state-names = "stop";
+
+               mba {
+                       memory-region = <&mba_region>;
+               };
+
+               mpss {
+                       memory-region = <&mpss_region>;
+               };
+       };
index 5a7386e38e2d88630682852a2a8a19cff91b8657..1b3c39a7de627f572ece87d2a1c6ddd2cff27144 100644 (file)
@@ -15,11 +15,14 @@ prototypes:
        int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(struct dentry *);
+       int (*d_init)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
        struct vfsmount *(*d_automount)(struct path *path);
        int (*d_manage)(struct dentry *, bool);
+       struct dentry *(*d_real)(struct dentry *, const struct inode *,
+                                unsigned int);
 
 locking rules:
                rename_lock     ->d_lock        may block       rcu-walk
@@ -28,12 +31,14 @@ d_weak_revalidate:no                no              yes             no
 d_hash         no              no              no              maybe
 d_compare:     yes             no              no              maybe
 d_delete:      no              yes             no              no
+d_init:        no              no              yes             no
 d_release:     no              no              yes             no
 d_prune:        no              yes             no              no
 d_iput:                no              no              yes             no
 d_dname:       no              no              no              no
 d_automount:   no              no              yes             no
 d_manage:      no              no              yes (ref-walk)  maybe
+d_real         no              no              yes             no
 
 --------------------------- inode_operations --------------------------- 
 prototypes:
@@ -66,7 +71,6 @@ prototypes:
                                struct file *, unsigned open_flag,
                                umode_t create_mode, int *opened);
        int (*tmpfile) (struct inode *, struct dentry *, umode_t);
-       int (*dentry_open)(struct dentry *, struct file *, const struct cred *);
 
 locking rules:
        all may block
@@ -95,7 +99,6 @@ fiemap:               no
 update_time:   no
 atomic_open:   yes
 tmpfile:       no
-dentry_open:   no
 
        Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
@@ -179,7 +182,6 @@ unlocks and drops the reference.
 prototypes:
        int (*writepage)(struct page *page, struct writeback_control *wbc);
        int (*readpage)(struct file *, struct page *);
-       int (*sync_page)(struct page *);
        int (*writepages)(struct address_space *, struct writeback_control *);
        int (*set_page_dirty)(struct page *page);
        int (*readpages)(struct file *filp, struct address_space *mapping,
@@ -210,7 +212,6 @@ locking rules:
                        PageLocked(page)        i_mutex
 writepage:             yes, unlocks (see below)
 readpage:              yes, unlocks
-sync_page:             maybe
 writepages:
 set_page_dirty         no
 readpages:
@@ -230,8 +231,8 @@ error_remove_page:  yes
 swap_activate:         no
 swap_deactivate:       no
 
-       ->write_begin(), ->write_end(), ->sync_page() and ->readpage()
-may be called from the request handler (/dev/loop).
+       ->write_begin(), ->write_end() and ->readpage() may be called from
+the request handler (/dev/loop).
 
        ->readpage() unlocks the page, either synchronously or via I/O
 completion.
@@ -287,11 +288,6 @@ will leave the page itself marked clean but it will be tagged as dirty in the
 radix tree.  This incoherency can lead to all sorts of hard-to-debug problems
 in the filesystem like having dirty inodes at umount and losing written data.
 
-       ->sync_page() locking rules are not well-defined - usually it is called
-with lock on page, but that is not guaranteed. Considering the currently
-existing instances of this method ->sync_page() itself doesn't look
-well-defined...
-
        ->writepages() is used for periodic writeback and for syscall-initiated
 sync operations.  The address_space should start I/O against at least
 *nr_to_write pages.  *nr_to_write must be decremented for each page which is
@@ -399,7 +395,7 @@ prototypes:
        int (*release) (struct gendisk *, fmode_t);
        int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
-       int (*direct_access) (struct block_device *, sector_t, void __pmem **,
+       int (*direct_access) (struct block_device *, sector_t, void **,
                                unsigned long *);
        int (*media_changed) (struct gendisk *);
        void (*unlock_native_capacity) (struct gendisk *);
index 900360cbcdaed762b597d1d3fe1343c15b907df2..8a196851f01dccf627d3d6582891ea0597b76ce5 100644 (file)
@@ -364,7 +364,6 @@ struct inode_operations {
        int (*atomic_open)(struct inode *, struct dentry *, struct file *,
                        unsigned open_flag, umode_t create_mode, int *opened);
        int (*tmpfile) (struct inode *, struct dentry *, umode_t);
-       int (*dentry_open)(struct dentry *, struct file *, const struct cred *);
 };
 
 Again, all methods are called without any locks being held, unless
@@ -534,9 +533,7 @@ __sync_single_inode) to check if ->writepages has been successful in
 writing out the whole address_space.
 
 The Writeback tag is used by filemap*wait* and sync_page* functions,
-via filemap_fdatawait_range, to wait for all writeback to
-complete.  While waiting ->sync_page (if defined) will be called on
-each page that is found to require writeback.
+via filemap_fdatawait_range, to wait for all writeback to complete.
 
 An address_space handler may attach extra information to a page,
 typically using the 'private' field in the 'struct page'.  If such
@@ -554,8 +551,8 @@ address_space has finer control of write sizes.
 
 The read process essentially only requires 'readpage'.  The write
 process is more complicated and uses write_begin/write_end or
-set_page_dirty to write data into the address_space, and writepage,
-sync_page, and writepages to writeback data to storage.
+set_page_dirty to write data into the address_space, and writepage
+and writepages to writeback data to storage.
 
 Adding and removing pages to/from an address_space is protected by the
 inode's i_mutex.
@@ -701,13 +698,6 @@ struct address_space_operations {
        but instead uses bmap to find out where the blocks in the file
        are and uses those addresses directly.
 
-  dentry_open: *WARNING: probably going away soon, do not use!* This is an
-       alternative to f_op->open(), the difference is that this method may open
-       a file not necessarily originating from the same filesystem as the one
-       i_op->open() was called on.  It may be useful for stacking filesystems
-       which want to allow native I/O directly on underlying files.
-
-
   invalidatepage: If a page has PagePrivate set, then invalidatepage
         will be called when part or all of the page is to be removed
        from the address space.  This generally corresponds to either a
@@ -944,11 +934,14 @@ struct dentry_operations {
        int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
+       int (*d_init)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)(struct dentry *, char *, int);
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(struct dentry *, bool);
+       struct dentry *(*d_real)(struct dentry *, const struct inode *,
+                                unsigned int);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -1014,6 +1007,8 @@ struct dentry_operations {
        always cache a reachable dentry. d_delete must be constant and
        idempotent.
 
+  d_init: called when a dentry is allocated
+
   d_release: called when a dentry is really deallocated
 
   d_iput: called when a dentry loses its inode (just prior to its
@@ -1033,6 +1028,14 @@ struct dentry_operations {
        at the end of the buffer, and returns a pointer to the first char.
        dynamic_dname() helper function is provided to take care of this.
 
+       Example :
+
+       static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
+       {
+               return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
+                               dentry->d_inode->i_ino);
+       }
+
   d_automount: called when an automount dentry is to be traversed (optional).
        This should create a new VFS mount record and return the record to the
        caller.  The caller is supplied with a path parameter giving the
@@ -1071,13 +1074,23 @@ struct dentry_operations {
        This function is only used if DCACHE_MANAGE_TRANSIT is set on the
        dentry being transited from.
 
-Example :
+  d_real: overlay/union type filesystems implement this method to return one of
+       the underlying dentries hidden by the overlay.  It is used in three
+       different modes:
 
-static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
-{
-       return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
-                               dentry->d_inode->i_ino);
-}
+       Called from open it may need to copy-up the file depending on the
+       supplied open flags.  This mode is selected with a non-zero flags
+       argument.  In this mode the d_real method can return an error.
+
+       Called from file_dentry() it returns the real dentry matching the inode
+       argument.  The real dentry may be from a lower layer already copied up,
+       but still referenced from the file.  This mode is selected with a
+       non-NULL inode argument.  This will always succeed.
+
+       With NULL inode and zero flags the topmost real underlying dentry is
+       returned.  This will always succeed.
+
+       This method is never called with both non-NULL inode and non-zero flags.
 
 Each dentry has a pointer to its parent dentry, as well as a hash list
 of child dentries. Child dentries are basically like files in a
diff --git a/Documentation/hid/hid-alps.txt b/Documentation/hid/hid-alps.txt
new file mode 100644 (file)
index 0000000..6b02a24
--- /dev/null
@@ -0,0 +1,139 @@
+ALPS HID Touchpad Protocol
+----------------------
+
+Introduction
+------------
+Currently ALPS HID driver supports U1 Touchpad device.
+
+U1 devuce basic information.
+Vender ID      0x044E
+Product ID     0x120B
+Version ID     0x0121
+
+
+HID Descriptor
+------------
+Byte   Field                   Value   Notes
+0      wHIDDescLength          001E    Length of HID Descriptor : 30 bytes
+2      bcdVersion              0100    Compliant with Version 1.00
+4      wReportDescLength       00B2    Report Descriptor is 178 Bytes (0x00B2)
+6      wReportDescRegister     0002    Identifier to read Report Descriptor
+8      wInputRegister          0003    Identifier to read Input Report
+10     wMaxInputLength         0053    Input Report is 80 Bytes + 2
+12     wOutputRegister         0000    Identifier to read Output Report
+14     wMaxOutputLength        0000    No Output Reports
+16     wCommandRegister        0005    Identifier for Command Register
+18     wDataRegister           0006    Identifier for Data Register
+20     wVendorID               044E    Vendor ID 0x044E
+22     wProductID              120B    Product ID 0x120B
+24     wVersionID              0121    Version 01.21
+26     RESERVED                0000    RESERVED
+
+
+Report ID
+------------
+ReportID-1     (Input Reports) (HIDUsage-Mouse) for TP&SP
+ReportID-2     (Input Reports) (HIDUsage-keyboard) for TP
+ReportID-3     (Input Reports) (Vendor Usage: Max 10 finger data) for TP
+ReportID-4     (Input Reports) (Vendor Usage: ON bit data) for GP
+ReportID-5     (Feature Reports)       Feature Reports
+ReportID-6     (Input Reports) (Vendor Usage: StickPointer data) for SP
+ReportID-7     (Feature Reports)       Flash update (Bootloader)
+
+
+Data pattern
+------------
+Case1  ReportID_1      TP/SP   Relative/Relative
+Case2  ReportID_3      TP      Absolute
+       ReportID_6      SP      Absolute
+
+
+Command Read/Write
+------------------
+To read/write to RAM, need to send a commands to the device.
+The command format is as below.
+
+DataByte(SET_REPORT)
+Byte1  Command Byte
+Byte2  Address - Byte 0 (LSB)
+Byte3  Address - Byte 1
+Byte4  Address - Byte 2
+Byte5  Address - Byte 3 (MSB)
+Byte6  Value Byte
+Byte7  Checksum
+
+Command Byte is read=0xD1/write=0xD2 .
+Address is read/write RAM address.
+Value Byte is writing data when you send the write commands.
+When you read RAM, there is no meaning.
+
+DataByte(GET_REPORT)
+Byte1  Response Byte
+Byte2  Address - Byte 0 (LSB)
+Byte3  Address - Byte 1
+Byte4  Address - Byte 2
+Byte5  Address - Byte 3 (MSB)
+Byte6  Value Byte
+Byte7  Checksum
+
+Read value is stored in Value Byte.
+
+
+Packet Format
+Touchpad data byte
+------------------
+       b7      b6      b5      b4      b3      b2      b1      b0
+1      0       0       SW6     SW5     SW4     SW3     SW2     SW1
+2      0       0       0       Fcv     Fn3     Fn2     Fn1     Fn0
+3      Xa0_7   Xa0_6   Xa0_5   Xa0_4   Xa0_3   Xa0_2   Xa0_1   Xa0_0
+4      Xa0_15  Xa0_14  Xa0_13  Xa0_12  Xa0_11  Xa0_10  Xa0_9   Xa0_8
+5      Ya0_7   Ya0_6   Ya0_5   Ya0_4   Ya0_3   Ya0_2   Ya0_1   Ya0_0
+6      Ya0_15  Ya0_14  Ya0_13  Ya0_12  Ya0_11  Ya0_10  Ya0_9   Ya0_8
+7      LFB0    Zs0_6   Zs0_5   Zs0_4   Zs0_3   Zs0_2   Zs0_1   Zs0_0
+
+8      Xa1_7   Xa1_6   Xa1_5   Xa1_4   Xa1_3   Xa1_2   Xa1_1   Xa1_0
+9      Xa1_15  Xa1_14  Xa1_13  Xa1_12  Xa1_11  Xa1_10  Xa1_9   Xa1_8
+10     Ya1_7   Ya1_6   Ya1_5   Ya1_4   Ya1_3   Ya1_2   Ya1_1   Ya1_0
+11     Ya1_15  Ya1_14  Ya1_13  Ya1_12  Ya1_11  Ya1_10  Ya1_9   Ya1_8
+12     LFB1    Zs1_6   Zs1_5   Zs1_4   Zs1_3   Zs1_2   Zs1_1   Zs1_0
+
+13     Xa2_7   Xa2_6   Xa2_5   Xa2_4   Xa2_3   Xa2_2   Xa2_1   Xa2_0
+14     Xa2_15  Xa2_14  Xa2_13  Xa2_12  Xa2_11  Xa2_10  Xa2_9   Xa2_8
+15     Ya2_7   Ya2_6   Ya2_5   Ya2_4   Ya2_3   Ya2_2   Ya2_1   Ya2_0
+16     Ya2_15  Ya2_14  Ya2_13  Ya2_12  Ya2_11  Ya2_10  Ya2_9   Ya2_8
+17     LFB2    Zs2_6   Zs2_5   Zs2_4   Zs2_3   Zs2_2   Zs2_1   Zs2_0
+
+18     Xa3_7   Xa3_6   Xa3_5   Xa3_4   Xa3_3   Xa3_2   Xa3_1   Xa3_0
+19     Xa3_15  Xa3_14  Xa3_13  Xa3_12  Xa3_11  Xa3_10  Xa3_9   Xa3_8
+20     Ya3_7   Ya3_6   Ya3_5   Ya3_4   Ya3_3   Ya3_2   Ya3_1   Ya3_0
+21     Ya3_15  Ya3_14  Ya3_13  Ya3_12  Ya3_11  Ya3_10  Ya3_9   Ya3_8
+22     LFB3    Zs3_6   Zs3_5   Zs3_4   Zs3_3   Zs3_2   Zs3_1   Zs3_0
+
+23     Xa4_7   Xa4_6   Xa4_5   Xa4_4   Xa4_3   Xa4_2   Xa4_1   Xa4_0
+24     Xa4_15  Xa4_14  Xa4_13  Xa4_12  Xa4_11  Xa4_10  Xa4_9   Xa4_8
+25     Ya4_7   Ya4_6   Ya4_5   Ya4_4   Ya4_3   Ya4_2   Ya4_1   Ya4_0
+26     Ya4_15  Ya4_14  Ya4_13  Ya4_12  Ya4_11  Ya4_10  Ya4_9   Ya4_8
+27     LFB4    Zs4_6   Zs4_5   Zs4_4   Zs4_3   Zs4_2   Zs4_1   Zs4_0
+
+
+SW1-SW6:       SW ON/OFF status
+Xan_15-0(16bit):X Absolute data of the "n"th finger
+Yan_15-0(16bit):Y Absolute data of the "n"th finger
+Zsn_6-0(7bit): Operation area of the "n"th finger
+
+
+StickPointer data byte
+------------------
+       b7      b6      b5      b4      b3      b2      b1      b0
+Byte1  1       1       1       0       1       SW3     SW2     SW1
+Byte2  X7      X6      X5      X4      X3      X2      X1      X0
+Byte3  X15     X14     X13     X12     X11     X10     X9      X8
+Byte4  Y7      Y6      Y5      Y4      Y3      Y2      Y1      Y0
+Byte5  Y15     Y14     Y13     Y12     Y11     Y10     Y9      Y8
+Byte6  Z7      Z6      Z5      Z4      Z3      Z2      Z1      Z0
+Byte7  T&P     Z14     Z13     Z12     Z11     Z10     Z9      Z8
+
+SW1-SW3:       SW ON/OFF status
+Xn_15-0(16bit):X Absolute data
+Yn_15-0(16bit):Y Absolute data
+Zn_14-0(15bit):Z
index b91443f577dcff68aa8961a73d77141ba8a73cd4..e293fb664924faa3494588a27b645ffdf09fdecf 100644 (file)
@@ -256,28 +256,18 @@ If any of these error conditions are encountered, the arena is put into a read
 only state using a flag in the info block.
 
 
-5. In-kernel usage
-==================
+5. Usage
+========
 
-Any block driver that supports byte granularity IO to the storage may register
-with the BTT. It will have to provide the rw_bytes interface in its
-block_device_operations struct:
+The BTT can be set up on any disk (namespace) exposed by the libnvdimm subsystem
+(pmem, or blk mode). The easiest way to set up such a namespace is using the
+'ndctl' utility [1]:
 
-       int (*rw_bytes)(struct gendisk *, void *, size_t, off_t, int rw);
+For example, the ndctl command line to setup a btt with a 4k sector size is:
 
-It may register with the BTT after it adds its own gendisk, using btt_init:
+    ndctl create-namespace -f -e namespace0.0 -m sector -l 4k
 
-       struct btt *btt_init(struct gendisk *disk, unsigned long long rawsize,
-                       u32 lbasize, u8 uuid[], int maxlane);
+See ndctl create-namespace --help for more options.
 
-note that maxlane is the maximum amount of concurrency the driver wishes to
-allow the BTT to use.
-
-The BTT 'disk' appears as a stacked block device that grabs the underlying block
-device in the O_EXCL mode.
-
-When the driver wishes to remove the backing disk, it should similarly call
-btt_fini using the same struct btt* handle that was provided to it by btt_init.
-
-       void btt_fini(struct btt *btt);
+[1]: https://github.com/pmem/ndctl
 
index 4976389e432d4dd5207d65ad7c37d407c00d9d87..0d3b9ce0a0b90575fbeff83bec518139ae609154 100644 (file)
@@ -286,13 +286,13 @@ see the section named "pin control requests from drivers" and
 "drivers needing both pin control and GPIOs" below for details. But in some
 situations a cross-subsystem mapping between pins and GPIOs is needed.
 
-Since the pin controller subsystem have its pinspace local to the pin
-controller we need a mapping so that the pin control subsystem can figure out
-which pin controller handles control of a certain GPIO pin. Since a single
-pin controller may be muxing several GPIO ranges (typically SoCs that have
-one set of pins, but internally several GPIO silicon blocks, each modelled as
-a struct gpio_chip) any number of GPIO ranges can be added to a pin controller
-instance like this:
+Since the pin controller subsystem has its pinspace local to the pin controller
+we need a mapping so that the pin control subsystem can figure out which pin
+controller handles control of a certain GPIO pin. Since a single pin controller
+may be muxing several GPIO ranges (typically SoCs that have one set of pins,
+but internally several GPIO silicon blocks, each modelled as a struct
+gpio_chip) any number of GPIO ranges can be added to a pin controller instance
+like this:
 
 struct gpio_chip chip_a;
 struct gpio_chip chip_b;
@@ -493,12 +493,12 @@ Definitions:
 - The combination of a FUNCTION and a PIN GROUP determine a certain function
   for a certain set of pins. The knowledge of the functions and pin groups
   and their machine-specific particulars are kept inside the pinmux driver,
-  from the outside only the enumerators are known, and the driver core can:
+  from the outside only the enumerators are known, and the driver core can
+  request:
 
-  - Request the name of a function with a certain selector (>= 0)
+  - The name of a function with a certain selector (>= 0)
   - A list of groups associated with a certain function
-  - Request that a certain group in that list to be activated for a certain
-    function
+  - That a certain group in that list to be activated for a certain function
 
   As already described above, pin groups are in turn self-descriptive, so
   the core will retrieve the actual pin range in a certain group from the
@@ -831,7 +831,7 @@ separate memory range only intended for GPIO driving, and the register
 range dealing with pin config and pin multiplexing get placed into a
 different memory range and a separate section of the data sheet.
 
-A flag "strict" in struct pinctrl_desc is available to check and deny
+A flag "strict" in struct pinmux_ops is available to check and deny
 simultaneous access to the same pin from GPIO and pin multiplexing
 consumers on hardware of this type. The pinctrl driver should set this flag
 accordingly.
index d68ea5fc812b0fdffc11085a3966c39d8b6f58e8..ea52ec1f8484353b904431a59f4f2e6cedce5830 100644 (file)
@@ -40,6 +40,7 @@ Synopsis of kprobe_events
   $stackN      : Fetch Nth entry of stack (N >= 0)
   $stack       : Fetch stack address.
   $retval      : Fetch return value.(*)
+  $comm                : Fetch current task comm.
   +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
@@ -62,6 +63,8 @@ offset, and container-size (usually 32). The syntax is;
 
  b<bit-width>@<bit-offset>/<container-size>
 
+For $comm, the default type is "string"; any other type is invalid.
+
 
 Per-Probe Event Filtering
 -------------------------
index f1cf9a34ad9d714cc87f4dcf36b2b996e551403e..72d1cd4f7bf3b2a3098f6b4f87fac3a91c859716 100644 (file)
@@ -36,6 +36,7 @@ Synopsis of uprobe_tracer
    $stackN     : Fetch Nth entry of stack (N >= 0)
    $stack      : Fetch stack address.
    $retval     : Fetch return value.(*)
+   $comm       : Fetch current task comm.
    +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
    NAME=FETCHARG     : Set NAME as the argument name of FETCHARG.
    FETCHARG:TYPE     : Set TYPE as the type of FETCHARG. Currently, basic types
@@ -57,6 +58,8 @@ offset, and container-size (usually 32). The syntax is;
 
  b<bit-width>@<bit-offset>/<container-size>
 
+For $comm, the default type is "string"; any other type is invalid.
+
 
 Event Profiling
 ---------------
index c1739eba622d66b5b021e3ea533b581bf4c5cfc3..febb29c4d0ca5d6cb48c6ae278d45963656d4538 100644 (file)
@@ -5334,8 +5334,9 @@ M:        Bjorn Andersson <bjorn.andersson@linaro.org>
 L:     linux-remoteproc@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/hwspinlock.git
+F:     Documentation/devicetree/bindings/hwlock/
 F:     Documentation/hwspinlock.txt
-F:     drivers/hwspinlock/hwspinlock_*
+F:     drivers/hwspinlock/
 F:     include/linux/hwspinlock.h
 
 HARMONY SOUND DRIVER
@@ -9732,8 +9733,9 @@ M:        Bjorn Andersson <bjorn.andersson@linaro.org>
 L:     linux-remoteproc@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git
 S:     Maintained
-F:     drivers/remoteproc/
+F:     Documentation/devicetree/bindings/remoteproc/
 F:     Documentation/remoteproc.txt
+F:     drivers/remoteproc/
 F:     include/linux/remoteproc.h
 
 REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM
@@ -11440,11 +11442,6 @@ F:     Documentation/thermal/cpu-cooling-api.txt
 F:     drivers/thermal/cpu_cooling.c
 F:     include/linux/cpu_cooling.h
 
-THINGM BLINK(1) USB RGB LED DRIVER
-M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
-S:     Maintained
-F:     drivers/hid/hid-thingm.c
-
 THINKPAD ACPI EXTRAS DRIVER
 M:     Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
 L:     ibm-acpi-devel@lists.sourceforge.net
index d384848478b947bb04004500e9d93ca4e10c3519..393b6159ae924c0758fc4443c85f50b88917fcb2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -620,6 +620,7 @@ include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS  += $(call cc-option,-fno-delete-null-pointer-checks,)
 KBUILD_CFLAGS  += $(call cc-disable-warning,maybe-uninitialized,)
+KBUILD_CFLAGS  += $(call cc-disable-warning,frame-address,)
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
 KBUILD_CFLAGS  += -Os
index 858f98ef7f1ba3b1fd1ccda9298f2484f7749418..0f92d97432a21a705af12efdff99597046b80cd9 100644 (file)
 #define ___DEF (_PAGE_PRESENT | _PAGE_CACHEABLE)
 
 /* Set of bits not changed in pte_modify */
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SPECIAL)
 
 /* More Abbrevaited helpers */
 #define PAGE_U_NONE     __pgprot(___DEF)
index 2ee7a4d758a882a2b4e36cacd74adb280648fced..5f8c0b47045aa55524f555d70b3cc8f424d23ef5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/cpu.h>
 #include <linux/of_fdt.h>
+#include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/cache.h>
 #include <asm/sections.h>
index 73d7e4c75b7dbc9140604b334ab5e22a8cdd7a8d..ab74b5d9186c918b8ec4407b78958a2d208985d0 100644 (file)
@@ -92,7 +92,8 @@ static void *arc_dma_alloc(struct device *dev, size_t size,
 static void arc_dma_free(struct device *dev, size_t size, void *vaddr,
                dma_addr_t dma_handle, struct dma_attrs *attrs)
 {
-       struct page *page = virt_to_page(dma_handle);
+       phys_addr_t paddr = plat_dma_to_phys(dev, dma_handle);
+       struct page *page = virt_to_page(paddr);
        int is_non_coh = 1;
 
        is_non_coh = dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs) ||
index 49b8abd1115c284251557bb745a612bed66c0e1b..f52b7db67fd3485615a6b5420bd79b691b1e80dd 100644 (file)
@@ -49,7 +49,7 @@ EXPORT_SYMBOL(ioremap);
 /*
  * ioremap with access flags
  * Cache semantics wise it is same as ioremap - "forced" uncached.
- * However unline vanilla ioremap which bypasses ARC MMU for addresses in
+ * However unlike vanilla ioremap which bypasses ARC MMU for addresses in
  * ARC hardware uncached region, this one still goes thru the MMU as caller
  * might need finer access control (R/W/X)
  */
index f0636ec949032276be07527f7f7178d068b8f6c4..4c445fb9c189fe1d527c086f87a572f876830d73 100644 (file)
@@ -1186,6 +1186,60 @@ config ARM_ERRATA_773022
          loop buffer may deliver incorrect instructions. This
          workaround disables the loop buffer to avoid the erratum.
 
+config ARM_ERRATA_818325_852422
+       bool "ARM errata: A12: some seqs of opposed cond code instrs => deadlock or corruption"
+       depends on CPU_V7
+       help
+         This option enables the workaround for:
+         - Cortex-A12 818325: Execution of an UNPREDICTABLE STR or STM
+           instruction might deadlock.  Fixed in r0p1.
+         - Cortex-A12 852422: Execution of a sequence of instructions might
+           lead to either a data corruption or a CPU deadlock.  Not fixed in
+           any Cortex-A12 cores yet.
+         This workaround for all both errata involves setting bit[12] of the
+         Feature Register. This bit disables an optimisation applied to a
+         sequence of 2 instructions that use opposing condition codes.
+
+config ARM_ERRATA_821420
+       bool "ARM errata: A12: sequence of VMOV to core registers might lead to a dead lock"
+       depends on CPU_V7
+       help
+         This option enables the workaround for the 821420 Cortex-A12
+         (all revs) erratum. In very rare timing conditions, a sequence
+         of VMOV to Core registers instructions, for which the second
+         one is in the shadow of a branch or abort, can lead to a
+         deadlock when the VMOV instructions are issued out-of-order.
+
+config ARM_ERRATA_825619
+       bool "ARM errata: A12: DMB NSHST/ISHST mixed ... might cause deadlock"
+       depends on CPU_V7
+       help
+         This option enables the workaround for the 825619 Cortex-A12
+         (all revs) erratum. Within rare timing constraints, executing a
+         DMB NSHST or DMB ISHST instruction followed by a mix of Cacheable
+         and Device/Strongly-Ordered loads and stores might cause deadlock
+
+config ARM_ERRATA_852421
+       bool "ARM errata: A17: DMB ST might fail to create order between stores"
+       depends on CPU_V7
+       help
+         This option enables the workaround for the 852421 Cortex-A17
+         (r1p0, r1p1, r1p2) erratum. Under very rare timing conditions,
+         execution of a DMB ST instruction might fail to properly order
+         stores from GroupA and stores from GroupB.
+
+config ARM_ERRATA_852423
+       bool "ARM errata: A17: some seqs of opposed cond code instrs => deadlock or corruption"
+       depends on CPU_V7
+       help
+         This option enables the workaround for:
+         - Cortex-A17 852423: Execution of a sequence of instructions might
+           lead to either a data corruption or a CPU deadlock.  Not fixed in
+           any Cortex-A17 cores yet.
+         This is identical to Cortex-A12 erratum 852422.  It is a separate
+         config option from the A12 erratum due to the way errata are checked
+         for and handled.
+
 endmenu
 
 source "arch/arm/common/Kconfig"
index 274e8a6582f1cd671731d1acbdda6f0f49c358c8..229afaf2058ba4229a8986ba0e4afb1151403431 100644 (file)
@@ -327,6 +327,7 @@ zImage: Image
 
 $(BOOT_TARGETS): vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+       @$(kecho) '  Kernel: $(boot)/$@ is ready'
 
 $(INSTALL_TARGETS):
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
index 5be33a2d59a9d8c685d40e9a4084de8bf374bdb5..bdc1d5af03d2de1d8e35c9dab9d164fb4d006997 100644 (file)
@@ -31,7 +31,7 @@ ifeq ($(CONFIG_XIP_KERNEL),y)
 
 $(obj)/xipImage: vmlinux FORCE
        $(call if_changed,objcopy)
-       @$(kecho) '  Kernel: $@ is ready (physical address: $(CONFIG_XIP_PHYS_ADDR))'
+       @$(kecho) '  Physical Address of xipImage: $(CONFIG_XIP_PHYS_ADDR)'
 
 $(obj)/Image $(obj)/zImage: FORCE
        @echo 'Kernel configured for XIP (CONFIG_XIP_KERNEL=y)'
@@ -46,14 +46,12 @@ $(obj)/xipImage: FORCE
 
 $(obj)/Image: vmlinux FORCE
        $(call if_changed,objcopy)
-       @$(kecho) '  Kernel: $@ is ready'
 
 $(obj)/compressed/vmlinux: $(obj)/Image FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
        $(call if_changed,objcopy)
-       @$(kecho) '  Kernel: $@ is ready'
 
 endif
 
@@ -78,14 +76,12 @@ fi
 $(obj)/uImage: $(obj)/zImage FORCE
        @$(check_for_multiple_loadaddr)
        $(call if_changed,uimage)
-       @$(kecho) '  Image $@ is ready'
 
 $(obj)/bootp/bootp: $(obj)/zImage initrd FORCE
        $(Q)$(MAKE) $(build)=$(obj)/bootp $@
 
 $(obj)/bootpImage: $(obj)/bootp/bootp FORCE
        $(call if_changed,objcopy)
-       @$(kecho) '  Kernel: $@ is ready'
 
 PHONY += initrd install zinstall uinstall
 initrd:
index b2bc8e11471d3ee3e4fcd5f207406222ffa04bf1..4eaea2173bf81e84d47f0453299a538b08d08e87 100644 (file)
@@ -480,13 +480,13 @@ THUMB(    orr     \reg , \reg , #PSR_T_BIT        )
        .macro  uaccess_save, tmp
 #ifdef CONFIG_CPU_SW_DOMAIN_PAN
        mrc     p15, 0, \tmp, c3, c0, 0
-       str     \tmp, [sp, #S_FRAME_SIZE]
+       str     \tmp, [sp, #SVC_DACR]
 #endif
        .endm
 
        .macro  uaccess_restore
 #ifdef CONFIG_CPU_SW_DOMAIN_PAN
-       ldr     r0, [sp, #S_FRAME_SIZE]
+       ldr     r0, [sp, #SVC_DACR]
        mcr     p15, 0, r0, c3, c0, 0
 #endif
        .endm
index 112cc1a5d47f2ccac216d568e7ba30e2c0eaa8e0..f5d698182d5002179ecb4b5d2a81cc9dd0d23237 100644 (file)
@@ -44,9 +44,7 @@ extern void arm_heavy_mb(void);
 #define __arm_heavy_mb(x...) dsb(x)
 #endif
 
-#ifdef CONFIG_ARCH_HAS_BARRIERS
-#include <mach/barriers.h>
-#elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
+#if defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
 #define mb()           __arm_heavy_mb()
 #define rmb()          dsb()
 #define wmb()          __arm_heavy_mb(st)
index dff714d886d58dbdce93a468e6a098cf45db98f6..b7a4281543556cfb82f716e0fc0337dae363187c 100644 (file)
@@ -10,8 +10,8 @@
 #include <asm/param.h> /* HZ */
 
 #define MAX_UDELAY_MS  2
-#define UDELAY_MULT    ((UL(2199023) * HZ) >> 11)
-#define UDELAY_SHIFT   30
+#define UDELAY_MULT    UL(2047 * HZ + 483648 * HZ / 1000000)
+#define UDELAY_SHIFT   31
 
 #ifndef __ASSEMBLY__
 
@@ -34,7 +34,7 @@ extern struct arm_delay_ops {
  * it, it means that you're calling udelay() with an out of range value.
  *
  * With currently imposed limits, this means that we support a max delay
- * of 2000us. Further limits: HZ<=1000 and bogomips<=3355
+ * of 2000us. Further limits: HZ<=1000
  */
 extern void __bad_udelay(void);
 
index f4882553fbb0125927776c0f3a032625937649c6..85a34cc8316ace1b906347fc1de1e79adbd0cb02 100644 (file)
@@ -17,7 +17,7 @@
 
 #define fd_outb(val,port)                      \
        do {                                    \
-               if ((port) == FD_DOR)           \
+               if ((port) == (u32)FD_DOR)      \
                        fd_setdor((val));       \
                else                            \
                        outb((val),(port));     \
index 781ef5fe235d4924372f0cc37f29c41770f319d4..021692c64de3bf9f55c4625769351fb8b4255e45 100644 (file)
@@ -282,7 +282,7 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
  * These perform PCI memory accesses via an ioremap region.  They don't
  * take an address as such, but a cookie.
  *
- * Again, this are defined to perform little endian accesses.  See the
+ * Again, these are defined to perform little endian accesses.  See the
  * IO port primitives for more information.
  */
 #ifndef readl
index 51622ba7c4a66a91494ecc49be4520fd4b14df88..e9c9a117bd25d5b69e8ba5313990f18f8db7311d 100644 (file)
 #include <uapi/asm/ptrace.h>
 
 #ifndef __ASSEMBLY__
+#include <linux/types.h>
+
 struct pt_regs {
        unsigned long uregs[18];
 };
 
+struct svc_pt_regs {
+       struct pt_regs regs;
+       u32 dacr;
+       u32 addr_limit;
+};
+
+#define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs)
+
 #define user_mode(regs)        \
        (((regs)->ARM_cpsr & 0xf) == 0)
 
index 35c9db857ebe9c7d53715ec42518a6e9fbe1dc6e..62a6f65029e61aebf9b64e1df59fb9383f4064a9 100644 (file)
@@ -104,14 +104,6 @@ static inline void set_fs(mm_segment_t fs)
 
 #define segment_eq(a, b)       ((a) == (b))
 
-#define __addr_ok(addr) ({ \
-       unsigned long flag; \
-       __asm__("cmp %2, %0; movlo %0, #0" \
-               : "=&r" (flag) \
-               : "0" (current_thread_info()->addr_limit), "r" (addr) \
-               : "cc"); \
-       (flag == 0); })
-
 /* We use 33-bit arithmetic here... */
 #define __range_ok(addr, size) ({ \
        unsigned long flag, roksum; \
@@ -238,49 +230,23 @@ extern int __put_user_2(void *, unsigned int);
 extern int __put_user_4(void *, unsigned int);
 extern int __put_user_8(void *, unsigned long long);
 
-#define __put_user_x(__r2, __p, __e, __l, __s)                         \
-          __asm__ __volatile__ (                                       \
-               __asmeq("%0", "r0") __asmeq("%2", "r2")                 \
-               __asmeq("%3", "r1")                                     \
-               "bl     __put_user_" #__s                               \
-               : "=&r" (__e)                                           \
-               : "0" (__p), "r" (__r2), "r" (__l)                      \
-               : "ip", "lr", "cc")
-
-#define __put_user_check(x, p)                                         \
+#define __put_user_check(__pu_val, __ptr, __err, __s)                  \
        ({                                                              \
                unsigned long __limit = current_thread_info()->addr_limit - 1; \
-               const typeof(*(p)) __user *__tmp_p = (p);               \
-               register const typeof(*(p)) __r2 asm("r2") = (x);       \
-               register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \
+               register typeof(__pu_val) __r2 asm("r2") = __pu_val;    \
+               register const void __user *__p asm("r0") = __ptr;      \
                register unsigned long __l asm("r1") = __limit;         \
                register int __e asm("r0");                             \
-               unsigned int __ua_flags = uaccess_save_and_enable();    \
-               switch (sizeof(*(__p))) {                               \
-               case 1:                                                 \
-                       __put_user_x(__r2, __p, __e, __l, 1);           \
-                       break;                                          \
-               case 2:                                                 \
-                       __put_user_x(__r2, __p, __e, __l, 2);           \
-                       break;                                          \
-               case 4:                                                 \
-                       __put_user_x(__r2, __p, __e, __l, 4);           \
-                       break;                                          \
-               case 8:                                                 \
-                       __put_user_x(__r2, __p, __e, __l, 8);           \
-                       break;                                          \
-               default: __e = __put_user_bad(); break;                 \
-               }                                                       \
-               uaccess_restore(__ua_flags);                            \
-               __e;                                                    \
+               __asm__ __volatile__ (                                  \
+                       __asmeq("%0", "r0") __asmeq("%2", "r2")         \
+                       __asmeq("%3", "r1")                             \
+                       "bl     __put_user_" #__s                       \
+                       : "=&r" (__e)                                   \
+                       : "0" (__p), "r" (__r2), "r" (__l)              \
+                       : "ip", "lr", "cc");                            \
+               __err = __e;                                            \
        })
 
-#define put_user(x, p)                                                 \
-       ({                                                              \
-               might_fault();                                          \
-               __put_user_check(x, p);                                 \
-        })
-
 #else /* CONFIG_MMU */
 
 /*
@@ -298,7 +264,7 @@ static inline void set_fs(mm_segment_t fs)
 }
 
 #define get_user(x, p) __get_user(x, p)
-#define put_user(x, p) __put_user(x, p)
+#define __put_user_check __put_user_nocheck
 
 #endif /* CONFIG_MMU */
 
@@ -389,36 +355,54 @@ do {                                                                      \
 #define __get_user_asm_word(x, addr, err)                      \
        __get_user_asm(x, addr, err, ldr)
 
+
+#define __put_user_switch(x, ptr, __err, __fn)                         \
+       do {                                                            \
+               const __typeof__(*(ptr)) __user *__pu_ptr = (ptr);      \
+               __typeof__(*(ptr)) __pu_val = (x);                      \
+               unsigned int __ua_flags;                                \
+               might_fault();                                          \
+               __ua_flags = uaccess_save_and_enable();                 \
+               switch (sizeof(*(ptr))) {                               \
+               case 1: __fn(__pu_val, __pu_ptr, __err, 1); break;      \
+               case 2: __fn(__pu_val, __pu_ptr, __err, 2); break;      \
+               case 4: __fn(__pu_val, __pu_ptr, __err, 4); break;      \
+               case 8: __fn(__pu_val, __pu_ptr, __err, 8); break;      \
+               default: __err = __put_user_bad(); break;               \
+               }                                                       \
+               uaccess_restore(__ua_flags);                            \
+       } while (0)
+
+#define put_user(x, ptr)                                               \
+({                                                                     \
+       int __pu_err = 0;                                               \
+       __put_user_switch((x), (ptr), __pu_err, __put_user_check);      \
+       __pu_err;                                                       \
+})
+
 #define __put_user(x, ptr)                                             \
 ({                                                                     \
        long __pu_err = 0;                                              \
-       __put_user_err((x), (ptr), __pu_err);                           \
+       __put_user_switch((x), (ptr), __pu_err, __put_user_nocheck);    \
        __pu_err;                                                       \
 })
 
 #define __put_user_error(x, ptr, err)                                  \
 ({                                                                     \
-       __put_user_err((x), (ptr), err);                                \
+       __put_user_switch((x), (ptr), (err), __put_user_nocheck);       \
        (void) 0;                                                       \
 })
 
-#define __put_user_err(x, ptr, err)                                    \
-do {                                                                   \
-       unsigned long __pu_addr = (unsigned long)(ptr);                 \
-       unsigned int __ua_flags;                                        \
-       __typeof__(*(ptr)) __pu_val = (x);                              \
-       __chk_user_ptr(ptr);                                            \
-       might_fault();                                                  \
-       __ua_flags = uaccess_save_and_enable();                         \
-       switch (sizeof(*(ptr))) {                                       \
-       case 1: __put_user_asm_byte(__pu_val, __pu_addr, err);  break;  \
-       case 2: __put_user_asm_half(__pu_val, __pu_addr, err);  break;  \
-       case 4: __put_user_asm_word(__pu_val, __pu_addr, err);  break;  \
-       case 8: __put_user_asm_dword(__pu_val, __pu_addr, err); break;  \
-       default: __put_user_bad();                                      \
-       }                                                               \
-       uaccess_restore(__ua_flags);                                    \
-} while (0)
+#define __put_user_nocheck(x, __pu_ptr, __err, __size)                 \
+       do {                                                            \
+               unsigned long __pu_addr = (unsigned long)__pu_ptr;      \
+               __put_user_nocheck_##__size(x, __pu_addr, __err);       \
+       } while (0)
+
+#define __put_user_nocheck_1 __put_user_asm_byte
+#define __put_user_nocheck_2 __put_user_asm_half
+#define __put_user_nocheck_4 __put_user_asm_word
+#define __put_user_nocheck_8 __put_user_asm_dword
 
 #define __put_user_asm(x, __pu_addr, err, instr)               \
        __asm__ __volatile__(                                   \
index 27d05813ff09c09d167a27b2c790bf1ba0135ba5..608008229c7db6881f8d103750153280d96105d7 100644 (file)
@@ -107,7 +107,10 @@ int main(void)
   DEFINE(S_PC,                 offsetof(struct pt_regs, ARM_pc));
   DEFINE(S_PSR,                        offsetof(struct pt_regs, ARM_cpsr));
   DEFINE(S_OLD_R0,             offsetof(struct pt_regs, ARM_ORIG_r0));
-  DEFINE(S_FRAME_SIZE,         sizeof(struct pt_regs));
+  DEFINE(PT_REGS_SIZE,         sizeof(struct pt_regs));
+  DEFINE(SVC_DACR,             offsetof(struct svc_pt_regs, dacr));
+  DEFINE(SVC_ADDR_LIMIT,       offsetof(struct svc_pt_regs, addr_limit));
+  DEFINE(SVC_REGS_SIZE,                sizeof(struct svc_pt_regs));
   BLANK();
 #ifdef CONFIG_CACHE_L2X0
   DEFINE(L2X0_R_PHY_BASE,      offsetof(struct l2x0_regs, phy_base));
index a44b268e12e1a2acbc1990afc8b5c2c65512256f..7dccc964d75f2fff2bdbfa89c4b3d0cc7bb92e61 100644 (file)
@@ -47,18 +47,13 @@ int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
  * This function calls the underlying arch specific low level PM code as
  * registered at the init time.
  *
- * Returns -EOPNOTSUPP if no suspend callback is defined, the result of the
- * callback otherwise.
+ * Returns the result of the suspend callback.
  */
 int arm_cpuidle_suspend(int index)
 {
-       int ret = -EOPNOTSUPP;
        int cpu = smp_processor_id();
 
-       if (cpuidle_ops[cpu].suspend)
-               ret = cpuidle_ops[cpu].suspend(index);
-
-       return ret;
+       return cpuidle_ops[cpu].suspend(index);
 }
 
 /**
@@ -92,7 +87,8 @@ static const struct cpuidle_ops *__init arm_cpuidle_get_ops(const char *method)
  * process.
  *
  * Return 0 on sucess, -ENOENT if no 'enable-method' is defined, -EOPNOTSUPP if
- * no cpuidle_ops is registered for the 'enable-method'.
+ * no cpuidle_ops is registered for the 'enable-method', or if either init or
+ * suspend callback isn't defined.
  */
 static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
 {
@@ -110,6 +106,12 @@ static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
                return -EOPNOTSUPP;
        }
 
+       if (!ops->init || !ops->suspend) {
+               pr_warn("cpuidle_ops '%s': no init or suspend callback\n",
+                       enable_method);
+               return -EOPNOTSUPP;
+       }
+
        cpuidle_ops[cpu] = *ops; /* structure copy */
 
        pr_notice("cpuidle: enable-method property '%s'"
@@ -129,7 +131,8 @@ static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
  * Returns:
  *  0 on success,
  *  -ENODEV if it fails to find the cpu node in the device tree,
- *  -EOPNOTSUPP if it does not find a registered cpuidle_ops for this cpu,
+ *  -EOPNOTSUPP if it does not find a registered and valid cpuidle_ops for
+ *  this cpu,
  *  -ENOENT if it fails to find an 'enable-method' property,
  *  -ENXIO if the HW reports a failure or a misconfiguration,
  *  -ENOMEM if the HW report an memory allocation failure 
@@ -143,7 +146,7 @@ int __init arm_cpuidle_init(int cpu)
                return -ENODEV;
 
        ret = arm_cpuidle_read_ops(cpu_node, cpu);
-       if (!ret && cpuidle_ops[cpu].init)
+       if (!ret)
                ret = cpuidle_ops[cpu].init(cpu_node, cpu);
 
        of_node_put(cpu_node);
index 2e26016a91a57116b9956973a19bb4aba723fc04..40ecd5f514a2217181781cbc66ab5e1ca26efa90 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/cputype.h>
 #include <asm/setup.h>
 #include <asm/page.h>
+#include <asm/prom.h>
 #include <asm/smp_plat.h>
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -213,6 +214,8 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
 
 #if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)
        DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
+               .l2c_aux_val = 0x0,
+               .l2c_aux_mask = ~0x0,
        MACHINE_END
 
        mdesc_best = &__mach_desc_GENERIC_DT;
index e2550500486d497c8455165b37916f2eb4974cd5..bc5f50799d75627fb3eb22b9afe6d849373e77d4 100644 (file)
@@ -92,7 +92,7 @@
  * Invalid mode handlers
  */
        .macro  inv_entry, reason
-       sub     sp, sp, #S_FRAME_SIZE
+       sub     sp, sp, #PT_REGS_SIZE
  ARM(  stmib   sp, {r1 - lr}           )
  THUMB(        stmia   sp, {r0 - r12}          )
  THUMB(        str     sp, [sp, #S_SP]         )
@@ -152,7 +152,7 @@ ENDPROC(__und_invalid)
        .macro  svc_entry, stack_hole=0, trace=1, uaccess=1
  UNWIND(.fnstart               )
  UNWIND(.save {r0 - pc}                )
-       sub     sp, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4)
+       sub     sp, sp, #(SVC_REGS_SIZE + \stack_hole - 4)
 #ifdef CONFIG_THUMB2_KERNEL
  SPFIX(        str     r0, [sp]        )       @ temporarily saved
  SPFIX(        mov     r0, sp          )
@@ -167,7 +167,7 @@ ENDPROC(__und_invalid)
        ldmia   r0, {r3 - r5}
        add     r7, sp, #S_SP - 4       @ here for interlock avoidance
        mov     r6, #-1                 @  ""  ""      ""       ""
-       add     r2, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4)
+       add     r2, sp, #(SVC_REGS_SIZE + \stack_hole - 4)
  SPFIX(        addeq   r2, r2, #4      )
        str     r3, [sp, #-4]!          @ save the "real" r0 copied
                                        @ from the exception stack
@@ -185,6 +185,12 @@ ENDPROC(__und_invalid)
        @
        stmia   r7, {r2 - r6}
 
+       get_thread_info tsk
+       ldr     r0, [tsk, #TI_ADDR_LIMIT]
+       mov     r1, #TASK_SIZE
+       str     r1, [tsk, #TI_ADDR_LIMIT]
+       str     r0, [sp, #SVC_ADDR_LIMIT]
+
        uaccess_save r0
        .if \uaccess
        uaccess_disable r0
@@ -213,7 +219,6 @@ __irq_svc:
        irq_handler
 
 #ifdef CONFIG_PREEMPT
-       get_thread_info tsk
        ldr     r8, [tsk, #TI_PREEMPT]          @ get preempt count
        ldr     r0, [tsk, #TI_FLAGS]            @ get flags
        teq     r8, #0                          @ if preempt count != 0
@@ -366,17 +371,17 @@ ENDPROC(__fiq_abt)
 /*
  * User mode handlers
  *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ * EABI note: sp_svc is always 64-bit aligned here, so should PT_REGS_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (PT_REGS_SIZE & 7)
 #error "sizeof(struct pt_regs) must be a multiple of 8"
 #endif
 
        .macro  usr_entry, trace=1, uaccess=1
  UNWIND(.fnstart       )
  UNWIND(.cantunwind    )       @ don't unwind the user space
-       sub     sp, sp, #S_FRAME_SIZE
+       sub     sp, sp, #PT_REGS_SIZE
  ARM(  stmib   sp, {r1 - r12}  )
  THUMB(        stmia   sp, {r0 - r12}  )
 
index 30a7228eaceba758fb368f9ef16511019b1cb5c5..10c3283d6c196b85bcab35264f80851eddcf0663 100644 (file)
@@ -145,7 +145,7 @@ ENTRY(vector_swi)
 #ifdef CONFIG_CPU_V7M
        v7m_exception_entry
 #else
-       sub     sp, sp, #S_FRAME_SIZE
+       sub     sp, sp, #PT_REGS_SIZE
        stmia   sp, {r0 - r12}                  @ Calling r0 - r12
  ARM(  add     r8, sp, #S_PC           )
  ARM(  stmdb   r8, {sp, lr}^           )       @ Calling sp, lr
index 0d22ad206d5230ba05a40b4101bb1dd2e4addd10..6391728c8f0377019404c6a6744df1e24697b3a8 100644 (file)
@@ -90,7 +90,7 @@
        @ Linux expects to have irqs off. Do it here before taking stack space
        cpsid   i
 
-       sub     sp, #S_FRAME_SIZE-S_IP
+       sub     sp, #PT_REGS_SIZE-S_IP
        stmdb   sp!, {r0-r11}
 
        @ load saved r12, lr, return address and xPSR.
        ldmia   sp!, {r0-r11}
 
        @ restore main sp
-       add     sp, sp, #S_FRAME_SIZE-S_IP
+       add     sp, sp, #PT_REGS_SIZE-S_IP
 
        cpsie   i
        bx      lr
        blne    trace_hardirqs_off
 #endif
        .endif
+       ldr     r1, [sp, #SVC_ADDR_LIMIT]
        uaccess_restore
+       str     r1, [tsk, #TI_ADDR_LIMIT]
 
 #ifndef CONFIG_THUMB2_KERNEL
        @ ARM mode SVC restore
        @ on the stack remains correct).
        @
        .macro  svc_exit_via_fiq
+       ldr     r1, [sp, #SVC_ADDR_LIMIT]
        uaccess_restore
+       str     r1, [tsk, #TI_ADDR_LIMIT]
 #ifndef CONFIG_THUMB2_KERNEL
        @ ARM mode restore
        mov     r0, sp
        .endif
        mov     r0, r0                          @ ARMv5T and earlier require a nop
                                                @ after ldm {}^
-       add     sp, sp, #\offset + S_FRAME_SIZE
+       add     sp, sp, #\offset + PT_REGS_SIZE
        movs    pc, lr                          @ return & move spsr_svc into cpsr
 #elif defined(CONFIG_CPU_V7M)
        @ V7M restore.
        .else
        ldmdb   sp, {r0 - r12}                  @ get calling r0 - r12
        .endif
-       add     sp, sp, #S_FRAME_SIZE - S_SP
+       add     sp, sp, #PT_REGS_SIZE - S_SP
        movs    pc, lr                          @ return & move spsr_svc into cpsr
 #endif /* !CONFIG_THUMB2_KERNEL */
        .endm
index 907534f97053abbc32b667ff43df88dc93c08fb7..abcf4784852593397daf3b1e6cf5d70cf47660e0 100644 (file)
@@ -73,7 +73,7 @@ __irq_entry:
        @ correctness they don't need to be restored. So only r8-r11 must be
        @ restored here. The easiest way to do so is to restore r0-r7, too.
        ldmia   sp!, {r0-r11}
-       add     sp, #S_FRAME_SIZE-S_IP
+       add     sp, #PT_REGS_SIZE-S_IP
        cpsie   i
        bx      lr
 ENDPROC(__irq_entry)
index 4a803c5a1ff7276859b823a7b9b02dc24ee6e564..612eb530f33fcd19bc4539facb26fc30a2583979 100644 (file)
@@ -96,19 +96,23 @@ void __show_regs(struct pt_regs *regs)
        unsigned long flags;
        char buf[64];
 #ifndef CONFIG_CPU_V7M
-       unsigned int domain;
+       unsigned int domain, fs;
 #ifdef CONFIG_CPU_SW_DOMAIN_PAN
        /*
         * Get the domain register for the parent context. In user
         * mode, we don't save the DACR, so lets use what it should
         * be. For other modes, we place it after the pt_regs struct.
         */
-       if (user_mode(regs))
+       if (user_mode(regs)) {
                domain = DACR_UACCESS_ENABLE;
-       else
-               domain = *(unsigned int *)(regs + 1);
+               fs = get_fs();
+       } else {
+               domain = to_svc_pt_regs(regs)->dacr;
+               fs = to_svc_pt_regs(regs)->addr_limit;
+       }
 #else
        domain = get_domain();
+       fs = get_fs();
 #endif
 #endif
 
@@ -144,7 +148,7 @@ void __show_regs(struct pt_regs *regs)
                if ((domain & domain_mask(DOMAIN_USER)) ==
                    domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
                        segment = "none";
-               else if (get_fs() == get_ds())
+               else if (fs == get_ds())
                        segment = "kernel";
                else
                        segment = "user";
index 261dae6f3fece20d58cecaaf5618ee9aa70b3fce..85a0bcb1f7ca59704f47f10d8c4bb359fd655513 100644 (file)
@@ -844,7 +844,7 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
        struct resource *res;
 
        kernel_code.start   = virt_to_phys(_text);
-       kernel_code.end     = virt_to_phys(_etext - 1);
+       kernel_code.end     = virt_to_phys(__init_begin - 1);
        kernel_data.start   = virt_to_phys(_sdata);
        kernel_data.end     = virt_to_phys(_end - 1);
 
index 2e72be4f623e22284f8b0ae1c441b30b867e7c0c..22313cb5336257cffa870b15e21279a1b4684e99 100644 (file)
@@ -93,17 +93,53 @@ void erratum_a15_798181_init(void)
        unsigned int revidr = read_cpuid(CPUID_REVIDR);
 
        /* Brahma-B15 r0p0..r0p2 affected
-        * Cortex-A15 r0p0..r3p2 w/o ECO fix affected */
-       if ((midr & 0xff0ffff0) == 0x420f00f0 && midr <= 0x420f00f2)
+        * Cortex-A15 r0p0..r3p3 w/o ECO fix affected
+        * Fixes applied to A15 with respect to the revision and revidr are:
+        *
+        * r0p0-r2p1: No fixes applied
+        * r2p2,r2p3:
+        *      REVIDR[4]: 798181 Moving a virtual page that is being accessed
+        *                 by an active process can lead to unexpected behavior
+        *      REVIDR[9]: Not defined
+        * r2p4,r3p0,r3p1,r3p2:
+        *      REVIDR[4]: 798181 Moving a virtual page that is being accessed
+        *                 by an active process can lead to unexpected behavior
+        *      REVIDR[9]: 798181 Moving a virtual page that is being accessed
+        *                 by an active process can lead to unexpected behavior
+        *                 - This is an update to a previously released ECO.
+        * r3p3:
+        *      REVIDR[4]: Reserved
+        *      REVIDR[9]: 798181 Moving a virtual page that is being accessed
+        *                 by an active process can lead to unexpected behavior
+        *                 - This is an update to a previously released ECO.
+        *
+        * Handling:
+        *      REVIDR[9] set -> No WA
+        *      REVIDR[4] set, REVIDR[9] cleared -> Partial WA
+        *      Both cleared -> Full WA
+        */
+       if ((midr & 0xff0ffff0) == 0x420f00f0 && midr <= 0x420f00f2) {
                erratum_a15_798181_handler = erratum_a15_798181_broadcast;
-       else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr <= 0x413fc0f2 &&
-                (revidr & 0x210) != 0x210) {
+       } else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr < 0x412fc0f2) {
+               erratum_a15_798181_handler = erratum_a15_798181_broadcast;
+       } else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr < 0x412fc0f4) {
                if (revidr & 0x10)
                        erratum_a15_798181_handler =
                                erratum_a15_798181_partial;
                else
                        erratum_a15_798181_handler =
                                erratum_a15_798181_broadcast;
+       } else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr < 0x413fc0f3) {
+               if ((revidr & 0x210) == 0)
+                       erratum_a15_798181_handler =
+                               erratum_a15_798181_broadcast;
+               else if (revidr & 0x10)
+                       erratum_a15_798181_handler =
+                               erratum_a15_798181_partial;
+       } else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr < 0x414fc0f0) {
+               if ((revidr & 0x200) == 0)
+                       erratum_a15_798181_handler =
+                               erratum_a15_798181_partial;
        }
 }
 #endif
index e2c6da096cefa491669ae8b4464b89f6df5f0a75..99420fc1f066796fdec9ea5a473a0d893647379b 100644 (file)
@@ -125,6 +125,8 @@ SECTIONS
 #ifdef CONFIG_DEBUG_ALIGN_RODATA
        . = ALIGN(1<<SECTION_SHIFT);
 #endif
+       _etext = .;                     /* End of text section */
+
        RO_DATA(PAGE_SIZE)
 
        . = ALIGN(4);
@@ -155,8 +157,6 @@ SECTIONS
 
        NOTES
 
-       _etext = .;                     /* End of text and rodata section */
-
 #ifdef CONFIG_DEBUG_RODATA
        . = ALIGN(1<<SECTION_SHIFT);
 #else
index d8a780799506b59bc2edd3f6a513021bcb45ebc0..27f4d96258a2e66193d6a3701bb4cf9a44399aad 100644 (file)
@@ -29,7 +29,10 @@ else
   lib-y        += io-readsw-armv4.o io-writesw-armv4.o
 endif
 
-lib-$(CONFIG_ARCH_RPC)         += ecard.o io-acorn.o floppydma.o
+ifeq ($(CONFIG_ARCH_RPC),y)
+  lib-y                                += ecard.o io-acorn.o floppydma.o
+  AFLAGS_delay-loop.o          += -march=armv4
+endif
 
 $(obj)/csumpartialcopy.o:      $(obj)/csumpartialcopygeneric.S
 $(obj)/csumpartialcopyuser.o:  $(obj)/csumpartialcopygeneric.S
index 518bf6e93f78a2cb1c74f7b857c6fa96b1018f53..792c59d885bc9d8274eaef7ea8c3a68539d9dc0a 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/delay.h>
+
                .text
 
 .LC0:          .word   loops_per_jiffy
@@ -17,7 +18,6 @@
 
 /*
  * r0  <= 2000
- * lpj <= 0x01ffffff (max. 3355 bogomips)
  * HZ  <= 1000
  */
 
@@ -25,16 +25,11 @@ ENTRY(__loop_udelay)
                ldr     r2, .LC1
                mul     r0, r2, r0
 ENTRY(__loop_const_udelay)                     @ 0 <= r0 <= 0x7fffff06
-               mov     r1, #-1
                ldr     r2, .LC0
-               ldr     r2, [r2]                @ max = 0x01ffffff
-               add     r0, r0, r1, lsr #32-14
-               mov     r0, r0, lsr #14         @ max = 0x0001ffff
-               add     r2, r2, r1, lsr #32-10
-               mov     r2, r2, lsr #10         @ max = 0x00007fff
-               mul     r0, r2, r0              @ max = 2^32-1
-               add     r0, r0, r1, lsr #32-6
-               movs    r0, r0, lsr #6
+               ldr     r2, [r2]
+               umull   r1, r0, r2, r0
+               adds    r1, r1, #0xffffffff
+               adcs    r0, r0, r0
                reteq   lr
 
 /*
index cb569b65a54ddcdaa8cce08d047799a24ba75f4b..d15a7fe51618ad70da5de7cf05408f882c6a4076 100644 (file)
@@ -1025,12 +1025,6 @@ config ARM_DMA_MEM_BUFFERABLE
 
          You are recommended say 'Y' here and debug any affected drivers.
 
-config ARCH_HAS_BARRIERS
-       bool
-       help
-         This option allows the use of custom mandatory barriers
-         included via the mach/barriers.h file.
-
 config ARM_HEAVY_MB
        bool
 
index ff7ed5697d3e4b67ba1691dded0f79029ec8f921..b7eed75960febac3fbc1103d09487e72f04564f5 100644 (file)
@@ -49,6 +49,7 @@ struct arm_dma_alloc_args {
        pgprot_t prot;
        const void *caller;
        bool want_vaddr;
+       int coherent_flag;
 };
 
 struct arm_dma_free_args {
@@ -59,6 +60,9 @@ struct arm_dma_free_args {
        bool want_vaddr;
 };
 
+#define NORMAL     0
+#define COHERENT    1
+
 struct arm_dma_allocator {
        void *(*alloc)(struct arm_dma_alloc_args *args,
                       struct page **ret_page);
@@ -272,7 +276,7 @@ static u64 get_coherent_dma_mask(struct device *dev)
        return mask;
 }
 
-static void __dma_clear_buffer(struct page *page, size_t size)
+static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag)
 {
        /*
         * Ensure that the allocated pages are zeroed, and that any data
@@ -284,17 +288,21 @@ static void __dma_clear_buffer(struct page *page, size_t size)
                while (size > 0) {
                        void *ptr = kmap_atomic(page);
                        memset(ptr, 0, PAGE_SIZE);
-                       dmac_flush_range(ptr, ptr + PAGE_SIZE);
+                       if (coherent_flag != COHERENT)
+                               dmac_flush_range(ptr, ptr + PAGE_SIZE);
                        kunmap_atomic(ptr);
                        page++;
                        size -= PAGE_SIZE;
                }
-               outer_flush_range(base, end);
+               if (coherent_flag != COHERENT)
+                       outer_flush_range(base, end);
        } else {
                void *ptr = page_address(page);
                memset(ptr, 0, size);
-               dmac_flush_range(ptr, ptr + size);
-               outer_flush_range(__pa(ptr), __pa(ptr) + size);
+               if (coherent_flag != COHERENT) {
+                       dmac_flush_range(ptr, ptr + size);
+                       outer_flush_range(__pa(ptr), __pa(ptr) + size);
+               }
        }
 }
 
@@ -302,7 +310,8 @@ static void __dma_clear_buffer(struct page *page, size_t size)
  * Allocate a DMA buffer for 'dev' of size 'size' using the
  * specified gfp mask.  Note that 'size' must be page aligned.
  */
-static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
+static struct page *__dma_alloc_buffer(struct device *dev, size_t size,
+                                      gfp_t gfp, int coherent_flag)
 {
        unsigned long order = get_order(size);
        struct page *page, *p, *e;
@@ -318,7 +327,7 @@ static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gf
        for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
                __free_page(p);
 
-       __dma_clear_buffer(page, size);
+       __dma_clear_buffer(page, size, coherent_flag);
 
        return page;
 }
@@ -340,7 +349,8 @@ static void __dma_free_buffer(struct page *page, size_t size)
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
                                     pgprot_t prot, struct page **ret_page,
-                                    const void *caller, bool want_vaddr);
+                                    const void *caller, bool want_vaddr,
+                                    int coherent_flag);
 
 static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
                                 pgprot_t prot, struct page **ret_page,
@@ -405,10 +415,13 @@ static int __init atomic_pool_init(void)
        atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
        if (!atomic_pool)
                goto out;
-
+       /*
+        * The atomic pool is only used for non-coherent allocations
+        * so we must pass NORMAL for coherent_flag.
+        */
        if (dev_get_cma_area(NULL))
                ptr = __alloc_from_contiguous(NULL, atomic_pool_size, prot,
-                                             &page, atomic_pool_init, true);
+                                     &page, atomic_pool_init, true, NORMAL);
        else
                ptr = __alloc_remap_buffer(NULL, atomic_pool_size, gfp, prot,
                                           &page, atomic_pool_init, true);
@@ -522,7 +535,11 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
 {
        struct page *page;
        void *ptr = NULL;
-       page = __dma_alloc_buffer(dev, size, gfp);
+       /*
+        * __alloc_remap_buffer is only called when the device is
+        * non-coherent
+        */
+       page = __dma_alloc_buffer(dev, size, gfp, NORMAL);
        if (!page)
                return NULL;
        if (!want_vaddr)
@@ -577,7 +594,8 @@ static int __free_from_pool(void *start, size_t size)
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
                                     pgprot_t prot, struct page **ret_page,
-                                    const void *caller, bool want_vaddr)
+                                    const void *caller, bool want_vaddr,
+                                    int coherent_flag)
 {
        unsigned long order = get_order(size);
        size_t count = size >> PAGE_SHIFT;
@@ -588,7 +606,7 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
        if (!page)
                return NULL;
 
-       __dma_clear_buffer(page, size);
+       __dma_clear_buffer(page, size, coherent_flag);
 
        if (!want_vaddr)
                goto out;
@@ -638,7 +656,7 @@ static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
 #define __get_dma_pgprot(attrs, prot)                          __pgprot(0)
 #define __alloc_remap_buffer(dev, size, gfp, prot, ret, c, wv) NULL
 #define __alloc_from_pool(size, ret_page)                      NULL
-#define __alloc_from_contiguous(dev, size, prot, ret, c, wv)   NULL
+#define __alloc_from_contiguous(dev, size, prot, ret, c, wv, coherent_flag)    NULL
 #define __free_from_pool(cpu_addr, size)                       do { } while (0)
 #define __free_from_contiguous(dev, page, cpu_addr, size, wv)  do { } while (0)
 #define __dma_free_remap(cpu_addr, size)                       do { } while (0)
@@ -649,7 +667,8 @@ static void *__alloc_simple_buffer(struct device *dev, size_t size, gfp_t gfp,
                                   struct page **ret_page)
 {
        struct page *page;
-       page = __dma_alloc_buffer(dev, size, gfp);
+       /* __alloc_simple_buffer is only called when the device is coherent */
+       page = __dma_alloc_buffer(dev, size, gfp, COHERENT);
        if (!page)
                return NULL;
 
@@ -679,7 +698,7 @@ static void *cma_allocator_alloc(struct arm_dma_alloc_args *args,
 {
        return __alloc_from_contiguous(args->dev, args->size, args->prot,
                                       ret_page, args->caller,
-                                      args->want_vaddr);
+                                      args->want_vaddr, args->coherent_flag);
 }
 
 static void cma_allocator_free(struct arm_dma_free_args *args)
@@ -746,6 +765,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
                .prot = prot,
                .caller = caller,
                .want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs),
+               .coherent_flag = is_coherent ? COHERENT : NORMAL,
        };
 
 #ifdef CONFIG_DMA_API_DEBUG
@@ -1253,7 +1273,8 @@ static inline void __free_iova(struct dma_iommu_mapping *mapping,
 static const int iommu_order_array[] = { 9, 8, 4, 0 };
 
 static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
-                                         gfp_t gfp, struct dma_attrs *attrs)
+                                         gfp_t gfp, struct dma_attrs *attrs,
+                                         int coherent_flag)
 {
        struct page **pages;
        int count = size >> PAGE_SHIFT;
@@ -1277,7 +1298,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
                if (!page)
                        goto error;
 
-               __dma_clear_buffer(page, size);
+               __dma_clear_buffer(page, size, coherent_flag);
 
                for (i = 0; i < count; i++)
                        pages[i] = page + i;
@@ -1327,7 +1348,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
                                pages[i + j] = pages[i] + j;
                }
 
-               __dma_clear_buffer(pages[i], PAGE_SIZE << order);
+               __dma_clear_buffer(pages[i], PAGE_SIZE << order, coherent_flag);
                i += 1 << order;
                count -= 1 << order;
        }
@@ -1455,13 +1476,16 @@ static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
        return NULL;
 }
 
-static void *__iommu_alloc_atomic(struct device *dev, size_t size,
-                                 dma_addr_t *handle)
+static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp,
+                                 dma_addr_t *handle, int coherent_flag)
 {
        struct page *page;
        void *addr;
 
-       addr = __alloc_from_pool(size, &page);
+       if (coherent_flag  == COHERENT)
+               addr = __alloc_simple_buffer(dev, size, gfp, &page);
+       else
+               addr = __alloc_from_pool(size, &page);
        if (!addr)
                return NULL;
 
@@ -1477,14 +1501,18 @@ err_mapping:
 }
 
 static void __iommu_free_atomic(struct device *dev, void *cpu_addr,
-                               dma_addr_t handle, size_t size)
+                       dma_addr_t handle, size_t size, int coherent_flag)
 {
        __iommu_remove_mapping(dev, handle, size);
-       __free_from_pool(cpu_addr, size);
+       if (coherent_flag == COHERENT)
+               __dma_free_buffer(virt_to_page(cpu_addr), size);
+       else
+               __free_from_pool(cpu_addr, size);
 }
 
-static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
-           dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
+           dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs,
+           int coherent_flag)
 {
        pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
        struct page **pages;
@@ -1493,8 +1521,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
        *handle = DMA_ERROR_CODE;
        size = PAGE_ALIGN(size);
 
-       if (!gfpflags_allow_blocking(gfp))
-               return __iommu_alloc_atomic(dev, size, handle);
+       if (coherent_flag  == COHERENT || !gfpflags_allow_blocking(gfp))
+               return __iommu_alloc_simple(dev, size, gfp, handle,
+                                           coherent_flag);
 
        /*
         * Following is a work-around (a.k.a. hack) to prevent pages
@@ -1505,7 +1534,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
         */
        gfp &= ~(__GFP_COMP);
 
-       pages = __iommu_alloc_buffer(dev, size, gfp, attrs);
+       pages = __iommu_alloc_buffer(dev, size, gfp, attrs, coherent_flag);
        if (!pages)
                return NULL;
 
@@ -1530,7 +1559,19 @@ err_buffer:
        return NULL;
 }
 
-static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
+                   dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+       return __arm_iommu_alloc_attrs(dev, size, handle, gfp, attrs, NORMAL);
+}
+
+static void *arm_coherent_iommu_alloc_attrs(struct device *dev, size_t size,
+                   dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+       return __arm_iommu_alloc_attrs(dev, size, handle, gfp, attrs, COHERENT);
+}
+
+static int __arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
                    void *cpu_addr, dma_addr_t dma_addr, size_t size,
                    struct dma_attrs *attrs)
 {
@@ -1540,8 +1581,6 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
        unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
        unsigned long off = vma->vm_pgoff;
 
-       vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
-
        if (!pages)
                return -ENXIO;
 
@@ -1562,19 +1601,34 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
 
        return 0;
 }
+static int arm_iommu_mmap_attrs(struct device *dev,
+               struct vm_area_struct *vma, void *cpu_addr,
+               dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+{
+       vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+
+       return __arm_iommu_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, attrs);
+}
+
+static int arm_coherent_iommu_mmap_attrs(struct device *dev,
+               struct vm_area_struct *vma, void *cpu_addr,
+               dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+{
+       return __arm_iommu_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, attrs);
+}
 
 /*
  * free a page as defined by the above mapping.
  * Must not be called with IRQs disabled.
  */
-void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
-                         dma_addr_t handle, struct dma_attrs *attrs)
+void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
+       dma_addr_t handle, struct dma_attrs *attrs, int coherent_flag)
 {
        struct page **pages;
        size = PAGE_ALIGN(size);
 
-       if (__in_atomic_pool(cpu_addr, size)) {
-               __iommu_free_atomic(dev, cpu_addr, handle, size);
+       if (coherent_flag == COHERENT || __in_atomic_pool(cpu_addr, size)) {
+               __iommu_free_atomic(dev, cpu_addr, handle, size, coherent_flag);
                return;
        }
 
@@ -1593,6 +1647,18 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
        __iommu_free_buffer(dev, pages, size, attrs);
 }
 
+void arm_iommu_free_attrs(struct device *dev, size_t size,
+                   void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs)
+{
+       __arm_iommu_free_attrs(dev, size, cpu_addr, handle, attrs, NORMAL);
+}
+
+void arm_coherent_iommu_free_attrs(struct device *dev, size_t size,
+                   void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs)
+{
+       __arm_iommu_free_attrs(dev, size, cpu_addr, handle, attrs, COHERENT);
+}
+
 static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
                                 void *cpu_addr, dma_addr_t dma_addr,
                                 size_t size, struct dma_attrs *attrs)
@@ -1997,9 +2063,9 @@ struct dma_map_ops iommu_ops = {
 };
 
 struct dma_map_ops iommu_coherent_ops = {
-       .alloc          = arm_iommu_alloc_attrs,
-       .free           = arm_iommu_free_attrs,
-       .mmap           = arm_iommu_mmap_attrs,
+       .alloc          = arm_coherent_iommu_alloc_attrs,
+       .free           = arm_coherent_iommu_free_attrs,
+       .mmap           = arm_coherent_iommu_mmap_attrs,
        .get_sgtable    = arm_iommu_get_sgtable,
 
        .map_page       = arm_coherent_iommu_map_page,
index 6fcaac8e200f888e18207ae6cdfeca8adc000c5e..a7123b4e129dfc40f9c0d0df4417d086e23ee9a0 100644 (file)
@@ -362,6 +362,39 @@ __ca15_errata:
 #endif
        b       __errata_finish
 
+__ca12_errata:
+#ifdef CONFIG_ARM_ERRATA_818325_852422
+       mrc     p15, 0, r10, c15, c0, 1         @ read diagnostic register
+       orr     r10, r10, #1 << 12              @ set bit #12
+       mcr     p15, 0, r10, c15, c0, 1         @ write diagnostic register
+#endif
+#ifdef CONFIG_ARM_ERRATA_821420
+       mrc     p15, 0, r10, c15, c0, 2         @ read internal feature reg
+       orr     r10, r10, #1 << 1               @ set bit #1
+       mcr     p15, 0, r10, c15, c0, 2         @ write internal feature reg
+#endif
+#ifdef CONFIG_ARM_ERRATA_825619
+       mrc     p15, 0, r10, c15, c0, 1         @ read diagnostic register
+       orr     r10, r10, #1 << 24              @ set bit #24
+       mcr     p15, 0, r10, c15, c0, 1         @ write diagnostic register
+#endif
+       b       __errata_finish
+
+__ca17_errata:
+#ifdef CONFIG_ARM_ERRATA_852421
+       cmp     r6, #0x12                       @ only present up to r1p2
+       mrcle   p15, 0, r10, c15, c0, 1         @ read diagnostic register
+       orrle   r10, r10, #1 << 24              @ set bit #24
+       mcrle   p15, 0, r10, c15, c0, 1         @ write diagnostic register
+#endif
+#ifdef CONFIG_ARM_ERRATA_852423
+       cmp     r6, #0x12                       @ only present up to r1p2
+       mrcle   p15, 0, r10, c15, c0, 1         @ read diagnostic register
+       orrle   r10, r10, #1 << 12              @ set bit #12
+       mcrle   p15, 0, r10, c15, c0, 1         @ write diagnostic register
+#endif
+       b       __errata_finish
+
 __v7_pj4b_setup:
 #ifdef CONFIG_CPU_PJ4B
 
@@ -443,6 +476,16 @@ __v7_setup_cont:
        teq     r0, r10
        beq     __ca9_errata
 
+       /* Cortex-A12 Errata */
+       ldr     r10, =0x00000c0d                @ Cortex-A12 primary part number
+       teq     r0, r10
+       beq     __ca12_errata
+
+       /* Cortex-A17 Errata */
+       ldr     r10, =0x00000c0e                @ Cortex-A17 primary part number
+       teq     r0, r10
+       beq     __ca17_errata
+
        /* Cortex-A15 Errata */
        ldr     r10, =0x00000c0f                @ Cortex-A15 primary part number
        teq     r0, r10
index 2ade7a6a10a704e880837e4fcae2f4ae1cbb6ae9..bbb7ee76e319f933aac802f005c056693bb7d87f 100644 (file)
@@ -224,7 +224,7 @@ void __init arm64_memblock_init(void)
         * via the linear mapping.
         */
        if (memory_limit != (phys_addr_t)ULLONG_MAX) {
-               memblock_enforce_memory_limit(memory_limit);
+               memblock_mem_limit_remove_map(memory_limit);
                memblock_add(__pa(_text), (u64)(_end - _text));
        }
 
index 60c0f3afc1f973a85425369e3c164b870cdecdf9..2c8a0d2b6c30b54fed09f3d363de235e45959ec3 100644 (file)
  * This file contains the system call numbers.
  */
 
-#define __NR_restart_syscall      0
-#define __NR_exit                1
-#define __NR_fork                2
-#define __NR_read                3
-#define __NR_write               4
-#define __NR_open                5
-#define __NR_close               6
-#define __NR_umask               7
-#define __NR_creat               8
-#define __NR_link                9
-#define __NR_unlink             10
-#define __NR_execve             11
-#define __NR_chdir              12
-#define __NR_time               13
-#define __NR_mknod              14
-#define __NR_chmod              15
-#define __NR_chown              16
-#define __NR_lchown             17
-#define __NR_lseek              18
-#define __NR__llseek            19
-#define __NR_getpid             20
-#define __NR_mount              21
-#define __NR_umount2            22
-#define __NR_setuid             23
-#define __NR_getuid             24
-#define __NR_stime              25
-#define __NR_ptrace             26
-#define __NR_alarm              27
-#define __NR_pause              28
-#define __NR_utime              29
-#define __NR_stat               30
-#define __NR_fstat              31
-#define __NR_lstat              32
-#define __NR_access             33
-#define __NR_chroot             34
-#define __NR_sync               35
-#define __NR_fsync              36
-#define __NR_kill               37
-#define __NR_rename             38
-#define __NR_mkdir              39
-#define __NR_rmdir              40
-#define __NR_dup                41
-#define __NR_pipe               42
-#define __NR_times              43
-#define __NR_clone              44
-#define __NR_brk                45
-#define __NR_setgid             46
-#define __NR_getgid             47
-#define __NR_getcwd             48
-#define __NR_geteuid            49
-#define __NR_getegid            50
-#define __NR_acct               51
-#define __NR_setfsuid           52
-#define __NR_setfsgid           53
-#define __NR_ioctl              54
-#define __NR_fcntl              55
-#define __NR_setpgid            56
-#define __NR_mremap             57
-#define __NR_setresuid          58
-#define __NR_getresuid          59
-#define __NR_setreuid           60
-#define __NR_setregid           61
-#define __NR_ustat              62
-#define __NR_dup2               63
-#define __NR_getppid            64
-#define __NR_getpgrp            65
-#define __NR_setsid             66
-#define __NR_rt_sigaction       67
-#define __NR_rt_sigreturn       68
-#define __NR_rt_sigprocmask     69
-#define __NR_rt_sigpending      70
-#define __NR_rt_sigtimedwait    71
-#define __NR_rt_sigqueueinfo    72
-#define __NR_rt_sigsuspend      73
-#define __NR_sethostname        74
-#define __NR_setrlimit          75
-#define __NR_getrlimit          76     /* SuS compliant getrlimit */
-#define __NR_getrusage          77
-#define __NR_gettimeofday       78
-#define __NR_settimeofday       79
-#define __NR_getgroups          80
-#define __NR_setgroups          81
-#define __NR_select             82
-#define __NR_symlink            83
-#define __NR_fchdir             84
-#define __NR_readlink           85
-#define __NR_pread              86
-#define __NR_pwrite             87
-#define __NR_swapon             88
-#define __NR_reboot             89
-#define __NR_mmap2              90
-#define __NR_munmap             91
-#define __NR_truncate           92
-#define __NR_ftruncate          93
-#define __NR_fchmod             94
-#define __NR_fchown             95
-#define __NR_getpriority        96
-#define __NR_setpriority        97
-#define __NR_wait4              98
-#define __NR_statfs             99
-#define __NR_fstatfs           100
-#define __NR_vhangup           101
-#define __NR_sigaltstack       102
-#define __NR_syslog            103
-#define __NR_setitimer         104
-#define __NR_getitimer         105
-#define __NR_swapoff           106
-#define __NR_sysinfo           107
+#define __NR_restart_syscall    0
+#define __NR_exit               1
+#define __NR_fork               2
+#define __NR_read               3
+#define __NR_write              4
+#define __NR_open               5
+#define __NR_close              6
+#define __NR_umask              7
+#define __NR_creat              8
+#define __NR_link               9
+#define __NR_unlink             10
+#define __NR_execve             11
+#define __NR_chdir              12
+#define __NR_time               13
+#define __NR_mknod              14
+#define __NR_chmod              15
+#define __NR_chown              16
+#define __NR_lchown             17
+#define __NR_lseek              18
+#define __NR__llseek            19
+#define __NR_getpid             20
+#define __NR_mount              21
+#define __NR_umount2            22
+#define __NR_setuid             23
+#define __NR_getuid             24
+#define __NR_stime              25
+#define __NR_ptrace             26
+#define __NR_alarm              27
+#define __NR_pause              28
+#define __NR_utime              29
+#define __NR_stat               30
+#define __NR_fstat              31
+#define __NR_lstat              32
+#define __NR_access             33
+#define __NR_chroot             34
+#define __NR_sync               35
+#define __NR_fsync              36
+#define __NR_kill               37
+#define __NR_rename             38
+#define __NR_mkdir              39
+#define __NR_rmdir              40
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_times              43
+#define __NR_clone              44
+#define __NR_brk                45
+#define __NR_setgid             46
+#define __NR_getgid             47
+#define __NR_getcwd             48
+#define __NR_geteuid            49
+#define __NR_getegid            50
+#define __NR_acct               51
+#define __NR_setfsuid           52
+#define __NR_setfsgid           53
+#define __NR_ioctl              54
+#define __NR_fcntl              55
+#define __NR_setpgid            56
+#define __NR_mremap             57
+#define __NR_setresuid          58
+#define __NR_getresuid          59
+#define __NR_setreuid           60
+#define __NR_setregid           61
+#define __NR_ustat              62
+#define __NR_dup2               63
+#define __NR_getppid            64
+#define __NR_getpgrp            65
+#define __NR_setsid             66
+#define __NR_rt_sigaction       67
+#define __NR_rt_sigreturn       68
+#define __NR_rt_sigprocmask     69
+#define __NR_rt_sigpending      70
+#define __NR_rt_sigtimedwait    71
+#define __NR_rt_sigqueueinfo    72
+#define __NR_rt_sigsuspend      73
+#define __NR_sethostname        74
+#define __NR_setrlimit          75
+#define __NR_getrlimit          76 /* SuS compliant getrlimit */
+#define __NR_getrusage          77
+#define __NR_gettimeofday       78
+#define __NR_settimeofday       79
+#define __NR_getgroups          80
+#define __NR_setgroups          81
+#define __NR_select             82
+#define __NR_symlink            83
+#define __NR_fchdir             84
+#define __NR_readlink           85
+#define __NR_pread              86
+#define __NR_pwrite             87
+#define __NR_swapon             88
+#define __NR_reboot             89
+#define __NR_mmap2              90
+#define __NR_munmap             91
+#define __NR_truncate           92
+#define __NR_ftruncate          93
+#define __NR_fchmod             94
+#define __NR_fchown             95
+#define __NR_getpriority        96
+#define __NR_setpriority        97
+#define __NR_wait4              98
+#define __NR_statfs             99
+#define __NR_fstatfs            100
+#define __NR_vhangup            101
+#define __NR_sigaltstack        102
+#define __NR_syslog             103
+#define __NR_setitimer          104
+#define __NR_getitimer          105
+#define __NR_swapoff            106
+#define __NR_sysinfo            107
 /* 108 was __NR_ipc for a little while */
-#define __NR_sendfile          109
-#define __NR_setdomainname     110
-#define __NR_uname             111
-#define __NR_adjtimex          112
-#define __NR_mprotect          113
-#define __NR_vfork             114
-#define __NR_init_module       115
-#define __NR_delete_module     116
-#define __NR_quotactl          117
-#define __NR_getpgid           118
-#define __NR_bdflush           119
-#define __NR_sysfs             120
-#define __NR_personality       121
-#define __NR_afs_syscall       122 /* Syscall for Andrew File System */
-#define __NR_getdents          123
-#define __NR_flock             124
-#define __NR_msync             125
-#define __NR_readv             126
-#define __NR_writev            127
-#define __NR_getsid            128
-#define __NR_fdatasync         129
-#define __NR__sysctl           130
-#define __NR_mlock             131
-#define __NR_munlock           132
-#define __NR_mlockall          133
-#define __NR_munlockall                134
-#define __NR_sched_setparam            135
-#define __NR_sched_getparam            136
-#define __NR_sched_setscheduler                137
-#define __NR_sched_getscheduler                138
-#define __NR_sched_yield               139
-#define __NR_sched_get_priority_max    140
-#define __NR_sched_get_priority_min    141
-#define __NR_sched_rr_get_interval     142
-#define __NR_nanosleep         143
-#define __NR_poll              144
-#define __NR_nfsservctl                145
-#define __NR_setresgid         146
-#define __NR_getresgid         147
+#define __NR_sendfile           109
+#define __NR_setdomainname      110
+#define __NR_uname              111
+#define __NR_adjtimex           112
+#define __NR_mprotect           113
+#define __NR_vfork              114
+#define __NR_init_module        115
+#define __NR_delete_module      116
+#define __NR_quotactl           117
+#define __NR_getpgid            118
+#define __NR_bdflush            119
+#define __NR_sysfs              120
+#define __NR_personality        121
+#define __NR_afs_syscall        122 /* Syscall for Andrew File System */
+#define __NR_getdents           123
+#define __NR_flock              124
+#define __NR_msync              125
+#define __NR_readv              126
+#define __NR_writev             127
+#define __NR_getsid             128
+#define __NR_fdatasync          129
+#define __NR__sysctl            130
+#define __NR_mlock              131
+#define __NR_munlock            132
+#define __NR_mlockall           133
+#define __NR_munlockall         134
+#define __NR_sched_setparam     135
+#define __NR_sched_getparam     136
+#define __NR_sched_setscheduler 137
+#define __NR_sched_getscheduler 138
+#define __NR_sched_yield        139
+#define __NR_sched_get_priority_max     140
+#define __NR_sched_get_priority_min     141
+#define __NR_sched_rr_get_interval      142
+#define __NR_nanosleep          143
+#define __NR_poll               144
+#define __NR_nfsservctl         145
+#define __NR_setresgid          146
+#define __NR_getresgid          147
 #define __NR_prctl              148
-#define __NR_socket            149
-#define __NR_bind              150
-#define __NR_connect           151
-#define __NR_listen            152
-#define __NR_accept            153
-#define __NR_getsockname       154
-#define __NR_getpeername       155
-#define __NR_socketpair                156
-#define __NR_send              157
-#define __NR_recv              158
-#define __NR_sendto            159
-#define __NR_recvfrom          160
-#define __NR_shutdown          161
-#define __NR_setsockopt                162
-#define __NR_getsockopt                163
-#define __NR_sendmsg           164
-#define __NR_recvmsg           165
-#define __NR_truncate64                166
-#define __NR_ftruncate64       167
-#define __NR_stat64            168
-#define __NR_lstat64           169
-#define __NR_fstat64           170
-#define __NR_pivot_root                171
-#define __NR_mincore           172
-#define __NR_madvise           173
-#define __NR_getdents64                174
-#define __NR_fcntl64           175
-#define __NR_gettid            176
-#define __NR_readahead         177
-#define __NR_setxattr          178
-#define __NR_lsetxattr         179
-#define __NR_fsetxattr         180
-#define __NR_getxattr          181
-#define __NR_lgetxattr         182
-#define __NR_fgetxattr         183
-#define __NR_listxattr         184
-#define __NR_llistxattr                185
-#define __NR_flistxattr                186
-#define __NR_removexattr       187
-#define __NR_lremovexattr      188
-#define __NR_fremovexattr      189
-#define __NR_tkill             190
-#define __NR_sendfile64                191
-#define __NR_futex             192
-#define __NR_sched_setaffinity 193
-#define __NR_sched_getaffinity 194
-#define __NR_capget            195
-#define __NR_capset            196
-#define __NR_io_setup          197
-#define __NR_io_destroy                198
-#define __NR_io_getevents      199
-#define __NR_io_submit         200
-#define __NR_io_cancel         201
-#define __NR_fadvise64         202
-#define __NR_exit_group                203
-#define __NR_lookup_dcookie    204
-#define __NR_epoll_create      205
-#define __NR_epoll_ctl         206
-#define __NR_epoll_wait                207
-#define __NR_remap_file_pages  208
-#define __NR_set_tid_address   209
-#define __NR_timer_create      210
-#define __NR_timer_settime     211
-#define __NR_timer_gettime     212
-#define __NR_timer_getoverrun  213
-#define __NR_timer_delete      214
-#define __NR_clock_settime     215
-#define __NR_clock_gettime     216
-#define __NR_clock_getres      217
-#define __NR_clock_nanosleep   218
-#define __NR_statfs64          219
-#define __NR_fstatfs64         220
-#define __NR_tgkill            221
-                               /* 222 reserved for tux */
-#define __NR_utimes            223
-#define __NR_fadvise64_64      224
-#define __NR_cacheflush                225
-
-#define __NR_vserver           226
-#define __NR_mq_open           227
-#define __NR_mq_unlink         228
-#define __NR_mq_timedsend      229
-#define __NR_mq_timedreceive   230
-#define __NR_mq_notify         231
-#define __NR_mq_getsetattr     232
-#define __NR_kexec_load                233
-#define __NR_waitid            234
-#define __NR_add_key           235
-#define __NR_request_key       236
-#define __NR_keyctl            237
-#define __NR_ioprio_set                238
-#define __NR_ioprio_get                239
-#define __NR_inotify_init      240
-#define __NR_inotify_add_watch 241
-#define __NR_inotify_rm_watch  242
-#define __NR_openat            243
-#define __NR_mkdirat           244
-#define __NR_mknodat           245
-#define __NR_fchownat          246
-#define __NR_futimesat         247
-#define __NR_fstatat64         248
-#define __NR_unlinkat          249
-#define __NR_renameat          250
-#define __NR_linkat            251
-#define __NR_symlinkat         252
-#define __NR_readlinkat                253
-#define __NR_fchmodat          254
-#define __NR_faccessat         255
-#define __NR_pselect6          256
-#define __NR_ppoll             257
-#define __NR_unshare           258
-#define __NR_set_robust_list   259
-#define __NR_get_robust_list   260
-#define __NR_splice            261
-#define __NR_sync_file_range   262
-#define __NR_tee               263
-#define __NR_vmsplice          264
-#define __NR_epoll_pwait       265
-#define __NR_msgget            266
-#define __NR_msgsnd            267
-#define __NR_msgrcv            268
-#define __NR_msgctl            269
-#define __NR_semget            270
-#define __NR_semop             271
-#define __NR_semctl            272
-#define __NR_semtimedop                273
-#define __NR_shmat             274
-#define __NR_shmget            275
-#define __NR_shmdt             276
-#define __NR_shmctl            277
-#define __NR_utimensat         278
-#define __NR_signalfd          279
+#define __NR_socket             149
+#define __NR_bind               150
+#define __NR_connect            151
+#define __NR_listen             152
+#define __NR_accept             153
+#define __NR_getsockname        154
+#define __NR_getpeername        155
+#define __NR_socketpair         156
+#define __NR_send               157
+#define __NR_recv               158
+#define __NR_sendto             159
+#define __NR_recvfrom           160
+#define __NR_shutdown           161
+#define __NR_setsockopt         162
+#define __NR_getsockopt         163
+#define __NR_sendmsg            164
+#define __NR_recvmsg            165
+#define __NR_truncate64         166
+#define __NR_ftruncate64        167
+#define __NR_stat64             168
+#define __NR_lstat64            169
+#define __NR_fstat64            170
+#define __NR_pivot_root         171
+#define __NR_mincore            172
+#define __NR_madvise            173
+#define __NR_getdents64         174
+#define __NR_fcntl64            175
+#define __NR_gettid             176
+#define __NR_readahead          177
+#define __NR_setxattr           178
+#define __NR_lsetxattr          179
+#define __NR_fsetxattr          180
+#define __NR_getxattr           181
+#define __NR_lgetxattr          182
+#define __NR_fgetxattr          183
+#define __NR_listxattr          184
+#define __NR_llistxattr         185
+#define __NR_flistxattr         186
+#define __NR_removexattr        187
+#define __NR_lremovexattr       188
+#define __NR_fremovexattr       189
+#define __NR_tkill              190
+#define __NR_sendfile64         191
+#define __NR_futex              192
+#define __NR_sched_setaffinity  193
+#define __NR_sched_getaffinity  194
+#define __NR_capget             195
+#define __NR_capset             196
+#define __NR_io_setup           197
+#define __NR_io_destroy         198
+#define __NR_io_getevents       199
+#define __NR_io_submit          200
+#define __NR_io_cancel          201
+#define __NR_fadvise64          202
+#define __NR_exit_group         203
+#define __NR_lookup_dcookie     204
+#define __NR_epoll_create       205
+#define __NR_epoll_ctl          206
+#define __NR_epoll_wait         207
+#define __NR_remap_file_pages   208
+#define __NR_set_tid_address    209
+#define __NR_timer_create       210
+#define __NR_timer_settime      211
+#define __NR_timer_gettime      212
+#define __NR_timer_getoverrun   213
+#define __NR_timer_delete       214
+#define __NR_clock_settime      215
+#define __NR_clock_gettime      216
+#define __NR_clock_getres       217
+#define __NR_clock_nanosleep    218
+#define __NR_statfs64           219
+#define __NR_fstatfs64          220
+#define __NR_tgkill             221
+/* 222 reserved for tux */
+#define __NR_utimes             223
+#define __NR_fadvise64_64       224
+#define __NR_cacheflush         225
+#define __NR_vserver            226
+#define __NR_mq_open            227
+#define __NR_mq_unlink          228
+#define __NR_mq_timedsend       229
+#define __NR_mq_timedreceive    230
+#define __NR_mq_notify          231
+#define __NR_mq_getsetattr      232
+#define __NR_kexec_load         233
+#define __NR_waitid             234
+#define __NR_add_key            235
+#define __NR_request_key        236
+#define __NR_keyctl             237
+#define __NR_ioprio_set         238
+#define __NR_ioprio_get         239
+#define __NR_inotify_init       240
+#define __NR_inotify_add_watch  241
+#define __NR_inotify_rm_watch   242
+#define __NR_openat             243
+#define __NR_mkdirat            244
+#define __NR_mknodat            245
+#define __NR_fchownat           246
+#define __NR_futimesat          247
+#define __NR_fstatat64          248
+#define __NR_unlinkat           249
+#define __NR_renameat           250
+#define __NR_linkat             251
+#define __NR_symlinkat          252
+#define __NR_readlinkat         253
+#define __NR_fchmodat           254
+#define __NR_faccessat          255
+#define __NR_pselect6           256
+#define __NR_ppoll              257
+#define __NR_unshare            258
+#define __NR_set_robust_list    259
+#define __NR_get_robust_list    260
+#define __NR_splice             261
+#define __NR_sync_file_range    262
+#define __NR_tee                263
+#define __NR_vmsplice           264
+#define __NR_epoll_pwait        265
+#define __NR_msgget             266
+#define __NR_msgsnd             267
+#define __NR_msgrcv             268
+#define __NR_msgctl             269
+#define __NR_semget             270
+#define __NR_semop              271
+#define __NR_semctl             272
+#define __NR_semtimedop         273
+#define __NR_shmat              274
+#define __NR_shmget             275
+#define __NR_shmdt              276
+#define __NR_shmctl             277
+#define __NR_utimensat          278
+#define __NR_signalfd           279
 /* 280 was __NR_timerfd */
-#define __NR_eventfd           281
-#define __NR_setns             283
-#define __NR_pread64           284
-#define __NR_pwrite64          285
-#define __NR_timerfd_create    286
-#define __NR_fallocate         287
-#define __NR_timerfd_settime   288
-#define __NR_timerfd_gettime   289
-#define __NR_signalfd4         290
-#define __NR_eventfd2          291
-#define __NR_epoll_create1     292
-#define __NR_dup3              293
-#define __NR_pipe2             294
-#define __NR_inotify_init1     295
-#define __NR_preadv            296
-#define __NR_pwritev           297
-#define __NR_rt_tgsigqueueinfo 298
-#define __NR_perf_event_open   299
-#define __NR_recvmmsg          300
-#define __NR_fanotify_init     301
-#define __NR_fanotify_mark     302
-#define __NR_prlimit64         303
-#define __NR_name_to_handle_at 304
-#define __NR_open_by_handle_at 305
-#define __NR_clock_adjtime     306
-#define __NR_syncfs            307
-#define __NR_sendmmsg          308
-#define __NR_process_vm_readv  309
-#define __NR_process_vm_writev 310
-#define __NR_kcmp              311
-#define __NR_finit_module      312
-#define __NR_sched_setattr     313
-#define __NR_sched_getattr     314
-#define __NR_renameat2         315
-#define __NR_seccomp           316
-#define __NR_getrandom         317
-#define __NR_memfd_create      318
-#define __NR_bpf               319
-#define __NR_execveat          320
-#define __NR_accept4           321
-#define __NR_userfaultfd       322
-#define __NR_membarrier                323
-#define __NR_mlock2            324
+#define __NR_eventfd            281
+/* 282 was half-implemented __NR_recvmmsg */
+#define __NR_setns              283
+#define __NR_pread64            284
+#define __NR_pwrite64           285
+#define __NR_timerfd_create     286
+#define __NR_fallocate          287
+#define __NR_timerfd_settime    288
+#define __NR_timerfd_gettime    289
+#define __NR_signalfd4          290
+#define __NR_eventfd2           291
+#define __NR_epoll_create1      292
+#define __NR_dup3               293
+#define __NR_pipe2              294
+#define __NR_inotify_init1      295
+#define __NR_preadv             296
+#define __NR_pwritev            297
+#define __NR_rt_tgsigqueueinfo  298
+#define __NR_perf_event_open    299
+#define __NR_recvmmsg           300
+#define __NR_fanotify_init      301
+#define __NR_fanotify_mark      302
+#define __NR_prlimit64          303
+#define __NR_name_to_handle_at  304
+#define __NR_open_by_handle_at  305
+#define __NR_clock_adjtime      306
+#define __NR_syncfs             307
+#define __NR_sendmmsg           308
+#define __NR_process_vm_readv   309
+#define __NR_process_vm_writev  310
+#define __NR_kcmp               311
+#define __NR_finit_module       312
+#define __NR_sched_setattr      313
+#define __NR_sched_getattr      314
+#define __NR_renameat2          315
+#define __NR_seccomp            316
+#define __NR_getrandom          317
+#define __NR_memfd_create       318
+#define __NR_bpf                319
+#define __NR_execveat           320
+#define __NR_accept4            321
+#define __NR_userfaultfd        322
+#define __NR_membarrier         323
+#define __NR_mlock2             324
 #define __NR_copy_file_range    325
+#define __NR_preadv2            326
+#define __NR_pwritev2           327
 
 #endif /* _UAPI__ASM_AVR32_UNISTD_H */
index cb3991552f14b56fdd79351b6bfb539d84548d62..cb256534ed925becf328cae60896bd04906f1527 100644 (file)
@@ -133,3 +133,21 @@ __sys_copy_file_range:
        call    sys_copy_file_range
        sub     sp, -4
        popm    pc
+
+       .global __sys_preadv2
+       .type   __sys_preadv2,@function
+__sys_preadv2:
+       pushm   lr
+       st.w    --sp, ARG6
+       call    sys_preadv2
+       sub     sp, -4
+       popm    pc
+
+       .global __sys_pwritev2
+       .type   __sys_pwritev2,@function
+__sys_pwritev2:
+       pushm   lr
+       st.w    --sp, ARG6
+       call    sys_pwritev2
+       sub     sp, -4
+       popm    pc
index 64d71a781fa88da2c687ee8bd102a49fee79ea22..7b348ba70e41d2e0f1816f56732e72368a435e2c 100644 (file)
  */
 
        .section .rodata,"a",@progbits
-       .type   sys_call_table,@object
-       .global sys_call_table
-       .align  2
+       .type sys_call_table,@object
+       .global sys_call_table
+       .align 2
 sys_call_table:
-       .long   sys_restart_syscall
-       .long   sys_exit
-       .long   sys_fork
-       .long   sys_read
-       .long   sys_write
-       .long   sys_open                /* 5 */
-       .long   sys_close
-       .long   sys_umask
-       .long   sys_creat
-       .long   sys_link
-       .long   sys_unlink              /* 10 */
-       .long   sys_execve
-       .long   sys_chdir
-       .long   sys_time
-       .long   sys_mknod
-       .long   sys_chmod               /* 15 */
-       .long   sys_chown
-       .long   sys_lchown
-       .long   sys_lseek
-       .long   sys_llseek
-       .long   sys_getpid              /* 20 */
-       .long   sys_mount
-       .long   sys_umount
-       .long   sys_setuid
-       .long   sys_getuid
-       .long   sys_stime               /* 25 */
-       .long   sys_ptrace
-       .long   sys_alarm
-       .long   sys_pause
-       .long   sys_utime
-       .long   sys_newstat             /* 30 */
-       .long   sys_newfstat
-       .long   sys_newlstat
-       .long   sys_access
-       .long   sys_chroot
-       .long   sys_sync                /* 35 */
-       .long   sys_fsync
-       .long   sys_kill
-       .long   sys_rename
-       .long   sys_mkdir
-       .long   sys_rmdir               /* 40 */
-       .long   sys_dup
-       .long   sys_pipe
-       .long   sys_times
-       .long   sys_clone
-       .long   sys_brk                 /* 45 */
-       .long   sys_setgid
-       .long   sys_getgid
-       .long   sys_getcwd
-       .long   sys_geteuid
-       .long   sys_getegid             /* 50 */
-       .long   sys_acct
-       .long   sys_setfsuid
-       .long   sys_setfsgid
-       .long   sys_ioctl
-       .long   sys_fcntl               /* 55 */
-       .long   sys_setpgid
-       .long   sys_mremap
-       .long   sys_setresuid
-       .long   sys_getresuid
-       .long   sys_setreuid            /* 60 */
-       .long   sys_setregid
-       .long   sys_ustat
-       .long   sys_dup2
-       .long   sys_getppid
-       .long   sys_getpgrp             /* 65 */
-       .long   sys_setsid
-       .long   sys_rt_sigaction
-       .long   __sys_rt_sigreturn
-       .long   sys_rt_sigprocmask
-       .long   sys_rt_sigpending       /* 70 */
-       .long   sys_rt_sigtimedwait
-       .long   sys_rt_sigqueueinfo
-       .long   __sys_rt_sigsuspend
-       .long   sys_sethostname
-       .long   sys_setrlimit           /* 75 */
-       .long   sys_getrlimit
-       .long   sys_getrusage
-       .long   sys_gettimeofday
-       .long   sys_settimeofday
-       .long   sys_getgroups           /* 80 */
-       .long   sys_setgroups
-       .long   sys_select
-       .long   sys_symlink
-       .long   sys_fchdir
-       .long   sys_readlink            /* 85 */
-       .long   sys_pread64
-       .long   sys_pwrite64
-       .long   sys_swapon
-       .long   sys_reboot
-       .long   __sys_mmap2             /* 90 */
-       .long   sys_munmap
-       .long   sys_truncate
-       .long   sys_ftruncate
-       .long   sys_fchmod
-       .long   sys_fchown              /* 95 */
-       .long   sys_getpriority
-       .long   sys_setpriority
-       .long   sys_wait4
-       .long   sys_statfs
-       .long   sys_fstatfs             /* 100 */
-       .long   sys_vhangup
-       .long   sys_sigaltstack
-       .long   sys_syslog
-       .long   sys_setitimer
-       .long   sys_getitimer           /* 105 */
-       .long   sys_swapoff
-       .long   sys_sysinfo
-       .long   sys_ni_syscall          /* was sys_ipc briefly */
-       .long   sys_sendfile
-       .long   sys_setdomainname       /* 110 */
-       .long   sys_newuname
-       .long   sys_adjtimex
-       .long   sys_mprotect
-       .long   sys_vfork
-       .long   sys_init_module         /* 115 */
-       .long   sys_delete_module
-       .long   sys_quotactl
-       .long   sys_getpgid
-       .long   sys_bdflush
-       .long   sys_sysfs               /* 120 */
-       .long   sys_personality
-       .long   sys_ni_syscall          /* reserved for afs_syscall */
-       .long   sys_getdents
-       .long   sys_flock
-       .long   sys_msync               /* 125 */
-       .long   sys_readv
-       .long   sys_writev
-       .long   sys_getsid
-       .long   sys_fdatasync
-       .long   sys_sysctl              /* 130 */
-       .long   sys_mlock
-       .long   sys_munlock
-       .long   sys_mlockall
-       .long   sys_munlockall
-       .long   sys_sched_setparam              /* 135 */
-       .long   sys_sched_getparam
-       .long   sys_sched_setscheduler
-       .long   sys_sched_getscheduler
-       .long   sys_sched_yield
-       .long   sys_sched_get_priority_max      /* 140 */
-       .long   sys_sched_get_priority_min
-       .long   sys_sched_rr_get_interval
-       .long   sys_nanosleep
-       .long   sys_poll
-       .long   sys_ni_syscall          /* 145 was nfsservctl */
-       .long   sys_setresgid
-       .long   sys_getresgid
-       .long   sys_prctl
-       .long   sys_socket
-       .long   sys_bind                /* 150 */
-       .long   sys_connect
-       .long   sys_listen
-       .long   sys_accept
-       .long   sys_getsockname
-       .long   sys_getpeername         /* 155 */
-       .long   sys_socketpair
-       .long   sys_send
-       .long   sys_recv
-       .long   __sys_sendto
-       .long   __sys_recvfrom          /* 160 */
-       .long   sys_shutdown
-       .long   sys_setsockopt
-       .long   sys_getsockopt
-       .long   sys_sendmsg
-       .long   sys_recvmsg             /* 165 */
-       .long   sys_truncate64
-       .long   sys_ftruncate64
-       .long   sys_stat64
-       .long   sys_lstat64
-       .long   sys_fstat64             /* 170 */
-       .long   sys_pivot_root
-       .long   sys_mincore
-       .long   sys_madvise
-       .long   sys_getdents64
-       .long   sys_fcntl64             /* 175 */
-       .long   sys_gettid
-       .long   sys_readahead
-       .long   sys_setxattr
-       .long   sys_lsetxattr
-       .long   sys_fsetxattr           /* 180 */
-       .long   sys_getxattr
-       .long   sys_lgetxattr
-       .long   sys_fgetxattr
-       .long   sys_listxattr
-       .long   sys_llistxattr          /* 185 */
-       .long   sys_flistxattr
-       .long   sys_removexattr
-       .long   sys_lremovexattr
-       .long   sys_fremovexattr
-       .long   sys_tkill               /* 190 */
-       .long   sys_sendfile64
-       .long   sys_futex
-       .long   sys_sched_setaffinity
-       .long   sys_sched_getaffinity
-       .long   sys_capget              /* 195 */
-       .long   sys_capset
-       .long   sys_io_setup
-       .long   sys_io_destroy
-       .long   sys_io_getevents
-       .long   sys_io_submit           /* 200 */
-       .long   sys_io_cancel
-       .long   sys_fadvise64
-       .long   sys_exit_group
-       .long   sys_lookup_dcookie
-       .long   sys_epoll_create        /* 205 */
-       .long   sys_epoll_ctl
-       .long   sys_epoll_wait
-       .long   sys_remap_file_pages
-       .long   sys_set_tid_address
-       .long   sys_timer_create        /* 210 */
-       .long   sys_timer_settime
-       .long   sys_timer_gettime
-       .long   sys_timer_getoverrun
-       .long   sys_timer_delete
-       .long   sys_clock_settime       /* 215 */
-       .long   sys_clock_gettime
-       .long   sys_clock_getres
-       .long   sys_clock_nanosleep
-       .long   sys_statfs64
-       .long   sys_fstatfs64           /* 220 */
-       .long   sys_tgkill
-       .long   sys_ni_syscall          /* reserved for TUX */
-       .long   sys_utimes
-       .long   sys_fadvise64_64
-       .long   sys_cacheflush          /* 225 */
-       .long   sys_ni_syscall          /* sys_vserver */
-       .long   sys_mq_open
-       .long   sys_mq_unlink
-       .long   sys_mq_timedsend
-       .long   sys_mq_timedreceive     /* 230 */
-       .long   sys_mq_notify
-       .long   sys_mq_getsetattr
-       .long   sys_kexec_load
-       .long   sys_waitid
-       .long   sys_add_key             /* 235 */
-       .long   sys_request_key
-       .long   sys_keyctl
-       .long   sys_ioprio_set
-       .long   sys_ioprio_get
-       .long   sys_inotify_init        /* 240 */
-       .long   sys_inotify_add_watch
-       .long   sys_inotify_rm_watch
-       .long   sys_openat
-       .long   sys_mkdirat
-       .long   sys_mknodat             /* 245 */
-       .long   sys_fchownat
-       .long   sys_futimesat
-       .long   sys_fstatat64
-       .long   sys_unlinkat
-       .long   sys_renameat            /* 250 */
-       .long   sys_linkat
-       .long   sys_symlinkat
-       .long   sys_readlinkat
-       .long   sys_fchmodat
-       .long   sys_faccessat           /* 255 */
-       .long   __sys_pselect6
-       .long   sys_ppoll
-       .long   sys_unshare
-       .long   sys_set_robust_list
-       .long   sys_get_robust_list     /* 260 */
-       .long   __sys_splice
-       .long   __sys_sync_file_range
-       .long   sys_tee
-       .long   sys_vmsplice
-       .long   __sys_epoll_pwait       /* 265 */
-       .long   sys_msgget
-       .long   sys_msgsnd
-       .long   sys_msgrcv
-       .long   sys_msgctl
-       .long   sys_semget              /* 270 */
-       .long   sys_semop
-       .long   sys_semctl
-       .long   sys_semtimedop
-       .long   sys_shmat
-       .long   sys_shmget              /* 275 */
-       .long   sys_shmdt
-       .long   sys_shmctl
-       .long   sys_utimensat
-       .long   sys_signalfd
-       .long   sys_ni_syscall          /* 280, was sys_timerfd */
-       .long   sys_eventfd
-       .long   sys_recvmmsg
-       .long   sys_setns
-       .long   sys_pread64
-       .long   sys_pwrite64            /* 285 */
-       .long   sys_timerfd_create
-       .long   __sys_fallocate
-       .long   sys_timerfd_settime
-       .long   sys_timerfd_gettime
-       .long   sys_signalfd4           /* 290 */
-       .long   sys_eventfd2
-       .long   sys_epoll_create1
-       .long   sys_dup3
-       .long   sys_pipe2
-       .long   sys_inotify_init1       /* 295 */
-       .long   sys_preadv
-       .long   sys_pwritev
-       .long   sys_rt_tgsigqueueinfo
-       .long   sys_perf_event_open
-       .long   sys_recvmmsg            /* 300 */
-       .long   sys_fanotify_init
-       .long   __sys_fanotify_mark
-       .long   sys_prlimit64
-       .long   sys_name_to_handle_at
-       .long   sys_open_by_handle_at   /* 305 */
-       .long   sys_clock_adjtime
-       .long   sys_syncfs
-       .long   sys_sendmmsg
-       .long   __sys_process_vm_readv
-       .long   __sys_process_vm_writev /* 310 */
-       .long   sys_kcmp
-       .long   sys_finit_module
-       .long   sys_sched_setattr
-       .long   sys_sched_getattr
-       .long   sys_renameat2           /* 315 */
-       .long   sys_seccomp
-       .long   sys_getrandom
-       .long   sys_memfd_create
-       .long   sys_bpf
-       .long   sys_execveat            /* 320 */
-       .long   sys_accept4
-       .long   sys_userfaultfd
-       .long   sys_membarrier
-       .long   sys_mlock2
-       .long   __sys_copy_file_range   /* 325 */
-       .long   sys_ni_syscall          /* r8 is saturated at nr_syscalls */
+       .long sys_restart_syscall
+       .long sys_exit
+       .long sys_fork
+       .long sys_read
+       .long sys_write
+       .long sys_open
+       .long sys_close
+       .long sys_umask
+       .long sys_creat
+       .long sys_link
+       .long sys_unlink /* 10 */
+       .long sys_execve
+       .long sys_chdir
+       .long sys_time
+       .long sys_mknod
+       .long sys_chmod
+       .long sys_chown
+       .long sys_lchown
+       .long sys_lseek
+       .long sys_llseek
+       .long sys_getpid /* 20 */
+       .long sys_mount
+       .long sys_umount
+       .long sys_setuid
+       .long sys_getuid
+       .long sys_stime
+       .long sys_ptrace
+       .long sys_alarm
+       .long sys_pause
+       .long sys_utime
+       .long sys_newstat /* 30 */
+       .long sys_newfstat
+       .long sys_newlstat
+       .long sys_access
+       .long sys_chroot
+       .long sys_sync
+       .long sys_fsync
+       .long sys_kill
+       .long sys_rename
+       .long sys_mkdir
+       .long sys_rmdir /* 40 */
+       .long sys_dup
+       .long sys_pipe
+       .long sys_times
+       .long sys_clone
+       .long sys_brk
+       .long sys_setgid
+       .long sys_getgid
+       .long sys_getcwd
+       .long sys_geteuid
+       .long sys_getegid /* 50 */
+       .long sys_acct
+       .long sys_setfsuid
+       .long sys_setfsgid
+       .long sys_ioctl
+       .long sys_fcntl
+       .long sys_setpgid
+       .long sys_mremap
+       .long sys_setresuid
+       .long sys_getresuid
+       .long sys_setreuid /* 60 */
+       .long sys_setregid
+       .long sys_ustat
+       .long sys_dup2
+       .long sys_getppid
+       .long sys_getpgrp
+       .long sys_setsid
+       .long sys_rt_sigaction
+       .long __sys_rt_sigreturn
+       .long sys_rt_sigprocmask
+       .long sys_rt_sigpending /* 70 */
+       .long sys_rt_sigtimedwait
+       .long sys_rt_sigqueueinfo
+       .long __sys_rt_sigsuspend
+       .long sys_sethostname
+       .long sys_setrlimit
+       .long sys_getrlimit
+       .long sys_getrusage
+       .long sys_gettimeofday
+       .long sys_settimeofday
+       .long sys_getgroups /* 80 */
+       .long sys_setgroups
+       .long sys_select
+       .long sys_symlink
+       .long sys_fchdir
+       .long sys_readlink
+       .long sys_pread64
+       .long sys_pwrite64
+       .long sys_swapon
+       .long sys_reboot
+       .long __sys_mmap2 /* 90 */
+       .long sys_munmap
+       .long sys_truncate
+       .long sys_ftruncate
+       .long sys_fchmod
+       .long sys_fchown
+       .long sys_getpriority
+       .long sys_setpriority
+       .long sys_wait4
+       .long sys_statfs
+       .long sys_fstatfs /* 100 */
+       .long sys_vhangup
+       .long sys_sigaltstack
+       .long sys_syslog
+       .long sys_setitimer
+       .long sys_getitimer
+       .long sys_swapoff
+       .long sys_sysinfo
+       .long sys_ni_syscall /* was sys_ipc briefly */
+       .long sys_sendfile
+       .long sys_setdomainname /* 110 */
+       .long sys_newuname
+       .long sys_adjtimex
+       .long sys_mprotect
+       .long sys_vfork
+       .long sys_init_module
+       .long sys_delete_module
+       .long sys_quotactl
+       .long sys_getpgid
+       .long sys_bdflush
+       .long sys_sysfs /* 120 */
+       .long sys_personality
+       .long sys_ni_syscall /* reserved for afs_syscall */
+       .long sys_getdents
+       .long sys_flock
+       .long sys_msync
+       .long sys_readv
+       .long sys_writev
+       .long sys_getsid
+       .long sys_fdatasync
+       .long sys_sysctl /* 130 */
+       .long sys_mlock
+       .long sys_munlock
+       .long sys_mlockall
+       .long sys_munlockall
+       .long sys_sched_setparam
+       .long sys_sched_getparam
+       .long sys_sched_setscheduler
+       .long sys_sched_getscheduler
+       .long sys_sched_yield
+       .long sys_sched_get_priority_max  /* 140 */
+       .long sys_sched_get_priority_min
+       .long sys_sched_rr_get_interval
+       .long sys_nanosleep
+       .long sys_poll
+       .long sys_ni_syscall /* 145 was nfsservctl */
+       .long sys_setresgid
+       .long sys_getresgid
+       .long sys_prctl
+       .long sys_socket
+       .long sys_bind /* 150 */
+       .long sys_connect
+       .long sys_listen
+       .long sys_accept
+       .long sys_getsockname
+       .long sys_getpeername
+       .long sys_socketpair
+       .long sys_send
+       .long sys_recv
+       .long __sys_sendto
+       .long __sys_recvfrom /* 160 */
+       .long sys_shutdown
+       .long sys_setsockopt
+       .long sys_getsockopt
+       .long sys_sendmsg
+       .long sys_recvmsg
+       .long sys_truncate64
+       .long sys_ftruncate64
+       .long sys_stat64
+       .long sys_lstat64
+       .long sys_fstat64 /* 170 */
+       .long sys_pivot_root
+       .long sys_mincore
+       .long sys_madvise
+       .long sys_getdents64
+       .long sys_fcntl64
+       .long sys_gettid
+       .long sys_readahead
+       .long sys_setxattr
+       .long sys_lsetxattr
+       .long sys_fsetxattr /* 180 */
+       .long sys_getxattr
+       .long sys_lgetxattr
+       .long sys_fgetxattr
+       .long sys_listxattr
+       .long sys_llistxattr
+       .long sys_flistxattr
+       .long sys_removexattr
+       .long sys_lremovexattr
+       .long sys_fremovexattr
+       .long sys_tkill /* 190 */
+       .long sys_sendfile64
+       .long sys_futex
+       .long sys_sched_setaffinity
+       .long sys_sched_getaffinity
+       .long sys_capget
+       .long sys_capset
+       .long sys_io_setup
+       .long sys_io_destroy
+       .long sys_io_getevents
+       .long sys_io_submit /* 200 */
+       .long sys_io_cancel
+       .long sys_fadvise64
+       .long sys_exit_group
+       .long sys_lookup_dcookie
+       .long sys_epoll_create
+       .long sys_epoll_ctl
+       .long sys_epoll_wait
+       .long sys_remap_file_pages
+       .long sys_set_tid_address
+       .long sys_timer_create /* 210 */
+       .long sys_timer_settime
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
+       .long sys_statfs64
+       .long sys_fstatfs64 /* 220 */
+       .long sys_tgkill
+       .long sys_ni_syscall /* reserved for TUX */
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_cacheflush
+       .long sys_ni_syscall /* sys_vserver */
+       .long sys_mq_open
+       .long sys_mq_unlink
+       .long sys_mq_timedsend
+       .long sys_mq_timedreceive /* 230 */
+       .long sys_mq_notify
+       .long sys_mq_getsetattr
+       .long sys_kexec_load
+       .long sys_waitid
+       .long sys_add_key
+       .long sys_request_key
+       .long sys_keyctl
+       .long sys_ioprio_set
+       .long sys_ioprio_get
+       .long sys_inotify_init /* 240 */
+       .long sys_inotify_add_watch
+       .long sys_inotify_rm_watch
+       .long sys_openat
+       .long sys_mkdirat
+       .long sys_mknodat
+       .long sys_fchownat
+       .long sys_futimesat
+       .long sys_fstatat64
+       .long sys_unlinkat
+       .long sys_renameat /* 250 */
+       .long sys_linkat
+       .long sys_symlinkat
+       .long sys_readlinkat
+       .long sys_fchmodat
+       .long sys_faccessat
+       .long __sys_pselect6
+       .long sys_ppoll
+       .long sys_unshare
+       .long sys_set_robust_list
+       .long sys_get_robust_list /* 260 */
+       .long __sys_splice
+       .long __sys_sync_file_range
+       .long sys_tee
+       .long sys_vmsplice
+       .long __sys_epoll_pwait
+       .long sys_msgget
+       .long sys_msgsnd
+       .long sys_msgrcv
+       .long sys_msgctl
+       .long sys_semget /* 270 */
+       .long sys_semop
+       .long sys_semctl
+       .long sys_semtimedop
+       .long sys_shmat
+       .long sys_shmget
+       .long sys_shmdt
+       .long sys_shmctl
+       .long sys_utimensat
+       .long sys_signalfd
+       .long sys_ni_syscall /* 280, was sys_timerfd */
+       .long sys_eventfd
+       .long sys_ni_syscall /* 282, was half-implemented recvmmsg */
+       .long sys_setns
+       .long sys_pread64
+       .long sys_pwrite64
+       .long sys_timerfd_create
+       .long __sys_fallocate
+       .long sys_timerfd_settime
+       .long sys_timerfd_gettime
+       .long sys_signalfd4 /* 290 */
+       .long sys_eventfd2
+       .long sys_epoll_create1
+       .long sys_dup3
+       .long sys_pipe2
+       .long sys_inotify_init1
+       .long sys_preadv
+       .long sys_pwritev
+       .long sys_rt_tgsigqueueinfo
+       .long sys_perf_event_open
+       .long sys_recvmmsg /* 300 */
+       .long sys_fanotify_init
+       .long __sys_fanotify_mark
+       .long sys_prlimit64
+       .long sys_name_to_handle_at
+       .long sys_open_by_handle_at
+       .long sys_clock_adjtime
+       .long sys_syncfs
+       .long sys_sendmmsg
+       .long __sys_process_vm_readv
+       .long __sys_process_vm_writev /* 310 */
+       .long sys_kcmp
+       .long sys_finit_module
+       .long sys_sched_setattr
+       .long sys_sched_getattr
+       .long sys_renameat2
+       .long sys_seccomp
+       .long sys_getrandom
+       .long sys_memfd_create
+       .long sys_bpf
+       .long sys_execveat /* 320 */
+       .long sys_accept4
+       .long sys_userfaultfd
+       .long sys_membarrier
+       .long sys_mlock2
+       .long __sys_copy_file_range
+       .long __sys_preadv2
+       .long __sys_pwritev2
+       .long sys_ni_syscall /* r8 is saturated at nr_syscalls */
index 83c2a0021b5627e909adf74b54214846327c43f2..13d3fc4270b7b4ab2f3bea5fb352b65f4e6e09db 100644 (file)
@@ -435,7 +435,7 @@ void __init at32_init_pio(struct platform_device *pdev)
        struct resource *regs;
        struct pio_device *pio;
 
-       if (pdev->id > MAX_NR_PIO_DEVICES) {
+       if (pdev->id >= MAX_NR_PIO_DEVICES) {
                dev_err(&pdev->dev, "only %d PIO devices supported\n",
                        MAX_NR_PIO_DEVICES);
                return;
index f9af6461521ab899396ce101d54e5a61af5a9df0..9144204442eb68438544a2e51af57ae13850af44 100644 (file)
@@ -143,12 +143,12 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
  */
 static long
 axon_ram_direct_access(struct block_device *device, sector_t sector,
-                      void __pmem **kaddr, pfn_t *pfn, long size)
+                      void **kaddr, pfn_t *pfn, long size)
 {
        struct axon_ram_bank *bank = device->bd_disk->private_data;
        loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT;
 
-       *kaddr = (void __pmem __force *) bank->io_addr + offset;
+       *kaddr = (void *) bank->io_addr + offset;
        *pfn = phys_to_pfn_t(bank->ph_addr + offset, PFN_DEV);
        return bank->size - offset;
 }
index edcf2a70694204c9685cb6ed019f8c93496749c6..598df5708501734307565d3d7ba7c2e8b3472f6e 100644 (file)
@@ -102,7 +102,7 @@ static void appldata_get_mem_data(void *data)
        mem_data->totalhigh = P2K(val.totalhigh);
        mem_data->freehigh  = P2K(val.freehigh);
        mem_data->bufferram = P2K(val.bufferram);
-       mem_data->cached    = P2K(global_page_state(NR_FILE_PAGES)
+       mem_data->cached    = P2K(global_node_page_state(NR_FILE_PAGES)
                                - val.bufferram);
 
        si_swapinfo(&val);
index c4d5bf841a7f19bc727abbff423ed12b20666f29..7cc6ee7f1a58391af570f8ada0507af631639bb9 100644 (file)
@@ -45,20 +45,20 @@ void show_mem(unsigned int filter)
        struct zone *zone;
 
        pr_err("Active:%lu inactive:%lu dirty:%lu writeback:%lu unstable:%lu free:%lu\n slab:%lu mapped:%lu pagetables:%lu bounce:%lu pagecache:%lu swap:%lu\n",
-              (global_page_state(NR_ACTIVE_ANON) +
-               global_page_state(NR_ACTIVE_FILE)),
-              (global_page_state(NR_INACTIVE_ANON) +
-               global_page_state(NR_INACTIVE_FILE)),
-              global_page_state(NR_FILE_DIRTY),
-              global_page_state(NR_WRITEBACK),
-              global_page_state(NR_UNSTABLE_NFS),
+              (global_node_page_state(NR_ACTIVE_ANON) +
+               global_node_page_state(NR_ACTIVE_FILE)),
+              (global_node_page_state(NR_INACTIVE_ANON) +
+               global_node_page_state(NR_INACTIVE_FILE)),
+              global_node_page_state(NR_FILE_DIRTY),
+              global_node_page_state(NR_WRITEBACK),
+              global_node_page_state(NR_UNSTABLE_NFS),
               global_page_state(NR_FREE_PAGES),
               (global_page_state(NR_SLAB_RECLAIMABLE) +
                global_page_state(NR_SLAB_UNRECLAIMABLE)),
-              global_page_state(NR_FILE_MAPPED),
+              global_node_page_state(NR_FILE_MAPPED),
               global_page_state(NR_PAGETABLE),
               global_page_state(NR_BOUNCE),
-              global_page_state(NR_FILE_PAGES),
+              global_node_page_state(NR_FILE_PAGES),
               get_nr_swap_pages());
 
        for_each_zone(zone) {
index c64b1e9c5d1a30d916be2d944a3e94134b240fb0..d683993248c8cf485cdc953325acb36a298b73c3 100644 (file)
 #define X86_FEATURE_RDSEED     ( 9*32+18) /* The RDSEED instruction */
 #define X86_FEATURE_ADX                ( 9*32+19) /* The ADCX and ADOX instructions */
 #define X86_FEATURE_SMAP       ( 9*32+20) /* Supervisor Mode Access Prevention */
-#define X86_FEATURE_PCOMMIT    ( 9*32+22) /* PCOMMIT instruction */
 #define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */
 #define X86_FEATURE_CLWB       ( 9*32+24) /* CLWB instruction */
 #define X86_FEATURE_AVX512PF   ( 9*32+26) /* AVX-512 Prefetch */
index fbc5e92e1ecc43bbf29e07de629d801a37d95ee5..643eba42d6206aa0fbcb57baa150606269577523 100644 (file)
  * @n: length of the copy in bytes
  *
  * Copy data to persistent memory media via non-temporal stores so that
- * a subsequent arch_wmb_pmem() can flush cpu and memory controller
- * write buffers to guarantee durability.
+ * a subsequent pmem driver flush operation will drain posted write queues.
  */
-static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src,
-               size_t n)
+static inline void arch_memcpy_to_pmem(void *dst, const void *src, size_t n)
 {
-       int unwritten;
+       int rem;
 
        /*
         * We are copying between two kernel buffers, if
@@ -40,59 +38,36 @@ static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src,
         * fault) we would have already reported a general protection fault
         * before the WARN+BUG.
         */
-       unwritten = __copy_from_user_inatomic_nocache((void __force *) dst,
-                       (void __user *) src, n);
-       if (WARN(unwritten, "%s: fault copying %p <- %p unwritten: %d\n",
-                               __func__, dst, src, unwritten))
+       rem = __copy_from_user_inatomic_nocache(dst, (void __user *) src, n);
+       if (WARN(rem, "%s: fault copying %p <- %p unwritten: %d\n",
+                               __func__, dst, src, rem))
                BUG();
 }
 
-static inline int arch_memcpy_from_pmem(void *dst, const void __pmem *src,
-               size_t n)
+static inline int arch_memcpy_from_pmem(void *dst, const void *src, size_t n)
 {
        if (static_cpu_has(X86_FEATURE_MCE_RECOVERY))
-               return memcpy_mcsafe(dst, (void __force *) src, n);
-       memcpy(dst, (void __force *) src, n);
+               return memcpy_mcsafe(dst, src, n);
+       memcpy(dst, src, n);
        return 0;
 }
 
-/**
- * arch_wmb_pmem - synchronize writes to persistent memory
- *
- * After a series of arch_memcpy_to_pmem() operations this drains data
- * from cpu write buffers and any platform (memory controller) buffers
- * to ensure that written data is durable on persistent memory media.
- */
-static inline void arch_wmb_pmem(void)
-{
-       /*
-        * wmb() to 'sfence' all previous writes such that they are
-        * architecturally visible to 'pcommit'.  Note, that we've
-        * already arranged for pmem writes to avoid the cache via
-        * arch_memcpy_to_pmem().
-        */
-       wmb();
-       pcommit_sfence();
-}
-
 /**
  * arch_wb_cache_pmem - write back a cache range with CLWB
  * @vaddr:     virtual start address
  * @size:      number of bytes to write back
  *
  * Write back a cache range using the CLWB (cache line write back)
- * instruction.  This function requires explicit ordering with an
- * arch_wmb_pmem() call.
+ * instruction.
  */
-static inline void arch_wb_cache_pmem(void __pmem *addr, size_t size)
+static inline void arch_wb_cache_pmem(void *addr, size_t size)
 {
        u16 x86_clflush_size = boot_cpu_data.x86_clflush_size;
        unsigned long clflush_mask = x86_clflush_size - 1;
-       void *vaddr = (void __force *)addr;
-       void *vend = vaddr + size;
+       void *vend = addr + size;
        void *p;
 
-       for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
+       for (p = (void *)((unsigned long)addr & ~clflush_mask);
             p < vend; p += x86_clflush_size)
                clwb(p);
 }
@@ -113,16 +88,14 @@ static inline bool __iter_needs_pmem_wb(struct iov_iter *i)
  * @i:         iterator with source data
  *
  * Copy data from the iterator 'i' to the PMEM buffer starting at 'addr'.
- * This function requires explicit ordering with an arch_wmb_pmem() call.
  */
-static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
+static inline size_t arch_copy_from_iter_pmem(void *addr, size_t bytes,
                struct iov_iter *i)
 {
-       void *vaddr = (void __force *)addr;
        size_t len;
 
        /* TODO: skip the write-back by always using non-temporal stores */
-       len = copy_from_iter_nocache(vaddr, bytes, i);
+       len = copy_from_iter_nocache(addr, bytes, i);
 
        if (__iter_needs_pmem_wb(i))
                arch_wb_cache_pmem(addr, bytes);
@@ -136,28 +109,16 @@ static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
  * @size:      number of bytes to zero
  *
  * Write zeros into the memory range starting at 'addr' for 'size' bytes.
- * This function requires explicit ordering with an arch_wmb_pmem() call.
  */
-static inline void arch_clear_pmem(void __pmem *addr, size_t size)
+static inline void arch_clear_pmem(void *addr, size_t size)
 {
-       void *vaddr = (void __force *)addr;
-
-       memset(vaddr, 0, size);
+       memset(addr, 0, size);
        arch_wb_cache_pmem(addr, size);
 }
 
-static inline void arch_invalidate_pmem(void __pmem *addr, size_t size)
+static inline void arch_invalidate_pmem(void *addr, size_t size)
 {
-       clflush_cache_range((void __force *) addr, size);
-}
-
-static inline bool __arch_has_wmb_pmem(void)
-{
-       /*
-        * We require that wmb() be an 'sfence', that is only guaranteed on
-        * 64-bit builds
-        */
-       return static_cpu_has(X86_FEATURE_PCOMMIT);
+       clflush_cache_range(addr, size);
 }
 #endif /* CONFIG_ARCH_HAS_PMEM_API */
 #endif /* __ASM_X86_PMEM_H__ */
index d96d0437776569f5c9c0e6f28d125dbc5671d037..587d7914ea4b56a539d9877b1526139285165419 100644 (file)
@@ -253,52 +253,6 @@ static inline void clwb(volatile void *__p)
                : [pax] "a" (p));
 }
 
-/**
- * pcommit_sfence() - persistent commit and fence
- *
- * The PCOMMIT instruction ensures that data that has been flushed from the
- * processor's cache hierarchy with CLWB, CLFLUSHOPT or CLFLUSH is accepted to
- * memory and is durable on the DIMM.  The primary use case for this is
- * persistent memory.
- *
- * This function shows how to properly use CLWB/CLFLUSHOPT/CLFLUSH and PCOMMIT
- * with appropriate fencing.
- *
- * Example:
- * void flush_and_commit_buffer(void *vaddr, unsigned int size)
- * {
- *         unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1;
- *         void *vend = vaddr + size;
- *         void *p;
- *
- *         for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
- *              p < vend; p += boot_cpu_data.x86_clflush_size)
- *                 clwb(p);
- *
- *         // SFENCE to order CLWB/CLFLUSHOPT/CLFLUSH cache flushes
- *         // MFENCE via mb() also works
- *         wmb();
- *
- *         // PCOMMIT and the required SFENCE for ordering
- *         pcommit_sfence();
- * }
- *
- * After this function completes the data pointed to by 'vaddr' has been
- * accepted to memory and will be durable if the 'vaddr' points to persistent
- * memory.
- *
- * PCOMMIT must always be ordered by an MFENCE or SFENCE, so to help simplify
- * things we include both the PCOMMIT and the required SFENCE in the
- * alternatives generated by pcommit_sfence().
- */
-static inline void pcommit_sfence(void)
-{
-       alternative(ASM_NOP7,
-                   ".byte 0x66, 0x0f, 0xae, 0xf8\n\t" /* pcommit */
-                   "sfence",
-                   X86_FEATURE_PCOMMIT);
-}
-
 #define nop() asm volatile ("nop")
 
 
index 14c63c7e8337a3d2bdfc98a5b4c14d2892de5580..a002b07a7099c1f5585e1d64989177fe8509a45f 100644 (file)
@@ -72,7 +72,6 @@
 #define SECONDARY_EXEC_SHADOW_VMCS              0x00004000
 #define SECONDARY_EXEC_ENABLE_PML               0x00020000
 #define SECONDARY_EXEC_XSAVES                  0x00100000
-#define SECONDARY_EXEC_PCOMMIT                 0x00200000
 #define SECONDARY_EXEC_TSC_SCALING              0x02000000
 
 #define PIN_BASED_EXT_INTR_MASK                 0x00000001
index 5b15d94a33f818d04ee7ae2a0f5685125bd89a40..37fee272618f1de348a7d5961f1792debba72991 100644 (file)
@@ -78,7 +78,6 @@
 #define EXIT_REASON_PML_FULL            62
 #define EXIT_REASON_XSAVES              63
 #define EXIT_REASON_XRSTORS             64
-#define EXIT_REASON_PCOMMIT             65
 
 #define VMX_EXIT_REASONS \
        { EXIT_REASON_EXCEPTION_NMI,         "EXCEPTION_NMI" }, \
        { EXIT_REASON_INVVPID,               "INVVPID" }, \
        { EXIT_REASON_INVPCID,               "INVPCID" }, \
        { EXIT_REASON_XSAVES,                "XSAVES" }, \
-       { EXIT_REASON_XRSTORS,               "XRSTORS" }, \
-       { EXIT_REASON_PCOMMIT,               "PCOMMIT" }
+       { EXIT_REASON_XRSTORS,               "XRSTORS" }
 
 #define VMX_ABORT_SAVE_GUEST_MSR_FAIL        1
 #define VMX_ABORT_LOAD_HOST_MSR_FAIL         4
index 7597b42a8a883c668ddbcf28ba03cde86cb30924..64356536449782e05dd1fd790bdb44deb8eafd6d 100644 (file)
@@ -366,7 +366,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
                F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
                F(ADX) | F(SMAP) | F(AVX512F) | F(AVX512PF) | F(AVX512ER) |
-               F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(PCOMMIT);
+               F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB);
 
        /* cpuid 0xD.1.eax */
        const u32 kvm_cpuid_D_1_eax_x86_features =
index e17a74b1d8525708a051c18f93854af5667805be..35058c2c0eeabe0fd9dedd45999478d5cb61fabb 100644 (file)
@@ -144,14 +144,6 @@ static inline bool guest_cpuid_has_rtm(struct kvm_vcpu *vcpu)
        return best && (best->ebx & bit(X86_FEATURE_RTM));
 }
 
-static inline bool guest_cpuid_has_pcommit(struct kvm_vcpu *vcpu)
-{
-       struct kvm_cpuid_entry2 *best;
-
-       best = kvm_find_cpuid_entry(vcpu, 7, 0);
-       return best && (best->ebx & bit(X86_FEATURE_PCOMMIT));
-}
-
 static inline bool guest_cpuid_has_rdtscp(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best;
index 7758680db20b78abbf35f1b263c5f9d8da33b5e1..df07a0a4611ffa81b059229aaa08d04a2981bc56 100644 (file)
@@ -2707,8 +2707,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
                SECONDARY_EXEC_APIC_REGISTER_VIRT |
                SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
                SECONDARY_EXEC_WBINVD_EXITING |
-               SECONDARY_EXEC_XSAVES |
-               SECONDARY_EXEC_PCOMMIT;
+               SECONDARY_EXEC_XSAVES;
 
        if (enable_ept) {
                /* nested EPT: emulate EPT also to L1 */
@@ -3270,7 +3269,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
                        SECONDARY_EXEC_SHADOW_VMCS |
                        SECONDARY_EXEC_XSAVES |
                        SECONDARY_EXEC_ENABLE_PML |
-                       SECONDARY_EXEC_PCOMMIT |
                        SECONDARY_EXEC_TSC_SCALING;
                if (adjust_vmx_controls(min2, opt2,
                                        MSR_IA32_VMX_PROCBASED_CTLS2,
@@ -4858,9 +4856,6 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx)
        if (!enable_pml)
                exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
 
-       /* Currently, we allow L1 guest to directly run pcommit instruction. */
-       exec_control &= ~SECONDARY_EXEC_PCOMMIT;
-
        return exec_control;
 }
 
@@ -4904,9 +4899,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 
        vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, vmx_exec_control(vmx));
 
-       if (cpu_has_secondary_exec_ctrls())
+       if (cpu_has_secondary_exec_ctrls()) {
                vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
                                vmx_secondary_exec_control(vmx));
+       }
 
        if (kvm_vcpu_apicv_active(&vmx->vcpu)) {
                vmcs_write64(EOI_EXIT_BITMAP0, 0);
@@ -7564,13 +7560,6 @@ static int handle_pml_full(struct kvm_vcpu *vcpu)
        return 1;
 }
 
-static int handle_pcommit(struct kvm_vcpu *vcpu)
-{
-       /* we never catch pcommit instruct for L1 guest. */
-       WARN_ON(1);
-       return 1;
-}
-
 /*
  * The exit handlers return 1 if the exit was handled fully and guest execution
  * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
@@ -7621,7 +7610,6 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
        [EXIT_REASON_XSAVES]                  = handle_xsaves,
        [EXIT_REASON_XRSTORS]                 = handle_xrstors,
        [EXIT_REASON_PML_FULL]                = handle_pml_full,
-       [EXIT_REASON_PCOMMIT]                 = handle_pcommit,
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -7930,8 +7918,6 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
                 * the XSS exit bitmap in vmcs12.
                 */
                return nested_cpu_has2(vmcs12, SECONDARY_EXEC_XSAVES);
-       case EXIT_REASON_PCOMMIT:
-               return nested_cpu_has2(vmcs12, SECONDARY_EXEC_PCOMMIT);
        default:
                return true;
        }
@@ -9094,15 +9080,6 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
 
        if (cpu_has_secondary_exec_ctrls())
                vmcs_set_secondary_exec_control(secondary_exec_ctl);
-
-       if (static_cpu_has(X86_FEATURE_PCOMMIT) && nested) {
-               if (guest_cpuid_has_pcommit(vcpu))
-                       vmx->nested.nested_vmx_secondary_ctls_high |=
-                               SECONDARY_EXEC_PCOMMIT;
-               else
-                       vmx->nested.nested_vmx_secondary_ctls_high &=
-                               ~SECONDARY_EXEC_PCOMMIT;
-       }
 }
 
 static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
@@ -9715,8 +9692,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
                exec_control &= ~(SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
                                  SECONDARY_EXEC_RDTSCP |
                                  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
-                                 SECONDARY_EXEC_APIC_REGISTER_VIRT |
-                                 SECONDARY_EXEC_PCOMMIT);
+                                 SECONDARY_EXEC_APIC_REGISTER_VIRT);
                if (nested_cpu_has(vmcs12,
                                CPU_BASED_ACTIVATE_SECONDARY_CONTROLS))
                        exec_control |= vmcs12->secondary_vm_exec_control;
index ec378cd7b71ee4e067d0a4a9beb59413def3296c..767be7c760340bd33b7e4a18b9a8f3a71d9db33e 100644 (file)
@@ -1012,7 +1012,7 @@ GrpTable: Grp15
 4: XSAVE
 5: XRSTOR | lfence (11B)
 6: XSAVEOPT | clwb (66) | mfence (11B)
-7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B)
+7: clflush | clflushopt (66) | sfence (11B)
 EndTable
 
 GrpTable: Grp16
index acad70a0bb0dcccdc6d263b5767535554b668c7c..aebd944bdaa125e6c0cd52dc475fe366c0feb4ba 100644 (file)
@@ -454,32 +454,7 @@ config ACPI_REDUCED_HARDWARE_ONLY
 
          If you are unsure what to do, do not enable this option.
 
-config ACPI_NFIT
-       tristate "ACPI NVDIMM Firmware Interface Table (NFIT)"
-       depends on PHYS_ADDR_T_64BIT
-       depends on BLK_DEV
-       depends on ARCH_HAS_MMIO_FLUSH
-       select LIBNVDIMM
-       help
-         Infrastructure to probe ACPI 6 compliant platforms for
-         NVDIMMs (NFIT) and register a libnvdimm device tree.  In
-         addition to storage devices this also enables libnvdimm to pass
-         ACPI._DSM messages for platform/dimm configuration.
-
-         To compile this driver as a module, choose M here:
-         the module will be called nfit.
-
-config ACPI_NFIT_DEBUG
-       bool "NFIT DSM debug"
-       depends on ACPI_NFIT
-       depends on DYNAMIC_DEBUG
-       default n
-       help
-         Enabling this option causes the nfit driver to dump the
-         input and output buffers of _DSM operations on the ACPI0012
-         device and its children.  This can be very verbose, so leave
-         it disabled unless you are debugging a hardware / firmware
-         issue.
+source "drivers/acpi/nfit/Kconfig"
 
 source "drivers/acpi/apei/Kconfig"
 source "drivers/acpi/dptf/Kconfig"
index 88f54f03e3d228a0bfabb674cc1a72b9a5177151..35a6ccbe302580ecf713d5ec623168dc7ab48a0d 100644 (file)
@@ -69,7 +69,7 @@ obj-$(CONFIG_ACPI_PCI_SLOT)   += pci_slot.o
 obj-$(CONFIG_ACPI_PROCESSOR)   += processor.o
 obj-$(CONFIG_ACPI)             += container.o
 obj-$(CONFIG_ACPI_THERMAL)     += thermal.o
-obj-$(CONFIG_ACPI_NFIT)                += nfit.o
+obj-$(CONFIG_ACPI_NFIT)                += nfit/
 obj-$(CONFIG_ACPI)             += acpi_memhotplug.o
 obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o
 obj-$(CONFIG_ACPI_BATTERY)     += battery.o
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
deleted file mode 100644 (file)
index 1f0e060..0000000
+++ /dev/null
@@ -1,2713 +0,0 @@
-/*
- * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-#include <linux/list_sort.h>
-#include <linux/libnvdimm.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/ndctl.h>
-#include <linux/delay.h>
-#include <linux/list.h>
-#include <linux/acpi.h>
-#include <linux/sort.h>
-#include <linux/pmem.h>
-#include <linux/io.h>
-#include <linux/nd.h>
-#include <asm/cacheflush.h>
-#include "nfit.h"
-
-/*
- * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
- * irrelevant.
- */
-#include <linux/io-64-nonatomic-hi-lo.h>
-
-static bool force_enable_dimms;
-module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
-
-static unsigned int scrub_timeout = NFIT_ARS_TIMEOUT;
-module_param(scrub_timeout, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(scrub_timeout, "Initial scrub timeout in seconds");
-
-/* after three payloads of overflow, it's dead jim */
-static unsigned int scrub_overflow_abort = 3;
-module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(scrub_overflow_abort,
-               "Number of times we overflow ARS results before abort");
-
-static bool disable_vendor_specific;
-module_param(disable_vendor_specific, bool, S_IRUGO);
-MODULE_PARM_DESC(disable_vendor_specific,
-               "Limit commands to the publicly specified set\n");
-
-static struct workqueue_struct *nfit_wq;
-
-struct nfit_table_prev {
-       struct list_head spas;
-       struct list_head memdevs;
-       struct list_head dcrs;
-       struct list_head bdws;
-       struct list_head idts;
-       struct list_head flushes;
-};
-
-static u8 nfit_uuid[NFIT_UUID_MAX][16];
-
-const u8 *to_nfit_uuid(enum nfit_uuids id)
-{
-       return nfit_uuid[id];
-}
-EXPORT_SYMBOL(to_nfit_uuid);
-
-static struct acpi_nfit_desc *to_acpi_nfit_desc(
-               struct nvdimm_bus_descriptor *nd_desc)
-{
-       return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
-}
-
-static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-
-       /*
-        * If provider == 'ACPI.NFIT' we can assume 'dev' is a struct
-        * acpi_device.
-        */
-       if (!nd_desc->provider_name
-                       || strcmp(nd_desc->provider_name, "ACPI.NFIT") != 0)
-               return NULL;
-
-       return to_acpi_device(acpi_desc->dev);
-}
-
-static int xlat_status(void *buf, unsigned int cmd)
-{
-       struct nd_cmd_clear_error *clear_err;
-       struct nd_cmd_ars_status *ars_status;
-       struct nd_cmd_ars_start *ars_start;
-       struct nd_cmd_ars_cap *ars_cap;
-       u16 flags;
-
-       switch (cmd) {
-       case ND_CMD_ARS_CAP:
-               ars_cap = buf;
-               if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
-                       return -ENOTTY;
-
-               /* Command failed */
-               if (ars_cap->status & 0xffff)
-                       return -EIO;
-
-               /* No supported scan types for this range */
-               flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
-               if ((ars_cap->status >> 16 & flags) == 0)
-                       return -ENOTTY;
-               break;
-       case ND_CMD_ARS_START:
-               ars_start = buf;
-               /* ARS is in progress */
-               if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY)
-                       return -EBUSY;
-
-               /* Command failed */
-               if (ars_start->status & 0xffff)
-                       return -EIO;
-               break;
-       case ND_CMD_ARS_STATUS:
-               ars_status = buf;
-               /* Command failed */
-               if (ars_status->status & 0xffff)
-                       return -EIO;
-               /* Check extended status (Upper two bytes) */
-               if (ars_status->status == NFIT_ARS_STATUS_DONE)
-                       return 0;
-
-               /* ARS is in progress */
-               if (ars_status->status == NFIT_ARS_STATUS_BUSY)
-                       return -EBUSY;
-
-               /* No ARS performed for the current boot */
-               if (ars_status->status == NFIT_ARS_STATUS_NONE)
-                       return -EAGAIN;
-
-               /*
-                * ARS interrupted, either we overflowed or some other
-                * agent wants the scan to stop.  If we didn't overflow
-                * then just continue with the returned results.
-                */
-               if (ars_status->status == NFIT_ARS_STATUS_INTR) {
-                       if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
-                               return -ENOSPC;
-                       return 0;
-               }
-
-               /* Unknown status */
-               if (ars_status->status >> 16)
-                       return -EIO;
-               break;
-       case ND_CMD_CLEAR_ERROR:
-               clear_err = buf;
-               if (clear_err->status & 0xffff)
-                       return -EIO;
-               if (!clear_err->cleared)
-                       return -EIO;
-               if (clear_err->length > clear_err->cleared)
-                       return clear_err->cleared;
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
-               struct nvdimm *nvdimm, unsigned int cmd, void *buf,
-               unsigned int buf_len, int *cmd_rc)
-{
-       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
-       union acpi_object in_obj, in_buf, *out_obj;
-       const struct nd_cmd_desc *desc = NULL;
-       struct device *dev = acpi_desc->dev;
-       struct nd_cmd_pkg *call_pkg = NULL;
-       const char *cmd_name, *dimm_name;
-       unsigned long cmd_mask, dsm_mask;
-       acpi_handle handle;
-       unsigned int func;
-       const u8 *uuid;
-       u32 offset;
-       int rc, i;
-
-       func = cmd;
-       if (cmd == ND_CMD_CALL) {
-               call_pkg = buf;
-               func = call_pkg->nd_command;
-       }
-
-       if (nvdimm) {
-               struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-               struct acpi_device *adev = nfit_mem->adev;
-
-               if (!adev)
-                       return -ENOTTY;
-               if (call_pkg && nfit_mem->family != call_pkg->nd_family)
-                       return -ENOTTY;
-
-               dimm_name = nvdimm_name(nvdimm);
-               cmd_name = nvdimm_cmd_name(cmd);
-               cmd_mask = nvdimm_cmd_mask(nvdimm);
-               dsm_mask = nfit_mem->dsm_mask;
-               desc = nd_cmd_dimm_desc(cmd);
-               uuid = to_nfit_uuid(nfit_mem->family);
-               handle = adev->handle;
-       } else {
-               struct acpi_device *adev = to_acpi_dev(acpi_desc);
-
-               cmd_name = nvdimm_bus_cmd_name(cmd);
-               cmd_mask = nd_desc->cmd_mask;
-               dsm_mask = cmd_mask;
-               desc = nd_cmd_bus_desc(cmd);
-               uuid = to_nfit_uuid(NFIT_DEV_BUS);
-               handle = adev->handle;
-               dimm_name = "bus";
-       }
-
-       if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))
-               return -ENOTTY;
-
-       if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask))
-               return -ENOTTY;
-
-       in_obj.type = ACPI_TYPE_PACKAGE;
-       in_obj.package.count = 1;
-       in_obj.package.elements = &in_buf;
-       in_buf.type = ACPI_TYPE_BUFFER;
-       in_buf.buffer.pointer = buf;
-       in_buf.buffer.length = 0;
-
-       /* libnvdimm has already validated the input envelope */
-       for (i = 0; i < desc->in_num; i++)
-               in_buf.buffer.length += nd_cmd_in_size(nvdimm, cmd, desc,
-                               i, buf);
-
-       if (call_pkg) {
-               /* skip over package wrapper */
-               in_buf.buffer.pointer = (void *) &call_pkg->nd_payload;
-               in_buf.buffer.length = call_pkg->nd_size_in;
-       }
-
-       if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {
-               dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n",
-                               __func__, dimm_name, cmd, func,
-                               in_buf.buffer.length);
-               print_hex_dump_debug("nvdimm in  ", DUMP_PREFIX_OFFSET, 4, 4,
-                       in_buf.buffer.pointer,
-                       min_t(u32, 256, in_buf.buffer.length), true);
-       }
-
-       out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj);
-       if (!out_obj) {
-               dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name,
-                               cmd_name);
-               return -EINVAL;
-       }
-
-       if (call_pkg) {
-               call_pkg->nd_fw_size = out_obj->buffer.length;
-               memcpy(call_pkg->nd_payload + call_pkg->nd_size_in,
-                       out_obj->buffer.pointer,
-                       min(call_pkg->nd_fw_size, call_pkg->nd_size_out));
-
-               ACPI_FREE(out_obj);
-               /*
-                * Need to support FW function w/o known size in advance.
-                * Caller can determine required size based upon nd_fw_size.
-                * If we return an error (like elsewhere) then caller wouldn't
-                * be able to rely upon data returned to make calculation.
-                */
-               return 0;
-       }
-
-       if (out_obj->package.type != ACPI_TYPE_BUFFER) {
-               dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n",
-                               __func__, dimm_name, cmd_name, out_obj->type);
-               rc = -EINVAL;
-               goto out;
-       }
-
-       if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {
-               dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__,
-                               dimm_name, cmd_name, out_obj->buffer.length);
-               print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,
-                               4, out_obj->buffer.pointer, min_t(u32, 128,
-                                       out_obj->buffer.length), true);
-       }
-
-       for (i = 0, offset = 0; i < desc->out_num; i++) {
-               u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, buf,
-                               (u32 *) out_obj->buffer.pointer);
-
-               if (offset + out_size > out_obj->buffer.length) {
-                       dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
-                                       __func__, dimm_name, cmd_name, i);
-                       break;
-               }
-
-               if (in_buf.buffer.length + offset + out_size > buf_len) {
-                       dev_dbg(dev, "%s:%s output overrun cmd: %s field: %d\n",
-                                       __func__, dimm_name, cmd_name, i);
-                       rc = -ENXIO;
-                       goto out;
-               }
-               memcpy(buf + in_buf.buffer.length + offset,
-                               out_obj->buffer.pointer + offset, out_size);
-               offset += out_size;
-       }
-       if (offset + in_buf.buffer.length < buf_len) {
-               if (i >= 1) {
-                       /*
-                        * status valid, return the number of bytes left
-                        * unfilled in the output buffer
-                        */
-                       rc = buf_len - offset - in_buf.buffer.length;
-                       if (cmd_rc)
-                               *cmd_rc = xlat_status(buf, cmd);
-               } else {
-                       dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
-                                       __func__, dimm_name, cmd_name, buf_len,
-                                       offset);
-                       rc = -ENXIO;
-               }
-       } else {
-               rc = 0;
-               if (cmd_rc)
-                       *cmd_rc = xlat_status(buf, cmd);
-       }
-
- out:
-       ACPI_FREE(out_obj);
-
-       return rc;
-}
-
-static const char *spa_type_name(u16 type)
-{
-       static const char *to_name[] = {
-               [NFIT_SPA_VOLATILE] = "volatile",
-               [NFIT_SPA_PM] = "pmem",
-               [NFIT_SPA_DCR] = "dimm-control-region",
-               [NFIT_SPA_BDW] = "block-data-window",
-               [NFIT_SPA_VDISK] = "volatile-disk",
-               [NFIT_SPA_VCD] = "volatile-cd",
-               [NFIT_SPA_PDISK] = "persistent-disk",
-               [NFIT_SPA_PCD] = "persistent-cd",
-
-       };
-
-       if (type > NFIT_SPA_PCD)
-               return "unknown";
-
-       return to_name[type];
-}
-
-static int nfit_spa_type(struct acpi_nfit_system_address *spa)
-{
-       int i;
-
-       for (i = 0; i < NFIT_UUID_MAX; i++)
-               if (memcmp(to_nfit_uuid(i), spa->range_guid, 16) == 0)
-                       return i;
-       return -1;
-}
-
-static bool add_spa(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_system_address *spa)
-{
-       size_t length = min_t(size_t, sizeof(*spa), spa->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_spa *nfit_spa;
-
-       list_for_each_entry(nfit_spa, &prev->spas, list) {
-               if (memcmp(nfit_spa->spa, spa, length) == 0) {
-                       list_move_tail(&nfit_spa->list, &acpi_desc->spas);
-                       return true;
-               }
-       }
-
-       nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa), GFP_KERNEL);
-       if (!nfit_spa)
-               return false;
-       INIT_LIST_HEAD(&nfit_spa->list);
-       nfit_spa->spa = spa;
-       list_add_tail(&nfit_spa->list, &acpi_desc->spas);
-       dev_dbg(dev, "%s: spa index: %d type: %s\n", __func__,
-                       spa->range_index,
-                       spa_type_name(nfit_spa_type(spa)));
-       return true;
-}
-
-static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_memory_map *memdev)
-{
-       size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_memdev *nfit_memdev;
-
-       list_for_each_entry(nfit_memdev, &prev->memdevs, list)
-               if (memcmp(nfit_memdev->memdev, memdev, length) == 0) {
-                       list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
-                       return true;
-               }
-
-       nfit_memdev = devm_kzalloc(dev, sizeof(*nfit_memdev), GFP_KERNEL);
-       if (!nfit_memdev)
-               return false;
-       INIT_LIST_HEAD(&nfit_memdev->list);
-       nfit_memdev->memdev = memdev;
-       list_add_tail(&nfit_memdev->list, &acpi_desc->memdevs);
-       dev_dbg(dev, "%s: memdev handle: %#x spa: %d dcr: %d\n",
-                       __func__, memdev->device_handle, memdev->range_index,
-                       memdev->region_index);
-       return true;
-}
-
-static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_control_region *dcr)
-{
-       size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_dcr *nfit_dcr;
-
-       list_for_each_entry(nfit_dcr, &prev->dcrs, list)
-               if (memcmp(nfit_dcr->dcr, dcr, length) == 0) {
-                       list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
-                       return true;
-               }
-
-       nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr), GFP_KERNEL);
-       if (!nfit_dcr)
-               return false;
-       INIT_LIST_HEAD(&nfit_dcr->list);
-       nfit_dcr->dcr = dcr;
-       list_add_tail(&nfit_dcr->list, &acpi_desc->dcrs);
-       dev_dbg(dev, "%s: dcr index: %d windows: %d\n", __func__,
-                       dcr->region_index, dcr->windows);
-       return true;
-}
-
-static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_data_region *bdw)
-{
-       size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_bdw *nfit_bdw;
-
-       list_for_each_entry(nfit_bdw, &prev->bdws, list)
-               if (memcmp(nfit_bdw->bdw, bdw, length) == 0) {
-                       list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
-                       return true;
-               }
-
-       nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw), GFP_KERNEL);
-       if (!nfit_bdw)
-               return false;
-       INIT_LIST_HEAD(&nfit_bdw->list);
-       nfit_bdw->bdw = bdw;
-       list_add_tail(&nfit_bdw->list, &acpi_desc->bdws);
-       dev_dbg(dev, "%s: bdw dcr: %d windows: %d\n", __func__,
-                       bdw->region_index, bdw->windows);
-       return true;
-}
-
-static bool add_idt(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_interleave *idt)
-{
-       size_t length = min_t(size_t, sizeof(*idt), idt->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_idt *nfit_idt;
-
-       list_for_each_entry(nfit_idt, &prev->idts, list)
-               if (memcmp(nfit_idt->idt, idt, length) == 0) {
-                       list_move_tail(&nfit_idt->list, &acpi_desc->idts);
-                       return true;
-               }
-
-       nfit_idt = devm_kzalloc(dev, sizeof(*nfit_idt), GFP_KERNEL);
-       if (!nfit_idt)
-               return false;
-       INIT_LIST_HEAD(&nfit_idt->list);
-       nfit_idt->idt = idt;
-       list_add_tail(&nfit_idt->list, &acpi_desc->idts);
-       dev_dbg(dev, "%s: idt index: %d num_lines: %d\n", __func__,
-                       idt->interleave_index, idt->line_count);
-       return true;
-}
-
-static bool add_flush(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_flush_address *flush)
-{
-       size_t length = min_t(size_t, sizeof(*flush), flush->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_flush *nfit_flush;
-
-       list_for_each_entry(nfit_flush, &prev->flushes, list)
-               if (memcmp(nfit_flush->flush, flush, length) == 0) {
-                       list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
-                       return true;
-               }
-
-       nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush), GFP_KERNEL);
-       if (!nfit_flush)
-               return false;
-       INIT_LIST_HEAD(&nfit_flush->list);
-       nfit_flush->flush = flush;
-       list_add_tail(&nfit_flush->list, &acpi_desc->flushes);
-       dev_dbg(dev, "%s: nfit_flush handle: %d hint_count: %d\n", __func__,
-                       flush->device_handle, flush->hint_count);
-       return true;
-}
-
-static void *add_table(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev, void *table, const void *end)
-{
-       struct device *dev = acpi_desc->dev;
-       struct acpi_nfit_header *hdr;
-       void *err = ERR_PTR(-ENOMEM);
-
-       if (table >= end)
-               return NULL;
-
-       hdr = table;
-       if (!hdr->length) {
-               dev_warn(dev, "found a zero length table '%d' parsing nfit\n",
-                       hdr->type);
-               return NULL;
-       }
-
-       switch (hdr->type) {
-       case ACPI_NFIT_TYPE_SYSTEM_ADDRESS:
-               if (!add_spa(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_MEMORY_MAP:
-               if (!add_memdev(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_CONTROL_REGION:
-               if (!add_dcr(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_DATA_REGION:
-               if (!add_bdw(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_INTERLEAVE:
-               if (!add_idt(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
-               if (!add_flush(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_SMBIOS:
-               dev_dbg(dev, "%s: smbios\n", __func__);
-               break;
-       default:
-               dev_err(dev, "unknown table '%d' parsing nfit\n", hdr->type);
-               break;
-       }
-
-       return table + hdr->length;
-}
-
-static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_mem *nfit_mem)
-{
-       u32 device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
-       u16 dcr = nfit_mem->dcr->region_index;
-       struct nfit_spa *nfit_spa;
-
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
-               u16 range_index = nfit_spa->spa->range_index;
-               int type = nfit_spa_type(nfit_spa->spa);
-               struct nfit_memdev *nfit_memdev;
-
-               if (type != NFIT_SPA_BDW)
-                       continue;
-
-               list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-                       if (nfit_memdev->memdev->range_index != range_index)
-                               continue;
-                       if (nfit_memdev->memdev->device_handle != device_handle)
-                               continue;
-                       if (nfit_memdev->memdev->region_index != dcr)
-                               continue;
-
-                       nfit_mem->spa_bdw = nfit_spa->spa;
-                       return;
-               }
-       }
-
-       dev_dbg(acpi_desc->dev, "SPA-BDW not found for SPA-DCR %d\n",
-                       nfit_mem->spa_dcr->range_index);
-       nfit_mem->bdw = NULL;
-}
-
-static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
-{
-       u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
-       struct nfit_memdev *nfit_memdev;
-       struct nfit_flush *nfit_flush;
-       struct nfit_bdw *nfit_bdw;
-       struct nfit_idt *nfit_idt;
-       u16 idt_idx, range_index;
-
-       list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
-               if (nfit_bdw->bdw->region_index != dcr)
-                       continue;
-               nfit_mem->bdw = nfit_bdw->bdw;
-               break;
-       }
-
-       if (!nfit_mem->bdw)
-               return;
-
-       nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
-
-       if (!nfit_mem->spa_bdw)
-               return;
-
-       range_index = nfit_mem->spa_bdw->range_index;
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               if (nfit_memdev->memdev->range_index != range_index ||
-                               nfit_memdev->memdev->region_index != dcr)
-                       continue;
-               nfit_mem->memdev_bdw = nfit_memdev->memdev;
-               idt_idx = nfit_memdev->memdev->interleave_index;
-               list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
-                       if (nfit_idt->idt->interleave_index != idt_idx)
-                               continue;
-                       nfit_mem->idt_bdw = nfit_idt->idt;
-                       break;
-               }
-
-               list_for_each_entry(nfit_flush, &acpi_desc->flushes, list) {
-                       if (nfit_flush->flush->device_handle !=
-                                       nfit_memdev->memdev->device_handle)
-                               continue;
-                       nfit_mem->nfit_flush = nfit_flush;
-                       break;
-               }
-               break;
-       }
-}
-
-static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa)
-{
-       struct nfit_mem *nfit_mem, *found;
-       struct nfit_memdev *nfit_memdev;
-       int type = nfit_spa_type(spa);
-
-       switch (type) {
-       case NFIT_SPA_DCR:
-       case NFIT_SPA_PM:
-               break;
-       default:
-               return 0;
-       }
-
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               struct nfit_dcr *nfit_dcr;
-               u32 device_handle;
-               u16 dcr;
-
-               if (nfit_memdev->memdev->range_index != spa->range_index)
-                       continue;
-               found = NULL;
-               dcr = nfit_memdev->memdev->region_index;
-               device_handle = nfit_memdev->memdev->device_handle;
-               list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
-                       if (__to_nfit_memdev(nfit_mem)->device_handle
-                                       == device_handle) {
-                               found = nfit_mem;
-                               break;
-                       }
-
-               if (found)
-                       nfit_mem = found;
-               else {
-                       nfit_mem = devm_kzalloc(acpi_desc->dev,
-                                       sizeof(*nfit_mem), GFP_KERNEL);
-                       if (!nfit_mem)
-                               return -ENOMEM;
-                       INIT_LIST_HEAD(&nfit_mem->list);
-                       nfit_mem->acpi_desc = acpi_desc;
-                       list_add(&nfit_mem->list, &acpi_desc->dimms);
-               }
-
-               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
-                       if (nfit_dcr->dcr->region_index != dcr)
-                               continue;
-                       /*
-                        * Record the control region for the dimm.  For
-                        * the ACPI 6.1 case, where there are separate
-                        * control regions for the pmem vs blk
-                        * interfaces, be sure to record the extended
-                        * blk details.
-                        */
-                       if (!nfit_mem->dcr)
-                               nfit_mem->dcr = nfit_dcr->dcr;
-                       else if (nfit_mem->dcr->windows == 0
-                                       && nfit_dcr->dcr->windows)
-                               nfit_mem->dcr = nfit_dcr->dcr;
-                       break;
-               }
-
-               if (dcr && !nfit_mem->dcr) {
-                       dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
-                                       spa->range_index, dcr);
-                       return -ENODEV;
-               }
-
-               if (type == NFIT_SPA_DCR) {
-                       struct nfit_idt *nfit_idt;
-                       u16 idt_idx;
-
-                       /* multiple dimms may share a SPA when interleaved */
-                       nfit_mem->spa_dcr = spa;
-                       nfit_mem->memdev_dcr = nfit_memdev->memdev;
-                       idt_idx = nfit_memdev->memdev->interleave_index;
-                       list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
-                               if (nfit_idt->idt->interleave_index != idt_idx)
-                                       continue;
-                               nfit_mem->idt_dcr = nfit_idt->idt;
-                               break;
-                       }
-                       nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
-               } else {
-                       /*
-                        * A single dimm may belong to multiple SPA-PM
-                        * ranges, record at least one in addition to
-                        * any SPA-DCR range.
-                        */
-                       nfit_mem->memdev_pmem = nfit_memdev->memdev;
-               }
-       }
-
-       return 0;
-}
-
-static int nfit_mem_cmp(void *priv, struct list_head *_a, struct list_head *_b)
-{
-       struct nfit_mem *a = container_of(_a, typeof(*a), list);
-       struct nfit_mem *b = container_of(_b, typeof(*b), list);
-       u32 handleA, handleB;
-
-       handleA = __to_nfit_memdev(a)->device_handle;
-       handleB = __to_nfit_memdev(b)->device_handle;
-       if (handleA < handleB)
-               return -1;
-       else if (handleA > handleB)
-               return 1;
-       return 0;
-}
-
-static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nfit_spa *nfit_spa;
-
-       /*
-        * For each SPA-DCR or SPA-PMEM address range find its
-        * corresponding MEMDEV(s).  From each MEMDEV find the
-        * corresponding DCR.  Then, if we're operating on a SPA-DCR,
-        * try to find a SPA-BDW and a corresponding BDW that references
-        * the DCR.  Throw it all into an nfit_mem object.  Note, that
-        * BDWs are optional.
-        */
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
-               int rc;
-
-               rc = nfit_mem_dcr_init(acpi_desc, nfit_spa->spa);
-               if (rc)
-                       return rc;
-       }
-
-       list_sort(NULL, &acpi_desc->dimms, nfit_mem_cmp);
-
-       return 0;
-}
-
-static ssize_t revision_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
-       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
-       struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-
-       return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
-}
-static DEVICE_ATTR_RO(revision);
-
-static struct attribute *acpi_nfit_attributes[] = {
-       &dev_attr_revision.attr,
-       NULL,
-};
-
-static struct attribute_group acpi_nfit_attribute_group = {
-       .name = "nfit",
-       .attrs = acpi_nfit_attributes,
-};
-
-static const struct attribute_group *acpi_nfit_attribute_groups[] = {
-       &nvdimm_bus_attribute_group,
-       &acpi_nfit_attribute_group,
-       NULL,
-};
-
-static struct acpi_nfit_memory_map *to_nfit_memdev(struct device *dev)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-
-       return __to_nfit_memdev(nfit_mem);
-}
-
-static struct acpi_nfit_control_region *to_nfit_dcr(struct device *dev)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-
-       return nfit_mem->dcr;
-}
-
-static ssize_t handle_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
-
-       return sprintf(buf, "%#x\n", memdev->device_handle);
-}
-static DEVICE_ATTR_RO(handle);
-
-static ssize_t phys_id_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
-
-       return sprintf(buf, "%#x\n", memdev->physical_id);
-}
-static DEVICE_ATTR_RO(phys_id);
-
-static ssize_t vendor_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->vendor_id));
-}
-static DEVICE_ATTR_RO(vendor);
-
-static ssize_t rev_id_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->revision_id));
-}
-static DEVICE_ATTR_RO(rev_id);
-
-static ssize_t device_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->device_id));
-}
-static DEVICE_ATTR_RO(device);
-
-static ssize_t subsystem_vendor_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_vendor_id));
-}
-static DEVICE_ATTR_RO(subsystem_vendor);
-
-static ssize_t subsystem_rev_id_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n",
-                       be16_to_cpu(dcr->subsystem_revision_id));
-}
-static DEVICE_ATTR_RO(subsystem_rev_id);
-
-static ssize_t subsystem_device_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_device_id));
-}
-static DEVICE_ATTR_RO(subsystem_device);
-
-static int num_nvdimm_formats(struct nvdimm *nvdimm)
-{
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-       int formats = 0;
-
-       if (nfit_mem->memdev_pmem)
-               formats++;
-       if (nfit_mem->memdev_bdw)
-               formats++;
-       return formats;
-}
-
-static ssize_t format_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", le16_to_cpu(dcr->code));
-}
-static DEVICE_ATTR_RO(format);
-
-static ssize_t format1_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       u32 handle;
-       ssize_t rc = -ENXIO;
-       struct nfit_mem *nfit_mem;
-       struct nfit_memdev *nfit_memdev;
-       struct acpi_nfit_desc *acpi_desc;
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       nfit_mem = nvdimm_provider_data(nvdimm);
-       acpi_desc = nfit_mem->acpi_desc;
-       handle = to_nfit_memdev(dev)->device_handle;
-
-       /* assumes DIMMs have at most 2 published interface codes */
-       mutex_lock(&acpi_desc->init_mutex);
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
-               struct nfit_dcr *nfit_dcr;
-
-               if (memdev->device_handle != handle)
-                       continue;
-
-               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
-                       if (nfit_dcr->dcr->region_index != memdev->region_index)
-                               continue;
-                       if (nfit_dcr->dcr->code == dcr->code)
-                               continue;
-                       rc = sprintf(buf, "0x%04x\n",
-                                       le16_to_cpu(nfit_dcr->dcr->code));
-                       break;
-               }
-               if (rc != ENXIO)
-                       break;
-       }
-       mutex_unlock(&acpi_desc->init_mutex);
-       return rc;
-}
-static DEVICE_ATTR_RO(format1);
-
-static ssize_t formats_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-
-       return sprintf(buf, "%d\n", num_nvdimm_formats(nvdimm));
-}
-static DEVICE_ATTR_RO(formats);
-
-static ssize_t serial_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%08x\n", be32_to_cpu(dcr->serial_number));
-}
-static DEVICE_ATTR_RO(serial);
-
-static ssize_t family_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-
-       if (nfit_mem->family < 0)
-               return -ENXIO;
-       return sprintf(buf, "%d\n", nfit_mem->family);
-}
-static DEVICE_ATTR_RO(family);
-
-static ssize_t dsm_mask_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-
-       if (nfit_mem->family < 0)
-               return -ENXIO;
-       return sprintf(buf, "%#lx\n", nfit_mem->dsm_mask);
-}
-static DEVICE_ATTR_RO(dsm_mask);
-
-static ssize_t flags_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       u16 flags = to_nfit_memdev(dev)->flags;
-
-       return sprintf(buf, "%s%s%s%s%s\n",
-               flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
-               flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "",
-               flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "",
-               flags & ACPI_NFIT_MEM_NOT_ARMED ? "not_armed " : "",
-               flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : "");
-}
-static DEVICE_ATTR_RO(flags);
-
-static ssize_t id_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID)
-               return sprintf(buf, "%04x-%02x-%04x-%08x\n",
-                               be16_to_cpu(dcr->vendor_id),
-                               dcr->manufacturing_location,
-                               be16_to_cpu(dcr->manufacturing_date),
-                               be32_to_cpu(dcr->serial_number));
-       else
-               return sprintf(buf, "%04x-%08x\n",
-                               be16_to_cpu(dcr->vendor_id),
-                               be32_to_cpu(dcr->serial_number));
-}
-static DEVICE_ATTR_RO(id);
-
-static struct attribute *acpi_nfit_dimm_attributes[] = {
-       &dev_attr_handle.attr,
-       &dev_attr_phys_id.attr,
-       &dev_attr_vendor.attr,
-       &dev_attr_device.attr,
-       &dev_attr_rev_id.attr,
-       &dev_attr_subsystem_vendor.attr,
-       &dev_attr_subsystem_device.attr,
-       &dev_attr_subsystem_rev_id.attr,
-       &dev_attr_format.attr,
-       &dev_attr_formats.attr,
-       &dev_attr_format1.attr,
-       &dev_attr_serial.attr,
-       &dev_attr_flags.attr,
-       &dev_attr_id.attr,
-       &dev_attr_family.attr,
-       &dev_attr_dsm_mask.attr,
-       NULL,
-};
-
-static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
-               struct attribute *a, int n)
-{
-       struct device *dev = container_of(kobj, struct device, kobj);
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-
-       if (!to_nfit_dcr(dev))
-               return 0;
-       if (a == &dev_attr_format1.attr && num_nvdimm_formats(nvdimm) <= 1)
-               return 0;
-       return a->mode;
-}
-
-static struct attribute_group acpi_nfit_dimm_attribute_group = {
-       .name = "nfit",
-       .attrs = acpi_nfit_dimm_attributes,
-       .is_visible = acpi_nfit_dimm_attr_visible,
-};
-
-static const struct attribute_group *acpi_nfit_dimm_attribute_groups[] = {
-       &nvdimm_attribute_group,
-       &nd_device_attribute_group,
-       &acpi_nfit_dimm_attribute_group,
-       NULL,
-};
-
-static struct nvdimm *acpi_nfit_dimm_by_handle(struct acpi_nfit_desc *acpi_desc,
-               u32 device_handle)
-{
-       struct nfit_mem *nfit_mem;
-
-       list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
-               if (__to_nfit_memdev(nfit_mem)->device_handle == device_handle)
-                       return nfit_mem->nvdimm;
-
-       return NULL;
-}
-
-static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_mem *nfit_mem, u32 device_handle)
-{
-       struct acpi_device *adev, *adev_dimm;
-       struct device *dev = acpi_desc->dev;
-       unsigned long dsm_mask;
-       const u8 *uuid;
-       int i;
-
-       /* nfit test assumes 1:1 relationship between commands and dsms */
-       nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en;
-       nfit_mem->family = NVDIMM_FAMILY_INTEL;
-       adev = to_acpi_dev(acpi_desc);
-       if (!adev)
-               return 0;
-
-       adev_dimm = acpi_find_child_device(adev, device_handle, false);
-       nfit_mem->adev = adev_dimm;
-       if (!adev_dimm) {
-               dev_err(dev, "no ACPI.NFIT device with _ADR %#x, disabling...\n",
-                               device_handle);
-               return force_enable_dimms ? 0 : -ENODEV;
-       }
-
-       /*
-        * Until standardization materializes we need to consider up to 3
-        * different command sets.  Note, that checking for function0 (bit0)
-        * tells us if any commands are reachable through this uuid.
-        */
-       for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_HPE2; i++)
-               if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))
-                       break;
-
-       /* limit the supported commands to those that are publicly documented */
-       nfit_mem->family = i;
-       if (nfit_mem->family == NVDIMM_FAMILY_INTEL) {
-               dsm_mask = 0x3fe;
-               if (disable_vendor_specific)
-                       dsm_mask &= ~(1 << ND_CMD_VENDOR);
-       } else if (nfit_mem->family == NVDIMM_FAMILY_HPE1)
-               dsm_mask = 0x1c3c76;
-       else if (nfit_mem->family == NVDIMM_FAMILY_HPE2) {
-               dsm_mask = 0x1fe;
-               if (disable_vendor_specific)
-                       dsm_mask &= ~(1 << 8);
-       } else {
-               dev_dbg(dev, "unknown dimm command family\n");
-               nfit_mem->family = -1;
-               /* DSMs are optional, continue loading the driver... */
-               return 0;
-       }
-
-       uuid = to_nfit_uuid(nfit_mem->family);
-       for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
-               if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i))
-                       set_bit(i, &nfit_mem->dsm_mask);
-
-       return 0;
-}
-
-static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nfit_mem *nfit_mem;
-       int dimm_count = 0;
-
-       list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
-               unsigned long flags = 0, cmd_mask;
-               struct nvdimm *nvdimm;
-               u32 device_handle;
-               u16 mem_flags;
-               int rc;
-
-               device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
-               nvdimm = acpi_nfit_dimm_by_handle(acpi_desc, device_handle);
-               if (nvdimm) {
-                       dimm_count++;
-                       continue;
-               }
-
-               if (nfit_mem->bdw && nfit_mem->memdev_pmem)
-                       flags |= NDD_ALIASING;
-
-               mem_flags = __to_nfit_memdev(nfit_mem)->flags;
-               if (mem_flags & ACPI_NFIT_MEM_NOT_ARMED)
-                       flags |= NDD_UNARMED;
-
-               rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle);
-               if (rc)
-                       continue;
-
-               /*
-                * TODO: provide translation for non-NVDIMM_FAMILY_INTEL
-                * devices (i.e. from nd_cmd to acpi_dsm) to standardize the
-                * userspace interface.
-                */
-               cmd_mask = 1UL << ND_CMD_CALL;
-               if (nfit_mem->family == NVDIMM_FAMILY_INTEL)
-                       cmd_mask |= nfit_mem->dsm_mask;
-
-               nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,
-                               acpi_nfit_dimm_attribute_groups,
-                               flags, cmd_mask);
-               if (!nvdimm)
-                       return -ENOMEM;
-
-               nfit_mem->nvdimm = nvdimm;
-               dimm_count++;
-
-               if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0)
-                       continue;
-
-               dev_info(acpi_desc->dev, "%s flags:%s%s%s%s\n",
-                               nvdimm_name(nvdimm),
-                 mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
-                 mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
-                 mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? " flush_fail" : "",
-                 mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : "");
-
-       }
-
-       return nvdimm_bus_check_dimm_count(acpi_desc->nvdimm_bus, dimm_count);
-}
-
-static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-       const u8 *uuid = to_nfit_uuid(NFIT_DEV_BUS);
-       struct acpi_device *adev;
-       int i;
-
-       nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;
-       adev = to_acpi_dev(acpi_desc);
-       if (!adev)
-               return;
-
-       for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)
-               if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i))
-                       set_bit(i, &nd_desc->cmd_mask);
-}
-
-static ssize_t range_index_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nd_region *nd_region = to_nd_region(dev);
-       struct nfit_spa *nfit_spa = nd_region_provider_data(nd_region);
-
-       return sprintf(buf, "%d\n", nfit_spa->spa->range_index);
-}
-static DEVICE_ATTR_RO(range_index);
-
-static struct attribute *acpi_nfit_region_attributes[] = {
-       &dev_attr_range_index.attr,
-       NULL,
-};
-
-static struct attribute_group acpi_nfit_region_attribute_group = {
-       .name = "nfit",
-       .attrs = acpi_nfit_region_attributes,
-};
-
-static const struct attribute_group *acpi_nfit_region_attribute_groups[] = {
-       &nd_region_attribute_group,
-       &nd_mapping_attribute_group,
-       &nd_device_attribute_group,
-       &nd_numa_attribute_group,
-       &acpi_nfit_region_attribute_group,
-       NULL,
-};
-
-/* enough info to uniquely specify an interleave set */
-struct nfit_set_info {
-       struct nfit_set_info_map {
-               u64 region_offset;
-               u32 serial_number;
-               u32 pad;
-       } mapping[0];
-};
-
-static size_t sizeof_nfit_set_info(int num_mappings)
-{
-       return sizeof(struct nfit_set_info)
-               + num_mappings * sizeof(struct nfit_set_info_map);
-}
-
-static int cmp_map(const void *m0, const void *m1)
-{
-       const struct nfit_set_info_map *map0 = m0;
-       const struct nfit_set_info_map *map1 = m1;
-
-       return memcmp(&map0->region_offset, &map1->region_offset,
-                       sizeof(u64));
-}
-
-/* Retrieve the nth entry referencing this spa */
-static struct acpi_nfit_memory_map *memdev_from_spa(
-               struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
-{
-       struct nfit_memdev *nfit_memdev;
-
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list)
-               if (nfit_memdev->memdev->range_index == range_index)
-                       if (n-- == 0)
-                               return nfit_memdev->memdev;
-       return NULL;
-}
-
-static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
-               struct nd_region_desc *ndr_desc,
-               struct acpi_nfit_system_address *spa)
-{
-       int i, spa_type = nfit_spa_type(spa);
-       struct device *dev = acpi_desc->dev;
-       struct nd_interleave_set *nd_set;
-       u16 nr = ndr_desc->num_mappings;
-       struct nfit_set_info *info;
-
-       if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE)
-               /* pass */;
-       else
-               return 0;
-
-       nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
-       if (!nd_set)
-               return -ENOMEM;
-
-       info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-       for (i = 0; i < nr; i++) {
-               struct nd_mapping *nd_mapping = &ndr_desc->nd_mapping[i];
-               struct nfit_set_info_map *map = &info->mapping[i];
-               struct nvdimm *nvdimm = nd_mapping->nvdimm;
-               struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-               struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc,
-                               spa->range_index, i);
-
-               if (!memdev || !nfit_mem->dcr) {
-                       dev_err(dev, "%s: failed to find DCR\n", __func__);
-                       return -ENODEV;
-               }
-
-               map->region_offset = memdev->region_offset;
-               map->serial_number = nfit_mem->dcr->serial_number;
-       }
-
-       sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
-                       cmp_map, NULL);
-       nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
-       ndr_desc->nd_set = nd_set;
-       devm_kfree(dev, info);
-
-       return 0;
-}
-
-static u64 to_interleave_offset(u64 offset, struct nfit_blk_mmio *mmio)
-{
-       struct acpi_nfit_interleave *idt = mmio->idt;
-       u32 sub_line_offset, line_index, line_offset;
-       u64 line_no, table_skip_count, table_offset;
-
-       line_no = div_u64_rem(offset, mmio->line_size, &sub_line_offset);
-       table_skip_count = div_u64_rem(line_no, mmio->num_lines, &line_index);
-       line_offset = idt->line_offset[line_index]
-               * mmio->line_size;
-       table_offset = table_skip_count * mmio->table_size;
-
-       return mmio->base_offset + line_offset + table_offset + sub_line_offset;
-}
-
-static void wmb_blk(struct nfit_blk *nfit_blk)
-{
-
-       if (nfit_blk->nvdimm_flush) {
-               /*
-                * The first wmb() is needed to 'sfence' all previous writes
-                * such that they are architecturally visible for the platform
-                * buffer flush.  Note that we've already arranged for pmem
-                * writes to avoid the cache via arch_memcpy_to_pmem().  The
-                * final wmb() ensures ordering for the NVDIMM flush write.
-                */
-               wmb();
-               writeq(1, nfit_blk->nvdimm_flush);
-               wmb();
-       } else
-               wmb_pmem();
-}
-
-static u32 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw)
-{
-       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
-       u64 offset = nfit_blk->stat_offset + mmio->size * bw;
-
-       if (mmio->num_lines)
-               offset = to_interleave_offset(offset, mmio);
-
-       return readl(mmio->addr.base + offset);
-}
-
-static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
-               resource_size_t dpa, unsigned int len, unsigned int write)
-{
-       u64 cmd, offset;
-       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
-
-       enum {
-               BCW_OFFSET_MASK = (1ULL << 48)-1,
-               BCW_LEN_SHIFT = 48,
-               BCW_LEN_MASK = (1ULL << 8) - 1,
-               BCW_CMD_SHIFT = 56,
-       };
-
-       cmd = (dpa >> L1_CACHE_SHIFT) & BCW_OFFSET_MASK;
-       len = len >> L1_CACHE_SHIFT;
-       cmd |= ((u64) len & BCW_LEN_MASK) << BCW_LEN_SHIFT;
-       cmd |= ((u64) write) << BCW_CMD_SHIFT;
-
-       offset = nfit_blk->cmd_offset + mmio->size * bw;
-       if (mmio->num_lines)
-               offset = to_interleave_offset(offset, mmio);
-
-       writeq(cmd, mmio->addr.base + offset);
-       wmb_blk(nfit_blk);
-
-       if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
-               readq(mmio->addr.base + offset);
-}
-
-static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
-               resource_size_t dpa, void *iobuf, size_t len, int rw,
-               unsigned int lane)
-{
-       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW];
-       unsigned int copied = 0;
-       u64 base_offset;
-       int rc;
-
-       base_offset = nfit_blk->bdw_offset + dpa % L1_CACHE_BYTES
-               + lane * mmio->size;
-       write_blk_ctl(nfit_blk, lane, dpa, len, rw);
-       while (len) {
-               unsigned int c;
-               u64 offset;
-
-               if (mmio->num_lines) {
-                       u32 line_offset;
-
-                       offset = to_interleave_offset(base_offset + copied,
-                                       mmio);
-                       div_u64_rem(offset, mmio->line_size, &line_offset);
-                       c = min_t(size_t, len, mmio->line_size - line_offset);
-               } else {
-                       offset = base_offset + nfit_blk->bdw_offset;
-                       c = len;
-               }
-
-               if (rw)
-                       memcpy_to_pmem(mmio->addr.aperture + offset,
-                                       iobuf + copied, c);
-               else {
-                       if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH)
-                               mmio_flush_range((void __force *)
-                                       mmio->addr.aperture + offset, c);
-
-                       memcpy_from_pmem(iobuf + copied,
-                                       mmio->addr.aperture + offset, c);
-               }
-
-               copied += c;
-               len -= c;
-       }
-
-       if (rw)
-               wmb_blk(nfit_blk);
-
-       rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
-       return rc;
-}
-
-static int acpi_nfit_blk_region_do_io(struct nd_blk_region *ndbr,
-               resource_size_t dpa, void *iobuf, u64 len, int rw)
-{
-       struct nfit_blk *nfit_blk = nd_blk_region_provider_data(ndbr);
-       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW];
-       struct nd_region *nd_region = nfit_blk->nd_region;
-       unsigned int lane, copied = 0;
-       int rc = 0;
-
-       lane = nd_region_acquire_lane(nd_region);
-       while (len) {
-               u64 c = min(len, mmio->size);
-
-               rc = acpi_nfit_blk_single_io(nfit_blk, dpa + copied,
-                               iobuf + copied, c, rw, lane);
-               if (rc)
-                       break;
-
-               copied += c;
-               len -= c;
-       }
-       nd_region_release_lane(nd_region, lane);
-
-       return rc;
-}
-
-static void nfit_spa_mapping_release(struct kref *kref)
-{
-       struct nfit_spa_mapping *spa_map = to_spa_map(kref);
-       struct acpi_nfit_system_address *spa = spa_map->spa;
-       struct acpi_nfit_desc *acpi_desc = spa_map->acpi_desc;
-
-       WARN_ON(!mutex_is_locked(&acpi_desc->spa_map_mutex));
-       dev_dbg(acpi_desc->dev, "%s: SPA%d\n", __func__, spa->range_index);
-       if (spa_map->type == SPA_MAP_APERTURE)
-               memunmap((void __force *)spa_map->addr.aperture);
-       else
-               iounmap(spa_map->addr.base);
-       release_mem_region(spa->address, spa->length);
-       list_del(&spa_map->list);
-       kfree(spa_map);
-}
-
-static struct nfit_spa_mapping *find_spa_mapping(
-               struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa)
-{
-       struct nfit_spa_mapping *spa_map;
-
-       WARN_ON(!mutex_is_locked(&acpi_desc->spa_map_mutex));
-       list_for_each_entry(spa_map, &acpi_desc->spa_maps, list)
-               if (spa_map->spa == spa)
-                       return spa_map;
-
-       return NULL;
-}
-
-static void nfit_spa_unmap(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa)
-{
-       struct nfit_spa_mapping *spa_map;
-
-       mutex_lock(&acpi_desc->spa_map_mutex);
-       spa_map = find_spa_mapping(acpi_desc, spa);
-
-       if (spa_map)
-               kref_put(&spa_map->kref, nfit_spa_mapping_release);
-       mutex_unlock(&acpi_desc->spa_map_mutex);
-}
-
-static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa, enum spa_map_type type)
-{
-       resource_size_t start = spa->address;
-       resource_size_t n = spa->length;
-       struct nfit_spa_mapping *spa_map;
-       struct resource *res;
-
-       WARN_ON(!mutex_is_locked(&acpi_desc->spa_map_mutex));
-
-       spa_map = find_spa_mapping(acpi_desc, spa);
-       if (spa_map) {
-               kref_get(&spa_map->kref);
-               return spa_map->addr.base;
-       }
-
-       spa_map = kzalloc(sizeof(*spa_map), GFP_KERNEL);
-       if (!spa_map)
-               return NULL;
-
-       INIT_LIST_HEAD(&spa_map->list);
-       spa_map->spa = spa;
-       kref_init(&spa_map->kref);
-       spa_map->acpi_desc = acpi_desc;
-
-       res = request_mem_region(start, n, dev_name(acpi_desc->dev));
-       if (!res)
-               goto err_mem;
-
-       spa_map->type = type;
-       if (type == SPA_MAP_APERTURE)
-               spa_map->addr.aperture = (void __pmem *)memremap(start, n,
-                                                       ARCH_MEMREMAP_PMEM);
-       else
-               spa_map->addr.base = ioremap_nocache(start, n);
-
-
-       if (!spa_map->addr.base)
-               goto err_map;
-
-       list_add_tail(&spa_map->list, &acpi_desc->spa_maps);
-       return spa_map->addr.base;
-
- err_map:
-       release_mem_region(start, n);
- err_mem:
-       kfree(spa_map);
-       return NULL;
-}
-
-/**
- * nfit_spa_map - interleave-aware managed-mappings of acpi_nfit_system_address ranges
- * @nvdimm_bus: NFIT-bus that provided the spa table entry
- * @nfit_spa: spa table to map
- * @type: aperture or control region
- *
- * In the case where block-data-window apertures and
- * dimm-control-regions are interleaved they will end up sharing a
- * single request_mem_region() + ioremap() for the address range.  In
- * the style of devm nfit_spa_map() mappings are automatically dropped
- * when all region devices referencing the same mapping are disabled /
- * unbound.
- */
-static void __iomem *nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa, enum spa_map_type type)
-{
-       void __iomem *iomem;
-
-       mutex_lock(&acpi_desc->spa_map_mutex);
-       iomem = __nfit_spa_map(acpi_desc, spa, type);
-       mutex_unlock(&acpi_desc->spa_map_mutex);
-
-       return iomem;
-}
-
-static int nfit_blk_init_interleave(struct nfit_blk_mmio *mmio,
-               struct acpi_nfit_interleave *idt, u16 interleave_ways)
-{
-       if (idt) {
-               mmio->num_lines = idt->line_count;
-               mmio->line_size = idt->line_size;
-               if (interleave_ways == 0)
-                       return -ENXIO;
-               mmio->table_size = mmio->num_lines * interleave_ways
-                       * mmio->line_size;
-       }
-
-       return 0;
-}
-
-static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc,
-               struct nvdimm *nvdimm, struct nfit_blk *nfit_blk)
-{
-       struct nd_cmd_dimm_flags flags;
-       int rc;
-
-       memset(&flags, 0, sizeof(flags));
-       rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags,
-                       sizeof(flags), NULL);
-
-       if (rc >= 0 && flags.status == 0)
-               nfit_blk->dimm_flags = flags.flags;
-       else if (rc == -ENOTTY) {
-               /* fall back to a conservative default */
-               nfit_blk->dimm_flags = NFIT_BLK_DCR_LATCH | NFIT_BLK_READ_FLUSH;
-               rc = 0;
-       } else
-               rc = -ENXIO;
-
-       return rc;
-}
-
-static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
-               struct device *dev)
-{
-       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
-       struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-       struct nd_blk_region *ndbr = to_nd_blk_region(dev);
-       struct nfit_flush *nfit_flush;
-       struct nfit_blk_mmio *mmio;
-       struct nfit_blk *nfit_blk;
-       struct nfit_mem *nfit_mem;
-       struct nvdimm *nvdimm;
-       int rc;
-
-       nvdimm = nd_blk_region_to_dimm(ndbr);
-       nfit_mem = nvdimm_provider_data(nvdimm);
-       if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) {
-               dev_dbg(dev, "%s: missing%s%s%s\n", __func__,
-                               nfit_mem ? "" : " nfit_mem",
-                               (nfit_mem && nfit_mem->dcr) ? "" : " dcr",
-                               (nfit_mem && nfit_mem->bdw) ? "" : " bdw");
-               return -ENXIO;
-       }
-
-       nfit_blk = devm_kzalloc(dev, sizeof(*nfit_blk), GFP_KERNEL);
-       if (!nfit_blk)
-               return -ENOMEM;
-       nd_blk_region_set_provider_data(ndbr, nfit_blk);
-       nfit_blk->nd_region = to_nd_region(dev);
-
-       /* map block aperture memory */
-       nfit_blk->bdw_offset = nfit_mem->bdw->offset;
-       mmio = &nfit_blk->mmio[BDW];
-       mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw,
-                       SPA_MAP_APERTURE);
-       if (!mmio->addr.base) {
-               dev_dbg(dev, "%s: %s failed to map bdw\n", __func__,
-                               nvdimm_name(nvdimm));
-               return -ENOMEM;
-       }
-       mmio->size = nfit_mem->bdw->size;
-       mmio->base_offset = nfit_mem->memdev_bdw->region_offset;
-       mmio->idt = nfit_mem->idt_bdw;
-       mmio->spa = nfit_mem->spa_bdw;
-       rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_bdw,
-                       nfit_mem->memdev_bdw->interleave_ways);
-       if (rc) {
-               dev_dbg(dev, "%s: %s failed to init bdw interleave\n",
-                               __func__, nvdimm_name(nvdimm));
-               return rc;
-       }
-
-       /* map block control memory */
-       nfit_blk->cmd_offset = nfit_mem->dcr->command_offset;
-       nfit_blk->stat_offset = nfit_mem->dcr->status_offset;
-       mmio = &nfit_blk->mmio[DCR];
-       mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr,
-                       SPA_MAP_CONTROL);
-       if (!mmio->addr.base) {
-               dev_dbg(dev, "%s: %s failed to map dcr\n", __func__,
-                               nvdimm_name(nvdimm));
-               return -ENOMEM;
-       }
-       mmio->size = nfit_mem->dcr->window_size;
-       mmio->base_offset = nfit_mem->memdev_dcr->region_offset;
-       mmio->idt = nfit_mem->idt_dcr;
-       mmio->spa = nfit_mem->spa_dcr;
-       rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_dcr,
-                       nfit_mem->memdev_dcr->interleave_ways);
-       if (rc) {
-               dev_dbg(dev, "%s: %s failed to init dcr interleave\n",
-                               __func__, nvdimm_name(nvdimm));
-               return rc;
-       }
-
-       rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk);
-       if (rc < 0) {
-               dev_dbg(dev, "%s: %s failed get DIMM flags\n",
-                               __func__, nvdimm_name(nvdimm));
-               return rc;
-       }
-
-       nfit_flush = nfit_mem->nfit_flush;
-       if (nfit_flush && nfit_flush->flush->hint_count != 0) {
-               nfit_blk->nvdimm_flush = devm_ioremap_nocache(dev,
-                               nfit_flush->flush->hint_address[0], 8);
-               if (!nfit_blk->nvdimm_flush)
-                       return -ENOMEM;
-       }
-
-       if (!arch_has_wmb_pmem() && !nfit_blk->nvdimm_flush)
-               dev_warn(dev, "unable to guarantee persistence of writes\n");
-
-       if (mmio->line_size == 0)
-               return 0;
-
-       if ((u32) nfit_blk->cmd_offset % mmio->line_size
-                       + 8 > mmio->line_size) {
-               dev_dbg(dev, "cmd_offset crosses interleave boundary\n");
-               return -ENXIO;
-       } else if ((u32) nfit_blk->stat_offset % mmio->line_size
-                       + 8 > mmio->line_size) {
-               dev_dbg(dev, "stat_offset crosses interleave boundary\n");
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
-static void acpi_nfit_blk_region_disable(struct nvdimm_bus *nvdimm_bus,
-               struct device *dev)
-{
-       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
-       struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-       struct nd_blk_region *ndbr = to_nd_blk_region(dev);
-       struct nfit_blk *nfit_blk = nd_blk_region_provider_data(ndbr);
-       int i;
-
-       if (!nfit_blk)
-               return; /* never enabled */
-
-       /* auto-free BLK spa mappings */
-       for (i = 0; i < 2; i++) {
-               struct nfit_blk_mmio *mmio = &nfit_blk->mmio[i];
-
-               if (mmio->addr.base)
-                       nfit_spa_unmap(acpi_desc, mmio->spa);
-       }
-       nd_blk_region_set_provider_data(ndbr, NULL);
-       /* devm will free nfit_blk */
-}
-
-static int ars_get_cap(struct acpi_nfit_desc *acpi_desc,
-               struct nd_cmd_ars_cap *cmd, struct nfit_spa *nfit_spa)
-{
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       int cmd_rc, rc;
-
-       cmd->address = spa->address;
-       cmd->length = spa->length;
-       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
-                       sizeof(*cmd), &cmd_rc);
-       if (rc < 0)
-               return rc;
-       return cmd_rc;
-}
-
-static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa)
-{
-       int rc;
-       int cmd_rc;
-       struct nd_cmd_ars_start ars_start;
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-
-       memset(&ars_start, 0, sizeof(ars_start));
-       ars_start.address = spa->address;
-       ars_start.length = spa->length;
-       if (nfit_spa_type(spa) == NFIT_SPA_PM)
-               ars_start.type = ND_ARS_PERSISTENT;
-       else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE)
-               ars_start.type = ND_ARS_VOLATILE;
-       else
-               return -ENOTTY;
-
-       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
-                       sizeof(ars_start), &cmd_rc);
-
-       if (rc < 0)
-               return rc;
-       return cmd_rc;
-}
-
-static int ars_continue(struct acpi_nfit_desc *acpi_desc)
-{
-       int rc, cmd_rc;
-       struct nd_cmd_ars_start ars_start;
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-       struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
-
-       memset(&ars_start, 0, sizeof(ars_start));
-       ars_start.address = ars_status->restart_address;
-       ars_start.length = ars_status->restart_length;
-       ars_start.type = ars_status->type;
-       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
-                       sizeof(ars_start), &cmd_rc);
-       if (rc < 0)
-               return rc;
-       return cmd_rc;
-}
-
-static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-       struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
-       int rc, cmd_rc;
-
-       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, ars_status,
-                       acpi_desc->ars_status_size, &cmd_rc);
-       if (rc < 0)
-               return rc;
-       return cmd_rc;
-}
-
-static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
-               struct nd_cmd_ars_status *ars_status)
-{
-       int rc;
-       u32 i;
-
-       for (i = 0; i < ars_status->num_records; i++) {
-               rc = nvdimm_bus_add_poison(nvdimm_bus,
-                               ars_status->records[i].err_address,
-                               ars_status->records[i].length);
-               if (rc)
-                       return rc;
-       }
-
-       return 0;
-}
-
-static void acpi_nfit_remove_resource(void *data)
-{
-       struct resource *res = data;
-
-       remove_resource(res);
-}
-
-static int acpi_nfit_insert_resource(struct acpi_nfit_desc *acpi_desc,
-               struct nd_region_desc *ndr_desc)
-{
-       struct resource *res, *nd_res = ndr_desc->res;
-       int is_pmem, ret;
-
-       /* No operation if the region is already registered as PMEM */
-       is_pmem = region_intersects(nd_res->start, resource_size(nd_res),
-                               IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY);
-       if (is_pmem == REGION_INTERSECTS)
-               return 0;
-
-       res = devm_kzalloc(acpi_desc->dev, sizeof(*res), GFP_KERNEL);
-       if (!res)
-               return -ENOMEM;
-
-       res->name = "Persistent Memory";
-       res->start = nd_res->start;
-       res->end = nd_res->end;
-       res->flags = IORESOURCE_MEM;
-       res->desc = IORES_DESC_PERSISTENT_MEMORY;
-
-       ret = insert_resource(&iomem_resource, res);
-       if (ret)
-               return ret;
-
-       ret = devm_add_action(acpi_desc->dev, acpi_nfit_remove_resource, res);
-       if (ret) {
-               remove_resource(res);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
-               struct nd_mapping *nd_mapping, struct nd_region_desc *ndr_desc,
-               struct acpi_nfit_memory_map *memdev,
-               struct nfit_spa *nfit_spa)
-{
-       struct nvdimm *nvdimm = acpi_nfit_dimm_by_handle(acpi_desc,
-                       memdev->device_handle);
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       struct nd_blk_region_desc *ndbr_desc;
-       struct nfit_mem *nfit_mem;
-       int blk_valid = 0;
-
-       if (!nvdimm) {
-               dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n",
-                               spa->range_index, memdev->device_handle);
-               return -ENODEV;
-       }
-
-       nd_mapping->nvdimm = nvdimm;
-       switch (nfit_spa_type(spa)) {
-       case NFIT_SPA_PM:
-       case NFIT_SPA_VOLATILE:
-               nd_mapping->start = memdev->address;
-               nd_mapping->size = memdev->region_size;
-               break;
-       case NFIT_SPA_DCR:
-               nfit_mem = nvdimm_provider_data(nvdimm);
-               if (!nfit_mem || !nfit_mem->bdw) {
-                       dev_dbg(acpi_desc->dev, "spa%d %s missing bdw\n",
-                                       spa->range_index, nvdimm_name(nvdimm));
-               } else {
-                       nd_mapping->size = nfit_mem->bdw->capacity;
-                       nd_mapping->start = nfit_mem->bdw->start_address;
-                       ndr_desc->num_lanes = nfit_mem->bdw->windows;
-                       blk_valid = 1;
-               }
-
-               ndr_desc->nd_mapping = nd_mapping;
-               ndr_desc->num_mappings = blk_valid;
-               ndbr_desc = to_blk_region_desc(ndr_desc);
-               ndbr_desc->enable = acpi_nfit_blk_region_enable;
-               ndbr_desc->disable = acpi_nfit_blk_region_disable;
-               ndbr_desc->do_io = acpi_desc->blk_do_io;
-               nfit_spa->nd_region = nvdimm_blk_region_create(acpi_desc->nvdimm_bus,
-                               ndr_desc);
-               if (!nfit_spa->nd_region)
-                       return -ENOMEM;
-               break;
-       }
-
-       return 0;
-}
-
-static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_spa *nfit_spa)
-{
-       static struct nd_mapping nd_mappings[ND_MAX_MAPPINGS];
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       struct nd_blk_region_desc ndbr_desc;
-       struct nd_region_desc *ndr_desc;
-       struct nfit_memdev *nfit_memdev;
-       struct nvdimm_bus *nvdimm_bus;
-       struct resource res;
-       int count = 0, rc;
-
-       if (nfit_spa->nd_region)
-               return 0;
-
-       if (spa->range_index == 0) {
-               dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n",
-                               __func__);
-               return 0;
-       }
-
-       memset(&res, 0, sizeof(res));
-       memset(&nd_mappings, 0, sizeof(nd_mappings));
-       memset(&ndbr_desc, 0, sizeof(ndbr_desc));
-       res.start = spa->address;
-       res.end = res.start + spa->length - 1;
-       ndr_desc = &ndbr_desc.ndr_desc;
-       ndr_desc->res = &res;
-       ndr_desc->provider_data = nfit_spa;
-       ndr_desc->attr_groups = acpi_nfit_region_attribute_groups;
-       if (spa->flags & ACPI_NFIT_PROXIMITY_VALID)
-               ndr_desc->numa_node = acpi_map_pxm_to_online_node(
-                                               spa->proximity_domain);
-       else
-               ndr_desc->numa_node = NUMA_NO_NODE;
-
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
-               struct nd_mapping *nd_mapping;
-
-               if (memdev->range_index != spa->range_index)
-                       continue;
-               if (count >= ND_MAX_MAPPINGS) {
-                       dev_err(acpi_desc->dev, "spa%d exceeds max mappings %d\n",
-                                       spa->range_index, ND_MAX_MAPPINGS);
-                       return -ENXIO;
-               }
-               nd_mapping = &nd_mappings[count++];
-               rc = acpi_nfit_init_mapping(acpi_desc, nd_mapping, ndr_desc,
-                               memdev, nfit_spa);
-               if (rc)
-                       goto out;
-       }
-
-       ndr_desc->nd_mapping = nd_mappings;
-       ndr_desc->num_mappings = count;
-       rc = acpi_nfit_init_interleave_set(acpi_desc, ndr_desc, spa);
-       if (rc)
-               goto out;
-
-       nvdimm_bus = acpi_desc->nvdimm_bus;
-       if (nfit_spa_type(spa) == NFIT_SPA_PM) {
-               rc = acpi_nfit_insert_resource(acpi_desc, ndr_desc);
-               if (rc) {
-                       dev_warn(acpi_desc->dev,
-                               "failed to insert pmem resource to iomem: %d\n",
-                               rc);
-                       goto out;
-               }
-
-               nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus,
-                               ndr_desc);
-               if (!nfit_spa->nd_region)
-                       rc = -ENOMEM;
-       } else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
-               nfit_spa->nd_region = nvdimm_volatile_region_create(nvdimm_bus,
-                               ndr_desc);
-               if (!nfit_spa->nd_region)
-                       rc = -ENOMEM;
-       }
-
- out:
-       if (rc)
-               dev_err(acpi_desc->dev, "failed to register spa range %d\n",
-                               nfit_spa->spa->range_index);
-       return rc;
-}
-
-static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc,
-               u32 max_ars)
-{
-       struct device *dev = acpi_desc->dev;
-       struct nd_cmd_ars_status *ars_status;
-
-       if (acpi_desc->ars_status && acpi_desc->ars_status_size >= max_ars) {
-               memset(acpi_desc->ars_status, 0, acpi_desc->ars_status_size);
-               return 0;
-       }
-
-       if (acpi_desc->ars_status)
-               devm_kfree(dev, acpi_desc->ars_status);
-       acpi_desc->ars_status = NULL;
-       ars_status = devm_kzalloc(dev, max_ars, GFP_KERNEL);
-       if (!ars_status)
-               return -ENOMEM;
-       acpi_desc->ars_status = ars_status;
-       acpi_desc->ars_status_size = max_ars;
-       return 0;
-}
-
-static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_spa *nfit_spa)
-{
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       int rc;
-
-       if (!nfit_spa->max_ars) {
-               struct nd_cmd_ars_cap ars_cap;
-
-               memset(&ars_cap, 0, sizeof(ars_cap));
-               rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa);
-               if (rc < 0)
-                       return rc;
-               nfit_spa->max_ars = ars_cap.max_ars_out;
-               nfit_spa->clear_err_unit = ars_cap.clear_err_unit;
-               /* check that the supported scrub types match the spa type */
-               if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE &&
-                               ((ars_cap.status >> 16) & ND_ARS_VOLATILE) == 0)
-                       return -ENOTTY;
-               else if (nfit_spa_type(spa) == NFIT_SPA_PM &&
-                               ((ars_cap.status >> 16) & ND_ARS_PERSISTENT) == 0)
-                       return -ENOTTY;
-       }
-
-       if (ars_status_alloc(acpi_desc, nfit_spa->max_ars))
-               return -ENOMEM;
-
-       rc = ars_get_status(acpi_desc);
-       if (rc < 0 && rc != -ENOSPC)
-               return rc;
-
-       if (ars_status_process_records(acpi_desc->nvdimm_bus,
-                               acpi_desc->ars_status))
-               return -ENOMEM;
-
-       return 0;
-}
-
-static void acpi_nfit_async_scrub(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_spa *nfit_spa)
-{
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       unsigned int overflow_retry = scrub_overflow_abort;
-       u64 init_ars_start = 0, init_ars_len = 0;
-       struct device *dev = acpi_desc->dev;
-       unsigned int tmo = scrub_timeout;
-       int rc;
-
-       if (nfit_spa->ars_done || !nfit_spa->nd_region)
-               return;
-
-       rc = ars_start(acpi_desc, nfit_spa);
-       /*
-        * If we timed out the initial scan we'll still be busy here,
-        * and will wait another timeout before giving up permanently.
-        */
-       if (rc < 0 && rc != -EBUSY)
-               return;
-
-       do {
-               u64 ars_start, ars_len;
-
-               if (acpi_desc->cancel)
-                       break;
-               rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
-               if (rc == -ENOTTY)
-                       break;
-               if (rc == -EBUSY && !tmo) {
-                       dev_warn(dev, "range %d ars timeout, aborting\n",
-                                       spa->range_index);
-                       break;
-               }
-
-               if (rc == -EBUSY) {
-                       /*
-                        * Note, entries may be appended to the list
-                        * while the lock is dropped, but the workqueue
-                        * being active prevents entries being deleted /
-                        * freed.
-                        */
-                       mutex_unlock(&acpi_desc->init_mutex);
-                       ssleep(1);
-                       tmo--;
-                       mutex_lock(&acpi_desc->init_mutex);
-                       continue;
-               }
-
-               /* we got some results, but there are more pending... */
-               if (rc == -ENOSPC && overflow_retry--) {
-                       if (!init_ars_len) {
-                               init_ars_len = acpi_desc->ars_status->length;
-                               init_ars_start = acpi_desc->ars_status->address;
-                       }
-                       rc = ars_continue(acpi_desc);
-               }
-
-               if (rc < 0) {
-                       dev_warn(dev, "range %d ars continuation failed\n",
-                                       spa->range_index);
-                       break;
-               }
-
-               if (init_ars_len) {
-                       ars_start = init_ars_start;
-                       ars_len = init_ars_len;
-               } else {
-                       ars_start = acpi_desc->ars_status->address;
-                       ars_len = acpi_desc->ars_status->length;
-               }
-               dev_dbg(dev, "spa range: %d ars from %#llx + %#llx complete\n",
-                               spa->range_index, ars_start, ars_len);
-               /* notify the region about new poison entries */
-               nvdimm_region_notify(nfit_spa->nd_region,
-                               NVDIMM_REVALIDATE_POISON);
-               break;
-       } while (1);
-}
-
-static void acpi_nfit_scrub(struct work_struct *work)
-{
-       struct device *dev;
-       u64 init_scrub_length = 0;
-       struct nfit_spa *nfit_spa;
-       u64 init_scrub_address = 0;
-       bool init_ars_done = false;
-       struct acpi_nfit_desc *acpi_desc;
-       unsigned int tmo = scrub_timeout;
-       unsigned int overflow_retry = scrub_overflow_abort;
-
-       acpi_desc = container_of(work, typeof(*acpi_desc), work);
-       dev = acpi_desc->dev;
-
-       /*
-        * We scrub in 2 phases.  The first phase waits for any platform
-        * firmware initiated scrubs to complete and then we go search for the
-        * affected spa regions to mark them scanned.  In the second phase we
-        * initiate a directed scrub for every range that was not scrubbed in
-        * phase 1.
-        */
-
-       /* process platform firmware initiated scrubs */
- retry:
-       mutex_lock(&acpi_desc->init_mutex);
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
-               struct nd_cmd_ars_status *ars_status;
-               struct acpi_nfit_system_address *spa;
-               u64 ars_start, ars_len;
-               int rc;
-
-               if (acpi_desc->cancel)
-                       break;
-
-               if (nfit_spa->nd_region)
-                       continue;
-
-               if (init_ars_done) {
-                       /*
-                        * No need to re-query, we're now just
-                        * reconciling all the ranges covered by the
-                        * initial scrub
-                        */
-                       rc = 0;
-               } else
-                       rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
-
-               if (rc == -ENOTTY) {
-                       /* no ars capability, just register spa and move on */
-                       acpi_nfit_register_region(acpi_desc, nfit_spa);
-                       continue;
-               }
-
-               if (rc == -EBUSY && !tmo) {
-                       /* fallthrough to directed scrub in phase 2 */
-                       dev_warn(dev, "timeout awaiting ars results, continuing...\n");
-                       break;
-               } else if (rc == -EBUSY) {
-                       mutex_unlock(&acpi_desc->init_mutex);
-                       ssleep(1);
-                       tmo--;
-                       goto retry;
-               }
-
-               /* we got some results, but there are more pending... */
-               if (rc == -ENOSPC && overflow_retry--) {
-                       ars_status = acpi_desc->ars_status;
-                       /*
-                        * Record the original scrub range, so that we
-                        * can recall all the ranges impacted by the
-                        * initial scrub.
-                        */
-                       if (!init_scrub_length) {
-                               init_scrub_length = ars_status->length;
-                               init_scrub_address = ars_status->address;
-                       }
-                       rc = ars_continue(acpi_desc);
-                       if (rc == 0) {
-                               mutex_unlock(&acpi_desc->init_mutex);
-                               goto retry;
-                       }
-               }
-
-               if (rc < 0) {
-                       /*
-                        * Initial scrub failed, we'll give it one more
-                        * try below...
-                        */
-                       break;
-               }
-
-               /* We got some final results, record completed ranges */
-               ars_status = acpi_desc->ars_status;
-               if (init_scrub_length) {
-                       ars_start = init_scrub_address;
-                       ars_len = ars_start + init_scrub_length;
-               } else {
-                       ars_start = ars_status->address;
-                       ars_len = ars_status->length;
-               }
-               spa = nfit_spa->spa;
-
-               if (!init_ars_done) {
-                       init_ars_done = true;
-                       dev_dbg(dev, "init scrub %#llx + %#llx complete\n",
-                                       ars_start, ars_len);
-               }
-               if (ars_start <= spa->address && ars_start + ars_len
-                               >= spa->address + spa->length)
-                       acpi_nfit_register_region(acpi_desc, nfit_spa);
-       }
-
-       /*
-        * For all the ranges not covered by an initial scrub we still
-        * want to see if there are errors, but it's ok to discover them
-        * asynchronously.
-        */
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
-               /*
-                * Flag all the ranges that still need scrubbing, but
-                * register them now to make data available.
-                */
-               if (nfit_spa->nd_region)
-                       nfit_spa->ars_done = 1;
-               else
-                       acpi_nfit_register_region(acpi_desc, nfit_spa);
-       }
-
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
-               acpi_nfit_async_scrub(acpi_desc, nfit_spa);
-       mutex_unlock(&acpi_desc->init_mutex);
-}
-
-static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nfit_spa *nfit_spa;
-       int rc;
-
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
-               if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) {
-                       /* BLK regions don't need to wait for ars results */
-                       rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
-                       if (rc)
-                               return rc;
-               }
-
-       queue_work(nfit_wq, &acpi_desc->work);
-       return 0;
-}
-
-static int acpi_nfit_check_deletions(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev)
-{
-       struct device *dev = acpi_desc->dev;
-
-       if (!list_empty(&prev->spas) ||
-                       !list_empty(&prev->memdevs) ||
-                       !list_empty(&prev->dcrs) ||
-                       !list_empty(&prev->bdws) ||
-                       !list_empty(&prev->idts) ||
-                       !list_empty(&prev->flushes)) {
-               dev_err(dev, "new nfit deletes entries (unsupported)\n");
-               return -ENXIO;
-       }
-       return 0;
-}
-
-int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
-{
-       struct device *dev = acpi_desc->dev;
-       struct nfit_table_prev prev;
-       const void *end;
-       u8 *data;
-       int rc;
-
-       mutex_lock(&acpi_desc->init_mutex);
-
-       INIT_LIST_HEAD(&prev.spas);
-       INIT_LIST_HEAD(&prev.memdevs);
-       INIT_LIST_HEAD(&prev.dcrs);
-       INIT_LIST_HEAD(&prev.bdws);
-       INIT_LIST_HEAD(&prev.idts);
-       INIT_LIST_HEAD(&prev.flushes);
-
-       list_cut_position(&prev.spas, &acpi_desc->spas,
-                               acpi_desc->spas.prev);
-       list_cut_position(&prev.memdevs, &acpi_desc->memdevs,
-                               acpi_desc->memdevs.prev);
-       list_cut_position(&prev.dcrs, &acpi_desc->dcrs,
-                               acpi_desc->dcrs.prev);
-       list_cut_position(&prev.bdws, &acpi_desc->bdws,
-                               acpi_desc->bdws.prev);
-       list_cut_position(&prev.idts, &acpi_desc->idts,
-                               acpi_desc->idts.prev);
-       list_cut_position(&prev.flushes, &acpi_desc->flushes,
-                               acpi_desc->flushes.prev);
-
-       data = (u8 *) acpi_desc->nfit;
-       end = data + sz;
-       while (!IS_ERR_OR_NULL(data))
-               data = add_table(acpi_desc, &prev, data, end);
-
-       if (IS_ERR(data)) {
-               dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__,
-                               PTR_ERR(data));
-               rc = PTR_ERR(data);
-               goto out_unlock;
-       }
-
-       rc = acpi_nfit_check_deletions(acpi_desc, &prev);
-       if (rc)
-               goto out_unlock;
-
-       if (nfit_mem_init(acpi_desc) != 0) {
-               rc = -ENOMEM;
-               goto out_unlock;
-       }
-
-       acpi_nfit_init_dsms(acpi_desc);
-
-       rc = acpi_nfit_register_dimms(acpi_desc);
-       if (rc)
-               goto out_unlock;
-
-       rc = acpi_nfit_register_regions(acpi_desc);
-
- out_unlock:
-       mutex_unlock(&acpi_desc->init_mutex);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(acpi_nfit_init);
-
-struct acpi_nfit_flush_work {
-       struct work_struct work;
-       struct completion cmp;
-};
-
-static void flush_probe(struct work_struct *work)
-{
-       struct acpi_nfit_flush_work *flush;
-
-       flush = container_of(work, typeof(*flush), work);
-       complete(&flush->cmp);
-}
-
-static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
-{
-       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
-       struct device *dev = acpi_desc->dev;
-       struct acpi_nfit_flush_work flush;
-
-       /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
-       device_lock(dev);
-       device_unlock(dev);
-
-       /*
-        * Scrub work could take 10s of seconds, userspace may give up so we
-        * need to be interruptible while waiting.
-        */
-       INIT_WORK_ONSTACK(&flush.work, flush_probe);
-       COMPLETION_INITIALIZER_ONSTACK(flush.cmp);
-       queue_work(nfit_wq, &flush.work);
-       return wait_for_completion_interruptible(&flush.cmp);
-}
-
-static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
-               struct nvdimm *nvdimm, unsigned int cmd)
-{
-       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
-
-       if (nvdimm)
-               return 0;
-       if (cmd != ND_CMD_ARS_START)
-               return 0;
-
-       /*
-        * The kernel and userspace may race to initiate a scrub, but
-        * the scrub thread is prepared to lose that initial race.  It
-        * just needs guarantees that any ars it initiates are not
-        * interrupted by any intervening start reqeusts from userspace.
-        */
-       if (work_busy(&acpi_desc->work))
-               return -EBUSY;
-
-       return 0;
-}
-
-void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
-{
-       struct nvdimm_bus_descriptor *nd_desc;
-
-       dev_set_drvdata(dev, acpi_desc);
-       acpi_desc->dev = dev;
-       acpi_desc->blk_do_io = acpi_nfit_blk_region_do_io;
-       nd_desc = &acpi_desc->nd_desc;
-       nd_desc->provider_name = "ACPI.NFIT";
-       nd_desc->ndctl = acpi_nfit_ctl;
-       nd_desc->flush_probe = acpi_nfit_flush_probe;
-       nd_desc->clear_to_send = acpi_nfit_clear_to_send;
-       nd_desc->attr_groups = acpi_nfit_attribute_groups;
-
-       INIT_LIST_HEAD(&acpi_desc->spa_maps);
-       INIT_LIST_HEAD(&acpi_desc->spas);
-       INIT_LIST_HEAD(&acpi_desc->dcrs);
-       INIT_LIST_HEAD(&acpi_desc->bdws);
-       INIT_LIST_HEAD(&acpi_desc->idts);
-       INIT_LIST_HEAD(&acpi_desc->flushes);
-       INIT_LIST_HEAD(&acpi_desc->memdevs);
-       INIT_LIST_HEAD(&acpi_desc->dimms);
-       mutex_init(&acpi_desc->spa_map_mutex);
-       mutex_init(&acpi_desc->init_mutex);
-       INIT_WORK(&acpi_desc->work, acpi_nfit_scrub);
-}
-EXPORT_SYMBOL_GPL(acpi_nfit_desc_init);
-
-static int acpi_nfit_add(struct acpi_device *adev)
-{
-       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_nfit_desc *acpi_desc;
-       struct device *dev = &adev->dev;
-       struct acpi_table_header *tbl;
-       acpi_status status = AE_OK;
-       acpi_size sz;
-       int rc;
-
-       status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz);
-       if (ACPI_FAILURE(status)) {
-               /* This is ok, we could have an nvdimm hotplugged later */
-               dev_dbg(dev, "failed to find NFIT at startup\n");
-               return 0;
-       }
-
-       acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
-       if (!acpi_desc)
-               return -ENOMEM;
-       acpi_nfit_desc_init(acpi_desc, &adev->dev);
-       acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, &acpi_desc->nd_desc);
-       if (!acpi_desc->nvdimm_bus)
-               return -ENOMEM;
-
-       /*
-        * Save the acpi header for later and then skip it,
-        * making nfit point to the first nfit table header.
-        */
-       acpi_desc->acpi_header = *tbl;
-       acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit);
-       sz -= sizeof(struct acpi_table_nfit);
-
-       /* Evaluate _FIT and override with that if present */
-       status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
-       if (ACPI_SUCCESS(status) && buf.length > 0) {
-               union acpi_object *obj;
-               /*
-                * Adjust for the acpi_object header of the _FIT
-                */
-               obj = buf.pointer;
-               if (obj->type == ACPI_TYPE_BUFFER) {
-                       acpi_desc->nfit =
-                               (struct acpi_nfit_header *)obj->buffer.pointer;
-                       sz = obj->buffer.length;
-               } else
-                       dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
-                                __func__, (int) obj->type);
-       }
-
-       rc = acpi_nfit_init(acpi_desc, sz);
-       if (rc) {
-               nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
-               return rc;
-       }
-       return 0;
-}
-
-static int acpi_nfit_remove(struct acpi_device *adev)
-{
-       struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
-
-       acpi_desc->cancel = 1;
-       flush_workqueue(nfit_wq);
-       nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
-       return 0;
-}
-
-static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
-{
-       struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
-       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_nfit_header *nfit_saved;
-       union acpi_object *obj;
-       struct device *dev = &adev->dev;
-       acpi_status status;
-       int ret;
-
-       dev_dbg(dev, "%s: event: %d\n", __func__, event);
-
-       device_lock(dev);
-       if (!dev->driver) {
-               /* dev->driver may be null if we're being removed */
-               dev_dbg(dev, "%s: no driver found for dev\n", __func__);
-               goto out_unlock;
-       }
-
-       if (!acpi_desc) {
-               acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
-               if (!acpi_desc)
-                       goto out_unlock;
-               acpi_nfit_desc_init(acpi_desc, &adev->dev);
-               acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, &acpi_desc->nd_desc);
-               if (!acpi_desc->nvdimm_bus)
-                       goto out_unlock;
-       } else {
-               /*
-                * Finish previous registration before considering new
-                * regions.
-                */
-               flush_workqueue(nfit_wq);
-       }
-
-       /* Evaluate _FIT */
-       status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
-       if (ACPI_FAILURE(status)) {
-               dev_err(dev, "failed to evaluate _FIT\n");
-               goto out_unlock;
-       }
-
-       nfit_saved = acpi_desc->nfit;
-       obj = buf.pointer;
-       if (obj->type == ACPI_TYPE_BUFFER) {
-               acpi_desc->nfit =
-                       (struct acpi_nfit_header *)obj->buffer.pointer;
-               ret = acpi_nfit_init(acpi_desc, obj->buffer.length);
-               if (ret) {
-                       /* Merge failed, restore old nfit, and exit */
-                       acpi_desc->nfit = nfit_saved;
-                       dev_err(dev, "failed to merge updated NFIT\n");
-               }
-       } else {
-               /* Bad _FIT, restore old nfit */
-               dev_err(dev, "Invalid _FIT\n");
-       }
-       kfree(buf.pointer);
-
- out_unlock:
-       device_unlock(dev);
-}
-
-static const struct acpi_device_id acpi_nfit_ids[] = {
-       { "ACPI0012", 0 },
-       { "", 0 },
-};
-MODULE_DEVICE_TABLE(acpi, acpi_nfit_ids);
-
-static struct acpi_driver acpi_nfit_driver = {
-       .name = KBUILD_MODNAME,
-       .ids = acpi_nfit_ids,
-       .ops = {
-               .add = acpi_nfit_add,
-               .remove = acpi_nfit_remove,
-               .notify = acpi_nfit_notify,
-       },
-};
-
-static __init int nfit_init(void)
-{
-       BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_interleave) != 20);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_smbios) != 9);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40);
-
-       acpi_str_to_uuid(UUID_VOLATILE_MEMORY, nfit_uuid[NFIT_SPA_VOLATILE]);
-       acpi_str_to_uuid(UUID_PERSISTENT_MEMORY, nfit_uuid[NFIT_SPA_PM]);
-       acpi_str_to_uuid(UUID_CONTROL_REGION, nfit_uuid[NFIT_SPA_DCR]);
-       acpi_str_to_uuid(UUID_DATA_REGION, nfit_uuid[NFIT_SPA_BDW]);
-       acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_VDISK]);
-       acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_CD, nfit_uuid[NFIT_SPA_VCD]);
-       acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_PDISK]);
-       acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]);
-       acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);
-       acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);
-       acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
-       acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
-
-       nfit_wq = create_singlethread_workqueue("nfit");
-       if (!nfit_wq)
-               return -ENOMEM;
-
-       return acpi_bus_register_driver(&acpi_nfit_driver);
-}
-
-static __exit void nfit_exit(void)
-{
-       acpi_bus_unregister_driver(&acpi_nfit_driver);
-       destroy_workqueue(nfit_wq);
-}
-
-module_init(nfit_init);
-module_exit(nfit_exit);
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
deleted file mode 100644 (file)
index 02b9ea1..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * NVDIMM Firmware Interface Table - NFIT
- *
- * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-#ifndef __NFIT_H__
-#define __NFIT_H__
-#include <linux/workqueue.h>
-#include <linux/libnvdimm.h>
-#include <linux/types.h>
-#include <linux/uuid.h>
-#include <linux/acpi.h>
-#include <acpi/acuuid.h>
-
-/* ACPI 6.1 */
-#define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
-
-/* http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf */
-#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
-
-/* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */
-#define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"
-#define UUID_NFIT_DIMM_N_HPE2 "5008664b-b758-41a0-a03c-27c2f2d04f7e"
-
-#define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
-               | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
-               | ACPI_NFIT_MEM_NOT_ARMED)
-
-enum nfit_uuids {
-       /* for simplicity alias the uuid index with the family id */
-       NFIT_DEV_DIMM = NVDIMM_FAMILY_INTEL,
-       NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1,
-       NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
-       NFIT_SPA_VOLATILE,
-       NFIT_SPA_PM,
-       NFIT_SPA_DCR,
-       NFIT_SPA_BDW,
-       NFIT_SPA_VDISK,
-       NFIT_SPA_VCD,
-       NFIT_SPA_PDISK,
-       NFIT_SPA_PCD,
-       NFIT_DEV_BUS,
-       NFIT_UUID_MAX,
-};
-
-/*
- * Region format interface codes are stored with the interface as the
- * LSB and the function as the MSB.
- */
-#define NFIT_FIC_BYTE cpu_to_le16(0x101) /* byte-addressable energy backed */
-#define NFIT_FIC_BLK cpu_to_le16(0x201) /* block-addressable non-energy backed */
-#define NFIT_FIC_BYTEN cpu_to_le16(0x301) /* byte-addressable non-energy backed */
-
-enum {
-       NFIT_BLK_READ_FLUSH = 1,
-       NFIT_BLK_DCR_LATCH = 2,
-       NFIT_ARS_STATUS_DONE = 0,
-       NFIT_ARS_STATUS_BUSY = 1 << 16,
-       NFIT_ARS_STATUS_NONE = 2 << 16,
-       NFIT_ARS_STATUS_INTR = 3 << 16,
-       NFIT_ARS_START_BUSY = 6,
-       NFIT_ARS_CAP_NONE = 1,
-       NFIT_ARS_F_OVERFLOW = 1,
-       NFIT_ARS_TIMEOUT = 90,
-};
-
-struct nfit_spa {
-       struct acpi_nfit_system_address *spa;
-       struct list_head list;
-       struct nd_region *nd_region;
-       unsigned int ars_done:1;
-       u32 clear_err_unit;
-       u32 max_ars;
-};
-
-struct nfit_dcr {
-       struct acpi_nfit_control_region *dcr;
-       struct list_head list;
-};
-
-struct nfit_bdw {
-       struct acpi_nfit_data_region *bdw;
-       struct list_head list;
-};
-
-struct nfit_idt {
-       struct acpi_nfit_interleave *idt;
-       struct list_head list;
-};
-
-struct nfit_flush {
-       struct acpi_nfit_flush_address *flush;
-       struct list_head list;
-};
-
-struct nfit_memdev {
-       struct acpi_nfit_memory_map *memdev;
-       struct list_head list;
-};
-
-/* assembled tables for a given dimm/memory-device */
-struct nfit_mem {
-       struct nvdimm *nvdimm;
-       struct acpi_nfit_memory_map *memdev_dcr;
-       struct acpi_nfit_memory_map *memdev_pmem;
-       struct acpi_nfit_memory_map *memdev_bdw;
-       struct acpi_nfit_control_region *dcr;
-       struct acpi_nfit_data_region *bdw;
-       struct acpi_nfit_system_address *spa_dcr;
-       struct acpi_nfit_system_address *spa_bdw;
-       struct acpi_nfit_interleave *idt_dcr;
-       struct acpi_nfit_interleave *idt_bdw;
-       struct nfit_flush *nfit_flush;
-       struct list_head list;
-       struct acpi_device *adev;
-       struct acpi_nfit_desc *acpi_desc;
-       unsigned long dsm_mask;
-       int family;
-};
-
-struct acpi_nfit_desc {
-       struct nvdimm_bus_descriptor nd_desc;
-       struct acpi_table_header acpi_header;
-       struct acpi_nfit_header *nfit;
-       struct mutex spa_map_mutex;
-       struct mutex init_mutex;
-       struct list_head spa_maps;
-       struct list_head memdevs;
-       struct list_head flushes;
-       struct list_head dimms;
-       struct list_head spas;
-       struct list_head dcrs;
-       struct list_head bdws;
-       struct list_head idts;
-       struct nvdimm_bus *nvdimm_bus;
-       struct device *dev;
-       struct nd_cmd_ars_status *ars_status;
-       size_t ars_status_size;
-       struct work_struct work;
-       unsigned int cancel:1;
-       unsigned long dimm_cmd_force_en;
-       unsigned long bus_cmd_force_en;
-       int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
-                       void *iobuf, u64 len, int rw);
-};
-
-enum nd_blk_mmio_selector {
-       BDW,
-       DCR,
-};
-
-struct nd_blk_addr {
-       union {
-               void __iomem *base;
-               void __pmem  *aperture;
-       };
-};
-
-struct nfit_blk {
-       struct nfit_blk_mmio {
-               struct nd_blk_addr addr;
-               u64 size;
-               u64 base_offset;
-               u32 line_size;
-               u32 num_lines;
-               u32 table_size;
-               struct acpi_nfit_interleave *idt;
-               struct acpi_nfit_system_address *spa;
-       } mmio[2];
-       struct nd_region *nd_region;
-       u64 bdw_offset; /* post interleave offset */
-       u64 stat_offset;
-       u64 cmd_offset;
-       void __iomem *nvdimm_flush;
-       u32 dimm_flags;
-};
-
-enum spa_map_type {
-       SPA_MAP_CONTROL,
-       SPA_MAP_APERTURE,
-};
-
-struct nfit_spa_mapping {
-       struct acpi_nfit_desc *acpi_desc;
-       struct acpi_nfit_system_address *spa;
-       struct list_head list;
-       struct kref kref;
-       enum spa_map_type type;
-       struct nd_blk_addr addr;
-};
-
-static inline struct nfit_spa_mapping *to_spa_map(struct kref *kref)
-{
-       return container_of(kref, struct nfit_spa_mapping, kref);
-}
-
-static inline struct acpi_nfit_memory_map *__to_nfit_memdev(
-               struct nfit_mem *nfit_mem)
-{
-       if (nfit_mem->memdev_dcr)
-               return nfit_mem->memdev_dcr;
-       return nfit_mem->memdev_pmem;
-}
-
-static inline struct acpi_nfit_desc *to_acpi_desc(
-               struct nvdimm_bus_descriptor *nd_desc)
-{
-       return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
-}
-
-const u8 *to_nfit_uuid(enum nfit_uuids id);
-int acpi_nfit_init(struct acpi_nfit_desc *nfit, acpi_size sz);
-void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
-#endif /* __NFIT_H__ */
diff --git a/drivers/acpi/nfit/Kconfig b/drivers/acpi/nfit/Kconfig
new file mode 100644 (file)
index 0000000..dd0d53c
--- /dev/null
@@ -0,0 +1,26 @@
+config ACPI_NFIT
+       tristate "ACPI NVDIMM Firmware Interface Table (NFIT)"
+       depends on PHYS_ADDR_T_64BIT
+       depends on BLK_DEV
+       depends on ARCH_HAS_MMIO_FLUSH
+       select LIBNVDIMM
+       help
+         Infrastructure to probe ACPI 6 compliant platforms for
+         NVDIMMs (NFIT) and register a libnvdimm device tree.  In
+         addition to storage devices this also enables libnvdimm to pass
+         ACPI._DSM messages for platform/dimm configuration.
+
+         To compile this driver as a module, choose M here:
+         the module will be called nfit.
+
+config ACPI_NFIT_DEBUG
+       bool "NFIT DSM debug"
+       depends on ACPI_NFIT
+       depends on DYNAMIC_DEBUG
+       default n
+       help
+         Enabling this option causes the nfit driver to dump the
+         input and output buffers of _DSM operations on the ACPI0012
+         device and its children.  This can be very verbose, so leave
+         it disabled unless you are debugging a hardware / firmware
+         issue.
diff --git a/drivers/acpi/nfit/Makefile b/drivers/acpi/nfit/Makefile
new file mode 100644 (file)
index 0000000..a407e76
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ACPI_NFIT) := nfit.o
+nfit-y := core.o
+nfit-$(CONFIG_X86_MCE) += mce.o
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
new file mode 100644 (file)
index 0000000..8c234dd
--- /dev/null
@@ -0,0 +1,2784 @@
+/*
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/list_sort.h>
+#include <linux/libnvdimm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/ndctl.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/acpi.h>
+#include <linux/sort.h>
+#include <linux/pmem.h>
+#include <linux/io.h>
+#include <linux/nd.h>
+#include <asm/cacheflush.h>
+#include "nfit.h"
+
+/*
+ * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
+ * irrelevant.
+ */
+#include <linux/io-64-nonatomic-hi-lo.h>
+
+static bool force_enable_dimms;
+module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
+
+static unsigned int scrub_timeout = NFIT_ARS_TIMEOUT;
+module_param(scrub_timeout, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scrub_timeout, "Initial scrub timeout in seconds");
+
+/* after three payloads of overflow, it's dead jim */
+static unsigned int scrub_overflow_abort = 3;
+module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scrub_overflow_abort,
+               "Number of times we overflow ARS results before abort");
+
+static bool disable_vendor_specific;
+module_param(disable_vendor_specific, bool, S_IRUGO);
+MODULE_PARM_DESC(disable_vendor_specific,
+               "Limit commands to the publicly specified set\n");
+
+LIST_HEAD(acpi_descs);
+DEFINE_MUTEX(acpi_desc_lock);
+
+static struct workqueue_struct *nfit_wq;
+
+struct nfit_table_prev {
+       struct list_head spas;
+       struct list_head memdevs;
+       struct list_head dcrs;
+       struct list_head bdws;
+       struct list_head idts;
+       struct list_head flushes;
+};
+
+static u8 nfit_uuid[NFIT_UUID_MAX][16];
+
+const u8 *to_nfit_uuid(enum nfit_uuids id)
+{
+       return nfit_uuid[id];
+}
+EXPORT_SYMBOL(to_nfit_uuid);
+
+static struct acpi_nfit_desc *to_acpi_nfit_desc(
+               struct nvdimm_bus_descriptor *nd_desc)
+{
+       return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
+}
+
+static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+
+       /*
+        * If provider == 'ACPI.NFIT' we can assume 'dev' is a struct
+        * acpi_device.
+        */
+       if (!nd_desc->provider_name
+                       || strcmp(nd_desc->provider_name, "ACPI.NFIT") != 0)
+               return NULL;
+
+       return to_acpi_device(acpi_desc->dev);
+}
+
+static int xlat_status(void *buf, unsigned int cmd)
+{
+       struct nd_cmd_clear_error *clear_err;
+       struct nd_cmd_ars_status *ars_status;
+       struct nd_cmd_ars_start *ars_start;
+       struct nd_cmd_ars_cap *ars_cap;
+       u16 flags;
+
+       switch (cmd) {
+       case ND_CMD_ARS_CAP:
+               ars_cap = buf;
+               if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
+                       return -ENOTTY;
+
+               /* Command failed */
+               if (ars_cap->status & 0xffff)
+                       return -EIO;
+
+               /* No supported scan types for this range */
+               flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
+               if ((ars_cap->status >> 16 & flags) == 0)
+                       return -ENOTTY;
+               break;
+       case ND_CMD_ARS_START:
+               ars_start = buf;
+               /* ARS is in progress */
+               if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY)
+                       return -EBUSY;
+
+               /* Command failed */
+               if (ars_start->status & 0xffff)
+                       return -EIO;
+               break;
+       case ND_CMD_ARS_STATUS:
+               ars_status = buf;
+               /* Command failed */
+               if (ars_status->status & 0xffff)
+                       return -EIO;
+               /* Check extended status (Upper two bytes) */
+               if (ars_status->status == NFIT_ARS_STATUS_DONE)
+                       return 0;
+
+               /* ARS is in progress */
+               if (ars_status->status == NFIT_ARS_STATUS_BUSY)
+                       return -EBUSY;
+
+               /* No ARS performed for the current boot */
+               if (ars_status->status == NFIT_ARS_STATUS_NONE)
+                       return -EAGAIN;
+
+               /*
+                * ARS interrupted, either we overflowed or some other
+                * agent wants the scan to stop.  If we didn't overflow
+                * then just continue with the returned results.
+                */
+               if (ars_status->status == NFIT_ARS_STATUS_INTR) {
+                       if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
+                               return -ENOSPC;
+                       return 0;
+               }
+
+               /* Unknown status */
+               if (ars_status->status >> 16)
+                       return -EIO;
+               break;
+       case ND_CMD_CLEAR_ERROR:
+               clear_err = buf;
+               if (clear_err->status & 0xffff)
+                       return -EIO;
+               if (!clear_err->cleared)
+                       return -EIO;
+               if (clear_err->length > clear_err->cleared)
+                       return clear_err->cleared;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
+               struct nvdimm *nvdimm, unsigned int cmd, void *buf,
+               unsigned int buf_len, int *cmd_rc)
+{
+       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
+       union acpi_object in_obj, in_buf, *out_obj;
+       const struct nd_cmd_desc *desc = NULL;
+       struct device *dev = acpi_desc->dev;
+       struct nd_cmd_pkg *call_pkg = NULL;
+       const char *cmd_name, *dimm_name;
+       unsigned long cmd_mask, dsm_mask;
+       acpi_handle handle;
+       unsigned int func;
+       const u8 *uuid;
+       u32 offset;
+       int rc, i;
+
+       func = cmd;
+       if (cmd == ND_CMD_CALL) {
+               call_pkg = buf;
+               func = call_pkg->nd_command;
+       }
+
+       if (nvdimm) {
+               struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+               struct acpi_device *adev = nfit_mem->adev;
+
+               if (!adev)
+                       return -ENOTTY;
+               if (call_pkg && nfit_mem->family != call_pkg->nd_family)
+                       return -ENOTTY;
+
+               dimm_name = nvdimm_name(nvdimm);
+               cmd_name = nvdimm_cmd_name(cmd);
+               cmd_mask = nvdimm_cmd_mask(nvdimm);
+               dsm_mask = nfit_mem->dsm_mask;
+               desc = nd_cmd_dimm_desc(cmd);
+               uuid = to_nfit_uuid(nfit_mem->family);
+               handle = adev->handle;
+       } else {
+               struct acpi_device *adev = to_acpi_dev(acpi_desc);
+
+               cmd_name = nvdimm_bus_cmd_name(cmd);
+               cmd_mask = nd_desc->cmd_mask;
+               dsm_mask = cmd_mask;
+               desc = nd_cmd_bus_desc(cmd);
+               uuid = to_nfit_uuid(NFIT_DEV_BUS);
+               handle = adev->handle;
+               dimm_name = "bus";
+       }
+
+       if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))
+               return -ENOTTY;
+
+       if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask))
+               return -ENOTTY;
+
+       in_obj.type = ACPI_TYPE_PACKAGE;
+       in_obj.package.count = 1;
+       in_obj.package.elements = &in_buf;
+       in_buf.type = ACPI_TYPE_BUFFER;
+       in_buf.buffer.pointer = buf;
+       in_buf.buffer.length = 0;
+
+       /* libnvdimm has already validated the input envelope */
+       for (i = 0; i < desc->in_num; i++)
+               in_buf.buffer.length += nd_cmd_in_size(nvdimm, cmd, desc,
+                               i, buf);
+
+       if (call_pkg) {
+               /* skip over package wrapper */
+               in_buf.buffer.pointer = (void *) &call_pkg->nd_payload;
+               in_buf.buffer.length = call_pkg->nd_size_in;
+       }
+
+       if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {
+               dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n",
+                               __func__, dimm_name, cmd, func,
+                               in_buf.buffer.length);
+               print_hex_dump_debug("nvdimm in  ", DUMP_PREFIX_OFFSET, 4, 4,
+                       in_buf.buffer.pointer,
+                       min_t(u32, 256, in_buf.buffer.length), true);
+       }
+
+       out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj);
+       if (!out_obj) {
+               dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name,
+                               cmd_name);
+               return -EINVAL;
+       }
+
+       if (call_pkg) {
+               call_pkg->nd_fw_size = out_obj->buffer.length;
+               memcpy(call_pkg->nd_payload + call_pkg->nd_size_in,
+                       out_obj->buffer.pointer,
+                       min(call_pkg->nd_fw_size, call_pkg->nd_size_out));
+
+               ACPI_FREE(out_obj);
+               /*
+                * Need to support FW function w/o known size in advance.
+                * Caller can determine required size based upon nd_fw_size.
+                * If we return an error (like elsewhere) then caller wouldn't
+                * be able to rely upon data returned to make calculation.
+                */
+               return 0;
+       }
+
+       if (out_obj->package.type != ACPI_TYPE_BUFFER) {
+               dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n",
+                               __func__, dimm_name, cmd_name, out_obj->type);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {
+               dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__,
+                               dimm_name, cmd_name, out_obj->buffer.length);
+               print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,
+                               4, out_obj->buffer.pointer, min_t(u32, 128,
+                                       out_obj->buffer.length), true);
+       }
+
+       for (i = 0, offset = 0; i < desc->out_num; i++) {
+               u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, buf,
+                               (u32 *) out_obj->buffer.pointer);
+
+               if (offset + out_size > out_obj->buffer.length) {
+                       dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
+                                       __func__, dimm_name, cmd_name, i);
+                       break;
+               }
+
+               if (in_buf.buffer.length + offset + out_size > buf_len) {
+                       dev_dbg(dev, "%s:%s output overrun cmd: %s field: %d\n",
+                                       __func__, dimm_name, cmd_name, i);
+                       rc = -ENXIO;
+                       goto out;
+               }
+               memcpy(buf + in_buf.buffer.length + offset,
+                               out_obj->buffer.pointer + offset, out_size);
+               offset += out_size;
+       }
+       if (offset + in_buf.buffer.length < buf_len) {
+               if (i >= 1) {
+                       /*
+                        * status valid, return the number of bytes left
+                        * unfilled in the output buffer
+                        */
+                       rc = buf_len - offset - in_buf.buffer.length;
+                       if (cmd_rc)
+                               *cmd_rc = xlat_status(buf, cmd);
+               } else {
+                       dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
+                                       __func__, dimm_name, cmd_name, buf_len,
+                                       offset);
+                       rc = -ENXIO;
+               }
+       } else {
+               rc = 0;
+               if (cmd_rc)
+                       *cmd_rc = xlat_status(buf, cmd);
+       }
+
+ out:
+       ACPI_FREE(out_obj);
+
+       return rc;
+}
+
+static const char *spa_type_name(u16 type)
+{
+       static const char *to_name[] = {
+               [NFIT_SPA_VOLATILE] = "volatile",
+               [NFIT_SPA_PM] = "pmem",
+               [NFIT_SPA_DCR] = "dimm-control-region",
+               [NFIT_SPA_BDW] = "block-data-window",
+               [NFIT_SPA_VDISK] = "volatile-disk",
+               [NFIT_SPA_VCD] = "volatile-cd",
+               [NFIT_SPA_PDISK] = "persistent-disk",
+               [NFIT_SPA_PCD] = "persistent-cd",
+
+       };
+
+       if (type > NFIT_SPA_PCD)
+               return "unknown";
+
+       return to_name[type];
+}
+
+int nfit_spa_type(struct acpi_nfit_system_address *spa)
+{
+       int i;
+
+       for (i = 0; i < NFIT_UUID_MAX; i++)
+               if (memcmp(to_nfit_uuid(i), spa->range_guid, 16) == 0)
+                       return i;
+       return -1;
+}
+
+static bool add_spa(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_system_address *spa)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_spa *nfit_spa;
+
+       if (spa->header.length != sizeof(*spa))
+               return false;
+
+       list_for_each_entry(nfit_spa, &prev->spas, list) {
+               if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) {
+                       list_move_tail(&nfit_spa->list, &acpi_desc->spas);
+                       return true;
+               }
+       }
+
+       nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa) + sizeof(*spa),
+                       GFP_KERNEL);
+       if (!nfit_spa)
+               return false;
+       INIT_LIST_HEAD(&nfit_spa->list);
+       memcpy(nfit_spa->spa, spa, sizeof(*spa));
+       list_add_tail(&nfit_spa->list, &acpi_desc->spas);
+       dev_dbg(dev, "%s: spa index: %d type: %s\n", __func__,
+                       spa->range_index,
+                       spa_type_name(nfit_spa_type(spa)));
+       return true;
+}
+
+static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_memory_map *memdev)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_memdev *nfit_memdev;
+
+       if (memdev->header.length != sizeof(*memdev))
+               return false;
+
+       list_for_each_entry(nfit_memdev, &prev->memdevs, list)
+               if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) {
+                       list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
+                       return true;
+               }
+
+       nfit_memdev = devm_kzalloc(dev, sizeof(*nfit_memdev) + sizeof(*memdev),
+                       GFP_KERNEL);
+       if (!nfit_memdev)
+               return false;
+       INIT_LIST_HEAD(&nfit_memdev->list);
+       memcpy(nfit_memdev->memdev, memdev, sizeof(*memdev));
+       list_add_tail(&nfit_memdev->list, &acpi_desc->memdevs);
+       dev_dbg(dev, "%s: memdev handle: %#x spa: %d dcr: %d\n",
+                       __func__, memdev->device_handle, memdev->range_index,
+                       memdev->region_index);
+       return true;
+}
+
+/*
+ * An implementation may provide a truncated control region if no block windows
+ * are defined.
+ */
+static size_t sizeof_dcr(struct acpi_nfit_control_region *dcr)
+{
+       if (dcr->header.length < offsetof(struct acpi_nfit_control_region,
+                               window_size))
+               return 0;
+       if (dcr->windows)
+               return sizeof(*dcr);
+       return offsetof(struct acpi_nfit_control_region, window_size);
+}
+
+static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_control_region *dcr)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_dcr *nfit_dcr;
+
+       if (!sizeof_dcr(dcr))
+               return false;
+
+       list_for_each_entry(nfit_dcr, &prev->dcrs, list)
+               if (memcmp(nfit_dcr->dcr, dcr, sizeof_dcr(dcr)) == 0) {
+                       list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
+                       return true;
+               }
+
+       nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr) + sizeof(*dcr),
+                       GFP_KERNEL);
+       if (!nfit_dcr)
+               return false;
+       INIT_LIST_HEAD(&nfit_dcr->list);
+       memcpy(nfit_dcr->dcr, dcr, sizeof_dcr(dcr));
+       list_add_tail(&nfit_dcr->list, &acpi_desc->dcrs);
+       dev_dbg(dev, "%s: dcr index: %d windows: %d\n", __func__,
+                       dcr->region_index, dcr->windows);
+       return true;
+}
+
+static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_data_region *bdw)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_bdw *nfit_bdw;
+
+       if (bdw->header.length != sizeof(*bdw))
+               return false;
+       list_for_each_entry(nfit_bdw, &prev->bdws, list)
+               if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) {
+                       list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
+                       return true;
+               }
+
+       nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw) + sizeof(*bdw),
+                       GFP_KERNEL);
+       if (!nfit_bdw)
+               return false;
+       INIT_LIST_HEAD(&nfit_bdw->list);
+       memcpy(nfit_bdw->bdw, bdw, sizeof(*bdw));
+       list_add_tail(&nfit_bdw->list, &acpi_desc->bdws);
+       dev_dbg(dev, "%s: bdw dcr: %d windows: %d\n", __func__,
+                       bdw->region_index, bdw->windows);
+       return true;
+}
+
+static size_t sizeof_idt(struct acpi_nfit_interleave *idt)
+{
+       if (idt->header.length < sizeof(*idt))
+               return 0;
+       return sizeof(*idt) + sizeof(u32) * (idt->line_count - 1);
+}
+
+static bool add_idt(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_interleave *idt)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_idt *nfit_idt;
+
+       if (!sizeof_idt(idt))
+               return false;
+
+       list_for_each_entry(nfit_idt, &prev->idts, list) {
+               if (sizeof_idt(nfit_idt->idt) != sizeof_idt(idt))
+                       continue;
+
+               if (memcmp(nfit_idt->idt, idt, sizeof_idt(idt)) == 0) {
+                       list_move_tail(&nfit_idt->list, &acpi_desc->idts);
+                       return true;
+               }
+       }
+
+       nfit_idt = devm_kzalloc(dev, sizeof(*nfit_idt) + sizeof_idt(idt),
+                       GFP_KERNEL);
+       if (!nfit_idt)
+               return false;
+       INIT_LIST_HEAD(&nfit_idt->list);
+       memcpy(nfit_idt->idt, idt, sizeof_idt(idt));
+       list_add_tail(&nfit_idt->list, &acpi_desc->idts);
+       dev_dbg(dev, "%s: idt index: %d num_lines: %d\n", __func__,
+                       idt->interleave_index, idt->line_count);
+       return true;
+}
+
+static size_t sizeof_flush(struct acpi_nfit_flush_address *flush)
+{
+       if (flush->header.length < sizeof(*flush))
+               return 0;
+       return sizeof(*flush) + sizeof(u64) * (flush->hint_count - 1);
+}
+
+static bool add_flush(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_flush_address *flush)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_flush *nfit_flush;
+
+       if (!sizeof_flush(flush))
+               return false;
+
+       list_for_each_entry(nfit_flush, &prev->flushes, list) {
+               if (sizeof_flush(nfit_flush->flush) != sizeof_flush(flush))
+                       continue;
+
+               if (memcmp(nfit_flush->flush, flush,
+                                       sizeof_flush(flush)) == 0) {
+                       list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
+                       return true;
+               }
+       }
+
+       nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush)
+                       + sizeof_flush(flush), GFP_KERNEL);
+       if (!nfit_flush)
+               return false;
+       INIT_LIST_HEAD(&nfit_flush->list);
+       memcpy(nfit_flush->flush, flush, sizeof_flush(flush));
+       list_add_tail(&nfit_flush->list, &acpi_desc->flushes);
+       dev_dbg(dev, "%s: nfit_flush handle: %d hint_count: %d\n", __func__,
+                       flush->device_handle, flush->hint_count);
+       return true;
+}
+
+static void *add_table(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev, void *table, const void *end)
+{
+       struct device *dev = acpi_desc->dev;
+       struct acpi_nfit_header *hdr;
+       void *err = ERR_PTR(-ENOMEM);
+
+       if (table >= end)
+               return NULL;
+
+       hdr = table;
+       if (!hdr->length) {
+               dev_warn(dev, "found a zero length table '%d' parsing nfit\n",
+                       hdr->type);
+               return NULL;
+       }
+
+       switch (hdr->type) {
+       case ACPI_NFIT_TYPE_SYSTEM_ADDRESS:
+               if (!add_spa(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_MEMORY_MAP:
+               if (!add_memdev(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_CONTROL_REGION:
+               if (!add_dcr(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_DATA_REGION:
+               if (!add_bdw(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_INTERLEAVE:
+               if (!add_idt(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
+               if (!add_flush(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_SMBIOS:
+               dev_dbg(dev, "%s: smbios\n", __func__);
+               break;
+       default:
+               dev_err(dev, "unknown table '%d' parsing nfit\n", hdr->type);
+               break;
+       }
+
+       return table + hdr->length;
+}
+
+static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_mem *nfit_mem)
+{
+       u32 device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
+       u16 dcr = nfit_mem->dcr->region_index;
+       struct nfit_spa *nfit_spa;
+
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               u16 range_index = nfit_spa->spa->range_index;
+               int type = nfit_spa_type(nfit_spa->spa);
+               struct nfit_memdev *nfit_memdev;
+
+               if (type != NFIT_SPA_BDW)
+                       continue;
+
+               list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+                       if (nfit_memdev->memdev->range_index != range_index)
+                               continue;
+                       if (nfit_memdev->memdev->device_handle != device_handle)
+                               continue;
+                       if (nfit_memdev->memdev->region_index != dcr)
+                               continue;
+
+                       nfit_mem->spa_bdw = nfit_spa->spa;
+                       return;
+               }
+       }
+
+       dev_dbg(acpi_desc->dev, "SPA-BDW not found for SPA-DCR %d\n",
+                       nfit_mem->spa_dcr->range_index);
+       nfit_mem->bdw = NULL;
+}
+
+static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
+{
+       u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
+       struct nfit_memdev *nfit_memdev;
+       struct nfit_bdw *nfit_bdw;
+       struct nfit_idt *nfit_idt;
+       u16 idt_idx, range_index;
+
+       list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
+               if (nfit_bdw->bdw->region_index != dcr)
+                       continue;
+               nfit_mem->bdw = nfit_bdw->bdw;
+               break;
+       }
+
+       if (!nfit_mem->bdw)
+               return;
+
+       nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
+
+       if (!nfit_mem->spa_bdw)
+               return;
+
+       range_index = nfit_mem->spa_bdw->range_index;
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               if (nfit_memdev->memdev->range_index != range_index ||
+                               nfit_memdev->memdev->region_index != dcr)
+                       continue;
+               nfit_mem->memdev_bdw = nfit_memdev->memdev;
+               idt_idx = nfit_memdev->memdev->interleave_index;
+               list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
+                       if (nfit_idt->idt->interleave_index != idt_idx)
+                               continue;
+                       nfit_mem->idt_bdw = nfit_idt->idt;
+                       break;
+               }
+               break;
+       }
+}
+
+static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
+               struct acpi_nfit_system_address *spa)
+{
+       struct nfit_mem *nfit_mem, *found;
+       struct nfit_memdev *nfit_memdev;
+       int type = nfit_spa_type(spa);
+
+       switch (type) {
+       case NFIT_SPA_DCR:
+       case NFIT_SPA_PM:
+               break;
+       default:
+               return 0;
+       }
+
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               struct nfit_flush *nfit_flush;
+               struct nfit_dcr *nfit_dcr;
+               u32 device_handle;
+               u16 dcr;
+
+               if (nfit_memdev->memdev->range_index != spa->range_index)
+                       continue;
+               found = NULL;
+               dcr = nfit_memdev->memdev->region_index;
+               device_handle = nfit_memdev->memdev->device_handle;
+               list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
+                       if (__to_nfit_memdev(nfit_mem)->device_handle
+                                       == device_handle) {
+                               found = nfit_mem;
+                               break;
+                       }
+
+               if (found)
+                       nfit_mem = found;
+               else {
+                       nfit_mem = devm_kzalloc(acpi_desc->dev,
+                                       sizeof(*nfit_mem), GFP_KERNEL);
+                       if (!nfit_mem)
+                               return -ENOMEM;
+                       INIT_LIST_HEAD(&nfit_mem->list);
+                       nfit_mem->acpi_desc = acpi_desc;
+                       list_add(&nfit_mem->list, &acpi_desc->dimms);
+               }
+
+               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+                       if (nfit_dcr->dcr->region_index != dcr)
+                               continue;
+                       /*
+                        * Record the control region for the dimm.  For
+                        * the ACPI 6.1 case, where there are separate
+                        * control regions for the pmem vs blk
+                        * interfaces, be sure to record the extended
+                        * blk details.
+                        */
+                       if (!nfit_mem->dcr)
+                               nfit_mem->dcr = nfit_dcr->dcr;
+                       else if (nfit_mem->dcr->windows == 0
+                                       && nfit_dcr->dcr->windows)
+                               nfit_mem->dcr = nfit_dcr->dcr;
+                       break;
+               }
+
+               list_for_each_entry(nfit_flush, &acpi_desc->flushes, list) {
+                       struct acpi_nfit_flush_address *flush;
+                       u16 i;
+
+                       if (nfit_flush->flush->device_handle != device_handle)
+                               continue;
+                       nfit_mem->nfit_flush = nfit_flush;
+                       flush = nfit_flush->flush;
+                       nfit_mem->flush_wpq = devm_kzalloc(acpi_desc->dev,
+                                       flush->hint_count
+                                       * sizeof(struct resource), GFP_KERNEL);
+                       if (!nfit_mem->flush_wpq)
+                               return -ENOMEM;
+                       for (i = 0; i < flush->hint_count; i++) {
+                               struct resource *res = &nfit_mem->flush_wpq[i];
+
+                               res->start = flush->hint_address[i];
+                               res->end = res->start + 8 - 1;
+                       }
+                       break;
+               }
+
+               if (dcr && !nfit_mem->dcr) {
+                       dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
+                                       spa->range_index, dcr);
+                       return -ENODEV;
+               }
+
+               if (type == NFIT_SPA_DCR) {
+                       struct nfit_idt *nfit_idt;
+                       u16 idt_idx;
+
+                       /* multiple dimms may share a SPA when interleaved */
+                       nfit_mem->spa_dcr = spa;
+                       nfit_mem->memdev_dcr = nfit_memdev->memdev;
+                       idt_idx = nfit_memdev->memdev->interleave_index;
+                       list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
+                               if (nfit_idt->idt->interleave_index != idt_idx)
+                                       continue;
+                               nfit_mem->idt_dcr = nfit_idt->idt;
+                               break;
+                       }
+                       nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
+               } else {
+                       /*
+                        * A single dimm may belong to multiple SPA-PM
+                        * ranges, record at least one in addition to
+                        * any SPA-DCR range.
+                        */
+                       nfit_mem->memdev_pmem = nfit_memdev->memdev;
+               }
+       }
+
+       return 0;
+}
+
+static int nfit_mem_cmp(void *priv, struct list_head *_a, struct list_head *_b)
+{
+       struct nfit_mem *a = container_of(_a, typeof(*a), list);
+       struct nfit_mem *b = container_of(_b, typeof(*b), list);
+       u32 handleA, handleB;
+
+       handleA = __to_nfit_memdev(a)->device_handle;
+       handleB = __to_nfit_memdev(b)->device_handle;
+       if (handleA < handleB)
+               return -1;
+       else if (handleA > handleB)
+               return 1;
+       return 0;
+}
+
+static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nfit_spa *nfit_spa;
+
+       /*
+        * For each SPA-DCR or SPA-PMEM address range find its
+        * corresponding MEMDEV(s).  From each MEMDEV find the
+        * corresponding DCR.  Then, if we're operating on a SPA-DCR,
+        * try to find a SPA-BDW and a corresponding BDW that references
+        * the DCR.  Throw it all into an nfit_mem object.  Note, that
+        * BDWs are optional.
+        */
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               int rc;
+
+               rc = nfit_mem_dcr_init(acpi_desc, nfit_spa->spa);
+               if (rc)
+                       return rc;
+       }
+
+       list_sort(NULL, &acpi_desc->dimms, nfit_mem_cmp);
+
+       return 0;
+}
+
+static ssize_t revision_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
+       struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
+
+       return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
+}
+static DEVICE_ATTR_RO(revision);
+
+/*
+ * This shows the number of full Address Range Scrubs that have been
+ * completed since driver load time. Userspace can wait on this using
+ * select/poll etc. A '+' at the end indicates an ARS is in progress
+ */
+static ssize_t scrub_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm_bus_descriptor *nd_desc;
+       ssize_t rc = -ENXIO;
+
+       device_lock(dev);
+       nd_desc = dev_get_drvdata(dev);
+       if (nd_desc) {
+               struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
+
+               rc = sprintf(buf, "%d%s", acpi_desc->scrub_count,
+                               (work_busy(&acpi_desc->work)) ? "+\n" : "\n");
+       }
+       device_unlock(dev);
+       return rc;
+}
+
+static ssize_t scrub_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct nvdimm_bus_descriptor *nd_desc;
+       ssize_t rc;
+       long val;
+
+       rc = kstrtol(buf, 0, &val);
+       if (rc)
+               return rc;
+       if (val != 1)
+               return -EINVAL;
+
+       device_lock(dev);
+       nd_desc = dev_get_drvdata(dev);
+       if (nd_desc) {
+               struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
+
+               rc = acpi_nfit_ars_rescan(acpi_desc);
+       }
+       device_unlock(dev);
+       if (rc)
+               return rc;
+       return size;
+}
+static DEVICE_ATTR_RW(scrub);
+
+static bool ars_supported(struct nvdimm_bus *nvdimm_bus)
+{
+       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
+       const unsigned long mask = 1 << ND_CMD_ARS_CAP | 1 << ND_CMD_ARS_START
+               | 1 << ND_CMD_ARS_STATUS;
+
+       return (nd_desc->cmd_mask & mask) == mask;
+}
+
+static umode_t nfit_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+
+       if (a == &dev_attr_scrub.attr && !ars_supported(nvdimm_bus))
+               return 0;
+       return a->mode;
+}
+
+static struct attribute *acpi_nfit_attributes[] = {
+       &dev_attr_revision.attr,
+       &dev_attr_scrub.attr,
+       NULL,
+};
+
+static struct attribute_group acpi_nfit_attribute_group = {
+       .name = "nfit",
+       .attrs = acpi_nfit_attributes,
+       .is_visible = nfit_visible,
+};
+
+static const struct attribute_group *acpi_nfit_attribute_groups[] = {
+       &nvdimm_bus_attribute_group,
+       &acpi_nfit_attribute_group,
+       NULL,
+};
+
+static struct acpi_nfit_memory_map *to_nfit_memdev(struct device *dev)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       return __to_nfit_memdev(nfit_mem);
+}
+
+static struct acpi_nfit_control_region *to_nfit_dcr(struct device *dev)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       return nfit_mem->dcr;
+}
+
+static ssize_t handle_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
+
+       return sprintf(buf, "%#x\n", memdev->device_handle);
+}
+static DEVICE_ATTR_RO(handle);
+
+static ssize_t phys_id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
+
+       return sprintf(buf, "%#x\n", memdev->physical_id);
+}
+static DEVICE_ATTR_RO(phys_id);
+
+static ssize_t vendor_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->vendor_id));
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t rev_id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->revision_id));
+}
+static DEVICE_ATTR_RO(rev_id);
+
+static ssize_t device_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->device_id));
+}
+static DEVICE_ATTR_RO(device);
+
+static ssize_t subsystem_vendor_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_vendor_id));
+}
+static DEVICE_ATTR_RO(subsystem_vendor);
+
+static ssize_t subsystem_rev_id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n",
+                       be16_to_cpu(dcr->subsystem_revision_id));
+}
+static DEVICE_ATTR_RO(subsystem_rev_id);
+
+static ssize_t subsystem_device_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_device_id));
+}
+static DEVICE_ATTR_RO(subsystem_device);
+
+static int num_nvdimm_formats(struct nvdimm *nvdimm)
+{
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+       int formats = 0;
+
+       if (nfit_mem->memdev_pmem)
+               formats++;
+       if (nfit_mem->memdev_bdw)
+               formats++;
+       return formats;
+}
+
+static ssize_t format_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", le16_to_cpu(dcr->code));
+}
+static DEVICE_ATTR_RO(format);
+
+static ssize_t format1_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       u32 handle;
+       ssize_t rc = -ENXIO;
+       struct nfit_mem *nfit_mem;
+       struct nfit_memdev *nfit_memdev;
+       struct acpi_nfit_desc *acpi_desc;
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       nfit_mem = nvdimm_provider_data(nvdimm);
+       acpi_desc = nfit_mem->acpi_desc;
+       handle = to_nfit_memdev(dev)->device_handle;
+
+       /* assumes DIMMs have at most 2 published interface codes */
+       mutex_lock(&acpi_desc->init_mutex);
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
+               struct nfit_dcr *nfit_dcr;
+
+               if (memdev->device_handle != handle)
+                       continue;
+
+               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+                       if (nfit_dcr->dcr->region_index != memdev->region_index)
+                               continue;
+                       if (nfit_dcr->dcr->code == dcr->code)
+                               continue;
+                       rc = sprintf(buf, "0x%04x\n",
+                                       le16_to_cpu(nfit_dcr->dcr->code));
+                       break;
+               }
+               if (rc != ENXIO)
+                       break;
+       }
+       mutex_unlock(&acpi_desc->init_mutex);
+       return rc;
+}
+static DEVICE_ATTR_RO(format1);
+
+static ssize_t formats_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+
+       return sprintf(buf, "%d\n", num_nvdimm_formats(nvdimm));
+}
+static DEVICE_ATTR_RO(formats);
+
+static ssize_t serial_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%08x\n", be32_to_cpu(dcr->serial_number));
+}
+static DEVICE_ATTR_RO(serial);
+
+static ssize_t family_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       if (nfit_mem->family < 0)
+               return -ENXIO;
+       return sprintf(buf, "%d\n", nfit_mem->family);
+}
+static DEVICE_ATTR_RO(family);
+
+static ssize_t dsm_mask_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       if (nfit_mem->family < 0)
+               return -ENXIO;
+       return sprintf(buf, "%#lx\n", nfit_mem->dsm_mask);
+}
+static DEVICE_ATTR_RO(dsm_mask);
+
+static ssize_t flags_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       u16 flags = to_nfit_memdev(dev)->flags;
+
+       return sprintf(buf, "%s%s%s%s%s\n",
+               flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
+               flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "",
+               flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "",
+               flags & ACPI_NFIT_MEM_NOT_ARMED ? "not_armed " : "",
+               flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : "");
+}
+static DEVICE_ATTR_RO(flags);
+
+static ssize_t id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID)
+               return sprintf(buf, "%04x-%02x-%04x-%08x\n",
+                               be16_to_cpu(dcr->vendor_id),
+                               dcr->manufacturing_location,
+                               be16_to_cpu(dcr->manufacturing_date),
+                               be32_to_cpu(dcr->serial_number));
+       else
+               return sprintf(buf, "%04x-%08x\n",
+                               be16_to_cpu(dcr->vendor_id),
+                               be32_to_cpu(dcr->serial_number));
+}
+static DEVICE_ATTR_RO(id);
+
+static struct attribute *acpi_nfit_dimm_attributes[] = {
+       &dev_attr_handle.attr,
+       &dev_attr_phys_id.attr,
+       &dev_attr_vendor.attr,
+       &dev_attr_device.attr,
+       &dev_attr_rev_id.attr,
+       &dev_attr_subsystem_vendor.attr,
+       &dev_attr_subsystem_device.attr,
+       &dev_attr_subsystem_rev_id.attr,
+       &dev_attr_format.attr,
+       &dev_attr_formats.attr,
+       &dev_attr_format1.attr,
+       &dev_attr_serial.attr,
+       &dev_attr_flags.attr,
+       &dev_attr_id.attr,
+       &dev_attr_family.attr,
+       &dev_attr_dsm_mask.attr,
+       NULL,
+};
+
+static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
+               struct attribute *a, int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+
+       if (!to_nfit_dcr(dev))
+               return 0;
+       if (a == &dev_attr_format1.attr && num_nvdimm_formats(nvdimm) <= 1)
+               return 0;
+       return a->mode;
+}
+
+static struct attribute_group acpi_nfit_dimm_attribute_group = {
+       .name = "nfit",
+       .attrs = acpi_nfit_dimm_attributes,
+       .is_visible = acpi_nfit_dimm_attr_visible,
+};
+
+static const struct attribute_group *acpi_nfit_dimm_attribute_groups[] = {
+       &nvdimm_attribute_group,
+       &nd_device_attribute_group,
+       &acpi_nfit_dimm_attribute_group,
+       NULL,
+};
+
+static struct nvdimm *acpi_nfit_dimm_by_handle(struct acpi_nfit_desc *acpi_desc,
+               u32 device_handle)
+{
+       struct nfit_mem *nfit_mem;
+
+       list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
+               if (__to_nfit_memdev(nfit_mem)->device_handle == device_handle)
+                       return nfit_mem->nvdimm;
+
+       return NULL;
+}
+
+static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_mem *nfit_mem, u32 device_handle)
+{
+       struct acpi_device *adev, *adev_dimm;
+       struct device *dev = acpi_desc->dev;
+       unsigned long dsm_mask;
+       const u8 *uuid;
+       int i;
+
+       /* nfit test assumes 1:1 relationship between commands and dsms */
+       nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en;
+       nfit_mem->family = NVDIMM_FAMILY_INTEL;
+       adev = to_acpi_dev(acpi_desc);
+       if (!adev)
+               return 0;
+
+       adev_dimm = acpi_find_child_device(adev, device_handle, false);
+       nfit_mem->adev = adev_dimm;
+       if (!adev_dimm) {
+               dev_err(dev, "no ACPI.NFIT device with _ADR %#x, disabling...\n",
+                               device_handle);
+               return force_enable_dimms ? 0 : -ENODEV;
+       }
+
+       /*
+        * Until standardization materializes we need to consider 4
+        * different command sets.  Note, that checking for function0 (bit0)
+        * tells us if any commands are reachable through this uuid.
+        */
+       for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_MSFT; i++)
+               if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))
+                       break;
+
+       /* limit the supported commands to those that are publicly documented */
+       nfit_mem->family = i;
+       if (nfit_mem->family == NVDIMM_FAMILY_INTEL) {
+               dsm_mask = 0x3fe;
+               if (disable_vendor_specific)
+                       dsm_mask &= ~(1 << ND_CMD_VENDOR);
+       } else if (nfit_mem->family == NVDIMM_FAMILY_HPE1) {
+               dsm_mask = 0x1c3c76;
+       } else if (nfit_mem->family == NVDIMM_FAMILY_HPE2) {
+               dsm_mask = 0x1fe;
+               if (disable_vendor_specific)
+                       dsm_mask &= ~(1 << 8);
+       } else if (nfit_mem->family == NVDIMM_FAMILY_MSFT) {
+               dsm_mask = 0xffffffff;
+       } else {
+               dev_dbg(dev, "unknown dimm command family\n");
+               nfit_mem->family = -1;
+               /* DSMs are optional, continue loading the driver... */
+               return 0;
+       }
+
+       uuid = to_nfit_uuid(nfit_mem->family);
+       for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
+               if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i))
+                       set_bit(i, &nfit_mem->dsm_mask);
+
+       return 0;
+}
+
+static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nfit_mem *nfit_mem;
+       int dimm_count = 0;
+
+       list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
+               struct acpi_nfit_flush_address *flush;
+               unsigned long flags = 0, cmd_mask;
+               struct nvdimm *nvdimm;
+               u32 device_handle;
+               u16 mem_flags;
+               int rc;
+
+               device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
+               nvdimm = acpi_nfit_dimm_by_handle(acpi_desc, device_handle);
+               if (nvdimm) {
+                       dimm_count++;
+                       continue;
+               }
+
+               if (nfit_mem->bdw && nfit_mem->memdev_pmem)
+                       flags |= NDD_ALIASING;
+
+               mem_flags = __to_nfit_memdev(nfit_mem)->flags;
+               if (mem_flags & ACPI_NFIT_MEM_NOT_ARMED)
+                       flags |= NDD_UNARMED;
+
+               rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle);
+               if (rc)
+                       continue;
+
+               /*
+                * TODO: provide translation for non-NVDIMM_FAMILY_INTEL
+                * devices (i.e. from nd_cmd to acpi_dsm) to standardize the
+                * userspace interface.
+                */
+               cmd_mask = 1UL << ND_CMD_CALL;
+               if (nfit_mem->family == NVDIMM_FAMILY_INTEL)
+                       cmd_mask |= nfit_mem->dsm_mask;
+
+               flush = nfit_mem->nfit_flush ? nfit_mem->nfit_flush->flush
+                       : NULL;
+               nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,
+                               acpi_nfit_dimm_attribute_groups,
+                               flags, cmd_mask, flush ? flush->hint_count : 0,
+                               nfit_mem->flush_wpq);
+               if (!nvdimm)
+                       return -ENOMEM;
+
+               nfit_mem->nvdimm = nvdimm;
+               dimm_count++;
+
+               if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0)
+                       continue;
+
+               dev_info(acpi_desc->dev, "%s flags:%s%s%s%s\n",
+                               nvdimm_name(nvdimm),
+                 mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
+                 mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
+                 mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? " flush_fail" : "",
+                 mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : "");
+
+       }
+
+       return nvdimm_bus_check_dimm_count(acpi_desc->nvdimm_bus, dimm_count);
+}
+
+static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+       const u8 *uuid = to_nfit_uuid(NFIT_DEV_BUS);
+       struct acpi_device *adev;
+       int i;
+
+       nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;
+       adev = to_acpi_dev(acpi_desc);
+       if (!adev)
+               return;
+
+       for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)
+               if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i))
+                       set_bit(i, &nd_desc->cmd_mask);
+}
+
+static ssize_t range_index_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nd_region *nd_region = to_nd_region(dev);
+       struct nfit_spa *nfit_spa = nd_region_provider_data(nd_region);
+
+       return sprintf(buf, "%d\n", nfit_spa->spa->range_index);
+}
+static DEVICE_ATTR_RO(range_index);
+
+static struct attribute *acpi_nfit_region_attributes[] = {
+       &dev_attr_range_index.attr,
+       NULL,
+};
+
+static struct attribute_group acpi_nfit_region_attribute_group = {
+       .name = "nfit",
+       .attrs = acpi_nfit_region_attributes,
+};
+
+static const struct attribute_group *acpi_nfit_region_attribute_groups[] = {
+       &nd_region_attribute_group,
+       &nd_mapping_attribute_group,
+       &nd_device_attribute_group,
+       &nd_numa_attribute_group,
+       &acpi_nfit_region_attribute_group,
+       NULL,
+};
+
+/* enough info to uniquely specify an interleave set */
+struct nfit_set_info {
+       struct nfit_set_info_map {
+               u64 region_offset;
+               u32 serial_number;
+               u32 pad;
+       } mapping[0];
+};
+
+static size_t sizeof_nfit_set_info(int num_mappings)
+{
+       return sizeof(struct nfit_set_info)
+               + num_mappings * sizeof(struct nfit_set_info_map);
+}
+
+static int cmp_map(const void *m0, const void *m1)
+{
+       const struct nfit_set_info_map *map0 = m0;
+       const struct nfit_set_info_map *map1 = m1;
+
+       return memcmp(&map0->region_offset, &map1->region_offset,
+                       sizeof(u64));
+}
+
+/* Retrieve the nth entry referencing this spa */
+static struct acpi_nfit_memory_map *memdev_from_spa(
+               struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
+{
+       struct nfit_memdev *nfit_memdev;
+
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list)
+               if (nfit_memdev->memdev->range_index == range_index)
+                       if (n-- == 0)
+                               return nfit_memdev->memdev;
+       return NULL;
+}
+
+static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
+               struct nd_region_desc *ndr_desc,
+               struct acpi_nfit_system_address *spa)
+{
+       int i, spa_type = nfit_spa_type(spa);
+       struct device *dev = acpi_desc->dev;
+       struct nd_interleave_set *nd_set;
+       u16 nr = ndr_desc->num_mappings;
+       struct nfit_set_info *info;
+
+       if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE)
+               /* pass */;
+       else
+               return 0;
+
+       nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
+       if (!nd_set)
+               return -ENOMEM;
+
+       info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       for (i = 0; i < nr; i++) {
+               struct nd_mapping *nd_mapping = &ndr_desc->nd_mapping[i];
+               struct nfit_set_info_map *map = &info->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+               struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+               struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc,
+                               spa->range_index, i);
+
+               if (!memdev || !nfit_mem->dcr) {
+                       dev_err(dev, "%s: failed to find DCR\n", __func__);
+                       return -ENODEV;
+               }
+
+               map->region_offset = memdev->region_offset;
+               map->serial_number = nfit_mem->dcr->serial_number;
+       }
+
+       sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
+                       cmp_map, NULL);
+       nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+       ndr_desc->nd_set = nd_set;
+       devm_kfree(dev, info);
+
+       return 0;
+}
+
+static u64 to_interleave_offset(u64 offset, struct nfit_blk_mmio *mmio)
+{
+       struct acpi_nfit_interleave *idt = mmio->idt;
+       u32 sub_line_offset, line_index, line_offset;
+       u64 line_no, table_skip_count, table_offset;
+
+       line_no = div_u64_rem(offset, mmio->line_size, &sub_line_offset);
+       table_skip_count = div_u64_rem(line_no, mmio->num_lines, &line_index);
+       line_offset = idt->line_offset[line_index]
+               * mmio->line_size;
+       table_offset = table_skip_count * mmio->table_size;
+
+       return mmio->base_offset + line_offset + table_offset + sub_line_offset;
+}
+
+static u32 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw)
+{
+       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
+       u64 offset = nfit_blk->stat_offset + mmio->size * bw;
+
+       if (mmio->num_lines)
+               offset = to_interleave_offset(offset, mmio);
+
+       return readl(mmio->addr.base + offset);
+}
+
+static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
+               resource_size_t dpa, unsigned int len, unsigned int write)
+{
+       u64 cmd, offset;
+       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
+
+       enum {
+               BCW_OFFSET_MASK = (1ULL << 48)-1,
+               BCW_LEN_SHIFT = 48,
+               BCW_LEN_MASK = (1ULL << 8) - 1,
+               BCW_CMD_SHIFT = 56,
+       };
+
+       cmd = (dpa >> L1_CACHE_SHIFT) & BCW_OFFSET_MASK;
+       len = len >> L1_CACHE_SHIFT;
+       cmd |= ((u64) len & BCW_LEN_MASK) << BCW_LEN_SHIFT;
+       cmd |= ((u64) write) << BCW_CMD_SHIFT;
+
+       offset = nfit_blk->cmd_offset + mmio->size * bw;
+       if (mmio->num_lines)
+               offset = to_interleave_offset(offset, mmio);
+
+       writeq(cmd, mmio->addr.base + offset);
+       nvdimm_flush(nfit_blk->nd_region);
+
+       if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
+               readq(mmio->addr.base + offset);
+}
+
+static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
+               resource_size_t dpa, void *iobuf, size_t len, int rw,
+               unsigned int lane)
+{
+       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW];
+       unsigned int copied = 0;
+       u64 base_offset;
+       int rc;
+
+       base_offset = nfit_blk->bdw_offset + dpa % L1_CACHE_BYTES
+               + lane * mmio->size;
+       write_blk_ctl(nfit_blk, lane, dpa, len, rw);
+       while (len) {
+               unsigned int c;
+               u64 offset;
+
+               if (mmio->num_lines) {
+                       u32 line_offset;
+
+                       offset = to_interleave_offset(base_offset + copied,
+                                       mmio);
+                       div_u64_rem(offset, mmio->line_size, &line_offset);
+                       c = min_t(size_t, len, mmio->line_size - line_offset);
+               } else {
+                       offset = base_offset + nfit_blk->bdw_offset;
+                       c = len;
+               }
+
+               if (rw)
+                       memcpy_to_pmem(mmio->addr.aperture + offset,
+                                       iobuf + copied, c);
+               else {
+                       if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH)
+                               mmio_flush_range((void __force *)
+                                       mmio->addr.aperture + offset, c);
+
+                       memcpy_from_pmem(iobuf + copied,
+                                       mmio->addr.aperture + offset, c);
+               }
+
+               copied += c;
+               len -= c;
+       }
+
+       if (rw)
+               nvdimm_flush(nfit_blk->nd_region);
+
+       rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
+       return rc;
+}
+
+static int acpi_nfit_blk_region_do_io(struct nd_blk_region *ndbr,
+               resource_size_t dpa, void *iobuf, u64 len, int rw)
+{
+       struct nfit_blk *nfit_blk = nd_blk_region_provider_data(ndbr);
+       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW];
+       struct nd_region *nd_region = nfit_blk->nd_region;
+       unsigned int lane, copied = 0;
+       int rc = 0;
+
+       lane = nd_region_acquire_lane(nd_region);
+       while (len) {
+               u64 c = min(len, mmio->size);
+
+               rc = acpi_nfit_blk_single_io(nfit_blk, dpa + copied,
+                               iobuf + copied, c, rw, lane);
+               if (rc)
+                       break;
+
+               copied += c;
+               len -= c;
+       }
+       nd_region_release_lane(nd_region, lane);
+
+       return rc;
+}
+
+static int nfit_blk_init_interleave(struct nfit_blk_mmio *mmio,
+               struct acpi_nfit_interleave *idt, u16 interleave_ways)
+{
+       if (idt) {
+               mmio->num_lines = idt->line_count;
+               mmio->line_size = idt->line_size;
+               if (interleave_ways == 0)
+                       return -ENXIO;
+               mmio->table_size = mmio->num_lines * interleave_ways
+                       * mmio->line_size;
+       }
+
+       return 0;
+}
+
+static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc,
+               struct nvdimm *nvdimm, struct nfit_blk *nfit_blk)
+{
+       struct nd_cmd_dimm_flags flags;
+       int rc;
+
+       memset(&flags, 0, sizeof(flags));
+       rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags,
+                       sizeof(flags), NULL);
+
+       if (rc >= 0 && flags.status == 0)
+               nfit_blk->dimm_flags = flags.flags;
+       else if (rc == -ENOTTY) {
+               /* fall back to a conservative default */
+               nfit_blk->dimm_flags = NFIT_BLK_DCR_LATCH | NFIT_BLK_READ_FLUSH;
+               rc = 0;
+       } else
+               rc = -ENXIO;
+
+       return rc;
+}
+
+static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
+               struct device *dev)
+{
+       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
+       struct nd_blk_region *ndbr = to_nd_blk_region(dev);
+       struct nfit_blk_mmio *mmio;
+       struct nfit_blk *nfit_blk;
+       struct nfit_mem *nfit_mem;
+       struct nvdimm *nvdimm;
+       int rc;
+
+       nvdimm = nd_blk_region_to_dimm(ndbr);
+       nfit_mem = nvdimm_provider_data(nvdimm);
+       if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) {
+               dev_dbg(dev, "%s: missing%s%s%s\n", __func__,
+                               nfit_mem ? "" : " nfit_mem",
+                               (nfit_mem && nfit_mem->dcr) ? "" : " dcr",
+                               (nfit_mem && nfit_mem->bdw) ? "" : " bdw");
+               return -ENXIO;
+       }
+
+       nfit_blk = devm_kzalloc(dev, sizeof(*nfit_blk), GFP_KERNEL);
+       if (!nfit_blk)
+               return -ENOMEM;
+       nd_blk_region_set_provider_data(ndbr, nfit_blk);
+       nfit_blk->nd_region = to_nd_region(dev);
+
+       /* map block aperture memory */
+       nfit_blk->bdw_offset = nfit_mem->bdw->offset;
+       mmio = &nfit_blk->mmio[BDW];
+       mmio->addr.base = devm_nvdimm_memremap(dev, nfit_mem->spa_bdw->address,
+                        nfit_mem->spa_bdw->length, ARCH_MEMREMAP_PMEM);
+       if (!mmio->addr.base) {
+               dev_dbg(dev, "%s: %s failed to map bdw\n", __func__,
+                               nvdimm_name(nvdimm));
+               return -ENOMEM;
+       }
+       mmio->size = nfit_mem->bdw->size;
+       mmio->base_offset = nfit_mem->memdev_bdw->region_offset;
+       mmio->idt = nfit_mem->idt_bdw;
+       mmio->spa = nfit_mem->spa_bdw;
+       rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_bdw,
+                       nfit_mem->memdev_bdw->interleave_ways);
+       if (rc) {
+               dev_dbg(dev, "%s: %s failed to init bdw interleave\n",
+                               __func__, nvdimm_name(nvdimm));
+               return rc;
+       }
+
+       /* map block control memory */
+       nfit_blk->cmd_offset = nfit_mem->dcr->command_offset;
+       nfit_blk->stat_offset = nfit_mem->dcr->status_offset;
+       mmio = &nfit_blk->mmio[DCR];
+       mmio->addr.base = devm_nvdimm_ioremap(dev, nfit_mem->spa_dcr->address,
+                       nfit_mem->spa_dcr->length);
+       if (!mmio->addr.base) {
+               dev_dbg(dev, "%s: %s failed to map dcr\n", __func__,
+                               nvdimm_name(nvdimm));
+               return -ENOMEM;
+       }
+       mmio->size = nfit_mem->dcr->window_size;
+       mmio->base_offset = nfit_mem->memdev_dcr->region_offset;
+       mmio->idt = nfit_mem->idt_dcr;
+       mmio->spa = nfit_mem->spa_dcr;
+       rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_dcr,
+                       nfit_mem->memdev_dcr->interleave_ways);
+       if (rc) {
+               dev_dbg(dev, "%s: %s failed to init dcr interleave\n",
+                               __func__, nvdimm_name(nvdimm));
+               return rc;
+       }
+
+       rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk);
+       if (rc < 0) {
+               dev_dbg(dev, "%s: %s failed get DIMM flags\n",
+                               __func__, nvdimm_name(nvdimm));
+               return rc;
+       }
+
+       if (nvdimm_has_flush(nfit_blk->nd_region) < 0)
+               dev_warn(dev, "unable to guarantee persistence of writes\n");
+
+       if (mmio->line_size == 0)
+               return 0;
+
+       if ((u32) nfit_blk->cmd_offset % mmio->line_size
+                       + 8 > mmio->line_size) {
+               dev_dbg(dev, "cmd_offset crosses interleave boundary\n");
+               return -ENXIO;
+       } else if ((u32) nfit_blk->stat_offset % mmio->line_size
+                       + 8 > mmio->line_size) {
+               dev_dbg(dev, "stat_offset crosses interleave boundary\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int ars_get_cap(struct acpi_nfit_desc *acpi_desc,
+               struct nd_cmd_ars_cap *cmd, struct nfit_spa *nfit_spa)
+{
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       int cmd_rc, rc;
+
+       cmd->address = spa->address;
+       cmd->length = spa->length;
+       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
+                       sizeof(*cmd), &cmd_rc);
+       if (rc < 0)
+               return rc;
+       return cmd_rc;
+}
+
+static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa)
+{
+       int rc;
+       int cmd_rc;
+       struct nd_cmd_ars_start ars_start;
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+
+       memset(&ars_start, 0, sizeof(ars_start));
+       ars_start.address = spa->address;
+       ars_start.length = spa->length;
+       if (nfit_spa_type(spa) == NFIT_SPA_PM)
+               ars_start.type = ND_ARS_PERSISTENT;
+       else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE)
+               ars_start.type = ND_ARS_VOLATILE;
+       else
+               return -ENOTTY;
+
+       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
+                       sizeof(ars_start), &cmd_rc);
+
+       if (rc < 0)
+               return rc;
+       return cmd_rc;
+}
+
+static int ars_continue(struct acpi_nfit_desc *acpi_desc)
+{
+       int rc, cmd_rc;
+       struct nd_cmd_ars_start ars_start;
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+       struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
+
+       memset(&ars_start, 0, sizeof(ars_start));
+       ars_start.address = ars_status->restart_address;
+       ars_start.length = ars_status->restart_length;
+       ars_start.type = ars_status->type;
+       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
+                       sizeof(ars_start), &cmd_rc);
+       if (rc < 0)
+               return rc;
+       return cmd_rc;
+}
+
+static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+       struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
+       int rc, cmd_rc;
+
+       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, ars_status,
+                       acpi_desc->ars_status_size, &cmd_rc);
+       if (rc < 0)
+               return rc;
+       return cmd_rc;
+}
+
+static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
+               struct nd_cmd_ars_status *ars_status)
+{
+       int rc;
+       u32 i;
+
+       for (i = 0; i < ars_status->num_records; i++) {
+               rc = nvdimm_bus_add_poison(nvdimm_bus,
+                               ars_status->records[i].err_address,
+                               ars_status->records[i].length);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static void acpi_nfit_remove_resource(void *data)
+{
+       struct resource *res = data;
+
+       remove_resource(res);
+}
+
+static int acpi_nfit_insert_resource(struct acpi_nfit_desc *acpi_desc,
+               struct nd_region_desc *ndr_desc)
+{
+       struct resource *res, *nd_res = ndr_desc->res;
+       int is_pmem, ret;
+
+       /* No operation if the region is already registered as PMEM */
+       is_pmem = region_intersects(nd_res->start, resource_size(nd_res),
+                               IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY);
+       if (is_pmem == REGION_INTERSECTS)
+               return 0;
+
+       res = devm_kzalloc(acpi_desc->dev, sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
+
+       res->name = "Persistent Memory";
+       res->start = nd_res->start;
+       res->end = nd_res->end;
+       res->flags = IORESOURCE_MEM;
+       res->desc = IORES_DESC_PERSISTENT_MEMORY;
+
+       ret = insert_resource(&iomem_resource, res);
+       if (ret)
+               return ret;
+
+       ret = devm_add_action_or_reset(acpi_desc->dev,
+                                       acpi_nfit_remove_resource,
+                                       res);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
+               struct nd_mapping *nd_mapping, struct nd_region_desc *ndr_desc,
+               struct acpi_nfit_memory_map *memdev,
+               struct nfit_spa *nfit_spa)
+{
+       struct nvdimm *nvdimm = acpi_nfit_dimm_by_handle(acpi_desc,
+                       memdev->device_handle);
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       struct nd_blk_region_desc *ndbr_desc;
+       struct nfit_mem *nfit_mem;
+       int blk_valid = 0;
+
+       if (!nvdimm) {
+               dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n",
+                               spa->range_index, memdev->device_handle);
+               return -ENODEV;
+       }
+
+       nd_mapping->nvdimm = nvdimm;
+       switch (nfit_spa_type(spa)) {
+       case NFIT_SPA_PM:
+       case NFIT_SPA_VOLATILE:
+               nd_mapping->start = memdev->address;
+               nd_mapping->size = memdev->region_size;
+               break;
+       case NFIT_SPA_DCR:
+               nfit_mem = nvdimm_provider_data(nvdimm);
+               if (!nfit_mem || !nfit_mem->bdw) {
+                       dev_dbg(acpi_desc->dev, "spa%d %s missing bdw\n",
+                                       spa->range_index, nvdimm_name(nvdimm));
+               } else {
+                       nd_mapping->size = nfit_mem->bdw->capacity;
+                       nd_mapping->start = nfit_mem->bdw->start_address;
+                       ndr_desc->num_lanes = nfit_mem->bdw->windows;
+                       blk_valid = 1;
+               }
+
+               ndr_desc->nd_mapping = nd_mapping;
+               ndr_desc->num_mappings = blk_valid;
+               ndbr_desc = to_blk_region_desc(ndr_desc);
+               ndbr_desc->enable = acpi_nfit_blk_region_enable;
+               ndbr_desc->do_io = acpi_desc->blk_do_io;
+               nfit_spa->nd_region = nvdimm_blk_region_create(acpi_desc->nvdimm_bus,
+                               ndr_desc);
+               if (!nfit_spa->nd_region)
+                       return -ENOMEM;
+               break;
+       }
+
+       return 0;
+}
+
+static bool nfit_spa_is_virtual(struct acpi_nfit_system_address *spa)
+{
+       return (nfit_spa_type(spa) == NFIT_SPA_VDISK ||
+               nfit_spa_type(spa) == NFIT_SPA_VCD   ||
+               nfit_spa_type(spa) == NFIT_SPA_PDISK ||
+               nfit_spa_type(spa) == NFIT_SPA_PCD);
+}
+
+static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_spa *nfit_spa)
+{
+       static struct nd_mapping nd_mappings[ND_MAX_MAPPINGS];
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       struct nd_blk_region_desc ndbr_desc;
+       struct nd_region_desc *ndr_desc;
+       struct nfit_memdev *nfit_memdev;
+       struct nvdimm_bus *nvdimm_bus;
+       struct resource res;
+       int count = 0, rc;
+
+       if (nfit_spa->nd_region)
+               return 0;
+
+       if (spa->range_index == 0 && !nfit_spa_is_virtual(spa)) {
+               dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n",
+                               __func__);
+               return 0;
+       }
+
+       memset(&res, 0, sizeof(res));
+       memset(&nd_mappings, 0, sizeof(nd_mappings));
+       memset(&ndbr_desc, 0, sizeof(ndbr_desc));
+       res.start = spa->address;
+       res.end = res.start + spa->length - 1;
+       ndr_desc = &ndbr_desc.ndr_desc;
+       ndr_desc->res = &res;
+       ndr_desc->provider_data = nfit_spa;
+       ndr_desc->attr_groups = acpi_nfit_region_attribute_groups;
+       if (spa->flags & ACPI_NFIT_PROXIMITY_VALID)
+               ndr_desc->numa_node = acpi_map_pxm_to_online_node(
+                                               spa->proximity_domain);
+       else
+               ndr_desc->numa_node = NUMA_NO_NODE;
+
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
+               struct nd_mapping *nd_mapping;
+
+               if (memdev->range_index != spa->range_index)
+                       continue;
+               if (count >= ND_MAX_MAPPINGS) {
+                       dev_err(acpi_desc->dev, "spa%d exceeds max mappings %d\n",
+                                       spa->range_index, ND_MAX_MAPPINGS);
+                       return -ENXIO;
+               }
+               nd_mapping = &nd_mappings[count++];
+               rc = acpi_nfit_init_mapping(acpi_desc, nd_mapping, ndr_desc,
+                               memdev, nfit_spa);
+               if (rc)
+                       goto out;
+       }
+
+       ndr_desc->nd_mapping = nd_mappings;
+       ndr_desc->num_mappings = count;
+       rc = acpi_nfit_init_interleave_set(acpi_desc, ndr_desc, spa);
+       if (rc)
+               goto out;
+
+       nvdimm_bus = acpi_desc->nvdimm_bus;
+       if (nfit_spa_type(spa) == NFIT_SPA_PM) {
+               rc = acpi_nfit_insert_resource(acpi_desc, ndr_desc);
+               if (rc) {
+                       dev_warn(acpi_desc->dev,
+                               "failed to insert pmem resource to iomem: %d\n",
+                               rc);
+                       goto out;
+               }
+
+               nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus,
+                               ndr_desc);
+               if (!nfit_spa->nd_region)
+                       rc = -ENOMEM;
+       } else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
+               nfit_spa->nd_region = nvdimm_volatile_region_create(nvdimm_bus,
+                               ndr_desc);
+               if (!nfit_spa->nd_region)
+                       rc = -ENOMEM;
+       } else if (nfit_spa_is_virtual(spa)) {
+               nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus,
+                               ndr_desc);
+               if (!nfit_spa->nd_region)
+                       rc = -ENOMEM;
+       }
+
+ out:
+       if (rc)
+               dev_err(acpi_desc->dev, "failed to register spa range %d\n",
+                               nfit_spa->spa->range_index);
+       return rc;
+}
+
+static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc,
+               u32 max_ars)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nd_cmd_ars_status *ars_status;
+
+       if (acpi_desc->ars_status && acpi_desc->ars_status_size >= max_ars) {
+               memset(acpi_desc->ars_status, 0, acpi_desc->ars_status_size);
+               return 0;
+       }
+
+       if (acpi_desc->ars_status)
+               devm_kfree(dev, acpi_desc->ars_status);
+       acpi_desc->ars_status = NULL;
+       ars_status = devm_kzalloc(dev, max_ars, GFP_KERNEL);
+       if (!ars_status)
+               return -ENOMEM;
+       acpi_desc->ars_status = ars_status;
+       acpi_desc->ars_status_size = max_ars;
+       return 0;
+}
+
+static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_spa *nfit_spa)
+{
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       int rc;
+
+       if (!nfit_spa->max_ars) {
+               struct nd_cmd_ars_cap ars_cap;
+
+               memset(&ars_cap, 0, sizeof(ars_cap));
+               rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa);
+               if (rc < 0)
+                       return rc;
+               nfit_spa->max_ars = ars_cap.max_ars_out;
+               nfit_spa->clear_err_unit = ars_cap.clear_err_unit;
+               /* check that the supported scrub types match the spa type */
+               if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE &&
+                               ((ars_cap.status >> 16) & ND_ARS_VOLATILE) == 0)
+                       return -ENOTTY;
+               else if (nfit_spa_type(spa) == NFIT_SPA_PM &&
+                               ((ars_cap.status >> 16) & ND_ARS_PERSISTENT) == 0)
+                       return -ENOTTY;
+       }
+
+       if (ars_status_alloc(acpi_desc, nfit_spa->max_ars))
+               return -ENOMEM;
+
+       rc = ars_get_status(acpi_desc);
+       if (rc < 0 && rc != -ENOSPC)
+               return rc;
+
+       if (ars_status_process_records(acpi_desc->nvdimm_bus,
+                               acpi_desc->ars_status))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void acpi_nfit_async_scrub(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_spa *nfit_spa)
+{
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       unsigned int overflow_retry = scrub_overflow_abort;
+       u64 init_ars_start = 0, init_ars_len = 0;
+       struct device *dev = acpi_desc->dev;
+       unsigned int tmo = scrub_timeout;
+       int rc;
+
+       if (!nfit_spa->ars_required || !nfit_spa->nd_region)
+               return;
+
+       rc = ars_start(acpi_desc, nfit_spa);
+       /*
+        * If we timed out the initial scan we'll still be busy here,
+        * and will wait another timeout before giving up permanently.
+        */
+       if (rc < 0 && rc != -EBUSY)
+               return;
+
+       do {
+               u64 ars_start, ars_len;
+
+               if (acpi_desc->cancel)
+                       break;
+               rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
+               if (rc == -ENOTTY)
+                       break;
+               if (rc == -EBUSY && !tmo) {
+                       dev_warn(dev, "range %d ars timeout, aborting\n",
+                                       spa->range_index);
+                       break;
+               }
+
+               if (rc == -EBUSY) {
+                       /*
+                        * Note, entries may be appended to the list
+                        * while the lock is dropped, but the workqueue
+                        * being active prevents entries being deleted /
+                        * freed.
+                        */
+                       mutex_unlock(&acpi_desc->init_mutex);
+                       ssleep(1);
+                       tmo--;
+                       mutex_lock(&acpi_desc->init_mutex);
+                       continue;
+               }
+
+               /* we got some results, but there are more pending... */
+               if (rc == -ENOSPC && overflow_retry--) {
+                       if (!init_ars_len) {
+                               init_ars_len = acpi_desc->ars_status->length;
+                               init_ars_start = acpi_desc->ars_status->address;
+                       }
+                       rc = ars_continue(acpi_desc);
+               }
+
+               if (rc < 0) {
+                       dev_warn(dev, "range %d ars continuation failed\n",
+                                       spa->range_index);
+                       break;
+               }
+
+               if (init_ars_len) {
+                       ars_start = init_ars_start;
+                       ars_len = init_ars_len;
+               } else {
+                       ars_start = acpi_desc->ars_status->address;
+                       ars_len = acpi_desc->ars_status->length;
+               }
+               dev_dbg(dev, "spa range: %d ars from %#llx + %#llx complete\n",
+                               spa->range_index, ars_start, ars_len);
+               /* notify the region about new poison entries */
+               nvdimm_region_notify(nfit_spa->nd_region,
+                               NVDIMM_REVALIDATE_POISON);
+               break;
+       } while (1);
+}
+
+static void acpi_nfit_scrub(struct work_struct *work)
+{
+       struct device *dev;
+       u64 init_scrub_length = 0;
+       struct nfit_spa *nfit_spa;
+       u64 init_scrub_address = 0;
+       bool init_ars_done = false;
+       struct acpi_nfit_desc *acpi_desc;
+       unsigned int tmo = scrub_timeout;
+       unsigned int overflow_retry = scrub_overflow_abort;
+
+       acpi_desc = container_of(work, typeof(*acpi_desc), work);
+       dev = acpi_desc->dev;
+
+       /*
+        * We scrub in 2 phases.  The first phase waits for any platform
+        * firmware initiated scrubs to complete and then we go search for the
+        * affected spa regions to mark them scanned.  In the second phase we
+        * initiate a directed scrub for every range that was not scrubbed in
+        * phase 1. If we're called for a 'rescan', we harmlessly pass through
+        * the first phase, but really only care about running phase 2, where
+        * regions can be notified of new poison.
+        */
+
+       /* process platform firmware initiated scrubs */
+ retry:
+       mutex_lock(&acpi_desc->init_mutex);
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               struct nd_cmd_ars_status *ars_status;
+               struct acpi_nfit_system_address *spa;
+               u64 ars_start, ars_len;
+               int rc;
+
+               if (acpi_desc->cancel)
+                       break;
+
+               if (nfit_spa->nd_region)
+                       continue;
+
+               if (init_ars_done) {
+                       /*
+                        * No need to re-query, we're now just
+                        * reconciling all the ranges covered by the
+                        * initial scrub
+                        */
+                       rc = 0;
+               } else
+                       rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
+
+               if (rc == -ENOTTY) {
+                       /* no ars capability, just register spa and move on */
+                       acpi_nfit_register_region(acpi_desc, nfit_spa);
+                       continue;
+               }
+
+               if (rc == -EBUSY && !tmo) {
+                       /* fallthrough to directed scrub in phase 2 */
+                       dev_warn(dev, "timeout awaiting ars results, continuing...\n");
+                       break;
+               } else if (rc == -EBUSY) {
+                       mutex_unlock(&acpi_desc->init_mutex);
+                       ssleep(1);
+                       tmo--;
+                       goto retry;
+               }
+
+               /* we got some results, but there are more pending... */
+               if (rc == -ENOSPC && overflow_retry--) {
+                       ars_status = acpi_desc->ars_status;
+                       /*
+                        * Record the original scrub range, so that we
+                        * can recall all the ranges impacted by the
+                        * initial scrub.
+                        */
+                       if (!init_scrub_length) {
+                               init_scrub_length = ars_status->length;
+                               init_scrub_address = ars_status->address;
+                       }
+                       rc = ars_continue(acpi_desc);
+                       if (rc == 0) {
+                               mutex_unlock(&acpi_desc->init_mutex);
+                               goto retry;
+                       }
+               }
+
+               if (rc < 0) {
+                       /*
+                        * Initial scrub failed, we'll give it one more
+                        * try below...
+                        */
+                       break;
+               }
+
+               /* We got some final results, record completed ranges */
+               ars_status = acpi_desc->ars_status;
+               if (init_scrub_length) {
+                       ars_start = init_scrub_address;
+                       ars_len = ars_start + init_scrub_length;
+               } else {
+                       ars_start = ars_status->address;
+                       ars_len = ars_status->length;
+               }
+               spa = nfit_spa->spa;
+
+               if (!init_ars_done) {
+                       init_ars_done = true;
+                       dev_dbg(dev, "init scrub %#llx + %#llx complete\n",
+                                       ars_start, ars_len);
+               }
+               if (ars_start <= spa->address && ars_start + ars_len
+                               >= spa->address + spa->length)
+                       acpi_nfit_register_region(acpi_desc, nfit_spa);
+       }
+
+       /*
+        * For all the ranges not covered by an initial scrub we still
+        * want to see if there are errors, but it's ok to discover them
+        * asynchronously.
+        */
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               /*
+                * Flag all the ranges that still need scrubbing, but
+                * register them now to make data available.
+                */
+               if (!nfit_spa->nd_region) {
+                       nfit_spa->ars_required = 1;
+                       acpi_nfit_register_region(acpi_desc, nfit_spa);
+               }
+       }
+
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
+               acpi_nfit_async_scrub(acpi_desc, nfit_spa);
+       acpi_desc->scrub_count++;
+       if (acpi_desc->scrub_count_state)
+               sysfs_notify_dirent(acpi_desc->scrub_count_state);
+       mutex_unlock(&acpi_desc->init_mutex);
+}
+
+static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nfit_spa *nfit_spa;
+       int rc;
+
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
+               if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) {
+                       /* BLK regions don't need to wait for ars results */
+                       rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
+                       if (rc)
+                               return rc;
+               }
+
+       queue_work(nfit_wq, &acpi_desc->work);
+       return 0;
+}
+
+static int acpi_nfit_check_deletions(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev)
+{
+       struct device *dev = acpi_desc->dev;
+
+       if (!list_empty(&prev->spas) ||
+                       !list_empty(&prev->memdevs) ||
+                       !list_empty(&prev->dcrs) ||
+                       !list_empty(&prev->bdws) ||
+                       !list_empty(&prev->idts) ||
+                       !list_empty(&prev->flushes)) {
+               dev_err(dev, "new nfit deletes entries (unsupported)\n");
+               return -ENXIO;
+       }
+       return 0;
+}
+
+static int acpi_nfit_desc_init_scrub_attr(struct acpi_nfit_desc *acpi_desc)
+{
+       struct device *dev = acpi_desc->dev;
+       struct kernfs_node *nfit;
+       struct device *bus_dev;
+
+       if (!ars_supported(acpi_desc->nvdimm_bus))
+               return 0;
+
+       bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus);
+       nfit = sysfs_get_dirent(bus_dev->kobj.sd, "nfit");
+       if (!nfit) {
+               dev_err(dev, "sysfs_get_dirent 'nfit' failed\n");
+               return -ENODEV;
+       }
+       acpi_desc->scrub_count_state = sysfs_get_dirent(nfit, "scrub");
+       sysfs_put(nfit);
+       if (!acpi_desc->scrub_count_state) {
+               dev_err(dev, "sysfs_get_dirent 'scrub' failed\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void acpi_nfit_destruct(void *data)
+{
+       struct acpi_nfit_desc *acpi_desc = data;
+       struct device *bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus);
+
+       /*
+        * Destruct under acpi_desc_lock so that nfit_handle_mce does not
+        * race teardown
+        */
+       mutex_lock(&acpi_desc_lock);
+       acpi_desc->cancel = 1;
+       /*
+        * Bounce the nvdimm bus lock to make sure any in-flight
+        * acpi_nfit_ars_rescan() submissions have had a chance to
+        * either submit or see ->cancel set.
+        */
+       device_lock(bus_dev);
+       device_unlock(bus_dev);
+
+       flush_workqueue(nfit_wq);
+       if (acpi_desc->scrub_count_state)
+               sysfs_put(acpi_desc->scrub_count_state);
+       nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+       acpi_desc->nvdimm_bus = NULL;
+       list_del(&acpi_desc->list);
+       mutex_unlock(&acpi_desc_lock);
+}
+
+int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_table_prev prev;
+       const void *end;
+       int rc;
+
+       if (!acpi_desc->nvdimm_bus) {
+               acpi_nfit_init_dsms(acpi_desc);
+
+               acpi_desc->nvdimm_bus = nvdimm_bus_register(dev,
+                               &acpi_desc->nd_desc);
+               if (!acpi_desc->nvdimm_bus)
+                       return -ENOMEM;
+
+               rc = devm_add_action_or_reset(dev, acpi_nfit_destruct,
+                               acpi_desc);
+               if (rc)
+                       return rc;
+
+               rc = acpi_nfit_desc_init_scrub_attr(acpi_desc);
+               if (rc)
+                       return rc;
+
+               /* register this acpi_desc for mce notifications */
+               mutex_lock(&acpi_desc_lock);
+               list_add_tail(&acpi_desc->list, &acpi_descs);
+               mutex_unlock(&acpi_desc_lock);
+       }
+
+       mutex_lock(&acpi_desc->init_mutex);
+
+       INIT_LIST_HEAD(&prev.spas);
+       INIT_LIST_HEAD(&prev.memdevs);
+       INIT_LIST_HEAD(&prev.dcrs);
+       INIT_LIST_HEAD(&prev.bdws);
+       INIT_LIST_HEAD(&prev.idts);
+       INIT_LIST_HEAD(&prev.flushes);
+
+       list_cut_position(&prev.spas, &acpi_desc->spas,
+                               acpi_desc->spas.prev);
+       list_cut_position(&prev.memdevs, &acpi_desc->memdevs,
+                               acpi_desc->memdevs.prev);
+       list_cut_position(&prev.dcrs, &acpi_desc->dcrs,
+                               acpi_desc->dcrs.prev);
+       list_cut_position(&prev.bdws, &acpi_desc->bdws,
+                               acpi_desc->bdws.prev);
+       list_cut_position(&prev.idts, &acpi_desc->idts,
+                               acpi_desc->idts.prev);
+       list_cut_position(&prev.flushes, &acpi_desc->flushes,
+                               acpi_desc->flushes.prev);
+
+       end = data + sz;
+       while (!IS_ERR_OR_NULL(data))
+               data = add_table(acpi_desc, &prev, data, end);
+
+       if (IS_ERR(data)) {
+               dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__,
+                               PTR_ERR(data));
+               rc = PTR_ERR(data);
+               goto out_unlock;
+       }
+
+       rc = acpi_nfit_check_deletions(acpi_desc, &prev);
+       if (rc)
+               goto out_unlock;
+
+       rc = nfit_mem_init(acpi_desc);
+       if (rc)
+               goto out_unlock;
+
+       rc = acpi_nfit_register_dimms(acpi_desc);
+       if (rc)
+               goto out_unlock;
+
+       rc = acpi_nfit_register_regions(acpi_desc);
+
+ out_unlock:
+       mutex_unlock(&acpi_desc->init_mutex);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(acpi_nfit_init);
+
+struct acpi_nfit_flush_work {
+       struct work_struct work;
+       struct completion cmp;
+};
+
+static void flush_probe(struct work_struct *work)
+{
+       struct acpi_nfit_flush_work *flush;
+
+       flush = container_of(work, typeof(*flush), work);
+       complete(&flush->cmp);
+}
+
+static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
+{
+       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
+       struct device *dev = acpi_desc->dev;
+       struct acpi_nfit_flush_work flush;
+
+       /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
+       device_lock(dev);
+       device_unlock(dev);
+
+       /*
+        * Scrub work could take 10s of seconds, userspace may give up so we
+        * need to be interruptible while waiting.
+        */
+       INIT_WORK_ONSTACK(&flush.work, flush_probe);
+       COMPLETION_INITIALIZER_ONSTACK(flush.cmp);
+       queue_work(nfit_wq, &flush.work);
+       return wait_for_completion_interruptible(&flush.cmp);
+}
+
+static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
+               struct nvdimm *nvdimm, unsigned int cmd)
+{
+       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
+
+       if (nvdimm)
+               return 0;
+       if (cmd != ND_CMD_ARS_START)
+               return 0;
+
+       /*
+        * The kernel and userspace may race to initiate a scrub, but
+        * the scrub thread is prepared to lose that initial race.  It
+        * just needs guarantees that any ars it initiates are not
+        * interrupted by any intervening start reqeusts from userspace.
+        */
+       if (work_busy(&acpi_desc->work))
+               return -EBUSY;
+
+       return 0;
+}
+
+int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_spa *nfit_spa;
+
+       if (work_busy(&acpi_desc->work))
+               return -EBUSY;
+
+       if (acpi_desc->cancel)
+               return 0;
+
+       mutex_lock(&acpi_desc->init_mutex);
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               struct acpi_nfit_system_address *spa = nfit_spa->spa;
+
+               if (nfit_spa_type(spa) != NFIT_SPA_PM)
+                       continue;
+
+               nfit_spa->ars_required = 1;
+       }
+       queue_work(nfit_wq, &acpi_desc->work);
+       dev_dbg(dev, "%s: ars_scan triggered\n", __func__);
+       mutex_unlock(&acpi_desc->init_mutex);
+
+       return 0;
+}
+
+void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
+{
+       struct nvdimm_bus_descriptor *nd_desc;
+
+       dev_set_drvdata(dev, acpi_desc);
+       acpi_desc->dev = dev;
+       acpi_desc->blk_do_io = acpi_nfit_blk_region_do_io;
+       nd_desc = &acpi_desc->nd_desc;
+       nd_desc->provider_name = "ACPI.NFIT";
+       nd_desc->module = THIS_MODULE;
+       nd_desc->ndctl = acpi_nfit_ctl;
+       nd_desc->flush_probe = acpi_nfit_flush_probe;
+       nd_desc->clear_to_send = acpi_nfit_clear_to_send;
+       nd_desc->attr_groups = acpi_nfit_attribute_groups;
+
+       INIT_LIST_HEAD(&acpi_desc->spas);
+       INIT_LIST_HEAD(&acpi_desc->dcrs);
+       INIT_LIST_HEAD(&acpi_desc->bdws);
+       INIT_LIST_HEAD(&acpi_desc->idts);
+       INIT_LIST_HEAD(&acpi_desc->flushes);
+       INIT_LIST_HEAD(&acpi_desc->memdevs);
+       INIT_LIST_HEAD(&acpi_desc->dimms);
+       INIT_LIST_HEAD(&acpi_desc->list);
+       mutex_init(&acpi_desc->init_mutex);
+       INIT_WORK(&acpi_desc->work, acpi_nfit_scrub);
+}
+EXPORT_SYMBOL_GPL(acpi_nfit_desc_init);
+
+static int acpi_nfit_add(struct acpi_device *adev)
+{
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_nfit_desc *acpi_desc;
+       struct device *dev = &adev->dev;
+       struct acpi_table_header *tbl;
+       acpi_status status = AE_OK;
+       acpi_size sz;
+       int rc = 0;
+
+       status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz);
+       if (ACPI_FAILURE(status)) {
+               /* This is ok, we could have an nvdimm hotplugged later */
+               dev_dbg(dev, "failed to find NFIT at startup\n");
+               return 0;
+       }
+
+       acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
+       if (!acpi_desc)
+               return -ENOMEM;
+       acpi_nfit_desc_init(acpi_desc, &adev->dev);
+
+       /* Save the acpi header for exporting the revision via sysfs */
+       acpi_desc->acpi_header = *tbl;
+
+       /* Evaluate _FIT and override with that if present */
+       status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
+       if (ACPI_SUCCESS(status) && buf.length > 0) {
+               union acpi_object *obj = buf.pointer;
+
+               if (obj->type == ACPI_TYPE_BUFFER)
+                       rc = acpi_nfit_init(acpi_desc, obj->buffer.pointer,
+                                       obj->buffer.length);
+               else
+                       dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
+                                __func__, (int) obj->type);
+               kfree(buf.pointer);
+       } else
+               /* skip over the lead-in header table */
+               rc = acpi_nfit_init(acpi_desc, (void *) tbl
+                               + sizeof(struct acpi_table_nfit),
+                               sz - sizeof(struct acpi_table_nfit));
+       return rc;
+}
+
+static int acpi_nfit_remove(struct acpi_device *adev)
+{
+       /* see acpi_nfit_destruct */
+       return 0;
+}
+
+static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
+{
+       struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct device *dev = &adev->dev;
+       union acpi_object *obj;
+       acpi_status status;
+       int ret;
+
+       dev_dbg(dev, "%s: event: %d\n", __func__, event);
+
+       device_lock(dev);
+       if (!dev->driver) {
+               /* dev->driver may be null if we're being removed */
+               dev_dbg(dev, "%s: no driver found for dev\n", __func__);
+               goto out_unlock;
+       }
+
+       if (!acpi_desc) {
+               acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
+               if (!acpi_desc)
+                       goto out_unlock;
+               acpi_nfit_desc_init(acpi_desc, &adev->dev);
+       } else {
+               /*
+                * Finish previous registration before considering new
+                * regions.
+                */
+               flush_workqueue(nfit_wq);
+       }
+
+       /* Evaluate _FIT */
+       status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
+       if (ACPI_FAILURE(status)) {
+               dev_err(dev, "failed to evaluate _FIT\n");
+               goto out_unlock;
+       }
+
+       obj = buf.pointer;
+       if (obj->type == ACPI_TYPE_BUFFER) {
+               ret = acpi_nfit_init(acpi_desc, obj->buffer.pointer,
+                               obj->buffer.length);
+               if (ret)
+                       dev_err(dev, "failed to merge updated NFIT\n");
+       } else
+               dev_err(dev, "Invalid _FIT\n");
+       kfree(buf.pointer);
+
+ out_unlock:
+       device_unlock(dev);
+}
+
+static const struct acpi_device_id acpi_nfit_ids[] = {
+       { "ACPI0012", 0 },
+       { "", 0 },
+};
+MODULE_DEVICE_TABLE(acpi, acpi_nfit_ids);
+
+static struct acpi_driver acpi_nfit_driver = {
+       .name = KBUILD_MODNAME,
+       .ids = acpi_nfit_ids,
+       .ops = {
+               .add = acpi_nfit_add,
+               .remove = acpi_nfit_remove,
+               .notify = acpi_nfit_notify,
+       },
+};
+
+static __init int nfit_init(void)
+{
+       BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_interleave) != 20);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_smbios) != 9);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40);
+
+       acpi_str_to_uuid(UUID_VOLATILE_MEMORY, nfit_uuid[NFIT_SPA_VOLATILE]);
+       acpi_str_to_uuid(UUID_PERSISTENT_MEMORY, nfit_uuid[NFIT_SPA_PM]);
+       acpi_str_to_uuid(UUID_CONTROL_REGION, nfit_uuid[NFIT_SPA_DCR]);
+       acpi_str_to_uuid(UUID_DATA_REGION, nfit_uuid[NFIT_SPA_BDW]);
+       acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_VDISK]);
+       acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_CD, nfit_uuid[NFIT_SPA_VCD]);
+       acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_PDISK]);
+       acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]);
+       acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);
+       acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);
+       acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
+       acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
+       acpi_str_to_uuid(UUID_NFIT_DIMM_N_MSFT, nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
+
+       nfit_wq = create_singlethread_workqueue("nfit");
+       if (!nfit_wq)
+               return -ENOMEM;
+
+       nfit_mce_register();
+
+       return acpi_bus_register_driver(&acpi_nfit_driver);
+}
+
+static __exit void nfit_exit(void)
+{
+       nfit_mce_unregister();
+       acpi_bus_unregister_driver(&acpi_nfit_driver);
+       destroy_workqueue(nfit_wq);
+       WARN_ON(!list_empty(&acpi_descs));
+}
+
+module_init(nfit_init);
+module_exit(nfit_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/acpi/nfit/mce.c b/drivers/acpi/nfit/mce.c
new file mode 100644 (file)
index 0000000..4c745bf
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * NFIT - Machine Check Handler
+ *
+ * Copyright(c) 2013-2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/notifier.h>
+#include <linux/acpi.h>
+#include <asm/mce.h>
+#include "nfit.h"
+
+static int nfit_handle_mce(struct notifier_block *nb, unsigned long val,
+                       void *data)
+{
+       struct mce *mce = (struct mce *)data;
+       struct acpi_nfit_desc *acpi_desc;
+       struct nfit_spa *nfit_spa;
+
+       /* We only care about memory errors */
+       if (!(mce->status & MCACOD))
+               return NOTIFY_DONE;
+
+       /*
+        * mce->addr contains the physical addr accessed that caused the
+        * machine check. We need to walk through the list of NFITs, and see
+        * if any of them matches that address, and only then start a scrub.
+        */
+       mutex_lock(&acpi_desc_lock);
+       list_for_each_entry(acpi_desc, &acpi_descs, list) {
+               struct device *dev = acpi_desc->dev;
+               int found_match = 0;
+
+               mutex_lock(&acpi_desc->init_mutex);
+               list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+                       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+
+                       if (nfit_spa_type(spa) == NFIT_SPA_PM)
+                               continue;
+                       /* find the spa that covers the mce addr */
+                       if (spa->address > mce->addr)
+                               continue;
+                       if ((spa->address + spa->length - 1) < mce->addr)
+                               continue;
+                       found_match = 1;
+                       dev_dbg(dev, "%s: addr in SPA %d (0x%llx, 0x%llx)\n",
+                               __func__, spa->range_index, spa->address,
+                               spa->length);
+                       /*
+                        * We can break at the first match because we're going
+                        * to rescan all the SPA ranges. There shouldn't be any
+                        * aliasing anyway.
+                        */
+                       break;
+               }
+               mutex_unlock(&acpi_desc->init_mutex);
+
+               /*
+                * We can ignore an -EBUSY here because if an ARS is already
+                * in progress, just let that be the last authoritative one
+                */
+               if (found_match)
+                       acpi_nfit_ars_rescan(acpi_desc);
+       }
+
+       mutex_unlock(&acpi_desc_lock);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block nfit_mce_dec = {
+       .notifier_call  = nfit_handle_mce,
+};
+
+void nfit_mce_register(void)
+{
+       mce_register_decode_chain(&nfit_mce_dec);
+}
+
+void nfit_mce_unregister(void)
+{
+       mce_unregister_decode_chain(&nfit_mce_dec);
+}
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
new file mode 100644 (file)
index 0000000..e894ded
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * NVDIMM Firmware Interface Table - NFIT
+ *
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+#ifndef __NFIT_H__
+#define __NFIT_H__
+#include <linux/workqueue.h>
+#include <linux/libnvdimm.h>
+#include <linux/ndctl.h>
+#include <linux/types.h>
+#include <linux/uuid.h>
+#include <linux/acpi.h>
+#include <acpi/acuuid.h>
+
+/* ACPI 6.1 */
+#define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
+
+/* http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf */
+#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
+
+/* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */
+#define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"
+#define UUID_NFIT_DIMM_N_HPE2 "5008664b-b758-41a0-a03c-27c2f2d04f7e"
+
+/* https://msdn.microsoft.com/library/windows/hardware/mt604741 */
+#define UUID_NFIT_DIMM_N_MSFT "1ee68b36-d4bd-4a1a-9a16-4f8e53d46e05"
+
+#define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
+               | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
+               | ACPI_NFIT_MEM_NOT_ARMED)
+
+enum nfit_uuids {
+       /* for simplicity alias the uuid index with the family id */
+       NFIT_DEV_DIMM = NVDIMM_FAMILY_INTEL,
+       NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1,
+       NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
+       NFIT_DEV_DIMM_N_MSFT = NVDIMM_FAMILY_MSFT,
+       NFIT_SPA_VOLATILE,
+       NFIT_SPA_PM,
+       NFIT_SPA_DCR,
+       NFIT_SPA_BDW,
+       NFIT_SPA_VDISK,
+       NFIT_SPA_VCD,
+       NFIT_SPA_PDISK,
+       NFIT_SPA_PCD,
+       NFIT_DEV_BUS,
+       NFIT_UUID_MAX,
+};
+
+/*
+ * Region format interface codes are stored with the interface as the
+ * LSB and the function as the MSB.
+ */
+#define NFIT_FIC_BYTE cpu_to_le16(0x101) /* byte-addressable energy backed */
+#define NFIT_FIC_BLK cpu_to_le16(0x201) /* block-addressable non-energy backed */
+#define NFIT_FIC_BYTEN cpu_to_le16(0x301) /* byte-addressable non-energy backed */
+
+enum {
+       NFIT_BLK_READ_FLUSH = 1,
+       NFIT_BLK_DCR_LATCH = 2,
+       NFIT_ARS_STATUS_DONE = 0,
+       NFIT_ARS_STATUS_BUSY = 1 << 16,
+       NFIT_ARS_STATUS_NONE = 2 << 16,
+       NFIT_ARS_STATUS_INTR = 3 << 16,
+       NFIT_ARS_START_BUSY = 6,
+       NFIT_ARS_CAP_NONE = 1,
+       NFIT_ARS_F_OVERFLOW = 1,
+       NFIT_ARS_TIMEOUT = 90,
+};
+
+struct nfit_spa {
+       struct list_head list;
+       struct nd_region *nd_region;
+       unsigned int ars_required:1;
+       u32 clear_err_unit;
+       u32 max_ars;
+       struct acpi_nfit_system_address spa[0];
+};
+
+struct nfit_dcr {
+       struct list_head list;
+       struct acpi_nfit_control_region dcr[0];
+};
+
+struct nfit_bdw {
+       struct list_head list;
+       struct acpi_nfit_data_region bdw[0];
+};
+
+struct nfit_idt {
+       struct list_head list;
+       struct acpi_nfit_interleave idt[0];
+};
+
+struct nfit_flush {
+       struct list_head list;
+       struct acpi_nfit_flush_address flush[0];
+};
+
+struct nfit_memdev {
+       struct list_head list;
+       struct acpi_nfit_memory_map memdev[0];
+};
+
+/* assembled tables for a given dimm/memory-device */
+struct nfit_mem {
+       struct nvdimm *nvdimm;
+       struct acpi_nfit_memory_map *memdev_dcr;
+       struct acpi_nfit_memory_map *memdev_pmem;
+       struct acpi_nfit_memory_map *memdev_bdw;
+       struct acpi_nfit_control_region *dcr;
+       struct acpi_nfit_data_region *bdw;
+       struct acpi_nfit_system_address *spa_dcr;
+       struct acpi_nfit_system_address *spa_bdw;
+       struct acpi_nfit_interleave *idt_dcr;
+       struct acpi_nfit_interleave *idt_bdw;
+       struct nfit_flush *nfit_flush;
+       struct list_head list;
+       struct acpi_device *adev;
+       struct acpi_nfit_desc *acpi_desc;
+       struct resource *flush_wpq;
+       unsigned long dsm_mask;
+       int family;
+};
+
+struct acpi_nfit_desc {
+       struct nvdimm_bus_descriptor nd_desc;
+       struct acpi_table_header acpi_header;
+       struct mutex init_mutex;
+       struct list_head memdevs;
+       struct list_head flushes;
+       struct list_head dimms;
+       struct list_head spas;
+       struct list_head dcrs;
+       struct list_head bdws;
+       struct list_head idts;
+       struct nvdimm_bus *nvdimm_bus;
+       struct device *dev;
+       struct nd_cmd_ars_status *ars_status;
+       size_t ars_status_size;
+       struct work_struct work;
+       struct list_head list;
+       struct kernfs_node *scrub_count_state;
+       unsigned int scrub_count;
+       unsigned int cancel:1;
+       unsigned long dimm_cmd_force_en;
+       unsigned long bus_cmd_force_en;
+       int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
+                       void *iobuf, u64 len, int rw);
+};
+
+enum nd_blk_mmio_selector {
+       BDW,
+       DCR,
+};
+
+struct nd_blk_addr {
+       union {
+               void __iomem *base;
+               void *aperture;
+       };
+};
+
+struct nfit_blk {
+       struct nfit_blk_mmio {
+               struct nd_blk_addr addr;
+               u64 size;
+               u64 base_offset;
+               u32 line_size;
+               u32 num_lines;
+               u32 table_size;
+               struct acpi_nfit_interleave *idt;
+               struct acpi_nfit_system_address *spa;
+       } mmio[2];
+       struct nd_region *nd_region;
+       u64 bdw_offset; /* post interleave offset */
+       u64 stat_offset;
+       u64 cmd_offset;
+       u32 dimm_flags;
+};
+
+extern struct list_head acpi_descs;
+extern struct mutex acpi_desc_lock;
+int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc);
+
+#ifdef CONFIG_X86_MCE
+void nfit_mce_register(void);
+void nfit_mce_unregister(void);
+#else
+static inline void nfit_mce_register(void)
+{
+}
+static inline void nfit_mce_unregister(void)
+{
+}
+#endif
+
+int nfit_spa_type(struct acpi_nfit_system_address *spa);
+
+static inline struct acpi_nfit_memory_map *__to_nfit_memdev(
+               struct nfit_mem *nfit_mem)
+{
+       if (nfit_mem->memdev_dcr)
+               return nfit_mem->memdev_dcr;
+       return nfit_mem->memdev_pmem;
+}
+
+static inline struct acpi_nfit_desc *to_acpi_desc(
+               struct nvdimm_bus_descriptor *nd_desc)
+{
+       return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
+}
+
+const u8 *to_nfit_uuid(enum nfit_uuids id);
+int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz);
+void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
+#endif /* __NFIT_H__ */
index 51c7db2c4ee2a6bc06cc5ee2c22758fc91cb7c66..29cd96661b3077f5272c40e17fd5d5f1b9b9d952 100644 (file)
@@ -56,6 +56,7 @@ static ssize_t node_read_meminfo(struct device *dev,
 {
        int n;
        int nid = dev->id;
+       struct pglist_data *pgdat = NODE_DATA(nid);
        struct sysinfo i;
 
        si_meminfo_node(&i, nid);
@@ -74,16 +75,16 @@ static ssize_t node_read_meminfo(struct device *dev,
                       nid, K(i.totalram),
                       nid, K(i.freeram),
                       nid, K(i.totalram - i.freeram),
-                      nid, K(node_page_state(nid, NR_ACTIVE_ANON) +
-                               node_page_state(nid, NR_ACTIVE_FILE)),
-                      nid, K(node_page_state(nid, NR_INACTIVE_ANON) +
-                               node_page_state(nid, NR_INACTIVE_FILE)),
-                      nid, K(node_page_state(nid, NR_ACTIVE_ANON)),
-                      nid, K(node_page_state(nid, NR_INACTIVE_ANON)),
-                      nid, K(node_page_state(nid, NR_ACTIVE_FILE)),
-                      nid, K(node_page_state(nid, NR_INACTIVE_FILE)),
-                      nid, K(node_page_state(nid, NR_UNEVICTABLE)),
-                      nid, K(node_page_state(nid, NR_MLOCK)));
+                      nid, K(node_page_state(pgdat, NR_ACTIVE_ANON) +
+                               node_page_state(pgdat, NR_ACTIVE_FILE)),
+                      nid, K(node_page_state(pgdat, NR_INACTIVE_ANON) +
+                               node_page_state(pgdat, NR_INACTIVE_FILE)),
+                      nid, K(node_page_state(pgdat, NR_ACTIVE_ANON)),
+                      nid, K(node_page_state(pgdat, NR_INACTIVE_ANON)),
+                      nid, K(node_page_state(pgdat, NR_ACTIVE_FILE)),
+                      nid, K(node_page_state(pgdat, NR_INACTIVE_FILE)),
+                      nid, K(node_page_state(pgdat, NR_UNEVICTABLE)),
+                      nid, K(sum_zone_node_page_state(nid, NR_MLOCK)));
 
 #ifdef CONFIG_HIGHMEM
        n += sprintf(buf + n,
@@ -117,31 +118,30 @@ static ssize_t node_read_meminfo(struct device *dev,
                       "Node %d ShmemPmdMapped: %8lu kB\n"
 #endif
                        ,
-                      nid, K(node_page_state(nid, NR_FILE_DIRTY)),
-                      nid, K(node_page_state(nid, NR_WRITEBACK)),
-                      nid, K(node_page_state(nid, NR_FILE_PAGES)),
-                      nid, K(node_page_state(nid, NR_FILE_MAPPED)),
-                      nid, K(node_page_state(nid, NR_ANON_PAGES)),
+                      nid, K(node_page_state(pgdat, NR_FILE_DIRTY)),
+                      nid, K(node_page_state(pgdat, NR_WRITEBACK)),
+                      nid, K(node_page_state(pgdat, NR_FILE_PAGES)),
+                      nid, K(node_page_state(pgdat, NR_FILE_MAPPED)),
+                      nid, K(node_page_state(pgdat, NR_ANON_MAPPED)),
                       nid, K(i.sharedram),
-                      nid, node_page_state(nid, NR_KERNEL_STACK) *
-                               THREAD_SIZE / 1024,
-                      nid, K(node_page_state(nid, NR_PAGETABLE)),
-                      nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
-                      nid, K(node_page_state(nid, NR_BOUNCE)),
-                      nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)),
-                      nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
-                               node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
-                      nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
+                      nid, sum_zone_node_page_state(nid, NR_KERNEL_STACK_KB),
+                      nid, K(sum_zone_node_page_state(nid, NR_PAGETABLE)),
+                      nid, K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
+                      nid, K(sum_zone_node_page_state(nid, NR_BOUNCE)),
+                      nid, K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
+                      nid, K(sum_zone_node_page_state(nid, NR_SLAB_RECLAIMABLE) +
+                               sum_zone_node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
+                      nid, K(sum_zone_node_page_state(nid, NR_SLAB_RECLAIMABLE)),
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-                      nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
-                      nid, K(node_page_state(nid, NR_ANON_THPS) *
+                      nid, K(sum_zone_node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
+                      nid, K(node_page_state(pgdat, NR_ANON_THPS) *
                                       HPAGE_PMD_NR),
-                      nid, K(node_page_state(nid, NR_SHMEM_THPS) *
+                      nid, K(node_page_state(pgdat, NR_SHMEM_THPS) *
                                       HPAGE_PMD_NR),
-                      nid, K(node_page_state(nid, NR_SHMEM_PMDMAPPED) *
+                      nid, K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED) *
                                       HPAGE_PMD_NR));
 #else
-                      nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
+                      nid, K(sum_zone_node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
 #endif
        n += hugetlb_report_node_meminfo(nid, buf + n);
        return n;
@@ -160,12 +160,12 @@ static ssize_t node_read_numastat(struct device *dev,
                       "interleave_hit %lu\n"
                       "local_node %lu\n"
                       "other_node %lu\n",
-                      node_page_state(dev->id, NUMA_HIT),
-                      node_page_state(dev->id, NUMA_MISS),
-                      node_page_state(dev->id, NUMA_FOREIGN),
-                      node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
-                      node_page_state(dev->id, NUMA_LOCAL),
-                      node_page_state(dev->id, NUMA_OTHER));
+                      sum_zone_node_page_state(dev->id, NUMA_HIT),
+                      sum_zone_node_page_state(dev->id, NUMA_MISS),
+                      sum_zone_node_page_state(dev->id, NUMA_FOREIGN),
+                      sum_zone_node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
+                      sum_zone_node_page_state(dev->id, NUMA_LOCAL),
+                      sum_zone_node_page_state(dev->id, NUMA_OTHER));
 }
 static DEVICE_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
 
@@ -173,12 +173,18 @@ static ssize_t node_read_vmstat(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        int nid = dev->id;
+       struct pglist_data *pgdat = NODE_DATA(nid);
        int i;
        int n = 0;
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
                n += sprintf(buf+n, "%s %lu\n", vmstat_text[i],
-                            node_page_state(nid, i));
+                            sum_zone_node_page_state(nid, i));
+
+       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],
+                            node_page_state(pgdat, i));
 
        return n;
 }
index ba5145d384d8013df86b1f36047303df26708518..3022dad240719138d0a0aca0f7b6a7d2486f862a 100644 (file)
@@ -379,7 +379,7 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector,
 
 #ifdef CONFIG_BLK_DEV_RAM_DAX
 static long brd_direct_access(struct block_device *bdev, sector_t sector,
-                       void __pmem **kaddr, pfn_t *pfn, long size)
+                       void **kaddr, pfn_t *pfn, long size)
 {
        struct brd_device *brd = bdev->bd_disk->private_data;
        struct page *page;
@@ -389,7 +389,7 @@ static long brd_direct_access(struct block_device *bdev, sector_t sector,
        page = brd_insert_page(brd, sector);
        if (!page)
                return -ENOSPC;
-       *kaddr = (void __pmem *)page_address(page);
+       *kaddr = page_address(page);
        *pfn = page_to_pfn_t(page);
 
        return PAGE_SIZE;
index be91a8d7c22aec8391d1aabcd44851070e3494e8..de5c3ee8a7906555f28acb98b6d34987e4b0d82c 100644 (file)
@@ -425,9 +425,6 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo
        /* Are we still linked,
         * or has debugfs_remove() already been called? */
        parent = file->f_path.dentry->d_parent;
-       /* not sure if this can happen: */
-       if (!parent || d_really_is_negative(parent))
-               goto out;
        /* serialize with d_delete() */
        inode_lock(d_inode(parent));
        /* Make sure the object is still alive */
@@ -440,7 +437,6 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo
                if (ret)
                        kref_put(kref, release);
        }
-out:
        return ret;
 }
 
index 8d0af74f656987f2d1be560e336962e2d7badf20..7f0622426b972fcaf4fb82b818f1079f7216e853 100644 (file)
@@ -1668,13 +1668,12 @@ static int rand_initialize(void)
 #ifdef CONFIG_NUMA
        pool = kmalloc(num_nodes * sizeof(void *),
                       GFP_KERNEL|__GFP_NOFAIL|__GFP_ZERO);
-       for (i=0; i < num_nodes; i++) {
+       for_each_online_node(i) {
                crng = kmalloc_node(sizeof(struct crng_state),
                                    GFP_KERNEL | __GFP_NOFAIL, i);
                spin_lock_init(&crng->lock);
                crng_initialize(crng);
                pool[i] = crng;
-
        }
        mb();
        crng_node_pool = pool;
index b891a129b275d56985a436bb30bf5486a5b81ec7..803f3953b341a42aa47adcc4f8405f5dfa501a06 100644 (file)
@@ -211,11 +211,9 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res,
        }
        dax_dev->dev = dev;
 
-       rc = devm_add_action(dax_region->dev, unregister_dax_dev, dev);
-       if (rc) {
-               unregister_dax_dev(dev);
+       rc = devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev);
+       if (rc)
                return rc;
-       }
 
        return 0;
 
index 55d510e36cd1bd2d9236dd6f00d34db640dbb171..dfb168568af1a6d2ba163a7010d611ec0ad3a3f0 100644 (file)
@@ -102,21 +102,19 @@ static int dax_pmem_probe(struct device *dev)
        if (rc)
                return rc;
 
-       rc = devm_add_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref);
-       if (rc) {
-               dax_pmem_percpu_exit(&dax_pmem->ref);
+       rc = devm_add_action_or_reset(dev, dax_pmem_percpu_exit,
+                                                       &dax_pmem->ref);
+       if (rc)
                return rc;
-       }
 
        addr = devm_memremap_pages(dev, &res, &dax_pmem->ref, altmap);
        if (IS_ERR(addr))
                return PTR_ERR(addr);
 
-       rc = devm_add_action(dev, dax_pmem_percpu_kill, &dax_pmem->ref);
-       if (rc) {
-               dax_pmem_percpu_kill(&dax_pmem->ref);
+       rc = devm_add_action_or_reset(dev, dax_pmem_percpu_kill,
+                                                       &dax_pmem->ref);
+       if (rc)
                return rc;
-       }
 
        nd_region = to_nd_region(dev->parent);
        dax_region = alloc_dax_region(dev, nd_region->id, &res,
index 8c98779a12b134f3688e1076f1e11211c23e2623..739f797b40d9843b7d75261e955439866c7aaa83 100644 (file)
@@ -339,6 +339,20 @@ config MV_XOR
        ---help---
          Enable support for the Marvell XOR engine.
 
+config MV_XOR_V2
+       bool "Marvell XOR engine version 2 support "
+       depends on ARM64
+       select DMA_ENGINE
+       select DMA_ENGINE_RAID
+       select ASYNC_TX_ENABLE_CHANNEL_SWITCH
+       select GENERIC_MSI_IRQ_DOMAIN
+       ---help---
+         Enable support for the Marvell version 2 XOR engine.
+
+         This engine provides acceleration for copy, XOR and RAID6
+         operations, and is available on Marvell Armada 7K and 8K
+         platforms.
+
 config MXS_DMA
        bool "MXS DMA support"
        depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q || SOC_IMX6UL
@@ -519,19 +533,31 @@ config XGENE_DMA
        help
          Enable support for the APM X-Gene SoC DMA engine.
 
-config XILINX_VDMA
-       tristate "Xilinx AXI VDMA Engine"
+config XILINX_DMA
+       tristate "Xilinx AXI DMAS Engine"
        depends on (ARCH_ZYNQ || MICROBLAZE || ARM64)
        select DMA_ENGINE
        help
          Enable support for Xilinx AXI VDMA Soft IP.
 
-         This engine provides high-bandwidth direct memory access
+         AXI VDMA engine provides high-bandwidth direct memory access
          between memory and AXI4-Stream video type target
          peripherals including peripherals which support AXI4-
          Stream Video Protocol.  It has two stream interfaces/
          channels, Memory Mapped to Stream (MM2S) and Stream to
          Memory Mapped (S2MM) for the data transfers.
+         AXI CDMA engine provides high-bandwidth direct memory access
+         between a memory-mapped source address and a memory-mapped
+         destination address.
+         AXI DMA engine provides high-bandwidth one dimensional direct
+         memory access between memory and AXI4-Stream target peripherals.
+
+config XILINX_ZYNQMP_DMA
+       tristate "Xilinx ZynqMP DMA Engine"
+       depends on (ARCH_ZYNQ || MICROBLAZE || ARM64)
+       select DMA_ENGINE
+       help
+         Enable support for Xilinx ZynqMP DMA controller.
 
 config ZX_DMA
        tristate "ZTE ZX296702 DMA support"
index 614f28b0b739de875823b05a66a62186a1e9f45f..e4dc9cac7ee8427184f821896364c232634a444f 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
 obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
 obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
 obj-$(CONFIG_MV_XOR) += mv_xor.o
+obj-$(CONFIG_MV_XOR_V2) += mv_xor_v2.o
 obj-$(CONFIG_MXS_DMA) += mxs-dma.o
 obj-$(CONFIG_MX3_IPU) += ipu/
 obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
index 81db1c4811ceef4f71e8c0c1e5adada3aec07de1..939a7c31f7605928b1a6b1a95591e683f1ab664e 100644 (file)
@@ -1443,8 +1443,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
        dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT);
        if (!dsg) {
                pl08x_free_txd(pl08x, txd);
-               dev_err(&pl08x->adev->dev, "%s no memory for pl080 sg\n",
-                               __func__);
                return NULL;
        }
        list_add_tail(&dsg->node, &txd->dsg_list);
@@ -1901,11 +1899,8 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
         */
        for (i = 0; i < channels; i++) {
                chan = kzalloc(sizeof(*chan), GFP_KERNEL);
-               if (!chan) {
-                       dev_err(&pl08x->adev->dev,
-                               "%s no memory for channel\n", __func__);
+               if (!chan)
                        return -ENOMEM;
-               }
 
                chan->host = pl08x;
                chan->state = PL08X_CHAN_IDLE;
@@ -2360,9 +2355,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->phy_chans = kzalloc((vd->channels * sizeof(*pl08x->phy_chans)),
                        GFP_KERNEL);
        if (!pl08x->phy_chans) {
-               dev_err(&adev->dev, "%s failed to allocate "
-                       "physical channel holders\n",
-                       __func__);
                ret = -ENOMEM;
                goto out_no_phychans;
        }
index 75bd6621dc5d7fb068ca6f4dd24d71bfa56ad640..e434ffe7bc5c57cfd22f7b9f163f0819a1294981 100644 (file)
@@ -456,7 +456,7 @@ static struct at_xdmac_desc *at_xdmac_alloc_desc(struct dma_chan *chan,
        return desc;
 }
 
-void at_xdmac_init_used_desc(struct at_xdmac_desc *desc)
+static void at_xdmac_init_used_desc(struct at_xdmac_desc *desc)
 {
        memset(&desc->lld, 0, sizeof(desc->lld));
        INIT_LIST_HEAD(&desc->descs_list);
@@ -1195,14 +1195,14 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
        desc->lld.mbr_cfg = chan_cc;
 
        dev_dbg(chan2dev(chan),
-               "%s: lld: mbr_da=%pad, mbr_ds=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
-               __func__, &desc->lld.mbr_da, &desc->lld.mbr_ds, desc->lld.mbr_ubc,
+               "%s: lld: mbr_da=%pad, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
+               __func__, &desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc,
                desc->lld.mbr_cfg);
 
        return desc;
 }
 
-struct dma_async_tx_descriptor *
+static struct dma_async_tx_descriptor *
 at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
                         size_t len, unsigned long flags)
 {
index 6149b27c33ad0962a19ed411055d9d05bfb252d3..e18dc596cf2447fa9ef7e41b62d9396e29043426 100644 (file)
@@ -393,11 +393,12 @@ static void bcm2835_dma_fill_cb_chain_with_sg(
        unsigned int sg_len)
 {
        struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
-       size_t max_len = bcm2835_dma_max_frame_length(c);
-       unsigned int i, len;
+       size_t len, max_len;
+       unsigned int i;
        dma_addr_t addr;
        struct scatterlist *sgent;
 
+       max_len = bcm2835_dma_max_frame_length(c);
        for_each_sg(sgl, sgent, sg_len, i) {
                for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
                     len > 0;
@@ -613,7 +614,7 @@ static void bcm2835_dma_issue_pending(struct dma_chan *chan)
        spin_unlock_irqrestore(&c->vc.lock, flags);
 }
 
-struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy(
+static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy(
        struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
        size_t len, unsigned long flags)
 {
index 180fedb418cc1983720072bb6a40b05ff9ea3a82..7ce843723003037495c3af240f20513d1099f6bb 100644 (file)
@@ -397,8 +397,6 @@ static int mpc52xx_bcom_probe(struct platform_device *op)
        /* Get a clean struct */
        bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
        if (!bcom_eng) {
-               printk(KERN_ERR DRIVER_NAME ": "
-                       "Can't allocate state structure\n");
                rv = -ENOMEM;
                goto error_sramclean;
        }
index c340ca9bd2b5dc953e6373f85314714836f8cf83..e4acd63e42aa37a9048b91a69f8351b444acc498 100644 (file)
@@ -266,7 +266,7 @@ static int dma_memcpy_channels[] = {
                        COH901318_CX_CTRL_DDMA_LEGACY | \
                        COH901318_CX_CTRL_PRDD_SOURCE)
 
-const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
+static const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
        {
                .number = U300_DMA_MSL_TX_0,
                .name = "MSL TX 0",
@@ -1280,6 +1280,7 @@ struct coh901318_desc {
 struct coh901318_base {
        struct device *dev;
        void __iomem *virtbase;
+       unsigned int irq;
        struct coh901318_pool pool;
        struct powersave pm;
        struct dma_device dma_slave;
@@ -1364,7 +1365,6 @@ static int coh901318_debugfs_read(struct file *file, char __user *buf,
 }
 
 static const struct file_operations coh901318_debugfs_status_operations = {
-       .owner          = THIS_MODULE,
        .open           = simple_open,
        .read           = coh901318_debugfs_read,
        .llseek         = default_llseek,
@@ -2422,7 +2422,7 @@ coh901318_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        enum dma_status ret;
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret == DMA_COMPLETE)
+       if (ret == DMA_COMPLETE || !txstate)
                return ret;
 
        dma_set_residue(txstate, coh901318_get_bytes_left(chan));
@@ -2680,6 +2680,8 @@ static int __init coh901318_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       base->irq = irq;
+
        err = coh901318_pool_create(&base->pool, &pdev->dev,
                                    sizeof(struct coh901318_lli),
                                    32);
@@ -2755,11 +2757,31 @@ static int __init coh901318_probe(struct platform_device *pdev)
        coh901318_pool_destroy(&base->pool);
        return err;
 }
+static void coh901318_base_remove(struct coh901318_base *base, const int *pick_chans)
+{
+       int chans_i;
+       int i = 0;
+       struct coh901318_chan *cohc;
+
+       for (chans_i = 0; pick_chans[chans_i] != -1; chans_i += 2) {
+               for (i = pick_chans[chans_i]; i <= pick_chans[chans_i+1]; i++) {
+                       cohc = &base->chans[i];
+
+                       tasklet_kill(&cohc->tasklet);
+               }
+       }
+
+}
 
 static int coh901318_remove(struct platform_device *pdev)
 {
        struct coh901318_base *base = platform_get_drvdata(pdev);
 
+       devm_free_irq(&pdev->dev, base->irq, base);
+
+       coh901318_base_remove(base, dma_slave_channels);
+       coh901318_base_remove(base, dma_memcpy_channels);
+
        of_dma_controller_free(pdev->dev.of_node);
        dma_async_device_unregister(&base->dma_memcpy);
        dma_async_device_unregister(&base->dma_slave);
@@ -2780,13 +2802,13 @@ static struct platform_driver coh901318_driver = {
        },
 };
 
-int __init coh901318_init(void)
+static int __init coh901318_init(void)
 {
        return platform_driver_probe(&coh901318_driver, coh901318_probe);
 }
 subsys_initcall(coh901318_init);
 
-void __exit coh901318_exit(void)
+static void __exit coh901318_exit(void)
 {
        platform_driver_unregister(&coh901318_driver);
 }
index ceedafbd23e01fcda6968fb04707ae141cff3a88..4b2317426c8e3851fc172002ddc50be1bcf69135 100644 (file)
@@ -497,16 +497,13 @@ static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
        struct cppi41_desc *d;
        struct scatterlist *sg;
        unsigned int i;
-       unsigned int num;
 
-       num = 0;
        d = c->desc;
        for_each_sg(sgl, sg, sg_len, i) {
                u32 addr;
                u32 len;
 
                /* We need to use more than one desc once musb supports sg */
-               BUG_ON(num > 0);
                addr = lower_32_bits(sg_dma_address(sg));
                len = sg_dma_len(sg);
 
index c3468094393ebe4f74d6bf9d8f482f169ac7b6cf..7f0b9aa158679aca780d86890426339f48586f4b 100644 (file)
@@ -270,6 +270,9 @@ static irqreturn_t axi_dmac_interrupt_handler(int irq, void *devid)
        unsigned int pending;
 
        pending = axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING);
+       if (!pending)
+               return IRQ_NONE;
+
        axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, pending);
 
        spin_lock(&dmac->chan.vchan.lock);
@@ -579,7 +582,9 @@ static int axi_dmac_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        dmac->irq = platform_get_irq(pdev, 0);
-       if (dmac->irq <= 0)
+       if (dmac->irq < 0)
+               return dmac->irq;
+       if (dmac->irq == 0)
                return -EINVAL;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -683,6 +688,7 @@ static const struct of_device_id axi_dmac_of_match_table[] = {
        { .compatible = "adi,axi-dmac-1.00.a" },
        { },
 };
+MODULE_DEVICE_TABLE(of, axi_dmac_of_match_table);
 
 static struct platform_driver axi_dmac_driver = {
        .driver = {
index 7638b24ce8d0dac2672da6d4e83ce9956f054607..9689b36c005ac2bc6485acf9e2f7ef4269d2cb39 100644 (file)
@@ -573,12 +573,26 @@ err_unregister:
        return ret;
 }
 
+static void jz4740_cleanup_vchan(struct dma_device *dmadev)
+{
+       struct jz4740_dmaengine_chan *chan, *_chan;
+
+       list_for_each_entry_safe(chan, _chan,
+                               &dmadev->channels, vchan.chan.device_node) {
+               list_del(&chan->vchan.chan.device_node);
+               tasklet_kill(&chan->vchan.task);
+       }
+}
+
+
 static int jz4740_dma_remove(struct platform_device *pdev)
 {
        struct jz4740_dma_dev *dmadev = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
 
        free_irq(irq, dmadev);
+
+       jz4740_cleanup_vchan(&dmadev->ddev);
        dma_async_device_unregister(&dmadev->ddev);
        clk_disable_unprepare(dmadev->clk);
 
index b8576fd6bd0e544730bfc07a19ce92b21ab1aba6..1245db5438e1b010cefc7a79a426f363f487ee7c 100644 (file)
@@ -51,6 +51,16 @@ module_param(iterations, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(iterations,
                "Iterations before stopping test (default: infinite)");
 
+static unsigned int sg_buffers = 1;
+module_param(sg_buffers, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sg_buffers,
+               "Number of scatter gather buffers (default: 1)");
+
+static unsigned int dmatest = 1;
+module_param(dmatest, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dmatest,
+               "dmatest 0-memcpy 1-slave_sg (default: 1)");
+
 static unsigned int xor_sources = 3;
 module_param(xor_sources, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(xor_sources,
@@ -431,6 +441,8 @@ static int dmatest_func(void *data)
        dev = chan->device;
        if (thread->type == DMA_MEMCPY)
                src_cnt = dst_cnt = 1;
+       else if (thread->type == DMA_SG)
+               src_cnt = dst_cnt = sg_buffers;
        else if (thread->type == DMA_XOR) {
                /* force odd to ensure dst = src */
                src_cnt = min_odd(params->xor_sources | 1, dev->max_xor);
@@ -485,6 +497,8 @@ static int dmatest_func(void *data)
                dma_addr_t *dsts;
                unsigned int src_off, dst_off, len;
                u8 align = 0;
+               struct scatterlist tx_sg[src_cnt];
+               struct scatterlist rx_sg[src_cnt];
 
                total_tests++;
 
@@ -577,10 +591,22 @@ static int dmatest_func(void *data)
                        um->bidi_cnt++;
                }
 
+               sg_init_table(tx_sg, src_cnt);
+               sg_init_table(rx_sg, src_cnt);
+               for (i = 0; i < src_cnt; i++) {
+                       sg_dma_address(&rx_sg[i]) = srcs[i];
+                       sg_dma_address(&tx_sg[i]) = dsts[i] + dst_off;
+                       sg_dma_len(&tx_sg[i]) = len;
+                       sg_dma_len(&rx_sg[i]) = len;
+               }
+
                if (thread->type == DMA_MEMCPY)
                        tx = dev->device_prep_dma_memcpy(chan,
                                                         dsts[0] + dst_off,
                                                         srcs[0], len, flags);
+               else if (thread->type == DMA_SG)
+                       tx = dev->device_prep_dma_sg(chan, tx_sg, src_cnt,
+                                                    rx_sg, src_cnt, flags);
                else if (thread->type == DMA_XOR)
                        tx = dev->device_prep_dma_xor(chan,
                                                      dsts[0] + dst_off,
@@ -748,6 +774,8 @@ static int dmatest_add_threads(struct dmatest_info *info,
 
        if (type == DMA_MEMCPY)
                op = "copy";
+       else if (type == DMA_SG)
+               op = "sg";
        else if (type == DMA_XOR)
                op = "xor";
        else if (type == DMA_PQ)
@@ -802,9 +830,19 @@ static int dmatest_add_channel(struct dmatest_info *info,
        INIT_LIST_HEAD(&dtc->threads);
 
        if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
-               cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY);
-               thread_count += cnt > 0 ? cnt : 0;
+               if (dmatest == 0) {
+                       cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY);
+                       thread_count += cnt > 0 ? cnt : 0;
+               }
        }
+
+       if (dma_has_cap(DMA_SG, dma_dev->cap_mask)) {
+               if (dmatest == 1) {
+                       cnt = dmatest_add_threads(info, dtc, DMA_SG);
+                       thread_count += cnt > 0 ? cnt : 0;
+               }
+       }
+
        if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
                cnt = dmatest_add_threads(info, dtc, DMA_XOR);
                thread_count += cnt > 0 ? cnt : 0;
@@ -877,6 +915,7 @@ static void run_threaded_test(struct dmatest_info *info)
 
        request_channels(info, DMA_MEMCPY);
        request_channels(info, DMA_XOR);
+       request_channels(info, DMA_SG);
        request_channels(info, DMA_PQ);
 }
 
index 8181ed1313865015a169b1e19e44de5ad3df8eb5..3d277fa76c1abb7397071ef58350a091e943ba4a 100644 (file)
@@ -239,6 +239,9 @@ struct edma_cc {
        bool                            chmap_exist;
        enum dma_event_q                default_queue;
 
+       unsigned int                    ccint;
+       unsigned int                    ccerrint;
+
        /*
         * The slot_inuse bit for each PaRAM slot is clear unless the slot is
         * in use by Linux or if it is allocated to be used by DSP.
@@ -1069,10 +1072,8 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
 
        edesc = kzalloc(sizeof(*edesc) + sg_len * sizeof(edesc->pset[0]),
                        GFP_ATOMIC);
-       if (!edesc) {
-               dev_err(dev, "%s: Failed to allocate a descriptor\n", __func__);
+       if (!edesc)
                return NULL;
-       }
 
        edesc->pset_nr = sg_len;
        edesc->residue = 0;
@@ -1114,14 +1115,17 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                edesc->absync = ret;
                edesc->residue += sg_dma_len(sg);
 
-               /* If this is the last in a current SG set of transactions,
-                  enable interrupts so that next set is processed */
-               if (!((i+1) % MAX_NR_SG))
-                       edesc->pset[i].param.opt |= TCINTEN;
-
-               /* If this is the last set, enable completion interrupt flag */
                if (i == sg_len - 1)
+                       /* Enable completion interrupt */
                        edesc->pset[i].param.opt |= TCINTEN;
+               else if (!((i+1) % MAX_NR_SG))
+                       /*
+                        * Enable early completion interrupt for the
+                        * intermediateset. In this case the driver will be
+                        * notified when the paRAM set is submitted to TC. This
+                        * will allow more time to set up the next set of slots.
+                        */
+                       edesc->pset[i].param.opt |= (TCINTEN | TCCMODE);
        }
        edesc->residue_stat = edesc->residue;
 
@@ -1173,10 +1177,8 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy(
 
        edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]),
                        GFP_ATOMIC);
-       if (!edesc) {
-               dev_dbg(dev, "Failed to allocate a descriptor\n");
+       if (!edesc)
                return NULL;
-       }
 
        edesc->pset_nr = nslots;
        edesc->residue = edesc->residue_stat = len;
@@ -1298,10 +1300,8 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
 
        edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]),
                        GFP_ATOMIC);
-       if (!edesc) {
-               dev_err(dev, "%s: Failed to allocate a descriptor\n", __func__);
+       if (!edesc)
                return NULL;
-       }
 
        edesc->cyclic = 1;
        edesc->pset_nr = nslots;
@@ -2207,10 +2207,8 @@ static int edma_probe(struct platform_device *pdev)
                return ret;
 
        ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
-       if (!ecc) {
-               dev_err(dev, "Can't allocate controller\n");
+       if (!ecc)
                return -ENOMEM;
-       }
 
        ecc->dev = dev;
        ecc->id = pdev->id;
@@ -2288,6 +2286,7 @@ static int edma_probe(struct platform_device *pdev)
                        dev_err(dev, "CCINT (%d) failed --> %d\n", irq, ret);
                        return ret;
                }
+               ecc->ccint = irq;
        }
 
        irq = platform_get_irq_byname(pdev, "edma3_ccerrint");
@@ -2303,6 +2302,7 @@ static int edma_probe(struct platform_device *pdev)
                        dev_err(dev, "CCERRINT (%d) failed --> %d\n", irq, ret);
                        return ret;
                }
+               ecc->ccerrint = irq;
        }
 
        ecc->dummy_slot = edma_alloc_slot(ecc, EDMA_SLOT_ANY);
@@ -2393,11 +2393,27 @@ err_reg1:
        return ret;
 }
 
+static void edma_cleanupp_vchan(struct dma_device *dmadev)
+{
+       struct edma_chan *echan, *_echan;
+
+       list_for_each_entry_safe(echan, _echan,
+                       &dmadev->channels, vchan.chan.device_node) {
+               list_del(&echan->vchan.chan.device_node);
+               tasklet_kill(&echan->vchan.task);
+       }
+}
+
 static int edma_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct edma_cc *ecc = dev_get_drvdata(dev);
 
+       devm_free_irq(dev, ecc->ccint, ecc);
+       devm_free_irq(dev, ecc->ccerrint, ecc);
+
+       edma_cleanupp_vchan(&ecc->dma_slave);
+
        if (dev->of_node)
                of_dma_controller_free(dev->of_node);
        dma_async_device_unregister(&ecc->dma_slave);
index be2e62b879481f592aa965d4fe165b4ae8771896..6775f2c74e25b7269417bbe001adfb03698dea97 100644 (file)
@@ -852,6 +852,25 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
        return 0;
 }
 
+static void fsl_edma_irq_exit(
+               struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
+{
+       if (fsl_edma->txirq == fsl_edma->errirq) {
+               devm_free_irq(&pdev->dev, fsl_edma->txirq, fsl_edma);
+       } else {
+               devm_free_irq(&pdev->dev, fsl_edma->txirq, fsl_edma);
+               devm_free_irq(&pdev->dev, fsl_edma->errirq, fsl_edma);
+       }
+}
+
+static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma)
+{
+       int i;
+
+       for (i = 0; i < DMAMUX_NR; i++)
+               clk_disable_unprepare(fsl_edma->muxclk[i]);
+}
+
 static int fsl_edma_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -897,6 +916,10 @@ static int fsl_edma_probe(struct platform_device *pdev)
 
                ret = clk_prepare_enable(fsl_edma->muxclk[i]);
                if (ret) {
+                       /* disable only clks which were enabled on error */
+                       for (; i >= 0; i--)
+                               clk_disable_unprepare(fsl_edma->muxclk[i]);
+
                        dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
                        return ret;
                }
@@ -951,14 +974,18 @@ static int fsl_edma_probe(struct platform_device *pdev)
 
        ret = dma_async_device_register(&fsl_edma->dma_dev);
        if (ret) {
-               dev_err(&pdev->dev, "Can't register Freescale eDMA engine.\n");
+               dev_err(&pdev->dev,
+                       "Can't register Freescale eDMA engine. (%d)\n", ret);
+               fsl_disable_clocks(fsl_edma);
                return ret;
        }
 
        ret = of_dma_controller_register(np, fsl_edma_xlate, fsl_edma);
        if (ret) {
-               dev_err(&pdev->dev, "Can't register Freescale eDMA of_dma.\n");
+               dev_err(&pdev->dev,
+                       "Can't register Freescale eDMA of_dma. (%d)\n", ret);
                dma_async_device_unregister(&fsl_edma->dma_dev);
+               fsl_disable_clocks(fsl_edma);
                return ret;
        }
 
@@ -968,17 +995,27 @@ static int fsl_edma_probe(struct platform_device *pdev)
        return 0;
 }
 
+static void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
+{
+       struct fsl_edma_chan *chan, *_chan;
+
+       list_for_each_entry_safe(chan, _chan,
+                               &dmadev->channels, vchan.chan.device_node) {
+               list_del(&chan->vchan.chan.device_node);
+               tasklet_kill(&chan->vchan.task);
+       }
+}
+
 static int fsl_edma_remove(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev);
-       int i;
 
+       fsl_edma_irq_exit(pdev, fsl_edma);
+       fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
        of_dma_controller_free(np);
        dma_async_device_unregister(&fsl_edma->dma_dev);
-
-       for (i = 0; i < DMAMUX_NR; i++)
-               clk_disable_unprepare(fsl_edma->muxclk[i]);
+       fsl_disable_clocks(fsl_edma);
 
        return 0;
 }
index 4d9470f16552ca8065e69832dc786364d6369814..aad167eaaee80b29e9386574c183533d0e8f0d83 100644 (file)
@@ -337,7 +337,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_genq(
 
        re_chan = container_of(chan, struct fsl_re_chan, chan);
        if (len > FSL_RE_MAX_DATA_LEN) {
-               dev_err(re_chan->dev, "genq tx length %lu, max length %d\n",
+               dev_err(re_chan->dev, "genq tx length %zu, max length %d\n",
                        len, FSL_RE_MAX_DATA_LEN);
                return NULL;
        }
@@ -424,7 +424,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_pq(
 
        re_chan = container_of(chan, struct fsl_re_chan, chan);
        if (len > FSL_RE_MAX_DATA_LEN) {
-               dev_err(re_chan->dev, "pq tx length is %lu, max length is %d\n",
+               dev_err(re_chan->dev, "pq tx length is %zu, max length is %d\n",
                        len, FSL_RE_MAX_DATA_LEN);
                return NULL;
        }
@@ -545,7 +545,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_memcpy(
        re_chan = container_of(chan, struct fsl_re_chan, chan);
 
        if (len > FSL_RE_MAX_DATA_LEN) {
-               dev_err(re_chan->dev, "cp tx length is %lu, max length is %d\n",
+               dev_err(re_chan->dev, "cp tx length is %zu, max length is %d\n",
                        len, FSL_RE_MAX_DATA_LEN);
                return NULL;
        }
@@ -856,6 +856,8 @@ static int fsl_re_probe(struct platform_device *ofdev)
 
 static void fsl_re_remove_chan(struct fsl_re_chan *chan)
 {
+       tasklet_kill(&chan->irqtask);
+
        dma_pool_free(chan->re_dev->hw_desc_pool, chan->inb_ring_virt_addr,
                      chan->inb_phys_addr);
 
@@ -890,7 +892,6 @@ static struct of_device_id fsl_re_ids[] = {
 static struct platform_driver fsl_re_driver = {
        .driver = {
                .name = "fsl-raideng",
-               .owner = THIS_MODULE,
                .of_match_table = fsl_re_ids,
        },
        .probe = fsl_re_probe,
index a8828ed639b3027c476fc7d82d4d6607221b2ae1..911b7177eb50487dc53269ac705c9c25dc6f8638 100644 (file)
@@ -1234,7 +1234,6 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
        /* alloc channel */
        chan = kzalloc(sizeof(*chan), GFP_KERNEL);
        if (!chan) {
-               dev_err(fdev->dev, "no free memory for DMA channels!\n");
                err = -ENOMEM;
                goto out_return;
        }
@@ -1340,7 +1339,6 @@ static int fsldma_of_probe(struct platform_device *op)
 
        fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
        if (!fdev) {
-               dev_err(&op->dev, "No enough memory for 'priv'\n");
                err = -ENOMEM;
                goto out_return;
        }
index 48d85f8b95fe1e97a014a47062e3ebcf27afd314..a960608c0a4db0cc918df3c95d4c6b0a2867d406 100644 (file)
@@ -167,6 +167,7 @@ struct imxdma_channel {
        u32                             ccr_to_device;
        bool                            enabled_2d;
        int                             slot_2d;
+       unsigned int                    irq;
 };
 
 enum imx_dma_type {
@@ -186,6 +187,9 @@ struct imxdma_engine {
        struct imx_dma_2d_config        slots_2d[IMX_DMA_2D_SLOTS];
        struct imxdma_channel           channel[IMX_DMA_CHANNELS];
        enum imx_dma_type               devtype;
+       unsigned int                    irq;
+       unsigned int                    irq_err;
+
 };
 
 struct imxdma_filter_data {
@@ -1048,7 +1052,7 @@ static struct dma_chan *imxdma_xlate(struct of_phandle_args *dma_spec,
 }
 
 static int __init imxdma_probe(struct platform_device *pdev)
-       {
+{
        struct imxdma_engine *imxdma;
        struct resource *res;
        const struct of_device_id *of_id;
@@ -1100,6 +1104,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
                        dev_warn(imxdma->dev, "Can't register IRQ for DMA\n");
                        goto disable_dma_ahb_clk;
                }
+               imxdma->irq = irq;
 
                irq_err = platform_get_irq(pdev, 1);
                if (irq_err < 0) {
@@ -1113,6 +1118,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
                        dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n");
                        goto disable_dma_ahb_clk;
                }
+               imxdma->irq_err = irq_err;
        }
 
        /* enable DMA module */
@@ -1150,6 +1156,8 @@ static int __init imxdma_probe(struct platform_device *pdev)
                                         irq + i, i);
                                goto disable_dma_ahb_clk;
                        }
+
+                       imxdmac->irq = irq + i;
                        init_timer(&imxdmac->watchdog);
                        imxdmac->watchdog.function = &imxdma_watchdog;
                        imxdmac->watchdog.data = (unsigned long)imxdmac;
@@ -1217,10 +1225,31 @@ disable_dma_ipg_clk:
        return ret;
 }
 
+static void imxdma_free_irq(struct platform_device *pdev, struct imxdma_engine *imxdma)
+{
+       int i;
+
+       if (is_imx1_dma(imxdma)) {
+               disable_irq(imxdma->irq);
+               disable_irq(imxdma->irq_err);
+       }
+
+       for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+               struct imxdma_channel *imxdmac = &imxdma->channel[i];
+
+               if (!is_imx1_dma(imxdma))
+                       disable_irq(imxdmac->irq);
+
+               tasklet_kill(&imxdmac->dma_tasklet);
+       }
+}
+
 static int imxdma_remove(struct platform_device *pdev)
 {
        struct imxdma_engine *imxdma = platform_get_drvdata(pdev);
 
+       imxdma_free_irq(pdev, imxdma);
+
         dma_async_device_unregister(&imxdma->dma_device);
 
        if (pdev->dev.of_node)
index 0f6fd42f55ca41975b12dbe267ef3aabdb81c017..03ec76fc22ff191423bc354e5b5005a621d83412 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
@@ -385,6 +386,7 @@ struct sdma_engine {
        const struct sdma_driver_data   *drvdata;
        u32                             spba_start_addr;
        u32                             spba_end_addr;
+       unsigned int                    irq;
 };
 
 static struct sdma_driver_data sdma_imx31 = {
@@ -571,28 +573,20 @@ static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
 static int sdma_run_channel0(struct sdma_engine *sdma)
 {
        int ret;
-       unsigned long timeout = 500;
+       u32 reg;
 
        sdma_enable_channel(sdma, 0);
 
-       while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) {
-               if (timeout-- <= 0)
-                       break;
-               udelay(1);
-       }
-
-       if (ret) {
-               /* Clear the interrupt status */
-               writel_relaxed(ret, sdma->regs + SDMA_H_INTR);
-       } else {
+       ret = readl_relaxed_poll_timeout_atomic(sdma->regs + SDMA_H_STATSTOP,
+                                               reg, !(reg & 1), 1, 500);
+       if (ret)
                dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
-       }
 
        /* Set bits of CONFIG register with dynamic context switching */
        if (readl(sdma->regs + SDMA_H_CONFIG) == 0)
                writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
 
-       return ret ? 0 : -ETIMEDOUT;
+       return ret;
 }
 
 static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
@@ -727,9 +721,9 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
        unsigned long stat;
 
        stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
-       /* not interested in channel 0 interrupts */
-       stat &= ~1;
        writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
+       /* channel 0 is special and not handled here, see run_channel0() */
+       stat &= ~1;
 
        while (stat) {
                int channel = fls(stat) - 1;
@@ -758,7 +752,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
         * These are needed once we start to support transfers between
         * two peripherals or memory-to-memory transfers
         */
-       int per_2_per = 0, emi_2_emi = 0;
+       int per_2_per = 0;
 
        sdmac->pc_from_device = 0;
        sdmac->pc_to_device = 0;
@@ -766,7 +760,6 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
 
        switch (peripheral_type) {
        case IMX_DMATYPE_MEMORY:
-               emi_2_emi = sdma->script_addrs->ap_2_ap_addr;
                break;
        case IMX_DMATYPE_DSP:
                emi_2_per = sdma->script_addrs->bp_2_ap_addr;
@@ -999,8 +992,6 @@ static int sdma_config_channel(struct dma_chan *chan)
                } else
                        __set_bit(sdmac->event_id0, sdmac->event_mask);
 
-               /* Watermark Level */
-               sdmac->watermark_level |= sdmac->watermark_level;
                /* Address */
                sdmac->shp_addr = sdmac->per_address;
                sdmac->per_addr = sdmac->per_address2;
@@ -1715,6 +1706,8 @@ static int sdma_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       sdma->irq = irq;
+
        sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
        if (!sdma->script_addrs)
                return -ENOMEM;
@@ -1840,6 +1833,7 @@ static int sdma_remove(struct platform_device *pdev)
        struct sdma_engine *sdma = platform_get_drvdata(pdev);
        int i;
 
+       devm_free_irq(&pdev->dev, sdma->irq, sdma);
        dma_async_device_unregister(&sdma->dma_device);
        kfree(sdma->script_addrs);
        /* Kill the tasklet */
index d406056e889246d1ec8e03dab74d0727046fd192..7145f7716a925e57d4190ceaf20dd9d13f3571bd 100644 (file)
@@ -1212,7 +1212,7 @@ static void ioat_shutdown(struct pci_dev *pdev)
        ioat_disable_interrupts(ioat_dma);
 }
 
-void ioat_resume(struct ioatdma_device *ioat_dma)
+static void ioat_resume(struct ioatdma_device *ioat_dma)
 {
        struct ioatdma_chan *ioat_chan;
        u32 chanerr;
index 1ba2fd73852d273ccf9f8df0e6e6cfc0144fb90d..39de8980128c1c0ae2092110f0a4138e0a6a4bab 100644 (file)
@@ -102,6 +102,7 @@ struct k3_dma_dev {
        struct clk              *clk;
        u32                     dma_channels;
        u32                     dma_requests;
+       unsigned int            irq;
 };
 
 #define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave)
@@ -425,10 +426,9 @@ static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
 
        num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
        ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
-       if (!ds) {
-               dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc);
+       if (!ds)
                return NULL;
-       }
+
        ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
        ds->size = len;
        ds->desc_num = num;
@@ -481,10 +481,9 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
        }
 
        ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
-       if (!ds) {
-               dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc);
+       if (!ds)
                return NULL;
-       }
+
        ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
        ds->desc_num = num;
        num = 0;
@@ -705,6 +704,8 @@ static int k3_dma_probe(struct platform_device *op)
        if (ret)
                return ret;
 
+       d->irq = irq;
+
        /* init phy channel */
        d->phy = devm_kzalloc(&op->dev,
                d->dma_channels * sizeof(struct k3_dma_phy), GFP_KERNEL);
@@ -759,7 +760,7 @@ static int k3_dma_probe(struct platform_device *op)
 
        ret = dma_async_device_register(&d->slave);
        if (ret)
-               return ret;
+               goto dma_async_register_fail;
 
        ret = of_dma_controller_register((&op->dev)->of_node,
                                        k3_of_dma_simple_xlate, d);
@@ -776,6 +777,8 @@ static int k3_dma_probe(struct platform_device *op)
 
 of_dma_register_fail:
        dma_async_device_unregister(&d->slave);
+dma_async_register_fail:
+       clk_disable_unprepare(d->clk);
        return ret;
 }
 
@@ -787,6 +790,8 @@ static int k3_dma_remove(struct platform_device *op)
        dma_async_device_unregister(&d->slave);
        of_dma_controller_free((&op->dev)->of_node);
 
+       devm_free_irq(&op->dev, d->irq, d);
+
        list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
                list_del(&c->vc.chan.device_node);
                tasklet_kill(&c->vc.task);
index 56f1fd68b6205af0de5c6f55687305c42de0f1e9..f4b25fb0d0402668bafad206b4576bcf808005cb 100644 (file)
@@ -931,6 +931,25 @@ static void dma_do_tasklet(unsigned long data)
 static int mmp_pdma_remove(struct platform_device *op)
 {
        struct mmp_pdma_device *pdev = platform_get_drvdata(op);
+       struct mmp_pdma_phy *phy;
+       int i, irq = 0, irq_num = 0;
+
+
+       for (i = 0; i < pdev->dma_channels; i++) {
+               if (platform_get_irq(op, i) > 0)
+                       irq_num++;
+       }
+
+       if (irq_num != pdev->dma_channels) {
+               irq = platform_get_irq(op, 0);
+               devm_free_irq(&op->dev, irq, pdev);
+       } else {
+               for (i = 0; i < pdev->dma_channels; i++) {
+                       phy = &pdev->phy[i];
+                       irq = platform_get_irq(op, i);
+                       devm_free_irq(&op->dev, irq, phy);
+               }
+       }
 
        dma_async_device_unregister(&pdev->device);
        return 0;
index 3df0422607d594f995b455782db4f7badced0fc4..b3441f57a3640d74f268637a7f9a4941d5d7daca 100644 (file)
@@ -404,7 +404,7 @@ static void mmp_tdma_free_chan_resources(struct dma_chan *chan)
        return;
 }
 
-struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
+static struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
 {
        struct gen_pool *gpool;
        int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
@@ -551,10 +551,9 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
 
        /* alloc channel */
        tdmac = devm_kzalloc(tdev->dev, sizeof(*tdmac), GFP_KERNEL);
-       if (!tdmac) {
-               dev_err(tdev->dev, "no free memory for DMA channels!\n");
+       if (!tdmac)
                return -ENOMEM;
-       }
+
        if (irq)
                tdmac->irq = irq;
        tdmac->dev         = tdev->dev;
@@ -593,7 +592,7 @@ static bool mmp_tdma_filter_fn(struct dma_chan *chan, void *fn_param)
        return true;
 }
 
-struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
+static struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
                               struct of_dma *ofdma)
 {
        struct mmp_tdma_device *tdev = ofdma->of_dma_data;
index 631c4435e075f25d39c6041a523710495d1bfd8d..a6e642792e5a34f1bb46e738e416a49cd3fcc442 100644 (file)
@@ -148,6 +148,7 @@ struct moxart_chan {
 struct moxart_dmadev {
        struct dma_device               dma_slave;
        struct moxart_chan              slave_chans[APB_DMA_MAX_CHANNEL];
+       unsigned int                    irq;
 };
 
 struct moxart_filter_data {
@@ -574,10 +575,8 @@ static int moxart_probe(struct platform_device *pdev)
        struct moxart_dmadev *mdc;
 
        mdc = devm_kzalloc(dev, sizeof(*mdc), GFP_KERNEL);
-       if (!mdc) {
-               dev_err(dev, "can't allocate DMA container\n");
+       if (!mdc)
                return -ENOMEM;
-       }
 
        irq = irq_of_parse_and_map(node, 0);
        if (irq == NO_IRQ) {
@@ -617,6 +616,7 @@ static int moxart_probe(struct platform_device *pdev)
                dev_err(dev, "devm_request_irq failed\n");
                return ret;
        }
+       mdc->irq = irq;
 
        ret = dma_async_device_register(&mdc->dma_slave);
        if (ret) {
@@ -640,6 +640,8 @@ static int moxart_remove(struct platform_device *pdev)
 {
        struct moxart_dmadev *m = platform_get_drvdata(pdev);
 
+       devm_free_irq(&pdev->dev, m->irq, m);
+
        dma_async_device_unregister(&m->dma_slave);
 
        if (pdev->dev.of_node)
index ccadafa51d5ed940842030c13b22f4900d8b160f..fa86592c7ae1d80b717a710a31a81f0f618b2acc 100644 (file)
@@ -1110,6 +1110,7 @@ static int mpc_dma_remove(struct platform_device *op)
        }
        free_irq(mdma->irq, mdma);
        irq_dispose_mapping(mdma->irq);
+       tasklet_kill(&mdma->tasklet);
 
        return 0;
 }
index d0446a75990aeb046acb8d50a329bfeb7a9999c6..f4c9f98ec35e51ac0ba46ae07ea7cb214d2988b3 100644 (file)
@@ -1057,7 +1057,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
 
 err_free_irq:
        free_irq(mv_chan->irq, mv_chan);
- err_free_dma:
+err_free_dma:
        dma_free_coherent(&pdev->dev, MV_XOR_POOL_SIZE,
                          mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool);
        return ERR_PTR(ret);
diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c
new file mode 100644 (file)
index 0000000..a28a01f
--- /dev/null
@@ -0,0 +1,878 @@
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include "dmaengine.h"
+
+/* DMA Engine Registers */
+#define MV_XOR_V2_DMA_DESQ_BALR_OFF                    0x000
+#define MV_XOR_V2_DMA_DESQ_BAHR_OFF                    0x004
+#define MV_XOR_V2_DMA_DESQ_SIZE_OFF                    0x008
+#define MV_XOR_V2_DMA_DESQ_DONE_OFF                    0x00C
+#define   MV_XOR_V2_DMA_DESQ_DONE_PENDING_MASK         0x7FFF
+#define   MV_XOR_V2_DMA_DESQ_DONE_PENDING_SHIFT                0
+#define   MV_XOR_V2_DMA_DESQ_DONE_READ_PTR_MASK                0x1FFF
+#define   MV_XOR_V2_DMA_DESQ_DONE_READ_PTR_SHIFT       16
+#define MV_XOR_V2_DMA_DESQ_ARATTR_OFF                  0x010
+#define   MV_XOR_V2_DMA_DESQ_ATTR_CACHE_MASK           0x3F3F
+#define   MV_XOR_V2_DMA_DESQ_ATTR_OUTER_SHAREABLE      0x202
+#define   MV_XOR_V2_DMA_DESQ_ATTR_CACHEABLE            0x3C3C
+#define MV_XOR_V2_DMA_IMSG_CDAT_OFF                    0x014
+#define MV_XOR_V2_DMA_IMSG_THRD_OFF                    0x018
+#define   MV_XOR_V2_DMA_IMSG_THRD_MASK                 0x7FFF
+#define   MV_XOR_V2_DMA_IMSG_THRD_SHIFT                        0x0
+#define MV_XOR_V2_DMA_DESQ_AWATTR_OFF                  0x01C
+  /* Same flags as MV_XOR_V2_DMA_DESQ_ARATTR_OFF */
+#define MV_XOR_V2_DMA_DESQ_ALLOC_OFF                   0x04C
+#define   MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_MASK          0xFFFF
+#define   MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_SHIFT         16
+#define MV_XOR_V2_DMA_IMSG_BALR_OFF                    0x050
+#define MV_XOR_V2_DMA_IMSG_BAHR_OFF                    0x054
+#define MV_XOR_V2_DMA_DESQ_CTRL_OFF                    0x100
+#define          MV_XOR_V2_DMA_DESQ_CTRL_32B                   1
+#define   MV_XOR_V2_DMA_DESQ_CTRL_128B                 7
+#define MV_XOR_V2_DMA_DESQ_STOP_OFF                    0x800
+#define MV_XOR_V2_DMA_DESQ_DEALLOC_OFF                 0x804
+#define MV_XOR_V2_DMA_DESQ_ADD_OFF                     0x808
+
+/* XOR Global registers */
+#define MV_XOR_V2_GLOB_BW_CTRL                         0x4
+#define   MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_SHIFT     0
+#define   MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_VAL       64
+#define   MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_SHIFT     8
+#define   MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_VAL       8
+#define   MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_SHIFT    12
+#define   MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_VAL      4
+#define   MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_SHIFT    16
+#define          MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_VAL       4
+#define MV_XOR_V2_GLOB_PAUSE                           0x014
+#define   MV_XOR_V2_GLOB_PAUSE_AXI_TIME_DIS_VAL                0x8
+#define MV_XOR_V2_GLOB_SYS_INT_CAUSE                   0x200
+#define MV_XOR_V2_GLOB_SYS_INT_MASK                    0x204
+#define MV_XOR_V2_GLOB_MEM_INT_CAUSE                   0x220
+#define MV_XOR_V2_GLOB_MEM_INT_MASK                    0x224
+
+#define MV_XOR_V2_MIN_DESC_SIZE                                32
+#define MV_XOR_V2_EXT_DESC_SIZE                                128
+
+#define MV_XOR_V2_DESC_RESERVED_SIZE                   12
+#define MV_XOR_V2_DESC_BUFF_D_ADDR_SIZE                        12
+
+#define MV_XOR_V2_CMD_LINE_NUM_MAX_D_BUF               8
+
+/*
+ * Descriptors queue size. With 32 bytes descriptors, up to 2^14
+ * descriptors are allowed, with 128 bytes descriptors, up to 2^12
+ * descriptors are allowed. This driver uses 128 bytes descriptors,
+ * but experimentation has shown that a set of 1024 descriptors is
+ * sufficient to reach a good level of performance.
+ */
+#define MV_XOR_V2_DESC_NUM                             1024
+
+/**
+ * struct mv_xor_v2_descriptor - DMA HW descriptor
+ * @desc_id: used by S/W and is not affected by H/W.
+ * @flags: error and status flags
+ * @crc32_result: CRC32 calculation result
+ * @desc_ctrl: operation mode and control flags
+ * @buff_size: amount of bytes to be processed
+ * @fill_pattern_src_addr: Fill-Pattern or Source-Address and
+ * AW-Attributes
+ * @data_buff_addr: Source (and might be RAID6 destination)
+ * addresses of data buffers in RAID5 and RAID6
+ * @reserved: reserved
+ */
+struct mv_xor_v2_descriptor {
+       u16 desc_id;
+       u16 flags;
+       u32 crc32_result;
+       u32 desc_ctrl;
+
+       /* Definitions for desc_ctrl */
+#define DESC_NUM_ACTIVE_D_BUF_SHIFT    22
+#define DESC_OP_MODE_SHIFT             28
+#define DESC_OP_MODE_NOP               0       /* Idle operation */
+#define DESC_OP_MODE_MEMCPY            1       /* Pure-DMA operation */
+#define DESC_OP_MODE_MEMSET            2       /* Mem-Fill operation */
+#define DESC_OP_MODE_MEMINIT           3       /* Mem-Init operation */
+#define DESC_OP_MODE_MEM_COMPARE       4       /* Mem-Compare operation */
+#define DESC_OP_MODE_CRC32             5       /* CRC32 calculation */
+#define DESC_OP_MODE_XOR               6       /* RAID5 (XOR) operation */
+#define DESC_OP_MODE_RAID6             7       /* RAID6 P&Q-generation */
+#define DESC_OP_MODE_RAID6_REC         8       /* RAID6 Recovery */
+#define DESC_Q_BUFFER_ENABLE           BIT(16)
+#define DESC_P_BUFFER_ENABLE           BIT(17)
+#define DESC_IOD                       BIT(27)
+
+       u32 buff_size;
+       u32 fill_pattern_src_addr[4];
+       u32 data_buff_addr[MV_XOR_V2_DESC_BUFF_D_ADDR_SIZE];
+       u32 reserved[MV_XOR_V2_DESC_RESERVED_SIZE];
+};
+
+/**
+ * struct mv_xor_v2_device - implements a xor device
+ * @lock: lock for the engine
+ * @dma_base: memory mapped DMA register base
+ * @glob_base: memory mapped global register base
+ * @irq_tasklet:
+ * @free_sw_desc: linked list of free SW descriptors
+ * @dmadev: dma device
+ * @dmachan: dma channel
+ * @hw_desq: HW descriptors queue
+ * @hw_desq_virt: virtual address of DESCQ
+ * @sw_desq: SW descriptors queue
+ * @desc_size: HW descriptor size
+ * @npendings: number of pending descriptors (for which tx_submit has
+ * been called, but not yet issue_pending)
+ */
+struct mv_xor_v2_device {
+       spinlock_t lock;
+       void __iomem *dma_base;
+       void __iomem *glob_base;
+       struct clk *clk;
+       struct tasklet_struct irq_tasklet;
+       struct list_head free_sw_desc;
+       struct dma_device dmadev;
+       struct dma_chan dmachan;
+       dma_addr_t hw_desq;
+       struct mv_xor_v2_descriptor *hw_desq_virt;
+       struct mv_xor_v2_sw_desc *sw_desq;
+       int desc_size;
+       unsigned int npendings;
+};
+
+/**
+ * struct mv_xor_v2_sw_desc - implements a xor SW descriptor
+ * @idx: descriptor index
+ * @async_tx: support for the async_tx api
+ * @hw_desc: assosiated HW descriptor
+ * @free_list: node of the free SW descriprots list
+*/
+struct mv_xor_v2_sw_desc {
+       int idx;
+       struct dma_async_tx_descriptor async_tx;
+       struct mv_xor_v2_descriptor hw_desc;
+       struct list_head free_list;
+};
+
+/*
+ * Fill the data buffers to a HW descriptor
+ */
+static void mv_xor_v2_set_data_buffers(struct mv_xor_v2_device *xor_dev,
+                                       struct mv_xor_v2_descriptor *desc,
+                                       dma_addr_t src, int index)
+{
+       int arr_index = ((index >> 1) * 3);
+
+       /*
+        * Fill the buffer's addresses to the descriptor.
+        *
+        * The format of the buffers address for 2 sequential buffers
+        * X and X + 1:
+        *
+        *  First word:  Buffer-DX-Address-Low[31:0]
+        *  Second word: Buffer-DX+1-Address-Low[31:0]
+        *  Third word:  DX+1-Buffer-Address-High[47:32] [31:16]
+        *               DX-Buffer-Address-High[47:32] [15:0]
+        */
+       if ((index & 0x1) == 0) {
+               desc->data_buff_addr[arr_index] = lower_32_bits(src);
+
+               desc->data_buff_addr[arr_index + 2] &= ~0xFFFF;
+               desc->data_buff_addr[arr_index + 2] |=
+                       upper_32_bits(src) & 0xFFFF;
+       } else {
+               desc->data_buff_addr[arr_index + 1] =
+                       lower_32_bits(src);
+
+               desc->data_buff_addr[arr_index + 2] &= ~0xFFFF0000;
+               desc->data_buff_addr[arr_index + 2] |=
+                       (upper_32_bits(src) & 0xFFFF) << 16;
+       }
+}
+
+/*
+ * Return the next available index in the DESQ.
+ */
+static int mv_xor_v2_get_desq_write_ptr(struct mv_xor_v2_device *xor_dev)
+{
+       /* read the index for the next available descriptor in the DESQ */
+       u32 reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ALLOC_OFF);
+
+       return ((reg >> MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_SHIFT)
+               & MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_MASK);
+}
+
+/*
+ * notify the engine of new descriptors, and update the available index.
+ */
+static void mv_xor_v2_add_desc_to_desq(struct mv_xor_v2_device *xor_dev,
+                                      int num_of_desc)
+{
+       /* write the number of new descriptors in the DESQ. */
+       writel(num_of_desc, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ADD_OFF);
+}
+
+/*
+ * free HW descriptors
+ */
+static void mv_xor_v2_free_desc_from_desq(struct mv_xor_v2_device *xor_dev,
+                                         int num_of_desc)
+{
+       /* write the number of new descriptors in the DESQ. */
+       writel(num_of_desc, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_DEALLOC_OFF);
+}
+
+/*
+ * Set descriptor size
+ * Return the HW descriptor size in bytes
+ */
+static int mv_xor_v2_set_desc_size(struct mv_xor_v2_device *xor_dev)
+{
+       writel(MV_XOR_V2_DMA_DESQ_CTRL_128B,
+              xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_CTRL_OFF);
+
+       return MV_XOR_V2_EXT_DESC_SIZE;
+}
+
+/*
+ * Set the IMSG threshold
+ */
+static inline
+void mv_xor_v2_set_imsg_thrd(struct mv_xor_v2_device *xor_dev, int thrd_val)
+{
+       u32 reg;
+
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
+
+       reg &= (~MV_XOR_V2_DMA_IMSG_THRD_MASK << MV_XOR_V2_DMA_IMSG_THRD_SHIFT);
+       reg |= (thrd_val << MV_XOR_V2_DMA_IMSG_THRD_SHIFT);
+
+       writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
+}
+
+static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data)
+{
+       struct mv_xor_v2_device *xor_dev = data;
+       unsigned int ndescs;
+       u32 reg;
+
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_DONE_OFF);
+
+       ndescs = ((reg >> MV_XOR_V2_DMA_DESQ_DONE_PENDING_SHIFT) &
+                 MV_XOR_V2_DMA_DESQ_DONE_PENDING_MASK);
+
+       /* No descriptors to process */
+       if (!ndescs)
+               return IRQ_NONE;
+
+       /*
+        * Update IMSG threshold, to disable new IMSG interrupts until
+        * end of the tasklet
+        */
+       mv_xor_v2_set_imsg_thrd(xor_dev, MV_XOR_V2_DESC_NUM);
+
+       /* schedule a tasklet to handle descriptors callbacks */
+       tasklet_schedule(&xor_dev->irq_tasklet);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * submit a descriptor to the DMA engine
+ */
+static dma_cookie_t
+mv_xor_v2_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       int desq_ptr;
+       void *dest_hw_desc;
+       dma_cookie_t cookie;
+       struct mv_xor_v2_sw_desc *sw_desc =
+               container_of(tx, struct mv_xor_v2_sw_desc, async_tx);
+       struct mv_xor_v2_device *xor_dev =
+               container_of(tx->chan, struct mv_xor_v2_device, dmachan);
+
+       dev_dbg(xor_dev->dmadev.dev,
+               "%s sw_desc %p: async_tx %p\n",
+               __func__, sw_desc, &sw_desc->async_tx);
+
+       /* assign coookie */
+       spin_lock_bh(&xor_dev->lock);
+       cookie = dma_cookie_assign(tx);
+
+       /* get the next available slot in the DESQ */
+       desq_ptr = mv_xor_v2_get_desq_write_ptr(xor_dev);
+
+       /* copy the HW descriptor from the SW descriptor to the DESQ */
+       dest_hw_desc = xor_dev->hw_desq_virt + desq_ptr;
+
+       memcpy(dest_hw_desc, &sw_desc->hw_desc, xor_dev->desc_size);
+
+       xor_dev->npendings++;
+
+       spin_unlock_bh(&xor_dev->lock);
+
+       return cookie;
+}
+
+/*
+ * Prepare a SW descriptor
+ */
+static struct mv_xor_v2_sw_desc        *
+mv_xor_v2_prep_sw_desc(struct mv_xor_v2_device *xor_dev)
+{
+       struct mv_xor_v2_sw_desc *sw_desc;
+
+       /* Lock the channel */
+       spin_lock_bh(&xor_dev->lock);
+
+       if (list_empty(&xor_dev->free_sw_desc)) {
+               spin_unlock_bh(&xor_dev->lock);
+               /* schedule tasklet to free some descriptors */
+               tasklet_schedule(&xor_dev->irq_tasklet);
+               return NULL;
+       }
+
+       /* get a free SW descriptor from the SW DESQ */
+       sw_desc = list_first_entry(&xor_dev->free_sw_desc,
+                                  struct mv_xor_v2_sw_desc, free_list);
+       list_del(&sw_desc->free_list);
+
+       /* Release the channel */
+       spin_unlock_bh(&xor_dev->lock);
+
+       /* set the async tx descriptor */
+       dma_async_tx_descriptor_init(&sw_desc->async_tx, &xor_dev->dmachan);
+       sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit;
+       async_tx_ack(&sw_desc->async_tx);
+
+       return sw_desc;
+}
+
+/*
+ * Prepare a HW descriptor for a memcpy operation
+ */
+static struct dma_async_tx_descriptor *
+mv_xor_v2_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
+                         dma_addr_t src, size_t len, unsigned long flags)
+{
+       struct mv_xor_v2_sw_desc *sw_desc;
+       struct mv_xor_v2_descriptor *hw_descriptor;
+       struct mv_xor_v2_device *xor_dev;
+
+       xor_dev = container_of(chan, struct mv_xor_v2_device, dmachan);
+
+       dev_dbg(xor_dev->dmadev.dev,
+               "%s len: %zu src %pad dest %pad flags: %ld\n",
+               __func__, len, &src, &dest, flags);
+
+       sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+
+       sw_desc->async_tx.flags = flags;
+
+       /* set the HW descriptor */
+       hw_descriptor = &sw_desc->hw_desc;
+
+       /* save the SW descriptor ID to restore when operation is done */
+       hw_descriptor->desc_id = sw_desc->idx;
+
+       /* Set the MEMCPY control word */
+       hw_descriptor->desc_ctrl =
+               DESC_OP_MODE_MEMCPY << DESC_OP_MODE_SHIFT;
+
+       if (flags & DMA_PREP_INTERRUPT)
+               hw_descriptor->desc_ctrl |= DESC_IOD;
+
+       /* Set source address */
+       hw_descriptor->fill_pattern_src_addr[0] = lower_32_bits(src);
+       hw_descriptor->fill_pattern_src_addr[1] =
+               upper_32_bits(src) & 0xFFFF;
+
+       /* Set Destination address */
+       hw_descriptor->fill_pattern_src_addr[2] = lower_32_bits(dest);
+       hw_descriptor->fill_pattern_src_addr[3] =
+               upper_32_bits(dest) & 0xFFFF;
+
+       /* Set buffers size */
+       hw_descriptor->buff_size = len;
+
+       /* return the async tx descriptor */
+       return &sw_desc->async_tx;
+}
+
+/*
+ * Prepare a HW descriptor for a XOR operation
+ */
+static struct dma_async_tx_descriptor *
+mv_xor_v2_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+                      unsigned int src_cnt, size_t len, unsigned long flags)
+{
+       struct mv_xor_v2_sw_desc *sw_desc;
+       struct mv_xor_v2_descriptor *hw_descriptor;
+       struct mv_xor_v2_device *xor_dev =
+               container_of(chan, struct mv_xor_v2_device, dmachan);
+       int i;
+
+       if (src_cnt > MV_XOR_V2_CMD_LINE_NUM_MAX_D_BUF || src_cnt < 1)
+               return NULL;
+
+       dev_dbg(xor_dev->dmadev.dev,
+               "%s src_cnt: %d len: %zu dest %pad flags: %ld\n",
+               __func__, src_cnt, len, &dest, flags);
+
+       sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+
+       sw_desc->async_tx.flags = flags;
+
+       /* set the HW descriptor */
+       hw_descriptor = &sw_desc->hw_desc;
+
+       /* save the SW descriptor ID to restore when operation is done */
+       hw_descriptor->desc_id = sw_desc->idx;
+
+       /* Set the XOR control word */
+       hw_descriptor->desc_ctrl =
+               DESC_OP_MODE_XOR << DESC_OP_MODE_SHIFT;
+       hw_descriptor->desc_ctrl |= DESC_P_BUFFER_ENABLE;
+
+       if (flags & DMA_PREP_INTERRUPT)
+               hw_descriptor->desc_ctrl |= DESC_IOD;
+
+       /* Set the data buffers */
+       for (i = 0; i < src_cnt; i++)
+               mv_xor_v2_set_data_buffers(xor_dev, hw_descriptor, src[i], i);
+
+       hw_descriptor->desc_ctrl |=
+               src_cnt << DESC_NUM_ACTIVE_D_BUF_SHIFT;
+
+       /* Set Destination address */
+       hw_descriptor->fill_pattern_src_addr[2] = lower_32_bits(dest);
+       hw_descriptor->fill_pattern_src_addr[3] =
+               upper_32_bits(dest) & 0xFFFF;
+
+       /* Set buffers size */
+       hw_descriptor->buff_size = len;
+
+       /* return the async tx descriptor */
+       return &sw_desc->async_tx;
+}
+
+/*
+ * Prepare a HW descriptor for interrupt operation.
+ */
+static struct dma_async_tx_descriptor *
+mv_xor_v2_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags)
+{
+       struct mv_xor_v2_sw_desc *sw_desc;
+       struct mv_xor_v2_descriptor *hw_descriptor;
+       struct mv_xor_v2_device *xor_dev =
+               container_of(chan, struct mv_xor_v2_device, dmachan);
+
+       sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+
+       /* set the HW descriptor */
+       hw_descriptor = &sw_desc->hw_desc;
+
+       /* save the SW descriptor ID to restore when operation is done */
+       hw_descriptor->desc_id = sw_desc->idx;
+
+       /* Set the INTERRUPT control word */
+       hw_descriptor->desc_ctrl =
+               DESC_OP_MODE_NOP << DESC_OP_MODE_SHIFT;
+       hw_descriptor->desc_ctrl |= DESC_IOD;
+
+       /* return the async tx descriptor */
+       return &sw_desc->async_tx;
+}
+
+/*
+ * push pending transactions to hardware
+ */
+static void mv_xor_v2_issue_pending(struct dma_chan *chan)
+{
+       struct mv_xor_v2_device *xor_dev =
+               container_of(chan, struct mv_xor_v2_device, dmachan);
+
+       spin_lock_bh(&xor_dev->lock);
+
+       /*
+        * update the engine with the number of descriptors to
+        * process
+        */
+       mv_xor_v2_add_desc_to_desq(xor_dev, xor_dev->npendings);
+       xor_dev->npendings = 0;
+
+       /* Activate the channel */
+       writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF);
+
+       spin_unlock_bh(&xor_dev->lock);
+}
+
+static inline
+int mv_xor_v2_get_pending_params(struct mv_xor_v2_device *xor_dev,
+                                int *pending_ptr)
+{
+       u32 reg;
+
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_DONE_OFF);
+
+       /* get the next pending descriptor index */
+       *pending_ptr = ((reg >> MV_XOR_V2_DMA_DESQ_DONE_READ_PTR_SHIFT) &
+                       MV_XOR_V2_DMA_DESQ_DONE_READ_PTR_MASK);
+
+       /* get the number of descriptors pending handle */
+       return ((reg >> MV_XOR_V2_DMA_DESQ_DONE_PENDING_SHIFT) &
+               MV_XOR_V2_DMA_DESQ_DONE_PENDING_MASK);
+}
+
+/*
+ * handle the descriptors after HW process
+ */
+static void mv_xor_v2_tasklet(unsigned long data)
+{
+       struct mv_xor_v2_device *xor_dev = (struct mv_xor_v2_device *) data;
+       int pending_ptr, num_of_pending, i;
+       struct mv_xor_v2_descriptor *next_pending_hw_desc = NULL;
+       struct mv_xor_v2_sw_desc *next_pending_sw_desc = NULL;
+
+       dev_dbg(xor_dev->dmadev.dev, "%s %d\n", __func__, __LINE__);
+
+       /* get the pending descriptors parameters */
+       num_of_pending = mv_xor_v2_get_pending_params(xor_dev, &pending_ptr);
+
+       /* next HW descriptor */
+       next_pending_hw_desc = xor_dev->hw_desq_virt + pending_ptr;
+
+       /* loop over free descriptors */
+       for (i = 0; i < num_of_pending; i++) {
+
+               if (pending_ptr > MV_XOR_V2_DESC_NUM)
+                       pending_ptr = 0;
+
+               if (next_pending_sw_desc != NULL)
+                       next_pending_hw_desc++;
+
+               /* get the SW descriptor related to the HW descriptor */
+               next_pending_sw_desc =
+                       &xor_dev->sw_desq[next_pending_hw_desc->desc_id];
+
+               /* call the callback */
+               if (next_pending_sw_desc->async_tx.cookie > 0) {
+                       /*
+                        * update the channel's completed cookie - no
+                        * lock is required the IMSG threshold provide
+                        * the locking
+                        */
+                       dma_cookie_complete(&next_pending_sw_desc->async_tx);
+
+                       if (next_pending_sw_desc->async_tx.callback)
+                               next_pending_sw_desc->async_tx.callback(
+                               next_pending_sw_desc->async_tx.callback_param);
+
+                       dma_descriptor_unmap(&next_pending_sw_desc->async_tx);
+               }
+
+               dma_run_dependencies(&next_pending_sw_desc->async_tx);
+
+               /* Lock the channel */
+               spin_lock_bh(&xor_dev->lock);
+
+               /* add the SW descriptor to the free descriptors list */
+               list_add(&next_pending_sw_desc->free_list,
+                        &xor_dev->free_sw_desc);
+
+               /* Release the channel */
+               spin_unlock_bh(&xor_dev->lock);
+
+               /* increment the next descriptor */
+               pending_ptr++;
+       }
+
+       if (num_of_pending != 0) {
+               /* free the descriptores */
+               mv_xor_v2_free_desc_from_desq(xor_dev, num_of_pending);
+       }
+
+       /* Update IMSG threshold, to enable new IMSG interrupts */
+       mv_xor_v2_set_imsg_thrd(xor_dev, 0);
+}
+
+/*
+ *     Set DMA Interrupt-message (IMSG) parameters
+ */
+static void mv_xor_v2_set_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+       struct mv_xor_v2_device *xor_dev = dev_get_drvdata(desc->dev);
+
+       writel(msg->address_lo,
+              xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_BALR_OFF);
+       writel(msg->address_hi & 0xFFFF,
+              xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_BAHR_OFF);
+       writel(msg->data,
+              xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_CDAT_OFF);
+}
+
+static int mv_xor_v2_descq_init(struct mv_xor_v2_device *xor_dev)
+{
+       u32 reg;
+
+       /* write the DESQ size to the DMA engine */
+       writel(MV_XOR_V2_DESC_NUM,
+              xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_SIZE_OFF);
+
+       /* write the DESQ address to the DMA enngine*/
+       writel(xor_dev->hw_desq & 0xFFFFFFFF,
+              xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BALR_OFF);
+       writel((xor_dev->hw_desq & 0xFFFF00000000) >> 32,
+              xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BAHR_OFF);
+
+       /* enable the DMA engine */
+       writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF);
+
+       /*
+        * This is a temporary solution, until we activate the
+        * SMMU. Set the attributes for reading & writing data buffers
+        * & descriptors to:
+        *
+        *  - OuterShareable - Snoops will be performed on CPU caches
+        *  - Enable cacheable - Bufferable, Modifiable, Other Allocate
+        *    and Allocate
+        */
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ARATTR_OFF);
+       reg &= ~MV_XOR_V2_DMA_DESQ_ATTR_CACHE_MASK;
+       reg |= MV_XOR_V2_DMA_DESQ_ATTR_OUTER_SHAREABLE |
+               MV_XOR_V2_DMA_DESQ_ATTR_CACHEABLE;
+       writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ARATTR_OFF);
+
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_AWATTR_OFF);
+       reg &= ~MV_XOR_V2_DMA_DESQ_ATTR_CACHE_MASK;
+       reg |= MV_XOR_V2_DMA_DESQ_ATTR_OUTER_SHAREABLE |
+               MV_XOR_V2_DMA_DESQ_ATTR_CACHEABLE;
+       writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_AWATTR_OFF);
+
+       /* BW CTRL - set values to optimize the XOR performance:
+        *
+        *  - Set WrBurstLen & RdBurstLen - the unit will issue
+        *    maximum of 256B write/read transactions.
+        * -  Limit the number of outstanding write & read data
+        *    (OBB/IBB) requests to the maximal value.
+       */
+       reg = ((MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_VAL <<
+               MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_SHIFT) |
+              (MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_VAL  <<
+               MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_SHIFT) |
+              (MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_VAL <<
+               MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_SHIFT) |
+              (MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_VAL <<
+               MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_SHIFT));
+       writel(reg, xor_dev->glob_base + MV_XOR_V2_GLOB_BW_CTRL);
+
+       /* Disable the AXI timer feature */
+       reg = readl(xor_dev->glob_base + MV_XOR_V2_GLOB_PAUSE);
+       reg |= MV_XOR_V2_GLOB_PAUSE_AXI_TIME_DIS_VAL;
+       writel(reg, xor_dev->glob_base + MV_XOR_V2_GLOB_PAUSE);
+
+       return 0;
+}
+
+static int mv_xor_v2_probe(struct platform_device *pdev)
+{
+       struct mv_xor_v2_device *xor_dev;
+       struct resource *res;
+       int i, ret = 0;
+       struct dma_device *dma_dev;
+       struct mv_xor_v2_sw_desc *sw_desc;
+       struct msi_desc *msi_desc;
+
+       BUILD_BUG_ON(sizeof(struct mv_xor_v2_descriptor) !=
+                    MV_XOR_V2_EXT_DESC_SIZE);
+
+       xor_dev = devm_kzalloc(&pdev->dev, sizeof(*xor_dev), GFP_KERNEL);
+       if (!xor_dev)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       xor_dev->dma_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(xor_dev->dma_base))
+               return PTR_ERR(xor_dev->dma_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       xor_dev->glob_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(xor_dev->glob_base))
+               return PTR_ERR(xor_dev->glob_base);
+
+       platform_set_drvdata(pdev, xor_dev);
+
+       xor_dev->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (!IS_ERR(xor_dev->clk)) {
+               ret = clk_prepare_enable(xor_dev->clk);
+               if (ret)
+                       return ret;
+       }
+
+       ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1,
+                                            mv_xor_v2_set_msi_msg);
+       if (ret)
+               goto disable_clk;
+
+       msi_desc = first_msi_entry(&pdev->dev);
+       if (!msi_desc)
+               goto free_msi_irqs;
+
+       ret = devm_request_irq(&pdev->dev, msi_desc->irq,
+                              mv_xor_v2_interrupt_handler, 0,
+                              dev_name(&pdev->dev), xor_dev);
+       if (ret)
+               goto free_msi_irqs;
+
+       tasklet_init(&xor_dev->irq_tasklet, mv_xor_v2_tasklet,
+                    (unsigned long) xor_dev);
+
+       xor_dev->desc_size = mv_xor_v2_set_desc_size(xor_dev);
+
+       dma_cookie_init(&xor_dev->dmachan);
+
+       /*
+        * allocate coherent memory for hardware descriptors
+        * note: writecombine gives slightly better performance, but
+        * requires that we explicitly flush the writes
+        */
+       xor_dev->hw_desq_virt =
+               dma_alloc_coherent(&pdev->dev,
+                                  xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
+                                  &xor_dev->hw_desq, GFP_KERNEL);
+       if (!xor_dev->hw_desq_virt) {
+               ret = -ENOMEM;
+               goto free_msi_irqs;
+       }
+
+       /* alloc memory for the SW descriptors */
+       xor_dev->sw_desq = devm_kzalloc(&pdev->dev, sizeof(*sw_desc) *
+                                       MV_XOR_V2_DESC_NUM, GFP_KERNEL);
+       if (!xor_dev->sw_desq) {
+               ret = -ENOMEM;
+               goto free_hw_desq;
+       }
+
+       spin_lock_init(&xor_dev->lock);
+
+       /* init the free SW descriptors list */
+       INIT_LIST_HEAD(&xor_dev->free_sw_desc);
+
+       /* add all SW descriptors to the free list */
+       for (i = 0; i < MV_XOR_V2_DESC_NUM; i++) {
+               xor_dev->sw_desq[i].idx = i;
+               list_add(&xor_dev->sw_desq[i].free_list,
+                        &xor_dev->free_sw_desc);
+       }
+
+       dma_dev = &xor_dev->dmadev;
+
+       /* set DMA capabilities */
+       dma_cap_zero(dma_dev->cap_mask);
+       dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
+       dma_cap_set(DMA_XOR, dma_dev->cap_mask);
+       dma_cap_set(DMA_INTERRUPT, dma_dev->cap_mask);
+
+       /* init dma link list */
+       INIT_LIST_HEAD(&dma_dev->channels);
+
+       /* set base routines */
+       dma_dev->device_tx_status = dma_cookie_status;
+       dma_dev->device_issue_pending = mv_xor_v2_issue_pending;
+       dma_dev->dev = &pdev->dev;
+
+       dma_dev->device_prep_dma_memcpy = mv_xor_v2_prep_dma_memcpy;
+       dma_dev->device_prep_dma_interrupt = mv_xor_v2_prep_dma_interrupt;
+       dma_dev->max_xor = 8;
+       dma_dev->device_prep_dma_xor = mv_xor_v2_prep_dma_xor;
+
+       xor_dev->dmachan.device = dma_dev;
+
+       list_add_tail(&xor_dev->dmachan.device_node,
+                     &dma_dev->channels);
+
+       mv_xor_v2_descq_init(xor_dev);
+
+       ret = dma_async_device_register(dma_dev);
+       if (ret)
+               goto free_hw_desq;
+
+       dev_notice(&pdev->dev, "Marvell Version 2 XOR driver\n");
+
+       return 0;
+
+free_hw_desq:
+       dma_free_coherent(&pdev->dev,
+                         xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
+                         xor_dev->hw_desq_virt, xor_dev->hw_desq);
+free_msi_irqs:
+       platform_msi_domain_free_irqs(&pdev->dev);
+disable_clk:
+       if (!IS_ERR(xor_dev->clk))
+               clk_disable_unprepare(xor_dev->clk);
+       return ret;
+}
+
+static int mv_xor_v2_remove(struct platform_device *pdev)
+{
+       struct mv_xor_v2_device *xor_dev = platform_get_drvdata(pdev);
+
+       dma_async_device_unregister(&xor_dev->dmadev);
+
+       dma_free_coherent(&pdev->dev,
+                         xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
+                         xor_dev->hw_desq_virt, xor_dev->hw_desq);
+
+       platform_msi_domain_free_irqs(&pdev->dev);
+
+       clk_disable_unprepare(xor_dev->clk);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mv_xor_v2_dt_ids[] = {
+       { .compatible = "marvell,xor-v2", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mv_xor_v2_dt_ids);
+#endif
+
+static struct platform_driver mv_xor_v2_driver = {
+       .probe          = mv_xor_v2_probe,
+       .remove         = mv_xor_v2_remove,
+       .driver         = {
+               .name   = "mv_xor_v2",
+               .of_match_table = of_match_ptr(mv_xor_v2_dt_ids),
+       },
+};
+
+module_platform_driver(mv_xor_v2_driver);
+
+MODULE_DESCRIPTION("DMA engine driver for Marvell's Version 2 of XOR engine");
+MODULE_LICENSE("GPL");
index 2b5a198ac77e483fdf9a0e0479b200935cc4f501..08c45c18554966fb0cc1aa657ad18cd5d1be5e30 100644 (file)
@@ -227,6 +227,7 @@ struct nbpf_device {
        void __iomem *base;
        struct clk *clk;
        const struct nbpf_config *config;
+       unsigned int eirq;
        struct nbpf_channel chan[];
 };
 
@@ -1300,10 +1301,9 @@ static int nbpf_probe(struct platform_device *pdev)
 
        nbpf = devm_kzalloc(dev, sizeof(*nbpf) + num_channels *
                            sizeof(nbpf->chan[0]), GFP_KERNEL);
-       if (!nbpf) {
-               dev_err(dev, "Memory allocation failed\n");
+       if (!nbpf)
                return -ENOMEM;
-       }
+
        dma_dev = &nbpf->dma_dev;
        dma_dev->dev = dev;
 
@@ -1376,6 +1376,7 @@ static int nbpf_probe(struct platform_device *pdev)
                               IRQF_SHARED, "dma error", nbpf);
        if (ret < 0)
                return ret;
+       nbpf->eirq = eirq;
 
        INIT_LIST_HEAD(&dma_dev->channels);
 
@@ -1447,6 +1448,17 @@ e_clk_off:
 static int nbpf_remove(struct platform_device *pdev)
 {
        struct nbpf_device *nbpf = platform_get_drvdata(pdev);
+       int i;
+
+       devm_free_irq(&pdev->dev, nbpf->eirq, nbpf);
+
+       for (i = 0; i < nbpf->config->num_channels; i++) {
+               struct nbpf_channel *chan = nbpf->chan + i;
+
+               devm_free_irq(&pdev->dev, chan->irq, chan);
+
+               tasklet_kill(&chan->tasklet);
+       }
 
        of_dma_controller_free(pdev->dev.of_node);
        dma_async_device_unregister(&nbpf->dma_dev);
index 1e984e18c1266b74fc01c247fad36f3e132ad587..d99ca2b511c4101ce262569106ffe1d3fa5644fb 100644 (file)
@@ -59,6 +59,8 @@ struct omap_sg {
        dma_addr_t addr;
        uint32_t en;            /* number of elements (24-bit) */
        uint32_t fn;            /* number of frames (16-bit) */
+       int32_t fi;             /* for double indexing */
+       int16_t ei;             /* for double indexing */
 };
 
 struct omap_desc {
@@ -66,7 +68,8 @@ struct omap_desc {
        enum dma_transfer_direction dir;
        dma_addr_t dev_addr;
 
-       int16_t fi;             /* for OMAP_DMA_SYNC_PACKET */
+       int32_t fi;             /* for OMAP_DMA_SYNC_PACKET / double indexing */
+       int16_t ei;             /* for double indexing */
        uint8_t es;             /* CSDP_DATA_TYPE_xxx */
        uint32_t ccr;           /* CCR value */
        uint16_t clnk_ctrl;     /* CLNK_CTRL value */
@@ -379,8 +382,8 @@ static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d,
        }
 
        omap_dma_chan_write(c, cxsa, sg->addr);
-       omap_dma_chan_write(c, cxei, 0);
-       omap_dma_chan_write(c, cxfi, 0);
+       omap_dma_chan_write(c, cxei, sg->ei);
+       omap_dma_chan_write(c, cxfi, sg->fi);
        omap_dma_chan_write(c, CEN, sg->en);
        omap_dma_chan_write(c, CFN, sg->fn);
 
@@ -425,7 +428,7 @@ static void omap_dma_start_desc(struct omap_chan *c)
        }
 
        omap_dma_chan_write(c, cxsa, d->dev_addr);
-       omap_dma_chan_write(c, cxei, 0);
+       omap_dma_chan_write(c, cxei, d->ei);
        omap_dma_chan_write(c, cxfi, d->fi);
        omap_dma_chan_write(c, CSDP, d->csdp);
        omap_dma_chan_write(c, CLNK_CTRL, d->clnk_ctrl);
@@ -971,6 +974,89 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_memcpy(
        return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
 }
 
+static struct dma_async_tx_descriptor *omap_dma_prep_dma_interleaved(
+       struct dma_chan *chan, struct dma_interleaved_template *xt,
+       unsigned long flags)
+{
+       struct omap_chan *c = to_omap_dma_chan(chan);
+       struct omap_desc *d;
+       struct omap_sg *sg;
+       uint8_t data_type;
+       size_t src_icg, dst_icg;
+
+       /* Slave mode is not supported */
+       if (is_slave_direction(xt->dir))
+               return NULL;
+
+       if (xt->frame_size != 1 || xt->numf == 0)
+               return NULL;
+
+       d = kzalloc(sizeof(*d) + sizeof(d->sg[0]), GFP_ATOMIC);
+       if (!d)
+               return NULL;
+
+       data_type = __ffs((xt->src_start | xt->dst_start | xt->sgl[0].size));
+       if (data_type > CSDP_DATA_TYPE_32)
+               data_type = CSDP_DATA_TYPE_32;
+
+       sg = &d->sg[0];
+       d->dir = DMA_MEM_TO_MEM;
+       d->dev_addr = xt->src_start;
+       d->es = data_type;
+       sg->en = xt->sgl[0].size / BIT(data_type);
+       sg->fn = xt->numf;
+       sg->addr = xt->dst_start;
+       d->sglen = 1;
+       d->ccr = c->ccr;
+
+       src_icg = dmaengine_get_src_icg(xt, &xt->sgl[0]);
+       dst_icg = dmaengine_get_dst_icg(xt, &xt->sgl[0]);
+       if (src_icg) {
+               d->ccr |= CCR_SRC_AMODE_DBLIDX;
+               d->ei = 1;
+               d->fi = src_icg;
+       } else if (xt->src_inc) {
+               d->ccr |= CCR_SRC_AMODE_POSTINC;
+               d->fi = 0;
+       } else {
+               dev_err(chan->device->dev,
+                       "%s: SRC constant addressing is not supported\n",
+                       __func__);
+               kfree(d);
+               return NULL;
+       }
+
+       if (dst_icg) {
+               d->ccr |= CCR_DST_AMODE_DBLIDX;
+               sg->ei = 1;
+               sg->fi = dst_icg;
+       } else if (xt->dst_inc) {
+               d->ccr |= CCR_DST_AMODE_POSTINC;
+               sg->fi = 0;
+       } else {
+               dev_err(chan->device->dev,
+                       "%s: DST constant addressing is not supported\n",
+                       __func__);
+               kfree(d);
+               return NULL;
+       }
+
+       d->cicr = CICR_DROP_IE | CICR_FRAME_IE;
+
+       d->csdp = data_type;
+
+       if (dma_omap1()) {
+               d->cicr |= CICR_TOUT_IE;
+               d->csdp |= CSDP_DST_PORT_EMIFF | CSDP_SRC_PORT_EMIFF;
+       } else {
+               d->csdp |= CSDP_DST_PACKED | CSDP_SRC_PACKED;
+               d->cicr |= CICR_MISALIGNED_ERR_IE | CICR_TRANS_ERR_IE;
+               d->csdp |= CSDP_DST_BURST_64 | CSDP_SRC_BURST_64;
+       }
+
+       return vchan_tx_prep(&c->vc, &d->vd, flags);
+}
+
 static int omap_dma_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)
 {
        struct omap_chan *c = to_omap_dma_chan(chan);
@@ -1116,6 +1202,7 @@ static int omap_dma_probe(struct platform_device *pdev)
        dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
        dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
        dma_cap_set(DMA_MEMCPY, od->ddev.cap_mask);
+       dma_cap_set(DMA_INTERLEAVE, od->ddev.cap_mask);
        od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources;
        od->ddev.device_free_chan_resources = omap_dma_free_chan_resources;
        od->ddev.device_tx_status = omap_dma_tx_status;
@@ -1123,6 +1210,7 @@ static int omap_dma_probe(struct platform_device *pdev)
        od->ddev.device_prep_slave_sg = omap_dma_prep_slave_sg;
        od->ddev.device_prep_dma_cyclic = omap_dma_prep_dma_cyclic;
        od->ddev.device_prep_dma_memcpy = omap_dma_prep_dma_memcpy;
+       od->ddev.device_prep_interleaved_dma = omap_dma_prep_dma_interleaved;
        od->ddev.device_config = omap_dma_slave_config;
        od->ddev.device_pause = omap_dma_pause;
        od->ddev.device_resume = omap_dma_resume;
@@ -1204,10 +1292,14 @@ static int omap_dma_probe(struct platform_device *pdev)
 static int omap_dma_remove(struct platform_device *pdev)
 {
        struct omap_dmadev *od = platform_get_drvdata(pdev);
+       int irq;
 
        if (pdev->dev.of_node)
                of_dma_controller_free(pdev->dev.of_node);
 
+       irq = platform_get_irq(pdev, 1);
+       devm_free_irq(&pdev->dev, irq, od);
+
        dma_async_device_unregister(&od->ddev);
 
        if (!od->legacy) {
index 372b4359da97d4d7753233884e65c40abc7261cb..4fc3ffbd5ca0d0a36b489eceba61091b323228e3 100644 (file)
@@ -2828,10 +2828,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 
        /* Allocate a new DMAC and its Channels */
        pl330 = devm_kzalloc(&adev->dev, sizeof(*pl330), GFP_KERNEL);
-       if (!pl330) {
-               dev_err(&adev->dev, "unable to allocate mem\n");
+       if (!pl330)
                return -ENOMEM;
-       }
 
        pd = &pl330->ddma;
        pd->dev = &adev->dev;
@@ -2890,7 +2888,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        pl330->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
        if (!pl330->peripherals) {
                ret = -ENOMEM;
-               dev_err(&adev->dev, "unable to allocate pl330->peripherals\n");
                goto probe_err2;
        }
 
@@ -3005,12 +3002,18 @@ static int pl330_remove(struct amba_device *adev)
 {
        struct pl330_dmac *pl330 = amba_get_drvdata(adev);
        struct dma_pl330_chan *pch, *_p;
+       int i, irq;
 
        pm_runtime_get_noresume(pl330->ddma.dev);
 
        if (adev->dev.of_node)
                of_dma_controller_free(adev->dev.of_node);
 
+       for (i = 0; i < AMBA_NR_IRQS; i++) {
+               irq = adev->irq[i];
+               devm_free_irq(&adev->dev, irq, pl330);
+       }
+
        dma_async_device_unregister(&pl330->ddma);
 
        /* Idle the DMAC */
index 9217f893b0d1af7efec3d56bdc281beeb426fcfe..da3688b94bdc1a460c913e5c36aa4cd80838a380 100644 (file)
@@ -4084,7 +4084,6 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
        /* create a device */
        adev = kzalloc(sizeof(*adev), GFP_KERNEL);
        if (!adev) {
-               dev_err(&ofdev->dev, "failed to allocate device\n");
                initcode = PPC_ADMA_INIT_ALLOC;
                ret = -ENOMEM;
                goto err_adev_alloc;
@@ -4145,7 +4144,6 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
        /* create a channel */
        chan = kzalloc(sizeof(*chan), GFP_KERNEL);
        if (!chan) {
-               dev_err(&ofdev->dev, "can't allocate channel structure\n");
                initcode = PPC_ADMA_INIT_CHANNEL;
                ret = -ENOMEM;
                goto err_chan_alloc;
index e756a30ccba2c9b46ea24b036a369b7aa0b07b8d..dc7850a422b8d4212495d067c4ea31c26e0af8a2 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
 #include <linux/of.h>
+#include <linux/wait.h>
 #include <linux/dma/pxa-dma.h>
 
 #include "dmaengine.h"
@@ -118,6 +119,8 @@ struct pxad_chan {
        struct pxad_phy         *phy;
        struct dma_pool         *desc_pool;     /* Descriptors pool */
        dma_cookie_t            bus_error;
+
+       wait_queue_head_t       wq_state;
 };
 
 struct pxad_device {
@@ -318,7 +321,6 @@ static int dbg_open_##name(struct inode *inode, struct file *file) \
        return single_open(file, dbg_show_##name, inode->i_private); \
 } \
 static const struct file_operations dbg_fops_##name = { \
-       .owner          = THIS_MODULE, \
        .open           = dbg_open_##name, \
        .llseek         = seq_lseek, \
        .read           = seq_read, \
@@ -572,6 +574,7 @@ static void pxad_launch_chan(struct pxad_chan *chan,
         */
        phy_writel(chan->phy, desc->first, DDADR);
        phy_enable(chan->phy, chan->misaligned);
+       wake_up(&chan->wq_state);
 }
 
 static void set_updater_desc(struct pxad_desc_sw *sw_desc,
@@ -717,6 +720,7 @@ static irqreturn_t pxad_chan_handler(int irq, void *dev_id)
                }
        }
        spin_unlock_irqrestore(&chan->vc.lock, flags);
+       wake_up(&chan->wq_state);
 
        return IRQ_HANDLED;
 }
@@ -1268,6 +1272,14 @@ static enum dma_status pxad_tx_status(struct dma_chan *dchan,
        return ret;
 }
 
+static void pxad_synchronize(struct dma_chan *dchan)
+{
+       struct pxad_chan *chan = to_pxad_chan(dchan);
+
+       wait_event(chan->wq_state, !is_chan_running(chan));
+       vchan_synchronize(&chan->vc);
+}
+
 static void pxad_free_channels(struct dma_device *dmadev)
 {
        struct pxad_chan *c, *cn;
@@ -1372,6 +1384,7 @@ static int pxad_init_dmadev(struct platform_device *op,
        pdev->slave.device_tx_status = pxad_tx_status;
        pdev->slave.device_issue_pending = pxad_issue_pending;
        pdev->slave.device_config = pxad_config;
+       pdev->slave.device_synchronize = pxad_synchronize;
        pdev->slave.device_terminate_all = pxad_terminate_all;
 
        if (op->dev.coherent_dma_mask)
@@ -1389,6 +1402,7 @@ static int pxad_init_dmadev(struct platform_device *op,
                        return -ENOMEM;
                c->vc.desc_free = pxad_free_desc;
                vchan_init(&c->vc, &pdev->slave);
+               init_waitqueue_head(&c->wq_state);
        }
 
        return dma_async_device_register(&pdev->slave);
index 969b48176745031f4b2d9bf952561b4101af00e7..03c4eb3fd314d31df1cc8ce39122dc37b85ce8ea 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/of_dma.h>
 #include <linux/clk.h>
 #include <linux/dmaengine.h>
+#include <linux/pm_runtime.h>
 
 #include "../dmaengine.h"
 #include "../virt-dma.h"
@@ -58,6 +59,8 @@ struct bam_desc_hw {
        __le16 flags;
 };
 
+#define BAM_DMA_AUTOSUSPEND_DELAY 100
+
 #define DESC_FLAG_INT BIT(15)
 #define DESC_FLAG_EOT BIT(14)
 #define DESC_FLAG_EOB BIT(13)
@@ -527,12 +530,17 @@ static void bam_free_chan(struct dma_chan *chan)
        struct bam_device *bdev = bchan->bdev;
        u32 val;
        unsigned long flags;
+       int ret;
+
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return;
 
        vchan_free_chan_resources(to_virt_chan(chan));
 
        if (bchan->curr_txd) {
                dev_err(bchan->bdev->dev, "Cannot free busy channel\n");
-               return;
+               goto err;
        }
 
        spin_lock_irqsave(&bchan->vc.lock, flags);
@@ -550,6 +558,10 @@ static void bam_free_chan(struct dma_chan *chan)
 
        /* disable irq */
        writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_IRQ_EN));
+
+err:
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 }
 
 /**
@@ -696,11 +708,18 @@ static int bam_pause(struct dma_chan *chan)
        struct bam_chan *bchan = to_bam_chan(chan);
        struct bam_device *bdev = bchan->bdev;
        unsigned long flag;
+       int ret;
+
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return ret;
 
        spin_lock_irqsave(&bchan->vc.lock, flag);
        writel_relaxed(1, bam_addr(bdev, bchan->id, BAM_P_HALT));
        bchan->paused = 1;
        spin_unlock_irqrestore(&bchan->vc.lock, flag);
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 
        return 0;
 }
@@ -715,11 +734,18 @@ static int bam_resume(struct dma_chan *chan)
        struct bam_chan *bchan = to_bam_chan(chan);
        struct bam_device *bdev = bchan->bdev;
        unsigned long flag;
+       int ret;
+
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return ret;
 
        spin_lock_irqsave(&bchan->vc.lock, flag);
        writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_HALT));
        bchan->paused = 0;
        spin_unlock_irqrestore(&bchan->vc.lock, flag);
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 
        return 0;
 }
@@ -795,6 +821,7 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
 {
        struct bam_device *bdev = data;
        u32 clr_mask = 0, srcs = 0;
+       int ret;
 
        srcs |= process_channel_irqs(bdev);
 
@@ -802,6 +829,10 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
        if (srcs & P_IRQ)
                tasklet_schedule(&bdev->task);
 
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return ret;
+
        if (srcs & BAM_IRQ) {
                clr_mask = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_STTS));
 
@@ -814,6 +845,9 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
                writel_relaxed(clr_mask, bam_addr(bdev, 0, BAM_IRQ_CLR));
        }
 
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
+
        return IRQ_HANDLED;
 }
 
@@ -893,6 +927,7 @@ static void bam_start_dma(struct bam_chan *bchan)
        struct bam_desc_hw *desc;
        struct bam_desc_hw *fifo = PTR_ALIGN(bchan->fifo_virt,
                                        sizeof(struct bam_desc_hw));
+       int ret;
 
        lockdep_assert_held(&bchan->vc.lock);
 
@@ -904,6 +939,10 @@ static void bam_start_dma(struct bam_chan *bchan)
        async_desc = container_of(vd, struct bam_async_desc, vd);
        bchan->curr_txd = async_desc;
 
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return;
+
        /* on first use, initialize the channel hardware */
        if (!bchan->initialized)
                bam_chan_init_hw(bchan, async_desc->dir);
@@ -946,6 +985,9 @@ static void bam_start_dma(struct bam_chan *bchan)
        wmb();
        writel_relaxed(bchan->tail * sizeof(struct bam_desc_hw),
                        bam_addr(bdev, bchan->id, BAM_P_EVNT_REG));
+
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 }
 
 /**
@@ -970,6 +1012,7 @@ static void dma_tasklet(unsigned long data)
                        bam_start_dma(bchan);
                spin_unlock_irqrestore(&bchan->vc.lock, flags);
        }
+
 }
 
 /**
@@ -1213,6 +1256,13 @@ static int bam_dma_probe(struct platform_device *pdev)
        if (ret)
                goto err_unregister_dma;
 
+       pm_runtime_irq_safe(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, BAM_DMA_AUTOSUSPEND_DELAY);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        return 0;
 
 err_unregister_dma:
@@ -1233,6 +1283,8 @@ static int bam_dma_remove(struct platform_device *pdev)
        struct bam_device *bdev = platform_get_drvdata(pdev);
        u32 i;
 
+       pm_runtime_force_suspend(&pdev->dev);
+
        of_dma_controller_free(pdev->dev.of_node);
        dma_async_device_unregister(&bdev->common);
 
@@ -1260,11 +1312,66 @@ static int bam_dma_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused bam_dma_runtime_suspend(struct device *dev)
+{
+       struct bam_device *bdev = dev_get_drvdata(dev);
+
+       clk_disable(bdev->bamclk);
+
+       return 0;
+}
+
+static int __maybe_unused bam_dma_runtime_resume(struct device *dev)
+{
+       struct bam_device *bdev = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_enable(bdev->bamclk);
+       if (ret < 0) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __maybe_unused bam_dma_suspend(struct device *dev)
+{
+       struct bam_device *bdev = dev_get_drvdata(dev);
+
+       pm_runtime_force_suspend(dev);
+
+       clk_unprepare(bdev->bamclk);
+
+       return 0;
+}
+
+static int __maybe_unused bam_dma_resume(struct device *dev)
+{
+       struct bam_device *bdev = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare(bdev->bamclk);
+       if (ret)
+               return ret;
+
+       pm_runtime_force_resume(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops bam_dma_pm_ops = {
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(bam_dma_suspend, bam_dma_resume)
+       SET_RUNTIME_PM_OPS(bam_dma_runtime_suspend, bam_dma_runtime_resume,
+                               NULL)
+};
+
 static struct platform_driver bam_dma_driver = {
        .probe = bam_dma_probe,
        .remove = bam_dma_remove,
        .driver = {
                .name = "bam-dma-engine",
+               .pm = &bam_dma_pm_ops,
                .of_match_table = bam_of_match,
        },
 };
index 41b5c6dee713239623b550dbbe39189f6110ba1c..b2374cd91e457f38b946548cd3bcda7aed47e82e 100644 (file)
@@ -708,6 +708,7 @@ static int hidma_remove(struct platform_device *pdev)
        pm_runtime_get_sync(dmadev->ddev.dev);
        dma_async_device_unregister(&dmadev->ddev);
        devm_free_irq(dmadev->ddev.dev, dmadev->irq, dmadev->lldev);
+       tasklet_kill(&dmadev->task);
        hidma_debug_uninit(dmadev);
        hidma_ll_uninit(dmadev->lldev);
        hidma_free(dmadev);
index f3929001539b0a464c30ff650a7934b22c588f52..ad20dfb64c71cb32d3b392c0fcb0dcd0002a5787 100644 (file)
@@ -831,6 +831,7 @@ int hidma_ll_uninit(struct hidma_lldev *lldev)
 
        required_bytes = sizeof(struct hidma_tre) * lldev->nr_tres;
        tasklet_kill(&lldev->task);
+       tasklet_kill(&lldev->rst_task);
        memset(lldev->trepool, 0, required_bytes);
        lldev->trepool = NULL;
        lldev->pending_tre_count = 0;
index c0e365321310009a6df4443b173a9f7823438a4d..82f36e4660830b33262bfc3d9a2acc5ef198a336 100644 (file)
@@ -371,8 +371,8 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np)
                pdevinfo.size_data = 0;
                pdevinfo.dma_mask = DMA_BIT_MASK(64);
                new_pdev = platform_device_register_full(&pdevinfo);
-               if (!new_pdev) {
-                       ret = -ENODEV;
+               if (IS_ERR(new_pdev)) {
+                       ret = PTR_ERR(new_pdev);
                        goto out;
                }
                of_dma_configure(&new_pdev->dev, child);
@@ -392,8 +392,7 @@ static int __init hidma_mgmt_init(void)
 #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
        struct device_node *child;
 
-       for (child = of_find_matching_node(NULL, hidma_mgmt_match); child;
-            child = of_find_matching_node(child, hidma_mgmt_match)) {
+       for_each_matching_node(child, hidma_mgmt_match) {
                /* device tree based firmware here */
                hidma_mgmt_of_populate_channels(child);
                of_node_put(child);
index 17ccdfd28f3702d7de7b0b98299262a36690df85..ce67075589f52813570bddc9a92bcdce4b8a4e60 100644 (file)
@@ -768,16 +768,12 @@ static enum dma_status s3c24xx_dma_tx_status(struct dma_chan *chan,
 
        spin_lock_irqsave(&s3cchan->vc.lock, flags);
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret == DMA_COMPLETE) {
-               spin_unlock_irqrestore(&s3cchan->vc.lock, flags);
-               return ret;
-       }
 
        /*
         * There's no point calculating the residue if there's
         * no txstate to store the value.
         */
-       if (!txstate) {
+       if (ret == DMA_COMPLETE || !txstate) {
                spin_unlock_irqrestore(&s3cchan->vc.lock, flags);
                return ret;
        }
@@ -1105,11 +1101,8 @@ static int s3c24xx_dma_init_virtual_channels(struct s3c24xx_dma_engine *s3cdma,
         */
        for (i = 0; i < channels; i++) {
                chan = devm_kzalloc(dmadev->dev, sizeof(*chan), GFP_KERNEL);
-               if (!chan) {
-                       dev_err(dmadev->dev,
-                               "%s no memory for channel\n", __func__);
+               if (!chan)
                        return -ENOMEM;
-               }
 
                chan->id = i;
                chan->host = s3cdma;
@@ -1143,8 +1136,10 @@ static void s3c24xx_dma_free_virtual_channels(struct dma_device *dmadev)
        struct s3c24xx_dma_chan *next;
 
        list_for_each_entry_safe(chan,
-                                next, &dmadev->channels, vc.chan.device_node)
+                                next, &dmadev->channels, vc.chan.device_node) {
                list_del(&chan->vc.chan.device_node);
+               tasklet_kill(&chan->vc.task);
+       }
 }
 
 /* s3c2410, s3c2440 and s3c2442 have a 0x40 stride without separate clocks */
@@ -1366,6 +1361,18 @@ err_memcpy:
        return ret;
 }
 
+static void s3c24xx_dma_free_irq(struct platform_device *pdev,
+                               struct s3c24xx_dma_engine *s3cdma)
+{
+       int i;
+
+       for (i = 0; i < s3cdma->pdata->num_phy_channels; i++) {
+               struct s3c24xx_dma_phy *phy = &s3cdma->phy_chans[i];
+
+               devm_free_irq(&pdev->dev, phy->irq, phy);
+       }
+}
+
 static int s3c24xx_dma_remove(struct platform_device *pdev)
 {
        const struct s3c24xx_dma_platdata *pdata = dev_get_platdata(&pdev->dev);
@@ -1376,6 +1383,8 @@ static int s3c24xx_dma_remove(struct platform_device *pdev)
        dma_async_device_unregister(&s3cdma->slave);
        dma_async_device_unregister(&s3cdma->memcpy);
 
+       s3c24xx_dma_free_irq(pdev, s3cdma);
+
        s3c24xx_dma_free_virtual_channels(&s3cdma->slave);
        s3c24xx_dma_free_virtual_channels(&s3cdma->memcpy);
 
index dfb17926297bd4f095a77b8105725335fa7c1aff..0dd953884d1d63eb90e3b1599aedcb3f02ac0caa 100644 (file)
@@ -311,7 +311,7 @@ static bool rcar_dmac_chan_is_busy(struct rcar_dmac_chan *chan)
 {
        u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
 
-       return (chcr & (RCAR_DMACHCR_DE | RCAR_DMACHCR_TE)) == RCAR_DMACHCR_DE;
+       return !!(chcr & (RCAR_DMACHCR_DE | RCAR_DMACHCR_TE));
 }
 
 static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan)
@@ -510,7 +510,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
 
        spin_lock_irqsave(&chan->lock, flags);
        list_splice_tail_init(&desc->chunks, &chan->desc.chunks_free);
-       list_add_tail(&desc->node, &chan->desc.free);
+       list_add(&desc->node, &chan->desc.free);
        spin_unlock_irqrestore(&chan->lock, flags);
 }
 
@@ -990,6 +990,8 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan)
        list_splice_init(&rchan->desc.done, &list);
        list_splice_init(&rchan->desc.wait, &list);
 
+       rchan->desc.running = NULL;
+
        list_for_each_entry(desc, &list, node)
                rcar_dmac_realloc_hwdesc(rchan, desc, 0);
 
@@ -1143,19 +1145,46 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
        struct rcar_dmac_desc *desc = chan->desc.running;
        struct rcar_dmac_xfer_chunk *running = NULL;
        struct rcar_dmac_xfer_chunk *chunk;
+       enum dma_status status;
        unsigned int residue = 0;
        unsigned int dptr = 0;
 
        if (!desc)
                return 0;
 
+       /*
+        * If the cookie corresponds to a descriptor that has been completed
+        * there is no residue. The same check has already been performed by the
+        * caller but without holding the channel lock, so the descriptor could
+        * now be complete.
+        */
+       status = dma_cookie_status(&chan->chan, cookie, NULL);
+       if (status == DMA_COMPLETE)
+               return 0;
+
        /*
         * If the cookie doesn't correspond to the currently running transfer
         * then the descriptor hasn't been processed yet, and the residue is
         * equal to the full descriptor size.
         */
-       if (cookie != desc->async_tx.cookie)
-               return desc->size;
+       if (cookie != desc->async_tx.cookie) {
+               list_for_each_entry(desc, &chan->desc.pending, node) {
+                       if (cookie == desc->async_tx.cookie)
+                               return desc->size;
+               }
+               list_for_each_entry(desc, &chan->desc.active, node) {
+                       if (cookie == desc->async_tx.cookie)
+                               return desc->size;
+               }
+
+               /*
+                * No descriptor found for the cookie, there's thus no residue.
+                * This shouldn't happen if the calling driver passes a correct
+                * cookie value.
+                */
+               WARN(1, "No descriptor for cookie!");
+               return 0;
+       }
 
        /*
         * In descriptor mode the descriptor running pointer is not maintained
@@ -1202,6 +1231,10 @@ static enum dma_status rcar_dmac_tx_status(struct dma_chan *chan,
        residue = rcar_dmac_chan_get_residue(rchan, cookie);
        spin_unlock_irqrestore(&rchan->lock, flags);
 
+       /* if there's no residue, the cookie is complete */
+       if (!residue)
+               return DMA_COMPLETE;
+
        dma_set_residue(txstate, residue);
 
        return status;
index 80d86402490eef39b9873ad3b5a31a39f790973b..c94ffab0d25c756609b1d0c01733a4abc322a8a1 100644 (file)
@@ -532,11 +532,8 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
 
        sh_chan = devm_kzalloc(sdev->dma_dev.dev, sizeof(struct sh_dmae_chan),
                               GFP_KERNEL);
-       if (!sh_chan) {
-               dev_err(sdev->dma_dev.dev,
-                       "No free memory for allocating dma channels!\n");
+       if (!sh_chan)
                return -ENOMEM;
-       }
 
        schan = &sh_chan->shdma_chan;
        schan->max_xfer_len = SH_DMA_TCR_MAX + 1;
@@ -732,10 +729,8 @@ static int sh_dmae_probe(struct platform_device *pdev)
 
        shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device),
                             GFP_KERNEL);
-       if (!shdev) {
-               dev_err(&pdev->dev, "Not enough memory\n");
+       if (!shdev)
                return -ENOMEM;
-       }
 
        dma_dev = &shdev->shdma_dev.dma_dev;
 
index 6da2eaa6c294e6018d481f8833ac7c3a379f607e..69b9564dc9d9cb2e68e2c3f9226075e40efd2b8d 100644 (file)
@@ -245,11 +245,8 @@ static int sudmac_chan_probe(struct sudmac_device *su_dev, int id, int irq,
        int err;
 
        sc = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_chan), GFP_KERNEL);
-       if (!sc) {
-               dev_err(sdev->dma_dev.dev,
-                       "No free memory for allocating dma channels!\n");
+       if (!sc)
                return -ENOMEM;
-       }
 
        schan = &sc->shdma_chan;
        schan->max_xfer_len = 64 * 1024 * 1024 - 1;
@@ -349,10 +346,8 @@ static int sudmac_probe(struct platform_device *pdev)
        err = -ENOMEM;
        su_dev = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_device),
                              GFP_KERNEL);
-       if (!su_dev) {
-               dev_err(&pdev->dev, "Not enough memory\n");
+       if (!su_dev)
                return err;
-       }
 
        dma_dev = &su_dev->shdma_dev.dma_dev;
 
index e48350e650899de4e6e6a90c275d1dd49c6ea582..d8bc3f2a71db1ad7dee743cd92999f970eb97832 100644 (file)
@@ -854,10 +854,9 @@ static int sirfsoc_dma_probe(struct platform_device *op)
        int ret, i;
 
        sdma = devm_kzalloc(dev, sizeof(*sdma), GFP_KERNEL);
-       if (!sdma) {
-               dev_err(dev, "Memory exhausted!\n");
+       if (!sdma)
                return -ENOMEM;
-       }
+
        data = (struct sirfsoc_dmadata *)
                (of_match_device(op->dev.driver->of_match_table,
                                 &op->dev)->data);
@@ -981,6 +980,7 @@ static int sirfsoc_dma_remove(struct platform_device *op)
        of_dma_controller_free(op->dev.of_node);
        dma_async_device_unregister(&sdma->dma);
        free_irq(sdma->irq, sdma);
+       tasklet_kill(&sdma->tasklet);
        irq_dispose_mapping(sdma->irq);
        pm_runtime_disable(&op->dev);
        if (!pm_runtime_status_suspended(&op->dev))
@@ -1126,17 +1126,17 @@ static const struct dev_pm_ops sirfsoc_dma_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_dma_pm_suspend, sirfsoc_dma_pm_resume)
 };
 
-struct sirfsoc_dmadata sirfsoc_dmadata_a6 = {
+static struct sirfsoc_dmadata sirfsoc_dmadata_a6 = {
        .exec = sirfsoc_dma_execute_hw_a6,
        .type = SIRFSOC_DMA_VER_A6,
 };
 
-struct sirfsoc_dmadata sirfsoc_dmadata_a7v1 = {
+static struct sirfsoc_dmadata sirfsoc_dmadata_a7v1 = {
        .exec = sirfsoc_dma_execute_hw_a7v1,
        .type = SIRFSOC_DMA_VER_A7V1,
 };
 
-struct sirfsoc_dmadata sirfsoc_dmadata_a7v2 = {
+static struct sirfsoc_dmadata sirfsoc_dmadata_a7v2 = {
        .exec = sirfsoc_dma_execute_hw_a7v2,
        .type = SIRFSOC_DMA_VER_A7V2,
 };
index 6fb8307468ab60b847dab3c21f2899cd99876c69..8b18e44a02d51438809216a6d1b16e002d60fbde 100644 (file)
@@ -2588,7 +2588,7 @@ static enum dma_status d40_tx_status(struct dma_chan *chan,
        }
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret != DMA_COMPLETE)
+       if (ret != DMA_COMPLETE && txstate)
                dma_set_residue(txstate, stedma40_residue(chan));
 
        if (d40_is_paused(d40c))
@@ -3237,10 +3237,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
                       (num_phy_chans + num_log_chans + num_memcpy_chans) *
                       sizeof(struct d40_chan), GFP_KERNEL);
 
-       if (base == NULL) {
-               d40_err(&pdev->dev, "Out of memory\n");
+       if (base == NULL)
                goto failure;
-       }
 
        base->rev = rev;
        base->clk = clk;
index 27b818dee7c7f85b5aa730d4db81b9fa4f231782..13b42dd9900c5136bcc6ee6048e2d7086f108bdc 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "ste_dma40_ll.h"
 
-u8 d40_width_to_bits(enum dma_slave_buswidth width)
+static u8 d40_width_to_bits(enum dma_slave_buswidth width)
 {
        if (width == DMA_SLAVE_BUSWIDTH_1_BYTE)
                return STEDMA40_ESIZE_8_BIT;
index 5065ca43facede040f92a2ac64fa35c147675fe3..3835fcde35456fb20e89e77d5b02644b98df4df8 100644 (file)
@@ -865,7 +865,7 @@ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan,
        size_t bytes = 0;
 
        ret = dma_cookie_status(chan, cookie, state);
-       if (ret == DMA_COMPLETE)
+       if (ret == DMA_COMPLETE || !state)
                return ret;
 
        spin_lock_irqsave(&vchan->vc.lock, flags);
index 01e316f73559ceb2c45dc487f1972b9c0f0a680e..6ab9eb98588a88514f64f4b1221d87da3ecc4721 100644 (file)
@@ -300,10 +300,8 @@ static struct tegra_dma_desc *tegra_dma_desc_get(
 
        /* Allocate DMA desc */
        dma_desc = kzalloc(sizeof(*dma_desc), GFP_NOWAIT);
-       if (!dma_desc) {
-               dev_err(tdc2dev(tdc), "dma_desc alloc failed\n");
+       if (!dma_desc)
                return NULL;
-       }
 
        dma_async_tx_descriptor_init(&dma_desc->txd, &tdc->dma_chan);
        dma_desc->txd.tx_submit = tegra_dma_tx_submit;
@@ -340,8 +338,7 @@ static struct tegra_dma_sg_req *tegra_dma_sg_req_get(
        spin_unlock_irqrestore(&tdc->lock, flags);
 
        sg_req = kzalloc(sizeof(struct tegra_dma_sg_req), GFP_NOWAIT);
-       if (!sg_req)
-               dev_err(tdc2dev(tdc), "sg_req alloc failed\n");
+
        return sg_req;
 }
 
@@ -484,7 +481,7 @@ static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc,
         * load new configuration.
         */
        tegra_dma_pause(tdc, false);
-       status  = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+       status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
 
        /*
         * If interrupt is pending then do nothing as the ISR will handle
@@ -822,13 +819,8 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
        /* Check on wait_ack desc status */
        list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) {
                if (dma_desc->txd.cookie == cookie) {
-                       residual =  dma_desc->bytes_requested -
-                                       (dma_desc->bytes_transferred %
-                                               dma_desc->bytes_requested);
-                       dma_set_residue(txstate, residual);
                        ret = dma_desc->dma_status;
-                       spin_unlock_irqrestore(&tdc->lock, flags);
-                       return ret;
+                       goto found;
                }
        }
 
@@ -836,17 +828,22 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
        list_for_each_entry(sg_req, &tdc->pending_sg_req, node) {
                dma_desc = sg_req->dma_desc;
                if (dma_desc->txd.cookie == cookie) {
-                       residual =  dma_desc->bytes_requested -
-                                       (dma_desc->bytes_transferred %
-                                               dma_desc->bytes_requested);
-                       dma_set_residue(txstate, residual);
                        ret = dma_desc->dma_status;
-                       spin_unlock_irqrestore(&tdc->lock, flags);
-                       return ret;
+                       goto found;
                }
        }
 
-       dev_dbg(tdc2dev(tdc), "cookie %d does not found\n", cookie);
+       dev_dbg(tdc2dev(tdc), "cookie %d not found\n", cookie);
+       dma_desc = NULL;
+
+found:
+       if (dma_desc && txstate) {
+               residual = dma_desc->bytes_requested -
+                          (dma_desc->bytes_transferred %
+                           dma_desc->bytes_requested);
+               dma_set_residue(txstate, residual);
+       }
+
        spin_unlock_irqrestore(&tdc->lock, flags);
        return ret;
 }
@@ -905,7 +902,6 @@ static int get_transfer_param(struct tegra_dma_channel *tdc,
        unsigned long *apb_seq, unsigned long *csr, unsigned int *burst_size,
        enum dma_slave_buswidth *slave_bw)
 {
-
        switch (direction) {
        case DMA_MEM_TO_DEV:
                *apb_addr = tdc->dma_sconfig.dst_addr;
@@ -948,8 +944,8 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
        struct tegra_dma_desc *dma_desc;
-       unsigned int        i;
-       struct scatterlist      *sg;
+       unsigned int i;
+       struct scatterlist *sg;
        unsigned long csr, ahb_seq, apb_ptr, apb_seq;
        struct list_head req_list;
        struct tegra_dma_sg_req  *sg_req = NULL;
@@ -1062,7 +1058,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
        struct tegra_dma_desc *dma_desc = NULL;
-       struct tegra_dma_sg_req  *sg_req = NULL;
+       struct tegra_dma_sg_req *sg_req = NULL;
        unsigned long csr, ahb_seq, apb_ptr, apb_seq;
        int len;
        size_t remain_len;
@@ -1204,7 +1200,6 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
        struct tegra_dma *tdma = tdc->tdma;
-
        struct tegra_dma_desc *dma_desc;
        struct tegra_dma_sg_req *sg_req;
        struct list_head dma_desc_list;
@@ -1305,7 +1300,7 @@ static const struct tegra_dma_chip_data tegra148_dma_chip_data = {
 
 static int tegra_dma_probe(struct platform_device *pdev)
 {
-       struct resource *res;
+       struct resource *res;
        struct tegra_dma *tdma;
        int ret;
        int i;
@@ -1319,10 +1314,8 @@ static int tegra_dma_probe(struct platform_device *pdev)
 
        tdma = devm_kzalloc(&pdev->dev, sizeof(*tdma) + cdata->nr_channels *
                        sizeof(struct tegra_dma_channel), GFP_KERNEL);
-       if (!tdma) {
-               dev_err(&pdev->dev, "Error: memory allocation failed\n");
+       if (!tdma)
                return -ENOMEM;
-       }
 
        tdma->dev = &pdev->dev;
        tdma->chip_data = cdata;
index e107779b1a2e81392e135c45a7513052bbaa0545..5ae294b256a7e45e6480b74c3c1cccc9cb480ba8 100644 (file)
@@ -452,7 +452,7 @@ static struct platform_driver ti_dma_xbar_driver = {
        .probe  = ti_dma_xbar_probe,
 };
 
-int omap_dmaxbar_init(void)
+static int omap_dmaxbar_init(void)
 {
        return platform_driver_register(&ti_dma_xbar_driver);
 }
index 559cd4073698ce806bf448274af6458bdb89ff83..e82745aa42a8bfc5deaecfb62f39d1b2a2972278 100644 (file)
@@ -337,18 +337,14 @@ static struct timb_dma_desc *td_alloc_init_desc(struct timb_dma_chan *td_chan)
        int err;
 
        td_desc = kzalloc(sizeof(struct timb_dma_desc), GFP_KERNEL);
-       if (!td_desc) {
-               dev_err(chan2dev(chan), "Failed to alloc descriptor\n");
+       if (!td_desc)
                goto out;
-       }
 
        td_desc->desc_list_len = td_chan->desc_elems * TIMB_DMA_DESC_SIZE;
 
        td_desc->desc_list = kzalloc(td_desc->desc_list_len, GFP_KERNEL);
-       if (!td_desc->desc_list) {
-               dev_err(chan2dev(chan), "Failed to alloc descriptor\n");
+       if (!td_desc->desc_list)
                goto err;
-       }
 
        dma_async_tx_descriptor_init(&td_desc->txd, chan);
        td_desc->txd.tx_submit = td_tx_submit;
index 8849318b32b7ab5b48f14ea8304027f8a0da7fd9..7632290e7c1438ff331a79c2750041366c352366 100644 (file)
@@ -1165,9 +1165,12 @@ static int txx9dmac_chan_remove(struct platform_device *pdev)
 {
        struct txx9dmac_chan *dc = platform_get_drvdata(pdev);
 
+
        dma_async_device_unregister(&dc->dma);
-       if (dc->irq >= 0)
+       if (dc->irq >= 0) {
+               devm_free_irq(&pdev->dev, dc->irq, dc);
                tasklet_kill(&dc->tasklet);
+       }
        dc->ddev->chan[pdev->id % TXX9_DMA_MAX_NR_CHANNELS] = NULL;
        return 0;
 }
@@ -1228,8 +1231,10 @@ static int txx9dmac_remove(struct platform_device *pdev)
        struct txx9dmac_dev *ddev = platform_get_drvdata(pdev);
 
        txx9dmac_off(ddev);
-       if (ddev->irq >= 0)
+       if (ddev->irq >= 0) {
+               devm_free_irq(&pdev->dev, ddev->irq, ddev);
                tasklet_kill(&ddev->tasklet);
+       }
        return 0;
 }
 
index 3c4e9f2fea2871dce7b300a345ac20531ecdf3a4..9e91f8f5b087a8cf5baa57a73305669225fb5f08 100644 (file)
@@ -1 +1,2 @@
-obj-$(CONFIG_XILINX_VDMA) += xilinx_vdma.o
+obj-$(CONFIG_XILINX_DMA) += xilinx_dma.o
+obj-$(CONFIG_XILINX_ZYNQMP_DMA) += zynqmp_dma.o
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
new file mode 100644 (file)
index 0000000..4e223d0
--- /dev/null
@@ -0,0 +1,2689 @@
+/*
+ * DMA driver for Xilinx Video DMA Engine
+ *
+ * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
+ *
+ * Based on the Freescale DMA driver.
+ *
+ * Description:
+ * The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP
+ * core that provides high-bandwidth direct memory access between memory
+ * and AXI4-Stream type video target peripherals. The core provides efficient
+ * two dimensional DMA operations with independent asynchronous read (S2MM)
+ * and write (MM2S) channel operation. It can be configured to have either
+ * one channel or two channels. If configured as two channels, one is to
+ * transmit to the video device (MM2S) and another is to receive from the
+ * video device (S2MM). Initialization, status, interrupt and management
+ * registers are accessed through an AXI4-Lite slave interface.
+ *
+ * The AXI Direct Memory Access (AXI DMA) core is a soft Xilinx IP core that
+ * provides high-bandwidth one dimensional direct memory access between memory
+ * and AXI4-Stream target peripherals. It supports one receive and one
+ * transmit channel, both of them optional at synthesis time.
+ *
+ * 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.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/dmapool.h>
+#include <linux/dma/xilinx_dma.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_dma.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+#include "../dmaengine.h"
+
+/* Register/Descriptor Offsets */
+#define XILINX_DMA_MM2S_CTRL_OFFSET            0x0000
+#define XILINX_DMA_S2MM_CTRL_OFFSET            0x0030
+#define XILINX_VDMA_MM2S_DESC_OFFSET           0x0050
+#define XILINX_VDMA_S2MM_DESC_OFFSET           0x00a0
+
+/* Control Registers */
+#define XILINX_DMA_REG_DMACR                   0x0000
+#define XILINX_DMA_DMACR_DELAY_MAX             0xff
+#define XILINX_DMA_DMACR_DELAY_SHIFT           24
+#define XILINX_DMA_DMACR_FRAME_COUNT_MAX       0xff
+#define XILINX_DMA_DMACR_FRAME_COUNT_SHIFT     16
+#define XILINX_DMA_DMACR_ERR_IRQ               BIT(14)
+#define XILINX_DMA_DMACR_DLY_CNT_IRQ           BIT(13)
+#define XILINX_DMA_DMACR_FRM_CNT_IRQ           BIT(12)
+#define XILINX_DMA_DMACR_MASTER_SHIFT          8
+#define XILINX_DMA_DMACR_FSYNCSRC_SHIFT        5
+#define XILINX_DMA_DMACR_FRAMECNT_EN           BIT(4)
+#define XILINX_DMA_DMACR_GENLOCK_EN            BIT(3)
+#define XILINX_DMA_DMACR_RESET                 BIT(2)
+#define XILINX_DMA_DMACR_CIRC_EN               BIT(1)
+#define XILINX_DMA_DMACR_RUNSTOP               BIT(0)
+#define XILINX_DMA_DMACR_FSYNCSRC_MASK         GENMASK(6, 5)
+
+#define XILINX_DMA_REG_DMASR                   0x0004
+#define XILINX_DMA_DMASR_EOL_LATE_ERR          BIT(15)
+#define XILINX_DMA_DMASR_ERR_IRQ               BIT(14)
+#define XILINX_DMA_DMASR_DLY_CNT_IRQ           BIT(13)
+#define XILINX_DMA_DMASR_FRM_CNT_IRQ           BIT(12)
+#define XILINX_DMA_DMASR_SOF_LATE_ERR          BIT(11)
+#define XILINX_DMA_DMASR_SG_DEC_ERR            BIT(10)
+#define XILINX_DMA_DMASR_SG_SLV_ERR            BIT(9)
+#define XILINX_DMA_DMASR_EOF_EARLY_ERR         BIT(8)
+#define XILINX_DMA_DMASR_SOF_EARLY_ERR         BIT(7)
+#define XILINX_DMA_DMASR_DMA_DEC_ERR           BIT(6)
+#define XILINX_DMA_DMASR_DMA_SLAVE_ERR         BIT(5)
+#define XILINX_DMA_DMASR_DMA_INT_ERR           BIT(4)
+#define XILINX_DMA_DMASR_IDLE                  BIT(1)
+#define XILINX_DMA_DMASR_HALTED                BIT(0)
+#define XILINX_DMA_DMASR_DELAY_MASK            GENMASK(31, 24)
+#define XILINX_DMA_DMASR_FRAME_COUNT_MASK      GENMASK(23, 16)
+
+#define XILINX_DMA_REG_CURDESC                 0x0008
+#define XILINX_DMA_REG_TAILDESC                0x0010
+#define XILINX_DMA_REG_REG_INDEX               0x0014
+#define XILINX_DMA_REG_FRMSTORE                0x0018
+#define XILINX_DMA_REG_THRESHOLD               0x001c
+#define XILINX_DMA_REG_FRMPTR_STS              0x0024
+#define XILINX_DMA_REG_PARK_PTR                0x0028
+#define XILINX_DMA_PARK_PTR_WR_REF_SHIFT       8
+#define XILINX_DMA_PARK_PTR_RD_REF_SHIFT       0
+#define XILINX_DMA_REG_VDMA_VERSION            0x002c
+
+/* Register Direct Mode Registers */
+#define XILINX_DMA_REG_VSIZE                   0x0000
+#define XILINX_DMA_REG_HSIZE                   0x0004
+
+#define XILINX_DMA_REG_FRMDLY_STRIDE           0x0008
+#define XILINX_DMA_FRMDLY_STRIDE_FRMDLY_SHIFT  24
+#define XILINX_DMA_FRMDLY_STRIDE_STRIDE_SHIFT  0
+
+#define XILINX_VDMA_REG_START_ADDRESS(n)       (0x000c + 4 * (n))
+#define XILINX_VDMA_REG_START_ADDRESS_64(n)    (0x000c + 8 * (n))
+
+/* HW specific definitions */
+#define XILINX_DMA_MAX_CHANS_PER_DEVICE        0x20
+
+#define XILINX_DMA_DMAXR_ALL_IRQ_MASK  \
+               (XILINX_DMA_DMASR_FRM_CNT_IRQ | \
+                XILINX_DMA_DMASR_DLY_CNT_IRQ | \
+                XILINX_DMA_DMASR_ERR_IRQ)
+
+#define XILINX_DMA_DMASR_ALL_ERR_MASK  \
+               (XILINX_DMA_DMASR_EOL_LATE_ERR | \
+                XILINX_DMA_DMASR_SOF_LATE_ERR | \
+                XILINX_DMA_DMASR_SG_DEC_ERR | \
+                XILINX_DMA_DMASR_SG_SLV_ERR | \
+                XILINX_DMA_DMASR_EOF_EARLY_ERR | \
+                XILINX_DMA_DMASR_SOF_EARLY_ERR | \
+                XILINX_DMA_DMASR_DMA_DEC_ERR | \
+                XILINX_DMA_DMASR_DMA_SLAVE_ERR | \
+                XILINX_DMA_DMASR_DMA_INT_ERR)
+
+/*
+ * Recoverable errors are DMA Internal error, SOF Early, EOF Early
+ * and SOF Late. They are only recoverable when C_FLUSH_ON_FSYNC
+ * is enabled in the h/w system.
+ */
+#define XILINX_DMA_DMASR_ERR_RECOVER_MASK      \
+               (XILINX_DMA_DMASR_SOF_LATE_ERR | \
+                XILINX_DMA_DMASR_EOF_EARLY_ERR | \
+                XILINX_DMA_DMASR_SOF_EARLY_ERR | \
+                XILINX_DMA_DMASR_DMA_INT_ERR)
+
+/* Axi VDMA Flush on Fsync bits */
+#define XILINX_DMA_FLUSH_S2MM          3
+#define XILINX_DMA_FLUSH_MM2S          2
+#define XILINX_DMA_FLUSH_BOTH          1
+
+/* Delay loop counter to prevent hardware failure */
+#define XILINX_DMA_LOOP_COUNT          1000000
+
+/* AXI DMA Specific Registers/Offsets */
+#define XILINX_DMA_REG_SRCDSTADDR      0x18
+#define XILINX_DMA_REG_BTT             0x28
+
+/* AXI DMA Specific Masks/Bit fields */
+#define XILINX_DMA_MAX_TRANS_LEN       GENMASK(22, 0)
+#define XILINX_DMA_CR_COALESCE_MAX     GENMASK(23, 16)
+#define XILINX_DMA_CR_CYCLIC_BD_EN_MASK        BIT(4)
+#define XILINX_DMA_CR_COALESCE_SHIFT   16
+#define XILINX_DMA_BD_SOP              BIT(27)
+#define XILINX_DMA_BD_EOP              BIT(26)
+#define XILINX_DMA_COALESCE_MAX                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
+
+/* AXI CDMA Specific Masks */
+#define XILINX_CDMA_CR_SGMODE          BIT(3)
+
+/**
+ * struct xilinx_vdma_desc_hw - Hardware Descriptor
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @pad1: Reserved @0x04
+ * @buf_addr: Buffer address @0x08
+ * @buf_addr_msb: MSB of Buffer address @0x0C
+ * @vsize: Vertical Size @0x10
+ * @hsize: Horizontal Size @0x14
+ * @stride: Number of bytes between the first
+ *         pixels of each horizontal line @0x18
+ */
+struct xilinx_vdma_desc_hw {
+       u32 next_desc;
+       u32 pad1;
+       u32 buf_addr;
+       u32 buf_addr_msb;
+       u32 vsize;
+       u32 hsize;
+       u32 stride;
+} __aligned(64);
+
+/**
+ * struct xilinx_axidma_desc_hw - Hardware Descriptor for AXI DMA
+ * @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
+ * @pad1: Reserved @0x10
+ * @pad2: Reserved @0x14
+ * @control: Control field @0x18
+ * @status: Status field @0x1C
+ * @app: APP Fields @0x20 - 0x30
+ */
+struct xilinx_axidma_desc_hw {
+       u32 next_desc;
+       u32 next_desc_msb;
+       u32 buf_addr;
+       u32 buf_addr_msb;
+       u32 mcdma_control;
+       u32 vsize_stride;
+       u32 control;
+       u32 status;
+       u32 app[XILINX_DMA_NUM_APP_WORDS];
+} __aligned(64);
+
+/**
+ * struct xilinx_cdma_desc_hw - Hardware Descriptor
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @next_descmsb: Next Descriptor Pointer MSB @0x04
+ * @src_addr: Source address @0x08
+ * @src_addrmsb: Source address MSB @0x0C
+ * @dest_addr: Destination address @0x10
+ * @dest_addrmsb: Destination address MSB @0x14
+ * @control: Control field @0x18
+ * @status: Status field @0x1C
+ */
+struct xilinx_cdma_desc_hw {
+       u32 next_desc;
+       u32 next_desc_msb;
+       u32 src_addr;
+       u32 src_addr_msb;
+       u32 dest_addr;
+       u32 dest_addr_msb;
+       u32 control;
+       u32 status;
+} __aligned(64);
+
+/**
+ * struct xilinx_vdma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_vdma_tx_segment {
+       struct xilinx_vdma_desc_hw hw;
+       struct list_head node;
+       dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_axidma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_axidma_tx_segment {
+       struct xilinx_axidma_desc_hw hw;
+       struct list_head node;
+       dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_cdma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_cdma_tx_segment {
+       struct xilinx_cdma_desc_hw hw;
+       struct list_head node;
+       dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_dma_tx_descriptor - Per Transaction structure
+ * @async_tx: Async transaction descriptor
+ * @segments: TX segments list
+ * @node: Node in the channel descriptors list
+ * @cyclic: Check for cyclic transfers.
+ */
+struct xilinx_dma_tx_descriptor {
+       struct dma_async_tx_descriptor async_tx;
+       struct list_head segments;
+       struct list_head node;
+       bool cyclic;
+};
+
+/**
+ * struct xilinx_dma_chan - Driver specific DMA channel structure
+ * @xdev: Driver specific device structure
+ * @ctrl_offset: Control registers offset
+ * @desc_offset: TX descriptor registers offset
+ * @lock: Descriptor operation lock
+ * @pending_list: Descriptors waiting
+ * @active_list: Descriptors ready to submit
+ * @done_list: Complete descriptors
+ * @common: DMA common channel
+ * @desc_pool: Descriptors pool
+ * @dev: The dma device
+ * @irq: Channel IRQ
+ * @id: Channel ID
+ * @direction: Transfer direction
+ * @num_frms: Number of frames
+ * @has_sg: Support scatter transfers
+ * @cyclic: Check for cyclic transfers.
+ * @genlock: Support genlock mode
+ * @err: Channel has errors
+ * @tasklet: Cleanup work after irq
+ * @config: Device configuration info
+ * @flush_on_fsync: Flush on Frame sync
+ * @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
+ * @cyclic_seg_v: Statically allocated segment base for cyclic transfers
+ * @start_transfer: Differentiate b/w DMA IP's transfer
+ */
+struct xilinx_dma_chan {
+       struct xilinx_dma_device *xdev;
+       u32 ctrl_offset;
+       u32 desc_offset;
+       spinlock_t lock;
+       struct list_head pending_list;
+       struct list_head active_list;
+       struct list_head done_list;
+       struct dma_chan common;
+       struct dma_pool *desc_pool;
+       struct device *dev;
+       int irq;
+       int id;
+       enum dma_transfer_direction direction;
+       int num_frms;
+       bool has_sg;
+       bool cyclic;
+       bool genlock;
+       bool err;
+       struct tasklet_struct tasklet;
+       struct xilinx_vdma_config config;
+       bool flush_on_fsync;
+       u32 desc_pendingcount;
+       bool ext_addr;
+       u32 desc_submitcount;
+       u32 residue;
+       struct xilinx_axidma_tx_segment *seg_v;
+       struct xilinx_axidma_tx_segment *cyclic_seg_v;
+       void (*start_transfer)(struct xilinx_dma_chan *chan);
+       u16 tdest;
+};
+
+struct xilinx_dma_config {
+       enum xdma_ip_type dmatype;
+       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);
+};
+
+/**
+ * struct xilinx_dma_device - DMA device structure
+ * @regs: I/O mapped base address
+ * @dev: Device Structure
+ * @common: DMA device structure
+ * @chan: Driver specific DMA channel
+ * @has_sg: Specifies whether Scatter-Gather is present or not
+ * @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
+ * @dma_config: DMA config structure
+ * @axi_clk: DMA Axi4-lite interace clock
+ * @tx_clk: DMA mm2s clock
+ * @txs_clk: DMA mm2s stream clock
+ * @rx_clk: DMA s2mm clock
+ * @rxs_clk: DMA s2mm stream clock
+ * @nr_channels: Number of channels DMA device supports
+ * @chan_id: DMA channel identifier
+ */
+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 has_sg;
+       bool mcdma;
+       u32 flush_on_fsync;
+       bool ext_addr;
+       struct platform_device  *pdev;
+       const struct xilinx_dma_config *dma_config;
+       struct clk *axi_clk;
+       struct clk *tx_clk;
+       struct clk *txs_clk;
+       struct clk *rx_clk;
+       struct clk *rxs_clk;
+       u32 nr_channels;
+       u32 chan_id;
+};
+
+/* Macros */
+#define to_xilinx_chan(chan) \
+       container_of(chan, struct xilinx_dma_chan, common)
+#define to_dma_tx_descriptor(tx) \
+       container_of(tx, struct xilinx_dma_tx_descriptor, async_tx)
+#define xilinx_dma_poll_timeout(chan, reg, val, cond, delay_us, timeout_us) \
+       readl_poll_timeout(chan->xdev->regs + chan->ctrl_offset + reg, val, \
+                          cond, delay_us, timeout_us)
+
+/* IO accessors */
+static inline u32 dma_read(struct xilinx_dma_chan *chan, u32 reg)
+{
+       return ioread32(chan->xdev->regs + reg);
+}
+
+static inline void dma_write(struct xilinx_dma_chan *chan, u32 reg, u32 value)
+{
+       iowrite32(value, chan->xdev->regs + reg);
+}
+
+static inline void vdma_desc_write(struct xilinx_dma_chan *chan, u32 reg,
+                                  u32 value)
+{
+       dma_write(chan, chan->desc_offset + reg, value);
+}
+
+static inline u32 dma_ctrl_read(struct xilinx_dma_chan *chan, u32 reg)
+{
+       return dma_read(chan, chan->ctrl_offset + reg);
+}
+
+static inline void dma_ctrl_write(struct xilinx_dma_chan *chan, u32 reg,
+                                  u32 value)
+{
+       dma_write(chan, chan->ctrl_offset + reg, value);
+}
+
+static inline void dma_ctrl_clr(struct xilinx_dma_chan *chan, u32 reg,
+                                u32 clr)
+{
+       dma_ctrl_write(chan, reg, dma_ctrl_read(chan, reg) & ~clr);
+}
+
+static inline void dma_ctrl_set(struct xilinx_dma_chan *chan, u32 reg,
+                                u32 set)
+{
+       dma_ctrl_write(chan, reg, dma_ctrl_read(chan, reg) | set);
+}
+
+/**
+ * vdma_desc_write_64 - 64-bit descriptor write
+ * @chan: Driver specific VDMA channel
+ * @reg: Register to write
+ * @value_lsb: lower address of the descriptor.
+ * @value_msb: upper address of the descriptor.
+ *
+ * Since vdma driver is trying to write to a register offset which is not a
+ * multiple of 64 bits(ex : 0x5c), we are writing as two separate 32 bits
+ * instead of a single 64 bit register write.
+ */
+static inline void vdma_desc_write_64(struct xilinx_dma_chan *chan, u32 reg,
+                                     u32 value_lsb, u32 value_msb)
+{
+       /* Write the lsb 32 bits*/
+       writel(value_lsb, chan->xdev->regs + chan->desc_offset + reg);
+
+       /* Write the msb 32 bits */
+       writel(value_msb, chan->xdev->regs + chan->desc_offset + reg + 4);
+}
+
+static inline void dma_writeq(struct xilinx_dma_chan *chan, u32 reg, u64 value)
+{
+       lo_hi_writeq(value, chan->xdev->regs + chan->ctrl_offset + reg);
+}
+
+static inline void xilinx_write(struct xilinx_dma_chan *chan, u32 reg,
+                               dma_addr_t addr)
+{
+       if (chan->ext_addr)
+               dma_writeq(chan, reg, addr);
+       else
+               dma_ctrl_write(chan, reg, addr);
+}
+
+static inline void xilinx_axidma_buf(struct xilinx_dma_chan *chan,
+                                    struct xilinx_axidma_desc_hw *hw,
+                                    dma_addr_t buf_addr, size_t sg_used,
+                                    size_t period_len)
+{
+       if (chan->ext_addr) {
+               hw->buf_addr = lower_32_bits(buf_addr + sg_used + period_len);
+               hw->buf_addr_msb = upper_32_bits(buf_addr + sg_used +
+                                                period_len);
+       } else {
+               hw->buf_addr = buf_addr + sg_used + period_len;
+       }
+}
+
+/* -----------------------------------------------------------------------------
+ * Descriptors and segments alloc and free
+ */
+
+/**
+ * xilinx_vdma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_vdma_tx_segment *
+xilinx_vdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_vdma_tx_segment *segment;
+       dma_addr_t phys;
+
+       segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys);
+       if (!segment)
+               return NULL;
+
+       segment->phys = phys;
+
+       return segment;
+}
+
+/**
+ * xilinx_cdma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_cdma_tx_segment *
+xilinx_cdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_cdma_tx_segment *segment;
+       dma_addr_t phys;
+
+       segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys);
+       if (!segment)
+               return NULL;
+
+       segment->phys = phys;
+
+       return segment;
+}
+
+/**
+ * xilinx_axidma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_axidma_tx_segment *
+xilinx_axidma_alloc_tx_segment(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_axidma_tx_segment *segment;
+       dma_addr_t phys;
+
+       segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys);
+       if (!segment)
+               return NULL;
+
+       segment->phys = phys;
+
+       return segment;
+}
+
+/**
+ * xilinx_dma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific DMA channel
+ * @segment: DMA transaction segment
+ */
+static void xilinx_dma_free_tx_segment(struct xilinx_dma_chan *chan,
+                               struct xilinx_axidma_tx_segment *segment)
+{
+       dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_cdma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific DMA channel
+ * @segment: DMA transaction segment
+ */
+static void xilinx_cdma_free_tx_segment(struct xilinx_dma_chan *chan,
+                               struct xilinx_cdma_tx_segment *segment)
+{
+       dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_vdma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific DMA channel
+ * @segment: DMA transaction segment
+ */
+static void xilinx_vdma_free_tx_segment(struct xilinx_dma_chan *chan,
+                                       struct xilinx_vdma_tx_segment *segment)
+{
+       dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_dma_tx_descriptor - Allocate transaction descriptor
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated descriptor on success and NULL on failure.
+ */
+static struct xilinx_dma_tx_descriptor *
+xilinx_dma_alloc_tx_descriptor(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *desc;
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return NULL;
+
+       INIT_LIST_HEAD(&desc->segments);
+
+       return desc;
+}
+
+/**
+ * xilinx_dma_free_tx_descriptor - Free transaction descriptor
+ * @chan: Driver specific DMA channel
+ * @desc: DMA transaction descriptor
+ */
+static void
+xilinx_dma_free_tx_descriptor(struct xilinx_dma_chan *chan,
+                              struct xilinx_dma_tx_descriptor *desc)
+{
+       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;
+
+       if (!desc)
+               return;
+
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+               list_for_each_entry_safe(segment, next, &desc->segments, node) {
+                       list_del(&segment->node);
+                       xilinx_vdma_free_tx_segment(chan, segment);
+               }
+       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+               list_for_each_entry_safe(cdma_segment, cdma_next,
+                                        &desc->segments, node) {
+                       list_del(&cdma_segment->node);
+                       xilinx_cdma_free_tx_segment(chan, cdma_segment);
+               }
+       } else {
+               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);
+               }
+       }
+
+       kfree(desc);
+}
+
+/* Required functions */
+
+/**
+ * xilinx_dma_free_desc_list - Free descriptors list
+ * @chan: Driver specific DMA channel
+ * @list: List to parse and delete the descriptor
+ */
+static void xilinx_dma_free_desc_list(struct xilinx_dma_chan *chan,
+                                       struct list_head *list)
+{
+       struct xilinx_dma_tx_descriptor *desc, *next;
+
+       list_for_each_entry_safe(desc, next, list, node) {
+               list_del(&desc->node);
+               xilinx_dma_free_tx_descriptor(chan, desc);
+       }
+}
+
+/**
+ * xilinx_dma_free_descriptors - Free channel descriptors
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_free_descriptors(struct xilinx_dma_chan *chan)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       xilinx_dma_free_desc_list(chan, &chan->pending_list);
+       xilinx_dma_free_desc_list(chan, &chan->done_list);
+       xilinx_dma_free_desc_list(chan, &chan->active_list);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_dma_free_chan_resources - Free channel resources
+ * @dchan: DMA channel
+ */
+static void xilinx_dma_free_chan_resources(struct dma_chan *dchan)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+
+       dev_dbg(chan->dev, "Free all channel resources.\n");
+
+       xilinx_dma_free_descriptors(chan);
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               xilinx_dma_free_tx_segment(chan, chan->cyclic_seg_v);
+               xilinx_dma_free_tx_segment(chan, chan->seg_v);
+       }
+       dma_pool_destroy(chan->desc_pool);
+       chan->desc_pool = NULL;
+}
+
+/**
+ * xilinx_dma_chan_handle_cyclic - Cyclic dma callback
+ * @chan: Driver specific dma channel
+ * @desc: dma transaction descriptor
+ * @flags: flags for spin lock
+ */
+static void xilinx_dma_chan_handle_cyclic(struct xilinx_dma_chan *chan,
+                                         struct xilinx_dma_tx_descriptor *desc,
+                                         unsigned long *flags)
+{
+       dma_async_tx_callback callback;
+       void *callback_param;
+
+       callback = desc->async_tx.callback;
+       callback_param = desc->async_tx.callback_param;
+       if (callback) {
+               spin_unlock_irqrestore(&chan->lock, *flags);
+               callback(callback_param);
+               spin_lock_irqsave(&chan->lock, *flags);
+       }
+}
+
+/**
+ * xilinx_dma_chan_desc_cleanup - Clean channel descriptors
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *desc, *next;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+               dma_async_tx_callback callback;
+               void *callback_param;
+
+               if (desc->cyclic) {
+                       xilinx_dma_chan_handle_cyclic(chan, desc, &flags);
+                       break;
+               }
+
+               /* Remove from the list of running transactions */
+               list_del(&desc->node);
+
+               /* Run the link descriptor callback function */
+               callback = desc->async_tx.callback;
+               callback_param = desc->async_tx.callback_param;
+               if (callback) {
+                       spin_unlock_irqrestore(&chan->lock, flags);
+                       callback(callback_param);
+                       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);
+       }
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_dma_do_tasklet - Schedule completion tasklet
+ * @data: Pointer to the Xilinx DMA channel structure
+ */
+static void xilinx_dma_do_tasklet(unsigned long data)
+{
+       struct xilinx_dma_chan *chan = (struct xilinx_dma_chan *)data;
+
+       xilinx_dma_chan_desc_cleanup(chan);
+}
+
+/**
+ * xilinx_dma_alloc_chan_resources - Allocate channel resources
+ * @dchan: DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+
+       /* Has this channel already been allocated? */
+       if (chan->desc_pool)
+               return 0;
+
+       /*
+        * We need the descriptor to be aligned to 64bytes
+        * for meeting Xilinx VDMA specification requirement.
+        */
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               chan->desc_pool = dma_pool_create("xilinx_dma_desc_pool",
+                                  chan->dev,
+                                  sizeof(struct xilinx_axidma_tx_segment),
+                                  __alignof__(struct xilinx_axidma_tx_segment),
+                                  0);
+       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+               chan->desc_pool = dma_pool_create("xilinx_cdma_desc_pool",
+                                  chan->dev,
+                                  sizeof(struct xilinx_cdma_tx_segment),
+                                  __alignof__(struct xilinx_cdma_tx_segment),
+                                  0);
+       } else {
+               chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool",
+                                    chan->dev,
+                                    sizeof(struct xilinx_vdma_tx_segment),
+                                    __alignof__(struct xilinx_vdma_tx_segment),
+                                    0);
+       }
+
+       if (!chan->desc_pool) {
+               dev_err(chan->dev,
+                       "unable to allocate channel %d descriptor pool\n",
+                       chan->id);
+               return -ENOMEM;
+       }
+
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               /*
+                * For AXI DMA case after submitting a pending_list, keep
+                * an extra segment allocated so that the "next descriptor"
+                * pointer on the tail descriptor always points to a
+                * valid descriptor, even when paused after reaching taildesc.
+                * This way, it is possible to issue additional
+                * transfers without halting and restarting the channel.
+                */
+               chan->seg_v = xilinx_axidma_alloc_tx_segment(chan);
+
+               /*
+                * For cyclic DMA mode we need to program the tail Descriptor
+                * register with a value which is not a part of the BD chain
+                * so allocating a desc segment during channel allocation for
+                * programming tail descriptor.
+                */
+               chan->cyclic_seg_v = xilinx_axidma_alloc_tx_segment(chan);
+       }
+
+       dma_cookie_init(dchan);
+
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               /* For AXI DMA resetting once channel will reset the
+                * other channel as well so enable the interrupts here.
+                */
+               dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
+                             XILINX_DMA_DMAXR_ALL_IRQ_MASK);
+       }
+
+       if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
+               dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
+                            XILINX_CDMA_CR_SGMODE);
+
+       return 0;
+}
+
+/**
+ * xilinx_dma_tx_status - Get DMA transaction status
+ * @dchan: DMA channel
+ * @cookie: Transaction identifier
+ * @txstate: Transaction state
+ *
+ * Return: DMA transaction status
+ */
+static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
+                                       dma_cookie_t cookie,
+                                       struct dma_tx_state *txstate)
+{
+       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;
+
+       ret = dma_cookie_status(dchan, cookie, txstate);
+       if (ret == DMA_COMPLETE || !txstate)
+               return ret;
+
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               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) &
+                                          XILINX_DMA_MAX_TRANS_LEN;
+                       }
+               }
+               spin_unlock_irqrestore(&chan->lock, flags);
+
+               chan->residue = residue;
+               dma_set_residue(txstate, chan->residue);
+       }
+
+       return ret;
+}
+
+/**
+ * xilinx_dma_is_running - Check if DMA channel is running
+ * @chan: Driver specific DMA channel
+ *
+ * Return: '1' if running, '0' if not.
+ */
+static bool xilinx_dma_is_running(struct xilinx_dma_chan *chan)
+{
+       return !(dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
+                XILINX_DMA_DMASR_HALTED) &&
+               (dma_ctrl_read(chan, XILINX_DMA_REG_DMACR) &
+                XILINX_DMA_DMACR_RUNSTOP);
+}
+
+/**
+ * xilinx_dma_is_idle - Check if DMA channel is idle
+ * @chan: Driver specific DMA channel
+ *
+ * Return: '1' if idle, '0' if not.
+ */
+static bool xilinx_dma_is_idle(struct xilinx_dma_chan *chan)
+{
+       return dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
+               XILINX_DMA_DMASR_IDLE;
+}
+
+/**
+ * xilinx_dma_halt - Halt DMA channel
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_halt(struct xilinx_dma_chan *chan)
+{
+       int err;
+       u32 val;
+
+       dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP);
+
+       /* Wait for the hardware to halt */
+       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
+                                     (val & XILINX_DMA_DMASR_HALTED), 0,
+                                     XILINX_DMA_LOOP_COUNT);
+
+       if (err) {
+               dev_err(chan->dev, "Cannot stop channel %p: %x\n",
+                       chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
+               chan->err = true;
+       }
+}
+
+/**
+ * xilinx_dma_start - Start DMA channel
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_start(struct xilinx_dma_chan *chan)
+{
+       int err;
+       u32 val;
+
+       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP);
+
+       /* Wait for the hardware to start */
+       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
+                                     !(val & XILINX_DMA_DMASR_HALTED), 0,
+                                     XILINX_DMA_LOOP_COUNT);
+
+       if (err) {
+               dev_err(chan->dev, "Cannot start channel %p: %x\n",
+                       chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
+
+               chan->err = true;
+       }
+}
+
+/**
+ * xilinx_vdma_start_transfer - Starts VDMA transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_vdma_config *config = &chan->config;
+       struct xilinx_dma_tx_descriptor *desc, *tail_desc;
+       u32 reg;
+       struct xilinx_vdma_tx_segment *tail_segment;
+
+       /* This function was invoked with lock held */
+       if (chan->err)
+               return;
+
+       if (list_empty(&chan->pending_list))
+               return;
+
+       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_vdma_tx_segment, node);
+
+       /* If it is SG mode and hardware is busy, cannot submit */
+       if (chan->has_sg && xilinx_dma_is_running(chan) &&
+           !xilinx_dma_is_idle(chan)) {
+               dev_dbg(chan->dev, "DMA controller still busy\n");
+               return;
+       }
+
+       /*
+        * If hardware is idle, then all descriptors on the running lists are
+        * done, start new transfers
+        */
+       if (chan->has_sg)
+               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
+                               desc->async_tx.phys);
+
+       /* Configure the hardware using info in the config structure */
+       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+
+       if (config->frm_cnt_en)
+               reg |= XILINX_DMA_DMACR_FRAMECNT_EN;
+       else
+               reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN;
+
+       /* Configure channel to allow number frame buffers */
+       dma_ctrl_write(chan, XILINX_DMA_REG_FRMSTORE,
+                       chan->desc_pendingcount);
+
+       /*
+        * With SG, start with circular mode, so that BDs can be fetched.
+        * In direct register mode, if not parking, enable circular mode
+        */
+       if (chan->has_sg || !config->park)
+               reg |= XILINX_DMA_DMACR_CIRC_EN;
+
+       if (config->park)
+               reg &= ~XILINX_DMA_DMACR_CIRC_EN;
+
+       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
+
+       if (config->park && (config->park_frm >= 0) &&
+                       (config->park_frm < chan->num_frms)) {
+               if (chan->direction == DMA_MEM_TO_DEV)
+                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
+                               config->park_frm <<
+                                       XILINX_DMA_PARK_PTR_RD_REF_SHIFT);
+               else
+                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
+                               config->park_frm <<
+                                       XILINX_DMA_PARK_PTR_WR_REF_SHIFT);
+       }
+
+       /* Start the hardware */
+       xilinx_dma_start(chan);
+
+       if (chan->err)
+               return;
+
+       /* Start the transfer */
+       if (chan->has_sg) {
+               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
+                               tail_segment->phys);
+       } else {
+               struct xilinx_vdma_tx_segment *segment, *last = NULL;
+               int i = 0;
+
+               if (chan->desc_submitcount < chan->num_frms)
+                       i = chan->desc_submitcount;
+
+               list_for_each_entry(segment, &desc->segments, node) {
+                       if (chan->ext_addr)
+                               vdma_desc_write_64(chan,
+                                       XILINX_VDMA_REG_START_ADDRESS_64(i++),
+                                       segment->hw.buf_addr,
+                                       segment->hw.buf_addr_msb);
+                       else
+                               vdma_desc_write(chan,
+                                       XILINX_VDMA_REG_START_ADDRESS(i++),
+                                       segment->hw.buf_addr);
+
+                       last = segment;
+               }
+
+               if (!last)
+                       return;
+
+               /* HW expects these parameters to be same for one transaction */
+               vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize);
+               vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE,
+                               last->hw.stride);
+               vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
+       }
+
+       if (!chan->has_sg) {
+               list_del(&desc->node);
+               list_add_tail(&desc->node, &chan->active_list);
+               chan->desc_submitcount++;
+               chan->desc_pendingcount--;
+               if (chan->desc_submitcount == chan->num_frms)
+                       chan->desc_submitcount = 0;
+       } else {
+               list_splice_tail_init(&chan->pending_list, &chan->active_list);
+               chan->desc_pendingcount = 0;
+       }
+}
+
+/**
+ * xilinx_cdma_start_transfer - Starts cdma transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
+       struct xilinx_cdma_tx_segment *tail_segment;
+       u32 ctrl_reg = dma_read(chan, XILINX_DMA_REG_DMACR);
+
+       if (chan->err)
+               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_cdma_tx_segment, node);
+
+       if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) {
+               ctrl_reg &= ~XILINX_DMA_CR_COALESCE_MAX;
+               ctrl_reg |= chan->desc_pendingcount <<
+                               XILINX_DMA_CR_COALESCE_SHIFT;
+               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, ctrl_reg);
+       }
+
+       if (chan->has_sg) {
+               xilinx_write(chan, XILINX_DMA_REG_CURDESC,
+                            head_desc->async_tx.phys);
+
+               /* Update tail ptr register which will start the transfer */
+               xilinx_write(chan, XILINX_DMA_REG_TAILDESC,
+                            tail_segment->phys);
+       } else {
+               /* In simple mode */
+               struct xilinx_cdma_tx_segment *segment;
+               struct xilinx_cdma_desc_hw *hw;
+
+               segment = list_first_entry(&head_desc->segments,
+                                          struct xilinx_cdma_tx_segment,
+                                          node);
+
+               hw = &segment->hw;
+
+               xilinx_write(chan, XILINX_CDMA_REG_SRCADDR, hw->src_addr);
+               xilinx_write(chan, XILINX_CDMA_REG_DSTADDR, hw->dest_addr);
+
+               /* Start the transfer */
+               dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
+                               hw->control & XILINX_DMA_MAX_TRANS_LEN);
+       }
+
+       list_splice_tail_init(&chan->pending_list, &chan->active_list);
+       chan->desc_pendingcount = 0;
+}
+
+/**
+ * xilinx_dma_start_transfer - Starts DMA transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
+       struct xilinx_axidma_tx_segment *tail_segment, *old_head, *new_head;
+       u32 reg;
+
+       if (chan->err)
+               return;
+
+       if (list_empty(&chan->pending_list))
+               return;
+
+       /* If it is SG mode and hardware is busy, cannot submit */
+       if (chan->has_sg && xilinx_dma_is_running(chan) &&
+           !xilinx_dma_is_idle(chan)) {
+               dev_dbg(chan->dev, "DMA controller still busy\n");
+               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);
+
+       if (chan->has_sg && !chan->xdev->mcdma) {
+               old_head = list_first_entry(&head_desc->segments,
+                                       struct xilinx_axidma_tx_segment, node);
+               new_head = chan->seg_v;
+               /* Copy Buffer Descriptor fields. */
+               new_head->hw = old_head->hw;
+
+               /* Swap and save new reserve */
+               list_replace_init(&old_head->node, &new_head->node);
+               chan->seg_v = old_head;
+
+               tail_segment->hw.next_desc = chan->seg_v->phys;
+               head_desc->async_tx.phys = new_head->phys;
+       }
+
+       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+
+       if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) {
+               reg &= ~XILINX_DMA_CR_COALESCE_MAX;
+               reg |= chan->desc_pendingcount <<
+                                 XILINX_DMA_CR_COALESCE_SHIFT;
+               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
+       }
+
+       if (chan->has_sg && !chan->xdev->mcdma)
+               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->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;
+
+               segment = list_first_entry(&head_desc->segments,
+                                          struct xilinx_axidma_tx_segment,
+                                          node);
+               hw = &segment->hw;
+
+               xilinx_write(chan, XILINX_DMA_REG_SRCDSTADDR, hw->buf_addr);
+
+               /* Start the transfer */
+               dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
+                              hw->control & XILINX_DMA_MAX_TRANS_LEN);
+       }
+
+       list_splice_tail_init(&chan->pending_list, &chan->active_list);
+       chan->desc_pendingcount = 0;
+}
+
+/**
+ * xilinx_dma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel
+ */
+static void xilinx_dma_issue_pending(struct dma_chan *dchan)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       chan->start_transfer(chan);
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_dma_complete_descriptor - Mark the active descriptor as complete
+ * @chan : xilinx DMA channel
+ *
+ * CONTEXT: hardirq
+ */
+static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *desc, *next;
+
+       /* This function was invoked with lock held */
+       if (list_empty(&chan->active_list))
+               return;
+
+       list_for_each_entry_safe(desc, next, &chan->active_list, node) {
+               list_del(&desc->node);
+               if (!desc->cyclic)
+                       dma_cookie_complete(&desc->async_tx);
+               list_add_tail(&desc->node, &chan->done_list);
+       }
+}
+
+/**
+ * xilinx_dma_reset - Reset DMA channel
+ * @chan: Driver specific DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_reset(struct xilinx_dma_chan *chan)
+{
+       int err;
+       u32 tmp;
+
+       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RESET);
+
+       /* Wait for the hardware to finish reset */
+       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMACR, tmp,
+                                     !(tmp & XILINX_DMA_DMACR_RESET), 0,
+                                     XILINX_DMA_LOOP_COUNT);
+
+       if (err) {
+               dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
+                       dma_ctrl_read(chan, XILINX_DMA_REG_DMACR),
+                       dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
+               return -ETIMEDOUT;
+       }
+
+       chan->err = false;
+
+       return err;
+}
+
+/**
+ * xilinx_dma_chan_reset - Reset DMA channel and enable interrupts
+ * @chan: Driver specific DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_chan_reset(struct xilinx_dma_chan *chan)
+{
+       int err;
+
+       /* Reset VDMA */
+       err = xilinx_dma_reset(chan);
+       if (err)
+               return err;
+
+       /* Enable interrupts */
+       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
+                     XILINX_DMA_DMAXR_ALL_IRQ_MASK);
+
+       return 0;
+}
+
+/**
+ * xilinx_dma_irq_handler - DMA Interrupt handler
+ * @irq: IRQ number
+ * @data: Pointer to the Xilinx DMA channel structure
+ *
+ * Return: IRQ_HANDLED/IRQ_NONE
+ */
+static irqreturn_t xilinx_dma_irq_handler(int irq, void *data)
+{
+       struct xilinx_dma_chan *chan = data;
+       u32 status;
+
+       /* Read the status and ack the interrupts. */
+       status = dma_ctrl_read(chan, XILINX_DMA_REG_DMASR);
+       if (!(status & XILINX_DMA_DMAXR_ALL_IRQ_MASK))
+               return IRQ_NONE;
+
+       dma_ctrl_write(chan, XILINX_DMA_REG_DMASR,
+                       status & XILINX_DMA_DMAXR_ALL_IRQ_MASK);
+
+       if (status & XILINX_DMA_DMASR_ERR_IRQ) {
+               /*
+                * An error occurred. If C_FLUSH_ON_FSYNC is enabled and the
+                * error is recoverable, ignore it. Otherwise flag the error.
+                *
+                * Only recoverable errors can be cleared in the DMASR register,
+                * make sure not to write to other error bits to 1.
+                */
+               u32 errors = status & XILINX_DMA_DMASR_ALL_ERR_MASK;
+
+               dma_ctrl_write(chan, XILINX_DMA_REG_DMASR,
+                               errors & XILINX_DMA_DMASR_ERR_RECOVER_MASK);
+
+               if (!chan->flush_on_fsync ||
+                   (errors & ~XILINX_DMA_DMASR_ERR_RECOVER_MASK)) {
+                       dev_err(chan->dev,
+                               "Channel %p has errors %x, cdr %x tdr %x\n",
+                               chan, errors,
+                               dma_ctrl_read(chan, XILINX_DMA_REG_CURDESC),
+                               dma_ctrl_read(chan, XILINX_DMA_REG_TAILDESC));
+                       chan->err = true;
+               }
+       }
+
+       if (status & XILINX_DMA_DMASR_DLY_CNT_IRQ) {
+               /*
+                * 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_DMA_DMASR_FRM_CNT_IRQ) {
+               spin_lock(&chan->lock);
+               xilinx_dma_complete_descriptor(chan);
+               chan->start_transfer(chan);
+               spin_unlock(&chan->lock);
+       }
+
+       tasklet_schedule(&chan->tasklet);
+       return IRQ_HANDLED;
+}
+
+/**
+ * append_desc_queue - Queuing descriptor
+ * @chan: Driver specific dma channel
+ * @desc: dma transaction descriptor
+ */
+static void append_desc_queue(struct xilinx_dma_chan *chan,
+                             struct xilinx_dma_tx_descriptor *desc)
+{
+       struct xilinx_vdma_tx_segment *tail_segment;
+       struct xilinx_dma_tx_descriptor *tail_desc;
+       struct xilinx_axidma_tx_segment *axidma_tail_segment;
+       struct xilinx_cdma_tx_segment *cdma_tail_segment;
+
+       if (list_empty(&chan->pending_list))
+               goto append;
+
+       /*
+        * Add the hardware descriptor to the chain of hardware descriptors
+        * that already exists in memory.
+        */
+       tail_desc = list_last_entry(&chan->pending_list,
+                                   struct xilinx_dma_tx_descriptor, node);
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+               tail_segment = list_last_entry(&tail_desc->segments,
+                                              struct xilinx_vdma_tx_segment,
+                                              node);
+               tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
+       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+               cdma_tail_segment = list_last_entry(&tail_desc->segments,
+                                               struct xilinx_cdma_tx_segment,
+                                               node);
+               cdma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
+       } else {
+               axidma_tail_segment = list_last_entry(&tail_desc->segments,
+                                              struct xilinx_axidma_tx_segment,
+                                              node);
+               axidma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
+       }
+
+       /*
+        * Add the software descriptor and all children to the list
+        * of pending transactions
+        */
+append:
+       list_add_tail(&desc->node, &chan->pending_list);
+       chan->desc_pendingcount++;
+
+       if (chan->has_sg && (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA)
+           && unlikely(chan->desc_pendingcount > chan->num_frms)) {
+               dev_dbg(chan->dev, "desc pendingcount is too high\n");
+               chan->desc_pendingcount = chan->num_frms;
+       }
+}
+
+/**
+ * xilinx_dma_tx_submit - Submit DMA transaction
+ * @tx: Async transaction descriptor
+ *
+ * Return: cookie value on success and failure value on error
+ */
+static dma_cookie_t xilinx_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct xilinx_dma_tx_descriptor *desc = to_dma_tx_descriptor(tx);
+       struct xilinx_dma_chan *chan = to_xilinx_chan(tx->chan);
+       dma_cookie_t cookie;
+       unsigned long flags;
+       int err;
+
+       if (chan->cyclic) {
+               xilinx_dma_free_tx_descriptor(chan, desc);
+               return -EBUSY;
+       }
+
+       if (chan->err) {
+               /*
+                * If reset fails, need to hard reset the system.
+                * Channel is no longer functional
+                */
+               err = xilinx_dma_chan_reset(chan);
+               if (err < 0)
+                       return err;
+       }
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       cookie = dma_cookie_assign(tx);
+
+       /* Put this transaction onto the tail of the pending queue */
+       append_desc_queue(chan, desc);
+
+       if (desc->cyclic)
+               chan->cyclic = true;
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       return cookie;
+}
+
+/**
+ * xilinx_vdma_dma_prep_interleaved - prepare a descriptor for a
+ *     DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @xt: Interleaved template pointer
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
+                                struct dma_interleaved_template *xt,
+                                unsigned long flags)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_vdma_tx_segment *segment, *prev = NULL;
+       struct xilinx_vdma_desc_hw *hw;
+
+       if (!is_slave_direction(xt->dir))
+               return NULL;
+
+       if (!xt->numf || !xt->sgl[0].size)
+               return NULL;
+
+       if (xt->frame_size != 1)
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+       async_tx_ack(&desc->async_tx);
+
+       /* Allocate the link descriptor from DMA pool */
+       segment = xilinx_vdma_alloc_tx_segment(chan);
+       if (!segment)
+               goto error;
+
+       /* Fill in the hardware descriptor */
+       hw = &segment->hw;
+       hw->vsize = xt->numf;
+       hw->hsize = xt->sgl[0].size;
+       hw->stride = (xt->sgl[0].icg + xt->sgl[0].size) <<
+                       XILINX_DMA_FRMDLY_STRIDE_STRIDE_SHIFT;
+       hw->stride |= chan->config.frm_dly <<
+                       XILINX_DMA_FRMDLY_STRIDE_FRMDLY_SHIFT;
+
+       if (xt->dir != DMA_MEM_TO_DEV) {
+               if (chan->ext_addr) {
+                       hw->buf_addr = lower_32_bits(xt->dst_start);
+                       hw->buf_addr_msb = upper_32_bits(xt->dst_start);
+               } else {
+                       hw->buf_addr = xt->dst_start;
+               }
+       } else {
+               if (chan->ext_addr) {
+                       hw->buf_addr = lower_32_bits(xt->src_start);
+                       hw->buf_addr_msb = upper_32_bits(xt->src_start);
+               } else {
+                       hw->buf_addr = xt->src_start;
+               }
+       }
+
+       /* Insert the segment into the descriptor segments list. */
+       list_add_tail(&segment->node, &desc->segments);
+
+       prev = segment;
+
+       /* Link the last hardware descriptor with the first. */
+       segment = list_first_entry(&desc->segments,
+                                  struct xilinx_vdma_tx_segment, node);
+       desc->async_tx.phys = segment->phys;
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_cdma_prep_memcpy - prepare descriptors for a memcpy transaction
+ * @dchan: DMA channel
+ * @dma_dst: destination address
+ * @dma_src: source address
+ * @len: transfer length
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst,
+                       dma_addr_t dma_src, size_t len, unsigned long flags)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_cdma_tx_segment *segment, *prev;
+       struct xilinx_cdma_desc_hw *hw;
+
+       if (!len || len > XILINX_DMA_MAX_TRANS_LEN)
+               return NULL;
+
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+
+       /* Allocate the link descriptor from DMA pool */
+       segment = xilinx_cdma_alloc_tx_segment(chan);
+       if (!segment)
+               goto error;
+
+       hw = &segment->hw;
+       hw->control = len;
+       hw->src_addr = dma_src;
+       hw->dest_addr = dma_dst;
+       if (chan->ext_addr) {
+               hw->src_addr_msb = upper_32_bits(dma_src);
+               hw->dest_addr_msb = upper_32_bits(dma_dst);
+       }
+
+       /* Fill the previous next descriptor with current */
+       prev = list_last_entry(&desc->segments,
+                              struct xilinx_cdma_tx_segment, node);
+       prev->hw.next_desc = segment->phys;
+
+       /* Insert the segment into the descriptor segments list. */
+       list_add_tail(&segment->node, &desc->segments);
+
+       prev = segment;
+
+       /* Link the last hardware descriptor with the first. */
+       segment = list_first_entry(&desc->segments,
+                               struct xilinx_cdma_tx_segment, node);
+       desc->async_tx.phys = segment->phys;
+       prev->hw.next_desc = segment->phys;
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @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_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 = NULL, *prev = NULL;
+       u32 *app_w = (u32 *)context;
+       struct scatterlist *sg;
+       size_t copy;
+       size_t sg_used;
+       unsigned int i;
+
+       if (!is_slave_direction(direction))
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+
+       /* Build transactions using information in the scatter gather list */
+       for_each_sg(sgl, sg, sg_len, i) {
+               sg_used = 0;
+
+               /* Loop until the entire scatterlist entry is used */
+               while (sg_used < sg_dma_len(sg)) {
+                       struct xilinx_axidma_desc_hw *hw;
+
+                       /* Get a free segment */
+                       segment = xilinx_axidma_alloc_tx_segment(chan);
+                       if (!segment)
+                               goto error;
+
+                       /*
+                        * 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,
+                                    XILINX_DMA_MAX_TRANS_LEN);
+                       hw = &segment->hw;
+
+                       /* Fill in the descriptor */
+                       xilinx_axidma_buf(chan, hw, sg_dma_address(sg),
+                                         sg_used, 0);
+
+                       hw->control = copy;
+
+                       if (chan->direction == DMA_MEM_TO_DEV) {
+                               if (app_w)
+                                       memcpy(hw->app, app_w, sizeof(u32) *
+                                              XILINX_DMA_NUM_APP_WORDS);
+                       }
+
+                       if (prev)
+                               prev->hw.next_desc = segment->phys;
+
+                       prev = segment;
+                       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);
+       desc->async_tx.phys = segment->phys;
+       prev->hw.next_desc = segment->phys;
+
+       /* For the last DMA_MEM_TO_DEV transfer, set EOP */
+       if (chan->direction == DMA_MEM_TO_DEV) {
+               segment->hw.control |= XILINX_DMA_BD_SOP;
+               segment = list_last_entry(&desc->segments,
+                                         struct xilinx_axidma_tx_segment,
+                                         node);
+               segment->hw.control |= XILINX_DMA_BD_EOP;
+       }
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_dma_prep_dma_cyclic - prepare descriptors for a DMA_SLAVE transaction
+ * @chan: DMA channel
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
+ * @flags: transfer ack flags
+ */
+static struct dma_async_tx_descriptor *xilinx_dma_prep_dma_cyclic(
+       struct dma_chan *dchan, dma_addr_t buf_addr, size_t buf_len,
+       size_t period_len, enum dma_transfer_direction direction,
+       unsigned long flags)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_axidma_tx_segment *segment, *head_segment, *prev = NULL;
+       size_t copy, sg_used;
+       unsigned int num_periods;
+       int i;
+       u32 reg;
+
+       if (!period_len)
+               return NULL;
+
+       num_periods = buf_len / period_len;
+
+       if (!num_periods)
+               return NULL;
+
+       if (!is_slave_direction(direction))
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       chan->direction = direction;
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+
+       for (i = 0; i < num_periods; ++i) {
+               sg_used = 0;
+
+               while (sg_used < period_len) {
+                       struct xilinx_axidma_desc_hw *hw;
+
+                       /* Get a free segment */
+                       segment = xilinx_axidma_alloc_tx_segment(chan);
+                       if (!segment)
+                               goto error;
+
+                       /*
+                        * Calculate the maximum number of bytes to transfer,
+                        * making sure it is less than the hw limit
+                        */
+                       copy = min_t(size_t, period_len - sg_used,
+                                    XILINX_DMA_MAX_TRANS_LEN);
+                       hw = &segment->hw;
+                       xilinx_axidma_buf(chan, hw, buf_addr, sg_used,
+                                         period_len * i);
+                       hw->control = copy;
+
+                       if (prev)
+                               prev->hw.next_desc = segment->phys;
+
+                       prev = segment;
+                       sg_used += copy;
+
+                       /*
+                        * Insert the segment into the descriptor segments
+                        * list.
+                        */
+                       list_add_tail(&segment->node, &desc->segments);
+               }
+       }
+
+       head_segment = list_first_entry(&desc->segments,
+                                  struct xilinx_axidma_tx_segment, node);
+       desc->async_tx.phys = head_segment->phys;
+
+       desc->cyclic = true;
+       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+       reg |= XILINX_DMA_CR_CYCLIC_BD_EN_MASK;
+       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
+
+       segment = list_last_entry(&desc->segments,
+                                 struct xilinx_axidma_tx_segment,
+                                 node);
+       segment->hw.next_desc = (u32) head_segment->phys;
+
+       /* For the last DMA_MEM_TO_DEV transfer, set EOP */
+       if (direction == DMA_MEM_TO_DEV) {
+               head_segment->hw.control |= XILINX_DMA_BD_SOP;
+               segment->hw.control |= XILINX_DMA_BD_EOP;
+       }
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_dma_prep_interleaved - prepare a descriptor for a
+ *     DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @xt: Interleaved template pointer
+ * @flags: transfer ack flags
+ *
+ * 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)
+{
+       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;
+
+       if (xt->frame_size != 1)
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       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;
+
+       hw = &segment->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;
+
+       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;
+
+       /*
+        * 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);
+       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;
+               segment = list_last_entry(&desc->segments,
+                                         struct xilinx_axidma_tx_segment,
+                                         node);
+               segment->hw.control |= XILINX_DMA_BD_EOP;
+       }
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_dma_terminate_all - Halt the channel and free descriptors
+ * @chan: Driver specific DMA Channel pointer
+ */
+static int xilinx_dma_terminate_all(struct dma_chan *dchan)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       u32 reg;
+
+       if (chan->cyclic)
+               xilinx_dma_chan_reset(chan);
+
+       /* Halt the DMA engine */
+       xilinx_dma_halt(chan);
+
+       /* Remove and free all of the descriptors in the lists */
+       xilinx_dma_free_descriptors(chan);
+
+       if (chan->cyclic) {
+               reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+               reg &= ~XILINX_DMA_CR_CYCLIC_BD_EN_MASK;
+               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
+               chan->cyclic = false;
+       }
+
+       return 0;
+}
+
+/**
+ * xilinx_dma_channel_set_config - Configure VDMA channel
+ * Run-time configuration for Axi VDMA, supports:
+ * . halt the channel
+ * . configure interrupt coalescing and inter-packet delay threshold
+ * . start/stop parking
+ * . enable genlock
+ *
+ * @dchan: DMA channel
+ * @cfg: VDMA device configuration pointer
+ *
+ * Return: '0' on success and failure value on error
+ */
+int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
+                                       struct xilinx_vdma_config *cfg)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       u32 dmacr;
+
+       if (cfg->reset)
+               return xilinx_dma_chan_reset(chan);
+
+       dmacr = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+
+       chan->config.frm_dly = cfg->frm_dly;
+       chan->config.park = cfg->park;
+
+       /* genlock settings */
+       chan->config.gen_lock = cfg->gen_lock;
+       chan->config.master = cfg->master;
+
+       if (cfg->gen_lock && chan->genlock) {
+               dmacr |= XILINX_DMA_DMACR_GENLOCK_EN;
+               dmacr |= cfg->master << XILINX_DMA_DMACR_MASTER_SHIFT;
+       }
+
+       chan->config.frm_cnt_en = cfg->frm_cnt_en;
+       if (cfg->park)
+               chan->config.park_frm = cfg->park_frm;
+       else
+               chan->config.park_frm = -1;
+
+       chan->config.coalesc = cfg->coalesc;
+       chan->config.delay = cfg->delay;
+
+       if (cfg->coalesc <= XILINX_DMA_DMACR_FRAME_COUNT_MAX) {
+               dmacr |= cfg->coalesc << XILINX_DMA_DMACR_FRAME_COUNT_SHIFT;
+               chan->config.coalesc = cfg->coalesc;
+       }
+
+       if (cfg->delay <= XILINX_DMA_DMACR_DELAY_MAX) {
+               dmacr |= cfg->delay << XILINX_DMA_DMACR_DELAY_SHIFT;
+               chan->config.delay = cfg->delay;
+       }
+
+       /* FSync Source selection */
+       dmacr &= ~XILINX_DMA_DMACR_FSYNCSRC_MASK;
+       dmacr |= cfg->ext_fsync << XILINX_DMA_DMACR_FSYNCSRC_SHIFT;
+
+       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, dmacr);
+
+       return 0;
+}
+EXPORT_SYMBOL(xilinx_vdma_channel_set_config);
+
+/* -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+/**
+ * xilinx_dma_chan_remove - Per Channel remove function
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan)
+{
+       /* Disable all interrupts */
+       dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR,
+                     XILINX_DMA_DMAXR_ALL_IRQ_MASK);
+
+       if (chan->irq > 0)
+               free_irq(chan->irq, chan);
+
+       tasklet_kill(&chan->tasklet);
+
+       list_del(&chan->common.device_node);
+}
+
+static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
+                           struct clk **tx_clk, struct clk **rx_clk,
+                           struct clk **sg_clk, struct clk **tmp_clk)
+{
+       int err;
+
+       *tmp_clk = NULL;
+
+       *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 (%u)\n", err);
+               return err;
+       }
+
+       *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
+       if (IS_ERR(*tx_clk))
+               *tx_clk = NULL;
+
+       *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
+       if (IS_ERR(*rx_clk))
+               *rx_clk = NULL;
+
+       *sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk");
+       if (IS_ERR(*sg_clk))
+               *sg_clk = NULL;
+
+       err = clk_prepare_enable(*axi_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(*tx_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
+               goto err_disable_axiclk;
+       }
+
+       err = clk_prepare_enable(*rx_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
+               goto err_disable_txclk;
+       }
+
+       err = clk_prepare_enable(*sg_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable sg_clk (%u)\n", err);
+               goto err_disable_rxclk;
+       }
+
+       return 0;
+
+err_disable_rxclk:
+       clk_disable_unprepare(*rx_clk);
+err_disable_txclk:
+       clk_disable_unprepare(*tx_clk);
+err_disable_axiclk:
+       clk_disable_unprepare(*axi_clk);
+
+       return err;
+}
+
+static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
+                           struct clk **dev_clk, struct clk **tmp_clk,
+                           struct clk **tmp1_clk, struct clk **tmp2_clk)
+{
+       int err;
+
+       *tmp_clk = NULL;
+       *tmp1_clk = NULL;
+       *tmp2_clk = NULL;
+
+       *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 (%u)\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 (%u)\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(*axi_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(*dev_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable dev_clk (%u)\n", err);
+               goto err_disable_axiclk;
+       }
+
+       return 0;
+
+err_disable_axiclk:
+       clk_disable_unprepare(*axi_clk);
+
+       return err;
+}
+
+static int axivdma_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)
+{
+       int err;
+
+       *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 (%u)\n", err);
+               return err;
+       }
+
+       *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
+       if (IS_ERR(*tx_clk))
+               *tx_clk = NULL;
+
+       *txs_clk = devm_clk_get(&pdev->dev, "m_axis_mm2s_aclk");
+       if (IS_ERR(*txs_clk))
+               *txs_clk = NULL;
+
+       *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
+       if (IS_ERR(*rx_clk))
+               *rx_clk = NULL;
+
+       *rxs_clk = devm_clk_get(&pdev->dev, "s_axis_s2mm_aclk");
+       if (IS_ERR(*rxs_clk))
+               *rxs_clk = NULL;
+
+       err = clk_prepare_enable(*axi_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(*tx_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
+               goto err_disable_axiclk;
+       }
+
+       err = clk_prepare_enable(*txs_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err);
+               goto err_disable_txclk;
+       }
+
+       err = clk_prepare_enable(*rx_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
+               goto err_disable_txsclk;
+       }
+
+       err = clk_prepare_enable(*rxs_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err);
+               goto err_disable_rxclk;
+       }
+
+       return 0;
+
+err_disable_rxclk:
+       clk_disable_unprepare(*rx_clk);
+err_disable_txsclk:
+       clk_disable_unprepare(*txs_clk);
+err_disable_txclk:
+       clk_disable_unprepare(*tx_clk);
+err_disable_axiclk:
+       clk_disable_unprepare(*axi_clk);
+
+       return err;
+}
+
+static void xdma_disable_allclks(struct xilinx_dma_device *xdev)
+{
+       clk_disable_unprepare(xdev->rxs_clk);
+       clk_disable_unprepare(xdev->rx_clk);
+       clk_disable_unprepare(xdev->txs_clk);
+       clk_disable_unprepare(xdev->tx_clk);
+       clk_disable_unprepare(xdev->axi_clk);
+}
+
+/**
+ * xilinx_dma_chan_probe - Per Channel Probing
+ * It get channel features from the device tree entry and
+ * initialize special channel handling routines
+ *
+ * @xdev: Driver specific device structure
+ * @node: Device node
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
+                                 struct device_node *node, int chan_id)
+{
+       struct xilinx_dma_chan *chan;
+       bool has_dre = false;
+       u32 value, width;
+       int err;
+
+       /* Allocate and initialize the channel structure */
+       chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               return -ENOMEM;
+
+       chan->dev = xdev->dev;
+       chan->xdev = xdev;
+       chan->has_sg = xdev->has_sg;
+       chan->desc_pendingcount = 0x0;
+       chan->ext_addr = xdev->ext_addr;
+
+       spin_lock_init(&chan->lock);
+       INIT_LIST_HEAD(&chan->pending_list);
+       INIT_LIST_HEAD(&chan->done_list);
+       INIT_LIST_HEAD(&chan->active_list);
+
+       /* Retrieve the channel properties from the device tree */
+       has_dre = of_property_read_bool(node, "xlnx,include-dre");
+
+       chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode");
+
+       err = of_property_read_u32(node, "xlnx,datawidth", &value);
+       if (err) {
+               dev_err(xdev->dev, "missing xlnx,datawidth property\n");
+               return err;
+       }
+       width = value >> 3; /* Convert bits to bytes */
+
+       /* If data width is greater than 8 bytes, DRE is not in hw */
+       if (width > 8)
+               has_dre = false;
+
+       if (!has_dre)
+               xdev->common.copy_align = fls(width - 1);
+
+       if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel") ||
+           of_device_is_compatible(node, "xlnx,axi-dma-mm2s-channel") ||
+           of_device_is_compatible(node, "xlnx,axi-cdma-channel")) {
+               chan->direction = DMA_MEM_TO_DEV;
+               chan->id = chan_id;
+               chan->tdest = chan_id;
+
+               chan->ctrl_offset = XILINX_DMA_MM2S_CTRL_OFFSET;
+               if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+                       chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
+
+                       if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
+                           xdev->flush_on_fsync == XILINX_DMA_FLUSH_MM2S)
+                               chan->flush_on_fsync = true;
+               }
+       } else if (of_device_is_compatible(node,
+                                          "xlnx,axi-vdma-s2mm-channel") ||
+                  of_device_is_compatible(node,
+                                          "xlnx,axi-dma-s2mm-channel")) {
+               chan->direction = DMA_DEV_TO_MEM;
+               chan->id = chan_id;
+               chan->tdest = chan_id - xdev->nr_channels;
+
+               chan->ctrl_offset = XILINX_DMA_S2MM_CTRL_OFFSET;
+               if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+                       chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
+
+                       if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
+                           xdev->flush_on_fsync == XILINX_DMA_FLUSH_S2MM)
+                               chan->flush_on_fsync = true;
+               }
+       } else {
+               dev_err(xdev->dev, "Invalid channel compatible node\n");
+               return -EINVAL;
+       }
+
+       /* 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);
+       if (err) {
+               dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq);
+               return err;
+       }
+
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
+               chan->start_transfer = xilinx_dma_start_transfer;
+       else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA)
+               chan->start_transfer = xilinx_cdma_start_transfer;
+       else
+               chan->start_transfer = xilinx_vdma_start_transfer;
+
+       /* Initialize the tasklet */
+       tasklet_init(&chan->tasklet, xilinx_dma_do_tasklet,
+                       (unsigned long)chan);
+
+       /*
+        * Initialize the DMA channel and add it to the DMA engine channels
+        * list.
+        */
+       chan->common.device = &xdev->common;
+
+       list_add_tail(&chan->common.device_node, &xdev->common.channels);
+       xdev->chan[chan->id] = chan;
+
+       /* Reset the channel */
+       err = xilinx_dma_chan_reset(chan);
+       if (err < 0) {
+               dev_err(xdev->dev, "Reset channel failed\n");
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * xilinx_dma_child_probe - Per child node probe
+ * It get number of dma-channels per child node from
+ * device-tree and initializes all the channels.
+ *
+ * @xdev: Driver specific device structure
+ * @node: Device node
+ *
+ * Return: 0 always.
+ */
+static int xilinx_dma_child_probe(struct xilinx_dma_device *xdev,
+                                   struct device_node *node) {
+       int ret, i, nr_channels = 1;
+
+       ret = of_property_read_u32(node, "dma-channels", &nr_channels);
+       if ((ret < 0) && xdev->mcdma)
+               dev_warn(xdev->dev, "missing dma-channels property\n");
+
+       for (i = 0; i < nr_channels; i++)
+               xilinx_dma_chan_probe(xdev, node, xdev->chan_id++);
+
+       xdev->nr_channels += nr_channels;
+
+       return 0;
+}
+
+/**
+ * of_dma_xilinx_xlate - Translation function
+ * @dma_spec: Pointer to DMA specifier as found in the device tree
+ * @ofdma: Pointer to DMA controller data
+ *
+ * Return: DMA channel pointer on success and NULL on error
+ */
+static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
+                                               struct of_dma *ofdma)
+{
+       struct xilinx_dma_device *xdev = ofdma->of_dma_data;
+       int chan_id = dma_spec->args[0];
+
+       if (chan_id >= xdev->nr_channels || !xdev->chan[chan_id])
+               return NULL;
+
+       return dma_get_slave_channel(&xdev->chan[chan_id]->common);
+}
+
+static const struct xilinx_dma_config axidma_config = {
+       .dmatype = XDMA_TYPE_AXIDMA,
+       .clk_init = axidma_clk_init,
+};
+
+static const struct xilinx_dma_config axicdma_config = {
+       .dmatype = XDMA_TYPE_CDMA,
+       .clk_init = axicdma_clk_init,
+};
+
+static const struct xilinx_dma_config axivdma_config = {
+       .dmatype = XDMA_TYPE_VDMA,
+       .clk_init = axivdma_clk_init,
+};
+
+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 },
+       {}
+};
+MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids);
+
+/**
+ * xilinx_dma_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_probe(struct platform_device *pdev)
+{
+       int (*clk_init)(struct platform_device *, struct clk **, struct clk **,
+                       struct clk **, struct clk **, struct clk **)
+                                       = axivdma_clk_init;
+       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;
+       int i, err;
+
+       /* Allocate and initialize the DMA engine structure */
+       xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+       if (!xdev)
+               return -ENOMEM;
+
+       xdev->dev = &pdev->dev;
+       if (np) {
+               const struct of_device_id *match;
+
+               match = of_match_node(xilinx_dma_of_ids, np);
+               if (match && match->data) {
+                       xdev->dma_config = match->data;
+                       clk_init = xdev->dma_config->clk_init;
+               }
+       }
+
+       err = clk_init(pdev, &xdev->axi_clk, &xdev->tx_clk, &xdev->txs_clk,
+                      &xdev->rx_clk, &xdev->rxs_clk);
+       if (err)
+               return err;
+
+       /* Request and map I/O memory */
+       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       xdev->regs = devm_ioremap_resource(&pdev->dev, io);
+       if (IS_ERR(xdev->regs))
+               return PTR_ERR(xdev->regs);
+
+       /* Retrieve the DMA engine properties from the device tree */
+       xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
+               xdev->mcdma = of_property_read_bool(node, "xlnx,mcdma");
+
+       if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+               err = of_property_read_u32(node, "xlnx,num-fstores",
+                                          &num_frames);
+               if (err < 0) {
+                       dev_err(xdev->dev,
+                               "missing xlnx,num-fstores property\n");
+                       return err;
+               }
+
+               err = of_property_read_u32(node, "xlnx,flush-fsync",
+                                          &xdev->flush_on_fsync);
+               if (err < 0)
+                       dev_warn(xdev->dev,
+                                "missing xlnx,flush-fsync property\n");
+       }
+
+       err = of_property_read_u32(node, "xlnx,addrwidth", &addr_width);
+       if (err < 0)
+               dev_warn(xdev->dev, "missing xlnx,addrwidth property\n");
+
+       if (addr_width > 32)
+               xdev->ext_addr = true;
+       else
+               xdev->ext_addr = false;
+
+       /* Set the dma mask bits */
+       dma_set_mask(xdev->dev, DMA_BIT_MASK(addr_width));
+
+       /* Initialize the DMA engine */
+       xdev->common.dev = &pdev->dev;
+
+       INIT_LIST_HEAD(&xdev->common.channels);
+       if (!(xdev->dma_config->dmatype == XDMA_TYPE_CDMA)) {
+               dma_cap_set(DMA_SLAVE, xdev->common.cap_mask);
+               dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask);
+       }
+
+       xdev->common.device_alloc_chan_resources =
+                               xilinx_dma_alloc_chan_resources;
+       xdev->common.device_free_chan_resources =
+                               xilinx_dma_free_chan_resources;
+       xdev->common.device_terminate_all = xilinx_dma_terminate_all;
+       xdev->common.device_tx_status = xilinx_dma_tx_status;
+       xdev->common.device_issue_pending = xilinx_dma_issue_pending;
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               dma_cap_set(DMA_CYCLIC, xdev->common.cap_mask);
+               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 */
+               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;
+       } else {
+               xdev->common.device_prep_interleaved_dma =
+                               xilinx_vdma_dma_prep_interleaved;
+       }
+
+       platform_set_drvdata(pdev, xdev);
+
+       /* Initialize the channels */
+       for_each_child_of_node(node, child) {
+               err = xilinx_dma_child_probe(xdev, child);
+               if (err < 0)
+                       goto disable_clks;
+       }
+
+       if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+               for (i = 0; i < xdev->nr_channels; i++)
+                       if (xdev->chan[i])
+                               xdev->chan[i]->num_frms = num_frames;
+       }
+
+       /* Register the DMA engine with the core */
+       dma_async_device_register(&xdev->common);
+
+       err = of_dma_controller_register(node, of_dma_xilinx_xlate,
+                                        xdev);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Unable to register DMA to DT\n");
+               dma_async_device_unregister(&xdev->common);
+               goto error;
+       }
+
+       dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n");
+
+       return 0;
+
+disable_clks:
+       xdma_disable_allclks(xdev);
+error:
+       for (i = 0; i < xdev->nr_channels; i++)
+               if (xdev->chan[i])
+                       xilinx_dma_chan_remove(xdev->chan[i]);
+
+       return err;
+}
+
+/**
+ * xilinx_dma_remove - Driver remove function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: Always '0'
+ */
+static int xilinx_dma_remove(struct platform_device *pdev)
+{
+       struct xilinx_dma_device *xdev = platform_get_drvdata(pdev);
+       int i;
+
+       of_dma_controller_free(pdev->dev.of_node);
+
+       dma_async_device_unregister(&xdev->common);
+
+       for (i = 0; i < xdev->nr_channels; i++)
+               if (xdev->chan[i])
+                       xilinx_dma_chan_remove(xdev->chan[i]);
+
+       xdma_disable_allclks(xdev);
+
+       return 0;
+}
+
+static struct platform_driver xilinx_vdma_driver = {
+       .driver = {
+               .name = "xilinx-vdma",
+               .of_match_table = xilinx_dma_of_ids,
+       },
+       .probe = xilinx_dma_probe,
+       .remove = xilinx_dma_remove,
+};
+
+module_platform_driver(xilinx_vdma_driver);
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx VDMA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c
deleted file mode 100644 (file)
index df91185..0000000
+++ /dev/null
@@ -1,2310 +0,0 @@
-/*
- * DMA driver for Xilinx Video DMA Engine
- *
- * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
- *
- * Based on the Freescale DMA driver.
- *
- * Description:
- * The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP
- * core that provides high-bandwidth direct memory access between memory
- * and AXI4-Stream type video target peripherals. The core provides efficient
- * two dimensional DMA operations with independent asynchronous read (S2MM)
- * and write (MM2S) channel operation. It can be configured to have either
- * one channel or two channels. If configured as two channels, one is to
- * transmit to the video device (MM2S) and another is to receive from the
- * video device (S2MM). Initialization, status, interrupt and management
- * registers are accessed through an AXI4-Lite slave interface.
- *
- * The AXI Direct Memory Access (AXI DMA) core is a soft Xilinx IP core that
- * provides high-bandwidth one dimensional direct memory access between memory
- * and AXI4-Stream target peripherals. It supports one receive and one
- * transmit channel, both of them optional at synthesis time.
- *
- * 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.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/bitops.h>
-#include <linux/dmapool.h>
-#include <linux/dma/xilinx_dma.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_dma.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-
-#include "../dmaengine.h"
-
-/* Register/Descriptor Offsets */
-#define XILINX_DMA_MM2S_CTRL_OFFSET            0x0000
-#define XILINX_DMA_S2MM_CTRL_OFFSET            0x0030
-#define XILINX_VDMA_MM2S_DESC_OFFSET           0x0050
-#define XILINX_VDMA_S2MM_DESC_OFFSET           0x00a0
-
-/* Control Registers */
-#define XILINX_DMA_REG_DMACR                   0x0000
-#define XILINX_DMA_DMACR_DELAY_MAX             0xff
-#define XILINX_DMA_DMACR_DELAY_SHIFT           24
-#define XILINX_DMA_DMACR_FRAME_COUNT_MAX       0xff
-#define XILINX_DMA_DMACR_FRAME_COUNT_SHIFT     16
-#define XILINX_DMA_DMACR_ERR_IRQ               BIT(14)
-#define XILINX_DMA_DMACR_DLY_CNT_IRQ           BIT(13)
-#define XILINX_DMA_DMACR_FRM_CNT_IRQ           BIT(12)
-#define XILINX_DMA_DMACR_MASTER_SHIFT          8
-#define XILINX_DMA_DMACR_FSYNCSRC_SHIFT        5
-#define XILINX_DMA_DMACR_FRAMECNT_EN           BIT(4)
-#define XILINX_DMA_DMACR_GENLOCK_EN            BIT(3)
-#define XILINX_DMA_DMACR_RESET                 BIT(2)
-#define XILINX_DMA_DMACR_CIRC_EN               BIT(1)
-#define XILINX_DMA_DMACR_RUNSTOP               BIT(0)
-#define XILINX_DMA_DMACR_FSYNCSRC_MASK         GENMASK(6, 5)
-
-#define XILINX_DMA_REG_DMASR                   0x0004
-#define XILINX_DMA_DMASR_EOL_LATE_ERR          BIT(15)
-#define XILINX_DMA_DMASR_ERR_IRQ               BIT(14)
-#define XILINX_DMA_DMASR_DLY_CNT_IRQ           BIT(13)
-#define XILINX_DMA_DMASR_FRM_CNT_IRQ           BIT(12)
-#define XILINX_DMA_DMASR_SOF_LATE_ERR          BIT(11)
-#define XILINX_DMA_DMASR_SG_DEC_ERR            BIT(10)
-#define XILINX_DMA_DMASR_SG_SLV_ERR            BIT(9)
-#define XILINX_DMA_DMASR_EOF_EARLY_ERR         BIT(8)
-#define XILINX_DMA_DMASR_SOF_EARLY_ERR         BIT(7)
-#define XILINX_DMA_DMASR_DMA_DEC_ERR           BIT(6)
-#define XILINX_DMA_DMASR_DMA_SLAVE_ERR         BIT(5)
-#define XILINX_DMA_DMASR_DMA_INT_ERR           BIT(4)
-#define XILINX_DMA_DMASR_IDLE                  BIT(1)
-#define XILINX_DMA_DMASR_HALTED                BIT(0)
-#define XILINX_DMA_DMASR_DELAY_MASK            GENMASK(31, 24)
-#define XILINX_DMA_DMASR_FRAME_COUNT_MASK      GENMASK(23, 16)
-
-#define XILINX_DMA_REG_CURDESC                 0x0008
-#define XILINX_DMA_REG_TAILDESC                0x0010
-#define XILINX_DMA_REG_REG_INDEX               0x0014
-#define XILINX_DMA_REG_FRMSTORE                0x0018
-#define XILINX_DMA_REG_THRESHOLD               0x001c
-#define XILINX_DMA_REG_FRMPTR_STS              0x0024
-#define XILINX_DMA_REG_PARK_PTR                0x0028
-#define XILINX_DMA_PARK_PTR_WR_REF_SHIFT       8
-#define XILINX_DMA_PARK_PTR_RD_REF_SHIFT       0
-#define XILINX_DMA_REG_VDMA_VERSION            0x002c
-
-/* Register Direct Mode Registers */
-#define XILINX_DMA_REG_VSIZE                   0x0000
-#define XILINX_DMA_REG_HSIZE                   0x0004
-
-#define XILINX_DMA_REG_FRMDLY_STRIDE           0x0008
-#define XILINX_DMA_FRMDLY_STRIDE_FRMDLY_SHIFT  24
-#define XILINX_DMA_FRMDLY_STRIDE_STRIDE_SHIFT  0
-
-#define XILINX_VDMA_REG_START_ADDRESS(n)       (0x000c + 4 * (n))
-#define XILINX_VDMA_REG_START_ADDRESS_64(n)    (0x000c + 8 * (n))
-
-/* HW specific definitions */
-#define XILINX_DMA_MAX_CHANS_PER_DEVICE        0x2
-
-#define XILINX_DMA_DMAXR_ALL_IRQ_MASK  \
-               (XILINX_DMA_DMASR_FRM_CNT_IRQ | \
-                XILINX_DMA_DMASR_DLY_CNT_IRQ | \
-                XILINX_DMA_DMASR_ERR_IRQ)
-
-#define XILINX_DMA_DMASR_ALL_ERR_MASK  \
-               (XILINX_DMA_DMASR_EOL_LATE_ERR | \
-                XILINX_DMA_DMASR_SOF_LATE_ERR | \
-                XILINX_DMA_DMASR_SG_DEC_ERR | \
-                XILINX_DMA_DMASR_SG_SLV_ERR | \
-                XILINX_DMA_DMASR_EOF_EARLY_ERR | \
-                XILINX_DMA_DMASR_SOF_EARLY_ERR | \
-                XILINX_DMA_DMASR_DMA_DEC_ERR | \
-                XILINX_DMA_DMASR_DMA_SLAVE_ERR | \
-                XILINX_DMA_DMASR_DMA_INT_ERR)
-
-/*
- * Recoverable errors are DMA Internal error, SOF Early, EOF Early
- * and SOF Late. They are only recoverable when C_FLUSH_ON_FSYNC
- * is enabled in the h/w system.
- */
-#define XILINX_DMA_DMASR_ERR_RECOVER_MASK      \
-               (XILINX_DMA_DMASR_SOF_LATE_ERR | \
-                XILINX_DMA_DMASR_EOF_EARLY_ERR | \
-                XILINX_DMA_DMASR_SOF_EARLY_ERR | \
-                XILINX_DMA_DMASR_DMA_INT_ERR)
-
-/* Axi VDMA Flush on Fsync bits */
-#define XILINX_DMA_FLUSH_S2MM          3
-#define XILINX_DMA_FLUSH_MM2S          2
-#define XILINX_DMA_FLUSH_BOTH          1
-
-/* Delay loop counter to prevent hardware failure */
-#define XILINX_DMA_LOOP_COUNT          1000000
-
-/* AXI DMA Specific Registers/Offsets */
-#define XILINX_DMA_REG_SRCDSTADDR      0x18
-#define XILINX_DMA_REG_BTT             0x28
-
-/* AXI DMA Specific Masks/Bit fields */
-#define XILINX_DMA_MAX_TRANS_LEN       GENMASK(22, 0)
-#define XILINX_DMA_CR_COALESCE_MAX     GENMASK(23, 16)
-#define XILINX_DMA_CR_COALESCE_SHIFT   16
-#define XILINX_DMA_BD_SOP              BIT(27)
-#define XILINX_DMA_BD_EOP              BIT(26)
-#define XILINX_DMA_COALESCE_MAX                255
-#define XILINX_DMA_NUM_APP_WORDS       5
-
-/* AXI CDMA Specific Registers/Offsets */
-#define XILINX_CDMA_REG_SRCADDR                0x18
-#define XILINX_CDMA_REG_DSTADDR                0x20
-
-/* AXI CDMA Specific Masks */
-#define XILINX_CDMA_CR_SGMODE          BIT(3)
-
-/**
- * struct xilinx_vdma_desc_hw - Hardware Descriptor
- * @next_desc: Next Descriptor Pointer @0x00
- * @pad1: Reserved @0x04
- * @buf_addr: Buffer address @0x08
- * @buf_addr_msb: MSB of Buffer address @0x0C
- * @vsize: Vertical Size @0x10
- * @hsize: Horizontal Size @0x14
- * @stride: Number of bytes between the first
- *         pixels of each horizontal line @0x18
- */
-struct xilinx_vdma_desc_hw {
-       u32 next_desc;
-       u32 pad1;
-       u32 buf_addr;
-       u32 buf_addr_msb;
-       u32 vsize;
-       u32 hsize;
-       u32 stride;
-} __aligned(64);
-
-/**
- * struct xilinx_axidma_desc_hw - Hardware Descriptor for AXI DMA
- * @next_desc: Next Descriptor Pointer @0x00
- * @pad1: Reserved @0x04
- * @buf_addr: Buffer address @0x08
- * @pad2: Reserved @0x0C
- * @pad3: Reserved @0x10
- * @pad4: Reserved @0x14
- * @control: Control field @0x18
- * @status: Status field @0x1C
- * @app: APP Fields @0x20 - 0x30
- */
-struct xilinx_axidma_desc_hw {
-       u32 next_desc;
-       u32 pad1;
-       u32 buf_addr;
-       u32 pad2;
-       u32 pad3;
-       u32 pad4;
-       u32 control;
-       u32 status;
-       u32 app[XILINX_DMA_NUM_APP_WORDS];
-} __aligned(64);
-
-/**
- * struct xilinx_cdma_desc_hw - Hardware Descriptor
- * @next_desc: Next Descriptor Pointer @0x00
- * @pad1: Reserved @0x04
- * @src_addr: Source address @0x08
- * @pad2: Reserved @0x0C
- * @dest_addr: Destination address @0x10
- * @pad3: Reserved @0x14
- * @control: Control field @0x18
- * @status: Status field @0x1C
- */
-struct xilinx_cdma_desc_hw {
-       u32 next_desc;
-       u32 pad1;
-       u32 src_addr;
-       u32 pad2;
-       u32 dest_addr;
-       u32 pad3;
-       u32 control;
-       u32 status;
-} __aligned(64);
-
-/**
- * struct xilinx_vdma_tx_segment - Descriptor segment
- * @hw: Hardware descriptor
- * @node: Node in the descriptor segments list
- * @phys: Physical address of segment
- */
-struct xilinx_vdma_tx_segment {
-       struct xilinx_vdma_desc_hw hw;
-       struct list_head node;
-       dma_addr_t phys;
-} __aligned(64);
-
-/**
- * struct xilinx_axidma_tx_segment - Descriptor segment
- * @hw: Hardware descriptor
- * @node: Node in the descriptor segments list
- * @phys: Physical address of segment
- */
-struct xilinx_axidma_tx_segment {
-       struct xilinx_axidma_desc_hw hw;
-       struct list_head node;
-       dma_addr_t phys;
-} __aligned(64);
-
-/**
- * struct xilinx_cdma_tx_segment - Descriptor segment
- * @hw: Hardware descriptor
- * @node: Node in the descriptor segments list
- * @phys: Physical address of segment
- */
-struct xilinx_cdma_tx_segment {
-       struct xilinx_cdma_desc_hw hw;
-       struct list_head node;
-       dma_addr_t phys;
-} __aligned(64);
-
-/**
- * struct xilinx_dma_tx_descriptor - Per Transaction structure
- * @async_tx: Async transaction descriptor
- * @segments: TX segments list
- * @node: Node in the channel descriptors list
- */
-struct xilinx_dma_tx_descriptor {
-       struct dma_async_tx_descriptor async_tx;
-       struct list_head segments;
-       struct list_head node;
-};
-
-/**
- * struct xilinx_dma_chan - Driver specific DMA channel structure
- * @xdev: Driver specific device structure
- * @ctrl_offset: Control registers offset
- * @desc_offset: TX descriptor registers offset
- * @lock: Descriptor operation lock
- * @pending_list: Descriptors waiting
- * @active_list: Descriptors ready to submit
- * @done_list: Complete descriptors
- * @common: DMA common channel
- * @desc_pool: Descriptors pool
- * @dev: The dma device
- * @irq: Channel IRQ
- * @id: Channel ID
- * @direction: Transfer direction
- * @num_frms: Number of frames
- * @has_sg: Support scatter transfers
- * @genlock: Support genlock mode
- * @err: Channel has errors
- * @tasklet: Cleanup work after irq
- * @config: Device configuration info
- * @flush_on_fsync: Flush on Frame sync
- * @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
- * @start_transfer: Differentiate b/w DMA IP's transfer
- */
-struct xilinx_dma_chan {
-       struct xilinx_dma_device *xdev;
-       u32 ctrl_offset;
-       u32 desc_offset;
-       spinlock_t lock;
-       struct list_head pending_list;
-       struct list_head active_list;
-       struct list_head done_list;
-       struct dma_chan common;
-       struct dma_pool *desc_pool;
-       struct device *dev;
-       int irq;
-       int id;
-       enum dma_transfer_direction direction;
-       int num_frms;
-       bool has_sg;
-       bool genlock;
-       bool err;
-       struct tasklet_struct tasklet;
-       struct xilinx_vdma_config config;
-       bool flush_on_fsync;
-       u32 desc_pendingcount;
-       bool ext_addr;
-       u32 desc_submitcount;
-       u32 residue;
-       struct xilinx_axidma_tx_segment *seg_v;
-       void (*start_transfer)(struct xilinx_dma_chan *chan);
-};
-
-struct xilinx_dma_config {
-       enum xdma_ip_type dmatype;
-       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);
-};
-
-/**
- * struct xilinx_dma_device - DMA device structure
- * @regs: I/O mapped base address
- * @dev: Device Structure
- * @common: DMA device structure
- * @chan: Driver specific DMA channel
- * @has_sg: Specifies whether Scatter-Gather 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
- * @dma_config: DMA config structure
- * @axi_clk: DMA Axi4-lite interace clock
- * @tx_clk: DMA mm2s clock
- * @txs_clk: DMA mm2s stream clock
- * @rx_clk: DMA s2mm clock
- * @rxs_clk: DMA s2mm stream clock
- */
-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 has_sg;
-       u32 flush_on_fsync;
-       bool ext_addr;
-       struct platform_device  *pdev;
-       const struct xilinx_dma_config *dma_config;
-       struct clk *axi_clk;
-       struct clk *tx_clk;
-       struct clk *txs_clk;
-       struct clk *rx_clk;
-       struct clk *rxs_clk;
-};
-
-/* Macros */
-#define to_xilinx_chan(chan) \
-       container_of(chan, struct xilinx_dma_chan, common)
-#define to_dma_tx_descriptor(tx) \
-       container_of(tx, struct xilinx_dma_tx_descriptor, async_tx)
-#define xilinx_dma_poll_timeout(chan, reg, val, cond, delay_us, timeout_us) \
-       readl_poll_timeout(chan->xdev->regs + chan->ctrl_offset + reg, val, \
-                          cond, delay_us, timeout_us)
-
-/* IO accessors */
-static inline u32 dma_read(struct xilinx_dma_chan *chan, u32 reg)
-{
-       return ioread32(chan->xdev->regs + reg);
-}
-
-static inline void dma_write(struct xilinx_dma_chan *chan, u32 reg, u32 value)
-{
-       iowrite32(value, chan->xdev->regs + reg);
-}
-
-static inline void vdma_desc_write(struct xilinx_dma_chan *chan, u32 reg,
-                                  u32 value)
-{
-       dma_write(chan, chan->desc_offset + reg, value);
-}
-
-static inline u32 dma_ctrl_read(struct xilinx_dma_chan *chan, u32 reg)
-{
-       return dma_read(chan, chan->ctrl_offset + reg);
-}
-
-static inline void dma_ctrl_write(struct xilinx_dma_chan *chan, u32 reg,
-                                  u32 value)
-{
-       dma_write(chan, chan->ctrl_offset + reg, value);
-}
-
-static inline void dma_ctrl_clr(struct xilinx_dma_chan *chan, u32 reg,
-                                u32 clr)
-{
-       dma_ctrl_write(chan, reg, dma_ctrl_read(chan, reg) & ~clr);
-}
-
-static inline void dma_ctrl_set(struct xilinx_dma_chan *chan, u32 reg,
-                                u32 set)
-{
-       dma_ctrl_write(chan, reg, dma_ctrl_read(chan, reg) | set);
-}
-
-/**
- * vdma_desc_write_64 - 64-bit descriptor write
- * @chan: Driver specific VDMA channel
- * @reg: Register to write
- * @value_lsb: lower address of the descriptor.
- * @value_msb: upper address of the descriptor.
- *
- * Since vdma driver is trying to write to a register offset which is not a
- * multiple of 64 bits(ex : 0x5c), we are writing as two separate 32 bits
- * instead of a single 64 bit register write.
- */
-static inline void vdma_desc_write_64(struct xilinx_dma_chan *chan, u32 reg,
-                                     u32 value_lsb, u32 value_msb)
-{
-       /* Write the lsb 32 bits*/
-       writel(value_lsb, chan->xdev->regs + chan->desc_offset + reg);
-
-       /* Write the msb 32 bits */
-       writel(value_msb, chan->xdev->regs + chan->desc_offset + reg + 4);
-}
-
-/* -----------------------------------------------------------------------------
- * Descriptors and segments alloc and free
- */
-
-/**
- * xilinx_vdma_alloc_tx_segment - Allocate transaction segment
- * @chan: Driver specific DMA channel
- *
- * Return: The allocated segment on success and NULL on failure.
- */
-static struct xilinx_vdma_tx_segment *
-xilinx_vdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_vdma_tx_segment *segment;
-       dma_addr_t phys;
-
-       segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys);
-       if (!segment)
-               return NULL;
-
-       segment->phys = phys;
-
-       return segment;
-}
-
-/**
- * xilinx_cdma_alloc_tx_segment - Allocate transaction segment
- * @chan: Driver specific DMA channel
- *
- * Return: The allocated segment on success and NULL on failure.
- */
-static struct xilinx_cdma_tx_segment *
-xilinx_cdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_cdma_tx_segment *segment;
-       dma_addr_t phys;
-
-       segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys);
-       if (!segment)
-               return NULL;
-
-       memset(segment, 0, sizeof(*segment));
-       segment->phys = phys;
-
-       return segment;
-}
-
-/**
- * xilinx_axidma_alloc_tx_segment - Allocate transaction segment
- * @chan: Driver specific DMA channel
- *
- * Return: The allocated segment on success and NULL on failure.
- */
-static struct xilinx_axidma_tx_segment *
-xilinx_axidma_alloc_tx_segment(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_axidma_tx_segment *segment;
-       dma_addr_t phys;
-
-       segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys);
-       if (!segment)
-               return NULL;
-
-       memset(segment, 0, sizeof(*segment));
-       segment->phys = phys;
-
-       return segment;
-}
-
-/**
- * xilinx_dma_free_tx_segment - Free transaction segment
- * @chan: Driver specific DMA channel
- * @segment: DMA transaction segment
- */
-static void xilinx_dma_free_tx_segment(struct xilinx_dma_chan *chan,
-                               struct xilinx_axidma_tx_segment *segment)
-{
-       dma_pool_free(chan->desc_pool, segment, segment->phys);
-}
-
-/**
- * xilinx_cdma_free_tx_segment - Free transaction segment
- * @chan: Driver specific DMA channel
- * @segment: DMA transaction segment
- */
-static void xilinx_cdma_free_tx_segment(struct xilinx_dma_chan *chan,
-                               struct xilinx_cdma_tx_segment *segment)
-{
-       dma_pool_free(chan->desc_pool, segment, segment->phys);
-}
-
-/**
- * xilinx_vdma_free_tx_segment - Free transaction segment
- * @chan: Driver specific DMA channel
- * @segment: DMA transaction segment
- */
-static void xilinx_vdma_free_tx_segment(struct xilinx_dma_chan *chan,
-                                       struct xilinx_vdma_tx_segment *segment)
-{
-       dma_pool_free(chan->desc_pool, segment, segment->phys);
-}
-
-/**
- * xilinx_dma_tx_descriptor - Allocate transaction descriptor
- * @chan: Driver specific DMA channel
- *
- * Return: The allocated descriptor on success and NULL on failure.
- */
-static struct xilinx_dma_tx_descriptor *
-xilinx_dma_alloc_tx_descriptor(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *desc;
-
-       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return NULL;
-
-       INIT_LIST_HEAD(&desc->segments);
-
-       return desc;
-}
-
-/**
- * xilinx_dma_free_tx_descriptor - Free transaction descriptor
- * @chan: Driver specific DMA channel
- * @desc: DMA transaction descriptor
- */
-static void
-xilinx_dma_free_tx_descriptor(struct xilinx_dma_chan *chan,
-                              struct xilinx_dma_tx_descriptor *desc)
-{
-       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;
-
-       if (!desc)
-               return;
-
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-               list_for_each_entry_safe(segment, next, &desc->segments, node) {
-                       list_del(&segment->node);
-                       xilinx_vdma_free_tx_segment(chan, segment);
-               }
-       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
-               list_for_each_entry_safe(cdma_segment, cdma_next,
-                                        &desc->segments, node) {
-                       list_del(&cdma_segment->node);
-                       xilinx_cdma_free_tx_segment(chan, cdma_segment);
-               }
-       } else {
-               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);
-               }
-       }
-
-       kfree(desc);
-}
-
-/* Required functions */
-
-/**
- * xilinx_dma_free_desc_list - Free descriptors list
- * @chan: Driver specific DMA channel
- * @list: List to parse and delete the descriptor
- */
-static void xilinx_dma_free_desc_list(struct xilinx_dma_chan *chan,
-                                       struct list_head *list)
-{
-       struct xilinx_dma_tx_descriptor *desc, *next;
-
-       list_for_each_entry_safe(desc, next, list, node) {
-               list_del(&desc->node);
-               xilinx_dma_free_tx_descriptor(chan, desc);
-       }
-}
-
-/**
- * xilinx_dma_free_descriptors - Free channel descriptors
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_free_descriptors(struct xilinx_dma_chan *chan)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->lock, flags);
-
-       xilinx_dma_free_desc_list(chan, &chan->pending_list);
-       xilinx_dma_free_desc_list(chan, &chan->done_list);
-       xilinx_dma_free_desc_list(chan, &chan->active_list);
-
-       spin_unlock_irqrestore(&chan->lock, flags);
-}
-
-/**
- * xilinx_dma_free_chan_resources - Free channel resources
- * @dchan: DMA channel
- */
-static void xilinx_dma_free_chan_resources(struct dma_chan *dchan)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-
-       dev_dbg(chan->dev, "Free all channel resources.\n");
-
-       xilinx_dma_free_descriptors(chan);
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
-               xilinx_dma_free_tx_segment(chan, chan->seg_v);
-       dma_pool_destroy(chan->desc_pool);
-       chan->desc_pool = NULL;
-}
-
-/**
- * xilinx_dma_chan_desc_cleanup - Clean channel descriptors
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *desc, *next;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->lock, flags);
-
-       list_for_each_entry_safe(desc, next, &chan->done_list, node) {
-               dma_async_tx_callback callback;
-               void *callback_param;
-
-               /* Remove from the list of running transactions */
-               list_del(&desc->node);
-
-               /* Run the link descriptor callback function */
-               callback = desc->async_tx.callback;
-               callback_param = desc->async_tx.callback_param;
-               if (callback) {
-                       spin_unlock_irqrestore(&chan->lock, flags);
-                       callback(callback_param);
-                       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);
-       }
-
-       spin_unlock_irqrestore(&chan->lock, flags);
-}
-
-/**
- * xilinx_dma_do_tasklet - Schedule completion tasklet
- * @data: Pointer to the Xilinx DMA channel structure
- */
-static void xilinx_dma_do_tasklet(unsigned long data)
-{
-       struct xilinx_dma_chan *chan = (struct xilinx_dma_chan *)data;
-
-       xilinx_dma_chan_desc_cleanup(chan);
-}
-
-/**
- * xilinx_dma_alloc_chan_resources - Allocate channel resources
- * @dchan: DMA channel
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-
-       /* Has this channel already been allocated? */
-       if (chan->desc_pool)
-               return 0;
-
-       /*
-        * We need the descriptor to be aligned to 64bytes
-        * for meeting Xilinx VDMA specification requirement.
-        */
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               chan->desc_pool = dma_pool_create("xilinx_dma_desc_pool",
-                                  chan->dev,
-                                  sizeof(struct xilinx_axidma_tx_segment),
-                                  __alignof__(struct xilinx_axidma_tx_segment),
-                                  0);
-       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
-               chan->desc_pool = dma_pool_create("xilinx_cdma_desc_pool",
-                                  chan->dev,
-                                  sizeof(struct xilinx_cdma_tx_segment),
-                                  __alignof__(struct xilinx_cdma_tx_segment),
-                                  0);
-       } else {
-               chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool",
-                                    chan->dev,
-                                    sizeof(struct xilinx_vdma_tx_segment),
-                                    __alignof__(struct xilinx_vdma_tx_segment),
-                                    0);
-       }
-
-       if (!chan->desc_pool) {
-               dev_err(chan->dev,
-                       "unable to allocate channel %d descriptor pool\n",
-                       chan->id);
-               return -ENOMEM;
-       }
-
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
-               /*
-                * For AXI DMA case after submitting a pending_list, keep
-                * an extra segment allocated so that the "next descriptor"
-                * pointer on the tail descriptor always points to a
-                * valid descriptor, even when paused after reaching taildesc.
-                * This way, it is possible to issue additional
-                * transfers without halting and restarting the channel.
-                */
-               chan->seg_v = xilinx_axidma_alloc_tx_segment(chan);
-
-       dma_cookie_init(dchan);
-
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               /* For AXI DMA resetting once channel will reset the
-                * other channel as well so enable the interrupts here.
-                */
-               dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
-                             XILINX_DMA_DMAXR_ALL_IRQ_MASK);
-       }
-
-       if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
-               dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
-                            XILINX_CDMA_CR_SGMODE);
-
-       return 0;
-}
-
-/**
- * xilinx_dma_tx_status - Get DMA transaction status
- * @dchan: DMA channel
- * @cookie: Transaction identifier
- * @txstate: Transaction state
- *
- * Return: DMA transaction status
- */
-static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
-                                       dma_cookie_t cookie,
-                                       struct dma_tx_state *txstate)
-{
-       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;
-
-       ret = dma_cookie_status(dchan, cookie, txstate);
-       if (ret == DMA_COMPLETE || !txstate)
-               return ret;
-
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               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) &
-                                          XILINX_DMA_MAX_TRANS_LEN;
-                       }
-               }
-               spin_unlock_irqrestore(&chan->lock, flags);
-
-               chan->residue = residue;
-               dma_set_residue(txstate, chan->residue);
-       }
-
-       return ret;
-}
-
-/**
- * xilinx_dma_is_running - Check if DMA channel is running
- * @chan: Driver specific DMA channel
- *
- * Return: '1' if running, '0' if not.
- */
-static bool xilinx_dma_is_running(struct xilinx_dma_chan *chan)
-{
-       return !(dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
-                XILINX_DMA_DMASR_HALTED) &&
-               (dma_ctrl_read(chan, XILINX_DMA_REG_DMACR) &
-                XILINX_DMA_DMACR_RUNSTOP);
-}
-
-/**
- * xilinx_dma_is_idle - Check if DMA channel is idle
- * @chan: Driver specific DMA channel
- *
- * Return: '1' if idle, '0' if not.
- */
-static bool xilinx_dma_is_idle(struct xilinx_dma_chan *chan)
-{
-       return dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
-               XILINX_DMA_DMASR_IDLE;
-}
-
-/**
- * xilinx_dma_halt - Halt DMA channel
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_halt(struct xilinx_dma_chan *chan)
-{
-       int err;
-       u32 val;
-
-       dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP);
-
-       /* Wait for the hardware to halt */
-       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
-                                     (val & XILINX_DMA_DMASR_HALTED), 0,
-                                     XILINX_DMA_LOOP_COUNT);
-
-       if (err) {
-               dev_err(chan->dev, "Cannot stop channel %p: %x\n",
-                       chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
-               chan->err = true;
-       }
-}
-
-/**
- * xilinx_dma_start - Start DMA channel
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_start(struct xilinx_dma_chan *chan)
-{
-       int err;
-       u32 val;
-
-       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP);
-
-       /* Wait for the hardware to start */
-       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
-                                     !(val & XILINX_DMA_DMASR_HALTED), 0,
-                                     XILINX_DMA_LOOP_COUNT);
-
-       if (err) {
-               dev_err(chan->dev, "Cannot start channel %p: %x\n",
-                       chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
-
-               chan->err = true;
-       }
-}
-
-/**
- * xilinx_vdma_start_transfer - Starts VDMA transfer
- * @chan: Driver specific channel struct pointer
- */
-static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_vdma_config *config = &chan->config;
-       struct xilinx_dma_tx_descriptor *desc, *tail_desc;
-       u32 reg;
-       struct xilinx_vdma_tx_segment *tail_segment;
-
-       /* This function was invoked with lock held */
-       if (chan->err)
-               return;
-
-       if (list_empty(&chan->pending_list))
-               return;
-
-       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_vdma_tx_segment, node);
-
-       /* If it is SG mode and hardware is busy, cannot submit */
-       if (chan->has_sg && xilinx_dma_is_running(chan) &&
-           !xilinx_dma_is_idle(chan)) {
-               dev_dbg(chan->dev, "DMA controller still busy\n");
-               return;
-       }
-
-       /*
-        * If hardware is idle, then all descriptors on the running lists are
-        * done, start new transfers
-        */
-       if (chan->has_sg)
-               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                               desc->async_tx.phys);
-
-       /* Configure the hardware using info in the config structure */
-       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
-
-       if (config->frm_cnt_en)
-               reg |= XILINX_DMA_DMACR_FRAMECNT_EN;
-       else
-               reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN;
-
-       /* Configure channel to allow number frame buffers */
-       dma_ctrl_write(chan, XILINX_DMA_REG_FRMSTORE,
-                       chan->desc_pendingcount);
-
-       /*
-        * With SG, start with circular mode, so that BDs can be fetched.
-        * In direct register mode, if not parking, enable circular mode
-        */
-       if (chan->has_sg || !config->park)
-               reg |= XILINX_DMA_DMACR_CIRC_EN;
-
-       if (config->park)
-               reg &= ~XILINX_DMA_DMACR_CIRC_EN;
-
-       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
-
-       if (config->park && (config->park_frm >= 0) &&
-                       (config->park_frm < chan->num_frms)) {
-               if (chan->direction == DMA_MEM_TO_DEV)
-                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
-                               config->park_frm <<
-                                       XILINX_DMA_PARK_PTR_RD_REF_SHIFT);
-               else
-                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
-                               config->park_frm <<
-                                       XILINX_DMA_PARK_PTR_WR_REF_SHIFT);
-       }
-
-       /* Start the hardware */
-       xilinx_dma_start(chan);
-
-       if (chan->err)
-               return;
-
-       /* Start the transfer */
-       if (chan->has_sg) {
-               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                               tail_segment->phys);
-       } else {
-               struct xilinx_vdma_tx_segment *segment, *last = NULL;
-               int i = 0;
-
-               if (chan->desc_submitcount < chan->num_frms)
-                       i = chan->desc_submitcount;
-
-               list_for_each_entry(segment, &desc->segments, node) {
-                       if (chan->ext_addr)
-                               vdma_desc_write_64(chan,
-                                       XILINX_VDMA_REG_START_ADDRESS_64(i++),
-                                       segment->hw.buf_addr,
-                                       segment->hw.buf_addr_msb);
-                       else
-                               vdma_desc_write(chan,
-                                       XILINX_VDMA_REG_START_ADDRESS(i++),
-                                       segment->hw.buf_addr);
-
-                       last = segment;
-               }
-
-               if (!last)
-                       return;
-
-               /* HW expects these parameters to be same for one transaction */
-               vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize);
-               vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE,
-                               last->hw.stride);
-               vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
-       }
-
-       if (!chan->has_sg) {
-               list_del(&desc->node);
-               list_add_tail(&desc->node, &chan->active_list);
-               chan->desc_submitcount++;
-               chan->desc_pendingcount--;
-               if (chan->desc_submitcount == chan->num_frms)
-                       chan->desc_submitcount = 0;
-       } else {
-               list_splice_tail_init(&chan->pending_list, &chan->active_list);
-               chan->desc_pendingcount = 0;
-       }
-}
-
-/**
- * xilinx_cdma_start_transfer - Starts cdma transfer
- * @chan: Driver specific channel struct pointer
- */
-static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
-       struct xilinx_cdma_tx_segment *tail_segment;
-       u32 ctrl_reg = dma_read(chan, XILINX_DMA_REG_DMACR);
-
-       if (chan->err)
-               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_cdma_tx_segment, node);
-
-       if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) {
-               ctrl_reg &= ~XILINX_DMA_CR_COALESCE_MAX;
-               ctrl_reg |= chan->desc_pendingcount <<
-                               XILINX_DMA_CR_COALESCE_SHIFT;
-               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, ctrl_reg);
-       }
-
-       if (chan->has_sg) {
-               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                          head_desc->async_tx.phys);
-
-               /* Update tail ptr register which will start the transfer */
-               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                              tail_segment->phys);
-       } else {
-               /* In simple mode */
-               struct xilinx_cdma_tx_segment *segment;
-               struct xilinx_cdma_desc_hw *hw;
-
-               segment = list_first_entry(&head_desc->segments,
-                                          struct xilinx_cdma_tx_segment,
-                                          node);
-
-               hw = &segment->hw;
-
-               dma_ctrl_write(chan, XILINX_CDMA_REG_SRCADDR, hw->src_addr);
-               dma_ctrl_write(chan, XILINX_CDMA_REG_DSTADDR, hw->dest_addr);
-
-               /* Start the transfer */
-               dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
-                               hw->control & XILINX_DMA_MAX_TRANS_LEN);
-       }
-
-       list_splice_tail_init(&chan->pending_list, &chan->active_list);
-       chan->desc_pendingcount = 0;
-}
-
-/**
- * xilinx_dma_start_transfer - Starts DMA transfer
- * @chan: Driver specific channel struct pointer
- */
-static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
-       struct xilinx_axidma_tx_segment *tail_segment, *old_head, *new_head;
-       u32 reg;
-
-       if (chan->err)
-               return;
-
-       if (list_empty(&chan->pending_list))
-               return;
-
-       /* If it is SG mode and hardware is busy, cannot submit */
-       if (chan->has_sg && xilinx_dma_is_running(chan) &&
-           !xilinx_dma_is_idle(chan)) {
-               dev_dbg(chan->dev, "DMA controller still busy\n");
-               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);
-
-       old_head = list_first_entry(&head_desc->segments,
-                               struct xilinx_axidma_tx_segment, node);
-       new_head = chan->seg_v;
-       /* Copy Buffer Descriptor fields. */
-       new_head->hw = old_head->hw;
-
-       /* Swap and save new reserve */
-       list_replace_init(&old_head->node, &new_head->node);
-       chan->seg_v = old_head;
-
-       tail_segment->hw.next_desc = chan->seg_v->phys;
-       head_desc->async_tx.phys = new_head->phys;
-
-       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
-
-       if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) {
-               reg &= ~XILINX_DMA_CR_COALESCE_MAX;
-               reg |= chan->desc_pendingcount <<
-                                 XILINX_DMA_CR_COALESCE_SHIFT;
-               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
-       }
-
-       if (chan->has_sg)
-               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                              head_desc->async_tx.phys);
-
-       xilinx_dma_start(chan);
-
-       if (chan->err)
-               return;
-
-       /* Start the transfer */
-       if (chan->has_sg) {
-               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                              tail_segment->phys);
-       } else {
-               struct xilinx_axidma_tx_segment *segment;
-               struct xilinx_axidma_desc_hw *hw;
-
-               segment = list_first_entry(&head_desc->segments,
-                                          struct xilinx_axidma_tx_segment,
-                                          node);
-               hw = &segment->hw;
-
-               dma_ctrl_write(chan, XILINX_DMA_REG_SRCDSTADDR, hw->buf_addr);
-
-               /* Start the transfer */
-               dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
-                              hw->control & XILINX_DMA_MAX_TRANS_LEN);
-       }
-
-       list_splice_tail_init(&chan->pending_list, &chan->active_list);
-       chan->desc_pendingcount = 0;
-}
-
-/**
- * xilinx_dma_issue_pending - Issue pending transactions
- * @dchan: DMA channel
- */
-static void xilinx_dma_issue_pending(struct dma_chan *dchan)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->lock, flags);
-       chan->start_transfer(chan);
-       spin_unlock_irqrestore(&chan->lock, flags);
-}
-
-/**
- * xilinx_dma_complete_descriptor - Mark the active descriptor as complete
- * @chan : xilinx DMA channel
- *
- * CONTEXT: hardirq
- */
-static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *desc, *next;
-
-       /* This function was invoked with lock held */
-       if (list_empty(&chan->active_list))
-               return;
-
-       list_for_each_entry_safe(desc, next, &chan->active_list, node) {
-               list_del(&desc->node);
-               dma_cookie_complete(&desc->async_tx);
-               list_add_tail(&desc->node, &chan->done_list);
-       }
-}
-
-/**
- * xilinx_dma_reset - Reset DMA channel
- * @chan: Driver specific DMA channel
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_reset(struct xilinx_dma_chan *chan)
-{
-       int err;
-       u32 tmp;
-
-       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RESET);
-
-       /* Wait for the hardware to finish reset */
-       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMACR, tmp,
-                                     !(tmp & XILINX_DMA_DMACR_RESET), 0,
-                                     XILINX_DMA_LOOP_COUNT);
-
-       if (err) {
-               dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
-                       dma_ctrl_read(chan, XILINX_DMA_REG_DMACR),
-                       dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
-               return -ETIMEDOUT;
-       }
-
-       chan->err = false;
-
-       return err;
-}
-
-/**
- * xilinx_dma_chan_reset - Reset DMA channel and enable interrupts
- * @chan: Driver specific DMA channel
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_chan_reset(struct xilinx_dma_chan *chan)
-{
-       int err;
-
-       /* Reset VDMA */
-       err = xilinx_dma_reset(chan);
-       if (err)
-               return err;
-
-       /* Enable interrupts */
-       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
-                     XILINX_DMA_DMAXR_ALL_IRQ_MASK);
-
-       return 0;
-}
-
-/**
- * xilinx_dma_irq_handler - DMA Interrupt handler
- * @irq: IRQ number
- * @data: Pointer to the Xilinx DMA channel structure
- *
- * Return: IRQ_HANDLED/IRQ_NONE
- */
-static irqreturn_t xilinx_dma_irq_handler(int irq, void *data)
-{
-       struct xilinx_dma_chan *chan = data;
-       u32 status;
-
-       /* Read the status and ack the interrupts. */
-       status = dma_ctrl_read(chan, XILINX_DMA_REG_DMASR);
-       if (!(status & XILINX_DMA_DMAXR_ALL_IRQ_MASK))
-               return IRQ_NONE;
-
-       dma_ctrl_write(chan, XILINX_DMA_REG_DMASR,
-                       status & XILINX_DMA_DMAXR_ALL_IRQ_MASK);
-
-       if (status & XILINX_DMA_DMASR_ERR_IRQ) {
-               /*
-                * An error occurred. If C_FLUSH_ON_FSYNC is enabled and the
-                * error is recoverable, ignore it. Otherwise flag the error.
-                *
-                * Only recoverable errors can be cleared in the DMASR register,
-                * make sure not to write to other error bits to 1.
-                */
-               u32 errors = status & XILINX_DMA_DMASR_ALL_ERR_MASK;
-
-               dma_ctrl_write(chan, XILINX_DMA_REG_DMASR,
-                               errors & XILINX_DMA_DMASR_ERR_RECOVER_MASK);
-
-               if (!chan->flush_on_fsync ||
-                   (errors & ~XILINX_DMA_DMASR_ERR_RECOVER_MASK)) {
-                       dev_err(chan->dev,
-                               "Channel %p has errors %x, cdr %x tdr %x\n",
-                               chan, errors,
-                               dma_ctrl_read(chan, XILINX_DMA_REG_CURDESC),
-                               dma_ctrl_read(chan, XILINX_DMA_REG_TAILDESC));
-                       chan->err = true;
-               }
-       }
-
-       if (status & XILINX_DMA_DMASR_DLY_CNT_IRQ) {
-               /*
-                * 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_DMA_DMASR_FRM_CNT_IRQ) {
-               spin_lock(&chan->lock);
-               xilinx_dma_complete_descriptor(chan);
-               chan->start_transfer(chan);
-               spin_unlock(&chan->lock);
-       }
-
-       tasklet_schedule(&chan->tasklet);
-       return IRQ_HANDLED;
-}
-
-/**
- * append_desc_queue - Queuing descriptor
- * @chan: Driver specific dma channel
- * @desc: dma transaction descriptor
- */
-static void append_desc_queue(struct xilinx_dma_chan *chan,
-                             struct xilinx_dma_tx_descriptor *desc)
-{
-       struct xilinx_vdma_tx_segment *tail_segment;
-       struct xilinx_dma_tx_descriptor *tail_desc;
-       struct xilinx_axidma_tx_segment *axidma_tail_segment;
-       struct xilinx_cdma_tx_segment *cdma_tail_segment;
-
-       if (list_empty(&chan->pending_list))
-               goto append;
-
-       /*
-        * Add the hardware descriptor to the chain of hardware descriptors
-        * that already exists in memory.
-        */
-       tail_desc = list_last_entry(&chan->pending_list,
-                                   struct xilinx_dma_tx_descriptor, node);
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-               tail_segment = list_last_entry(&tail_desc->segments,
-                                              struct xilinx_vdma_tx_segment,
-                                              node);
-               tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
-       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
-               cdma_tail_segment = list_last_entry(&tail_desc->segments,
-                                               struct xilinx_cdma_tx_segment,
-                                               node);
-               cdma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
-       } else {
-               axidma_tail_segment = list_last_entry(&tail_desc->segments,
-                                              struct xilinx_axidma_tx_segment,
-                                              node);
-               axidma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
-       }
-
-       /*
-        * Add the software descriptor and all children to the list
-        * of pending transactions
-        */
-append:
-       list_add_tail(&desc->node, &chan->pending_list);
-       chan->desc_pendingcount++;
-
-       if (chan->has_sg && (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA)
-           && unlikely(chan->desc_pendingcount > chan->num_frms)) {
-               dev_dbg(chan->dev, "desc pendingcount is too high\n");
-               chan->desc_pendingcount = chan->num_frms;
-       }
-}
-
-/**
- * xilinx_dma_tx_submit - Submit DMA transaction
- * @tx: Async transaction descriptor
- *
- * Return: cookie value on success and failure value on error
- */
-static dma_cookie_t xilinx_dma_tx_submit(struct dma_async_tx_descriptor *tx)
-{
-       struct xilinx_dma_tx_descriptor *desc = to_dma_tx_descriptor(tx);
-       struct xilinx_dma_chan *chan = to_xilinx_chan(tx->chan);
-       dma_cookie_t cookie;
-       unsigned long flags;
-       int err;
-
-       if (chan->err) {
-               /*
-                * If reset fails, need to hard reset the system.
-                * Channel is no longer functional
-                */
-               err = xilinx_dma_chan_reset(chan);
-               if (err < 0)
-                       return err;
-       }
-
-       spin_lock_irqsave(&chan->lock, flags);
-
-       cookie = dma_cookie_assign(tx);
-
-       /* Put this transaction onto the tail of the pending queue */
-       append_desc_queue(chan, desc);
-
-       spin_unlock_irqrestore(&chan->lock, flags);
-
-       return cookie;
-}
-
-/**
- * xilinx_vdma_dma_prep_interleaved - prepare a descriptor for a
- *     DMA_SLAVE transaction
- * @dchan: DMA channel
- * @xt: Interleaved template pointer
- * @flags: transfer ack flags
- *
- * Return: Async transaction descriptor on success and NULL on failure
- */
-static struct dma_async_tx_descriptor *
-xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
-                                struct dma_interleaved_template *xt,
-                                unsigned long flags)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_vdma_tx_segment *segment, *prev = NULL;
-       struct xilinx_vdma_desc_hw *hw;
-
-       if (!is_slave_direction(xt->dir))
-               return NULL;
-
-       if (!xt->numf || !xt->sgl[0].size)
-               return NULL;
-
-       if (xt->frame_size != 1)
-               return NULL;
-
-       /* Allocate a transaction descriptor. */
-       desc = xilinx_dma_alloc_tx_descriptor(chan);
-       if (!desc)
-               return NULL;
-
-       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
-       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
-       async_tx_ack(&desc->async_tx);
-
-       /* Allocate the link descriptor from DMA pool */
-       segment = xilinx_vdma_alloc_tx_segment(chan);
-       if (!segment)
-               goto error;
-
-       /* Fill in the hardware descriptor */
-       hw = &segment->hw;
-       hw->vsize = xt->numf;
-       hw->hsize = xt->sgl[0].size;
-       hw->stride = (xt->sgl[0].icg + xt->sgl[0].size) <<
-                       XILINX_DMA_FRMDLY_STRIDE_STRIDE_SHIFT;
-       hw->stride |= chan->config.frm_dly <<
-                       XILINX_DMA_FRMDLY_STRIDE_FRMDLY_SHIFT;
-
-       if (xt->dir != DMA_MEM_TO_DEV) {
-               if (chan->ext_addr) {
-                       hw->buf_addr = lower_32_bits(xt->dst_start);
-                       hw->buf_addr_msb = upper_32_bits(xt->dst_start);
-               } else {
-                       hw->buf_addr = xt->dst_start;
-               }
-       } else {
-               if (chan->ext_addr) {
-                       hw->buf_addr = lower_32_bits(xt->src_start);
-                       hw->buf_addr_msb = upper_32_bits(xt->src_start);
-               } else {
-                       hw->buf_addr = xt->src_start;
-               }
-       }
-
-       /* Insert the segment into the descriptor segments list. */
-       list_add_tail(&segment->node, &desc->segments);
-
-       prev = segment;
-
-       /* Link the last hardware descriptor with the first. */
-       segment = list_first_entry(&desc->segments,
-                                  struct xilinx_vdma_tx_segment, node);
-       desc->async_tx.phys = segment->phys;
-
-       return &desc->async_tx;
-
-error:
-       xilinx_dma_free_tx_descriptor(chan, desc);
-       return NULL;
-}
-
-/**
- * xilinx_cdma_prep_memcpy - prepare descriptors for a memcpy transaction
- * @dchan: DMA channel
- * @dma_dst: destination address
- * @dma_src: source address
- * @len: transfer length
- * @flags: transfer ack flags
- *
- * Return: Async transaction descriptor on success and NULL on failure
- */
-static struct dma_async_tx_descriptor *
-xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst,
-                       dma_addr_t dma_src, size_t len, unsigned long flags)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_cdma_tx_segment *segment, *prev;
-       struct xilinx_cdma_desc_hw *hw;
-
-       if (!len || len > XILINX_DMA_MAX_TRANS_LEN)
-               return NULL;
-
-       desc = xilinx_dma_alloc_tx_descriptor(chan);
-       if (!desc)
-               return NULL;
-
-       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
-       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
-
-       /* Allocate the link descriptor from DMA pool */
-       segment = xilinx_cdma_alloc_tx_segment(chan);
-       if (!segment)
-               goto error;
-
-       hw = &segment->hw;
-       hw->control = len;
-       hw->src_addr = dma_src;
-       hw->dest_addr = dma_dst;
-
-       /* Fill the previous next descriptor with current */
-       prev = list_last_entry(&desc->segments,
-                              struct xilinx_cdma_tx_segment, node);
-       prev->hw.next_desc = segment->phys;
-
-       /* Insert the segment into the descriptor segments list. */
-       list_add_tail(&segment->node, &desc->segments);
-
-       prev = segment;
-
-       /* Link the last hardware descriptor with the first. */
-       segment = list_first_entry(&desc->segments,
-                               struct xilinx_cdma_tx_segment, node);
-       desc->async_tx.phys = segment->phys;
-       prev->hw.next_desc = segment->phys;
-
-       return &desc->async_tx;
-
-error:
-       xilinx_dma_free_tx_descriptor(chan, desc);
-       return NULL;
-}
-
-/**
- * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
- * @dchan: DMA channel
- * @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_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 = NULL, *prev = NULL;
-       u32 *app_w = (u32 *)context;
-       struct scatterlist *sg;
-       size_t copy;
-       size_t sg_used;
-       unsigned int i;
-
-       if (!is_slave_direction(direction))
-               return NULL;
-
-       /* Allocate a transaction descriptor. */
-       desc = xilinx_dma_alloc_tx_descriptor(chan);
-       if (!desc)
-               return NULL;
-
-       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
-       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
-
-       /* Build transactions using information in the scatter gather list */
-       for_each_sg(sgl, sg, sg_len, i) {
-               sg_used = 0;
-
-               /* Loop until the entire scatterlist entry is used */
-               while (sg_used < sg_dma_len(sg)) {
-                       struct xilinx_axidma_desc_hw *hw;
-
-                       /* Get a free segment */
-                       segment = xilinx_axidma_alloc_tx_segment(chan);
-                       if (!segment)
-                               goto error;
-
-                       /*
-                        * 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,
-                                    XILINX_DMA_MAX_TRANS_LEN);
-                       hw = &segment->hw;
-
-                       /* Fill in the descriptor */
-                       hw->buf_addr = sg_dma_address(sg) + sg_used;
-
-                       hw->control = copy;
-
-                       if (chan->direction == DMA_MEM_TO_DEV) {
-                               if (app_w)
-                                       memcpy(hw->app, app_w, sizeof(u32) *
-                                              XILINX_DMA_NUM_APP_WORDS);
-                       }
-
-                       if (prev)
-                               prev->hw.next_desc = segment->phys;
-
-                       prev = segment;
-                       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);
-       desc->async_tx.phys = segment->phys;
-       prev->hw.next_desc = segment->phys;
-
-       /* For the last DMA_MEM_TO_DEV transfer, set EOP */
-       if (chan->direction == DMA_MEM_TO_DEV) {
-               segment->hw.control |= XILINX_DMA_BD_SOP;
-               segment = list_last_entry(&desc->segments,
-                                         struct xilinx_axidma_tx_segment,
-                                         node);
-               segment->hw.control |= XILINX_DMA_BD_EOP;
-       }
-
-       return &desc->async_tx;
-
-error:
-       xilinx_dma_free_tx_descriptor(chan, desc);
-       return NULL;
-}
-
-/**
- * xilinx_dma_terminate_all - Halt the channel and free descriptors
- * @chan: Driver specific DMA Channel pointer
- */
-static int xilinx_dma_terminate_all(struct dma_chan *dchan)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-
-       /* Halt the DMA engine */
-       xilinx_dma_halt(chan);
-
-       /* Remove and free all of the descriptors in the lists */
-       xilinx_dma_free_descriptors(chan);
-
-       return 0;
-}
-
-/**
- * xilinx_dma_channel_set_config - Configure VDMA channel
- * Run-time configuration for Axi VDMA, supports:
- * . halt the channel
- * . configure interrupt coalescing and inter-packet delay threshold
- * . start/stop parking
- * . enable genlock
- *
- * @dchan: DMA channel
- * @cfg: VDMA device configuration pointer
- *
- * Return: '0' on success and failure value on error
- */
-int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
-                                       struct xilinx_vdma_config *cfg)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       u32 dmacr;
-
-       if (cfg->reset)
-               return xilinx_dma_chan_reset(chan);
-
-       dmacr = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
-
-       chan->config.frm_dly = cfg->frm_dly;
-       chan->config.park = cfg->park;
-
-       /* genlock settings */
-       chan->config.gen_lock = cfg->gen_lock;
-       chan->config.master = cfg->master;
-
-       if (cfg->gen_lock && chan->genlock) {
-               dmacr |= XILINX_DMA_DMACR_GENLOCK_EN;
-               dmacr |= cfg->master << XILINX_DMA_DMACR_MASTER_SHIFT;
-       }
-
-       chan->config.frm_cnt_en = cfg->frm_cnt_en;
-       if (cfg->park)
-               chan->config.park_frm = cfg->park_frm;
-       else
-               chan->config.park_frm = -1;
-
-       chan->config.coalesc = cfg->coalesc;
-       chan->config.delay = cfg->delay;
-
-       if (cfg->coalesc <= XILINX_DMA_DMACR_FRAME_COUNT_MAX) {
-               dmacr |= cfg->coalesc << XILINX_DMA_DMACR_FRAME_COUNT_SHIFT;
-               chan->config.coalesc = cfg->coalesc;
-       }
-
-       if (cfg->delay <= XILINX_DMA_DMACR_DELAY_MAX) {
-               dmacr |= cfg->delay << XILINX_DMA_DMACR_DELAY_SHIFT;
-               chan->config.delay = cfg->delay;
-       }
-
-       /* FSync Source selection */
-       dmacr &= ~XILINX_DMA_DMACR_FSYNCSRC_MASK;
-       dmacr |= cfg->ext_fsync << XILINX_DMA_DMACR_FSYNCSRC_SHIFT;
-
-       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, dmacr);
-
-       return 0;
-}
-EXPORT_SYMBOL(xilinx_vdma_channel_set_config);
-
-/* -----------------------------------------------------------------------------
- * Probe and remove
- */
-
-/**
- * xilinx_dma_chan_remove - Per Channel remove function
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan)
-{
-       /* Disable all interrupts */
-       dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR,
-                     XILINX_DMA_DMAXR_ALL_IRQ_MASK);
-
-       if (chan->irq > 0)
-               free_irq(chan->irq, chan);
-
-       tasklet_kill(&chan->tasklet);
-
-       list_del(&chan->common.device_node);
-}
-
-static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
-                           struct clk **tx_clk, struct clk **rx_clk,
-                           struct clk **sg_clk, struct clk **tmp_clk)
-{
-       int err;
-
-       *tmp_clk = NULL;
-
-       *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 (%u)\n", err);
-               return err;
-       }
-
-       *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
-       if (IS_ERR(*tx_clk))
-               *tx_clk = NULL;
-
-       *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
-       if (IS_ERR(*rx_clk))
-               *rx_clk = NULL;
-
-       *sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk");
-       if (IS_ERR(*sg_clk))
-               *sg_clk = NULL;
-
-       err = clk_prepare_enable(*axi_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
-               return err;
-       }
-
-       err = clk_prepare_enable(*tx_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
-               goto err_disable_axiclk;
-       }
-
-       err = clk_prepare_enable(*rx_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
-               goto err_disable_txclk;
-       }
-
-       err = clk_prepare_enable(*sg_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable sg_clk (%u)\n", err);
-               goto err_disable_rxclk;
-       }
-
-       return 0;
-
-err_disable_rxclk:
-       clk_disable_unprepare(*rx_clk);
-err_disable_txclk:
-       clk_disable_unprepare(*tx_clk);
-err_disable_axiclk:
-       clk_disable_unprepare(*axi_clk);
-
-       return err;
-}
-
-static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
-                           struct clk **dev_clk, struct clk **tmp_clk,
-                           struct clk **tmp1_clk, struct clk **tmp2_clk)
-{
-       int err;
-
-       *tmp_clk = NULL;
-       *tmp1_clk = NULL;
-       *tmp2_clk = NULL;
-
-       *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 (%u)\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 (%u)\n", err);
-               return err;
-       }
-
-       err = clk_prepare_enable(*axi_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
-               return err;
-       }
-
-       err = clk_prepare_enable(*dev_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable dev_clk (%u)\n", err);
-               goto err_disable_axiclk;
-       }
-
-       return 0;
-
-err_disable_axiclk:
-       clk_disable_unprepare(*axi_clk);
-
-       return err;
-}
-
-static int axivdma_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)
-{
-       int err;
-
-       *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 (%u)\n", err);
-               return err;
-       }
-
-       *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
-       if (IS_ERR(*tx_clk))
-               *tx_clk = NULL;
-
-       *txs_clk = devm_clk_get(&pdev->dev, "m_axis_mm2s_aclk");
-       if (IS_ERR(*txs_clk))
-               *txs_clk = NULL;
-
-       *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
-       if (IS_ERR(*rx_clk))
-               *rx_clk = NULL;
-
-       *rxs_clk = devm_clk_get(&pdev->dev, "s_axis_s2mm_aclk");
-       if (IS_ERR(*rxs_clk))
-               *rxs_clk = NULL;
-
-       err = clk_prepare_enable(*axi_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
-               return err;
-       }
-
-       err = clk_prepare_enable(*tx_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
-               goto err_disable_axiclk;
-       }
-
-       err = clk_prepare_enable(*txs_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err);
-               goto err_disable_txclk;
-       }
-
-       err = clk_prepare_enable(*rx_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
-               goto err_disable_txsclk;
-       }
-
-       err = clk_prepare_enable(*rxs_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err);
-               goto err_disable_rxclk;
-       }
-
-       return 0;
-
-err_disable_rxclk:
-       clk_disable_unprepare(*rx_clk);
-err_disable_txsclk:
-       clk_disable_unprepare(*txs_clk);
-err_disable_txclk:
-       clk_disable_unprepare(*tx_clk);
-err_disable_axiclk:
-       clk_disable_unprepare(*axi_clk);
-
-       return err;
-}
-
-static void xdma_disable_allclks(struct xilinx_dma_device *xdev)
-{
-       clk_disable_unprepare(xdev->rxs_clk);
-       clk_disable_unprepare(xdev->rx_clk);
-       clk_disable_unprepare(xdev->txs_clk);
-       clk_disable_unprepare(xdev->tx_clk);
-       clk_disable_unprepare(xdev->axi_clk);
-}
-
-/**
- * xilinx_dma_chan_probe - Per Channel Probing
- * It get channel features from the device tree entry and
- * initialize special channel handling routines
- *
- * @xdev: Driver specific device structure
- * @node: Device node
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
-                                 struct device_node *node)
-{
-       struct xilinx_dma_chan *chan;
-       bool has_dre = false;
-       u32 value, width;
-       int err;
-
-       /* Allocate and initialize the channel structure */
-       chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL);
-       if (!chan)
-               return -ENOMEM;
-
-       chan->dev = xdev->dev;
-       chan->xdev = xdev;
-       chan->has_sg = xdev->has_sg;
-       chan->desc_pendingcount = 0x0;
-       chan->ext_addr = xdev->ext_addr;
-
-       spin_lock_init(&chan->lock);
-       INIT_LIST_HEAD(&chan->pending_list);
-       INIT_LIST_HEAD(&chan->done_list);
-       INIT_LIST_HEAD(&chan->active_list);
-
-       /* Retrieve the channel properties from the device tree */
-       has_dre = of_property_read_bool(node, "xlnx,include-dre");
-
-       chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode");
-
-       err = of_property_read_u32(node, "xlnx,datawidth", &value);
-       if (err) {
-               dev_err(xdev->dev, "missing xlnx,datawidth property\n");
-               return err;
-       }
-       width = value >> 3; /* Convert bits to bytes */
-
-       /* If data width is greater than 8 bytes, DRE is not in hw */
-       if (width > 8)
-               has_dre = false;
-
-       if (!has_dre)
-               xdev->common.copy_align = fls(width - 1);
-
-       if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel")) {
-               chan->direction = DMA_MEM_TO_DEV;
-               chan->id = 0;
-
-               chan->ctrl_offset = XILINX_DMA_MM2S_CTRL_OFFSET;
-               if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-                       chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
-
-                       if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
-                           xdev->flush_on_fsync == XILINX_DMA_FLUSH_MM2S)
-                               chan->flush_on_fsync = true;
-               }
-       } else if (of_device_is_compatible(node,
-                                           "xlnx,axi-vdma-s2mm-channel")) {
-               chan->direction = DMA_DEV_TO_MEM;
-               chan->id = 1;
-
-               chan->ctrl_offset = XILINX_DMA_S2MM_CTRL_OFFSET;
-               if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-                       chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
-
-                       if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
-                           xdev->flush_on_fsync == XILINX_DMA_FLUSH_S2MM)
-                               chan->flush_on_fsync = true;
-               }
-       } else {
-               dev_err(xdev->dev, "Invalid channel compatible node\n");
-               return -EINVAL;
-       }
-
-       /* 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);
-       if (err) {
-               dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq);
-               return err;
-       }
-
-       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
-               chan->start_transfer = xilinx_dma_start_transfer;
-       else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA)
-               chan->start_transfer = xilinx_cdma_start_transfer;
-       else
-               chan->start_transfer = xilinx_vdma_start_transfer;
-
-       /* Initialize the tasklet */
-       tasklet_init(&chan->tasklet, xilinx_dma_do_tasklet,
-                       (unsigned long)chan);
-
-       /*
-        * Initialize the DMA channel and add it to the DMA engine channels
-        * list.
-        */
-       chan->common.device = &xdev->common;
-
-       list_add_tail(&chan->common.device_node, &xdev->common.channels);
-       xdev->chan[chan->id] = chan;
-
-       /* Reset the channel */
-       err = xilinx_dma_chan_reset(chan);
-       if (err < 0) {
-               dev_err(xdev->dev, "Reset channel failed\n");
-               return err;
-       }
-
-       return 0;
-}
-
-/**
- * of_dma_xilinx_xlate - Translation function
- * @dma_spec: Pointer to DMA specifier as found in the device tree
- * @ofdma: Pointer to DMA controller data
- *
- * Return: DMA channel pointer on success and NULL on error
- */
-static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
-                                               struct of_dma *ofdma)
-{
-       struct xilinx_dma_device *xdev = ofdma->of_dma_data;
-       int chan_id = dma_spec->args[0];
-
-       if (chan_id >= XILINX_DMA_MAX_CHANS_PER_DEVICE || !xdev->chan[chan_id])
-               return NULL;
-
-       return dma_get_slave_channel(&xdev->chan[chan_id]->common);
-}
-
-static const struct xilinx_dma_config axidma_config = {
-       .dmatype = XDMA_TYPE_AXIDMA,
-       .clk_init = axidma_clk_init,
-};
-
-static const struct xilinx_dma_config axicdma_config = {
-       .dmatype = XDMA_TYPE_CDMA,
-       .clk_init = axicdma_clk_init,
-};
-
-static const struct xilinx_dma_config axivdma_config = {
-       .dmatype = XDMA_TYPE_VDMA,
-       .clk_init = axivdma_clk_init,
-};
-
-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 },
-       {}
-};
-MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids);
-
-/**
- * xilinx_dma_probe - Driver probe function
- * @pdev: Pointer to the platform_device structure
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_probe(struct platform_device *pdev)
-{
-       int (*clk_init)(struct platform_device *, struct clk **, struct clk **,
-                       struct clk **, struct clk **, struct clk **)
-                                       = axivdma_clk_init;
-       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;
-       int i, err;
-
-       /* Allocate and initialize the DMA engine structure */
-       xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
-       if (!xdev)
-               return -ENOMEM;
-
-       xdev->dev = &pdev->dev;
-       if (np) {
-               const struct of_device_id *match;
-
-               match = of_match_node(xilinx_dma_of_ids, np);
-               if (match && match->data) {
-                       xdev->dma_config = match->data;
-                       clk_init = xdev->dma_config->clk_init;
-               }
-       }
-
-       err = clk_init(pdev, &xdev->axi_clk, &xdev->tx_clk, &xdev->txs_clk,
-                      &xdev->rx_clk, &xdev->rxs_clk);
-       if (err)
-               return err;
-
-       /* Request and map I/O memory */
-       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       xdev->regs = devm_ioremap_resource(&pdev->dev, io);
-       if (IS_ERR(xdev->regs))
-               return PTR_ERR(xdev->regs);
-
-       /* Retrieve the DMA engine properties from the device tree */
-       xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
-
-       if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-               err = of_property_read_u32(node, "xlnx,num-fstores",
-                                          &num_frames);
-               if (err < 0) {
-                       dev_err(xdev->dev,
-                               "missing xlnx,num-fstores property\n");
-                       return err;
-               }
-
-               err = of_property_read_u32(node, "xlnx,flush-fsync",
-                                          &xdev->flush_on_fsync);
-               if (err < 0)
-                       dev_warn(xdev->dev,
-                                "missing xlnx,flush-fsync property\n");
-       }
-
-       err = of_property_read_u32(node, "xlnx,addrwidth", &addr_width);
-       if (err < 0)
-               dev_warn(xdev->dev, "missing xlnx,addrwidth property\n");
-
-       if (addr_width > 32)
-               xdev->ext_addr = true;
-       else
-               xdev->ext_addr = false;
-
-       /* Set the dma mask bits */
-       dma_set_mask(xdev->dev, DMA_BIT_MASK(addr_width));
-
-       /* Initialize the DMA engine */
-       xdev->common.dev = &pdev->dev;
-
-       INIT_LIST_HEAD(&xdev->common.channels);
-       if (!(xdev->dma_config->dmatype == XDMA_TYPE_CDMA)) {
-               dma_cap_set(DMA_SLAVE, xdev->common.cap_mask);
-               dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask);
-       }
-
-       xdev->common.device_alloc_chan_resources =
-                               xilinx_dma_alloc_chan_resources;
-       xdev->common.device_free_chan_resources =
-                               xilinx_dma_free_chan_resources;
-       xdev->common.device_terminate_all = xilinx_dma_terminate_all;
-       xdev->common.device_tx_status = xilinx_dma_tx_status;
-       xdev->common.device_issue_pending = xilinx_dma_issue_pending;
-       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               xdev->common.device_prep_slave_sg = xilinx_dma_prep_slave_sg;
-               /* Residue calculation is supported by only AXI DMA */
-               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;
-       } else {
-               xdev->common.device_prep_interleaved_dma =
-                               xilinx_vdma_dma_prep_interleaved;
-       }
-
-       platform_set_drvdata(pdev, xdev);
-
-       /* Initialize the channels */
-       for_each_child_of_node(node, child) {
-               err = xilinx_dma_chan_probe(xdev, child);
-               if (err < 0)
-                       goto disable_clks;
-       }
-
-       if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-               for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++)
-                       if (xdev->chan[i])
-                               xdev->chan[i]->num_frms = num_frames;
-       }
-
-       /* Register the DMA engine with the core */
-       dma_async_device_register(&xdev->common);
-
-       err = of_dma_controller_register(node, of_dma_xilinx_xlate,
-                                        xdev);
-       if (err < 0) {
-               dev_err(&pdev->dev, "Unable to register DMA to DT\n");
-               dma_async_device_unregister(&xdev->common);
-               goto error;
-       }
-
-       dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n");
-
-       return 0;
-
-disable_clks:
-       xdma_disable_allclks(xdev);
-error:
-       for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++)
-               if (xdev->chan[i])
-                       xilinx_dma_chan_remove(xdev->chan[i]);
-
-       return err;
-}
-
-/**
- * xilinx_dma_remove - Driver remove function
- * @pdev: Pointer to the platform_device structure
- *
- * Return: Always '0'
- */
-static int xilinx_dma_remove(struct platform_device *pdev)
-{
-       struct xilinx_dma_device *xdev = platform_get_drvdata(pdev);
-       int i;
-
-       of_dma_controller_free(pdev->dev.of_node);
-
-       dma_async_device_unregister(&xdev->common);
-
-       for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++)
-               if (xdev->chan[i])
-                       xilinx_dma_chan_remove(xdev->chan[i]);
-
-       xdma_disable_allclks(xdev);
-
-       return 0;
-}
-
-static struct platform_driver xilinx_vdma_driver = {
-       .driver = {
-               .name = "xilinx-vdma",
-               .of_match_table = xilinx_dma_of_ids,
-       },
-       .probe = xilinx_dma_probe,
-       .remove = xilinx_dma_remove,
-};
-
-module_platform_driver(xilinx_vdma_driver);
-
-MODULE_AUTHOR("Xilinx, Inc.");
-MODULE_DESCRIPTION("Xilinx VDMA driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
new file mode 100644 (file)
index 0000000..6d221e5
--- /dev/null
@@ -0,0 +1,1151 @@
+/*
+ * DMA driver for Xilinx ZynqMP DMA Engine
+ *
+ * Copyright (C) 2016 Xilinx, Inc. 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 as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/dmapool.h>
+#include <linux/dma/xilinx_dma.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_dma.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+#include "../dmaengine.h"
+
+/* Register Offsets */
+#define ZYNQMP_DMA_ISR                 0x100
+#define ZYNQMP_DMA_IMR                 0x104
+#define ZYNQMP_DMA_IER                 0x108
+#define ZYNQMP_DMA_IDS                 0x10C
+#define ZYNQMP_DMA_CTRL0               0x110
+#define ZYNQMP_DMA_CTRL1               0x114
+#define ZYNQMP_DMA_DATA_ATTR           0x120
+#define ZYNQMP_DMA_DSCR_ATTR           0x124
+#define ZYNQMP_DMA_SRC_DSCR_WRD0       0x128
+#define ZYNQMP_DMA_SRC_DSCR_WRD1       0x12C
+#define ZYNQMP_DMA_SRC_DSCR_WRD2       0x130
+#define ZYNQMP_DMA_SRC_DSCR_WRD3       0x134
+#define ZYNQMP_DMA_DST_DSCR_WRD0       0x138
+#define ZYNQMP_DMA_DST_DSCR_WRD1       0x13C
+#define ZYNQMP_DMA_DST_DSCR_WRD2       0x140
+#define ZYNQMP_DMA_DST_DSCR_WRD3       0x144
+#define ZYNQMP_DMA_SRC_START_LSB       0x158
+#define ZYNQMP_DMA_SRC_START_MSB       0x15C
+#define ZYNQMP_DMA_DST_START_LSB       0x160
+#define ZYNQMP_DMA_DST_START_MSB       0x164
+#define ZYNQMP_DMA_RATE_CTRL           0x18C
+#define ZYNQMP_DMA_IRQ_SRC_ACCT                0x190
+#define ZYNQMP_DMA_IRQ_DST_ACCT                0x194
+#define ZYNQMP_DMA_CTRL2               0x200
+
+/* Interrupt registers bit field definitions */
+#define ZYNQMP_DMA_DONE                        BIT(10)
+#define ZYNQMP_DMA_AXI_WR_DATA         BIT(9)
+#define ZYNQMP_DMA_AXI_RD_DATA         BIT(8)
+#define ZYNQMP_DMA_AXI_RD_DST_DSCR     BIT(7)
+#define ZYNQMP_DMA_AXI_RD_SRC_DSCR     BIT(6)
+#define ZYNQMP_DMA_IRQ_DST_ACCT_ERR    BIT(5)
+#define ZYNQMP_DMA_IRQ_SRC_ACCT_ERR    BIT(4)
+#define ZYNQMP_DMA_BYTE_CNT_OVRFL      BIT(3)
+#define ZYNQMP_DMA_DST_DSCR_DONE       BIT(2)
+#define ZYNQMP_DMA_INV_APB             BIT(0)
+
+/* Control 0 register bit field definitions */
+#define ZYNQMP_DMA_OVR_FETCH           BIT(7)
+#define ZYNQMP_DMA_POINT_TYPE_SG       BIT(6)
+#define ZYNQMP_DMA_RATE_CTRL_EN                BIT(3)
+
+/* Control 1 register bit field definitions */
+#define ZYNQMP_DMA_SRC_ISSUE           GENMASK(4, 0)
+
+/* Data Attribute register bit field definitions */
+#define ZYNQMP_DMA_ARBURST             GENMASK(27, 26)
+#define ZYNQMP_DMA_ARCACHE             GENMASK(25, 22)
+#define ZYNQMP_DMA_ARCACHE_OFST                22
+#define ZYNQMP_DMA_ARQOS               GENMASK(21, 18)
+#define ZYNQMP_DMA_ARQOS_OFST          18
+#define ZYNQMP_DMA_ARLEN               GENMASK(17, 14)
+#define ZYNQMP_DMA_ARLEN_OFST          14
+#define ZYNQMP_DMA_AWBURST             GENMASK(13, 12)
+#define ZYNQMP_DMA_AWCACHE             GENMASK(11, 8)
+#define ZYNQMP_DMA_AWCACHE_OFST                8
+#define ZYNQMP_DMA_AWQOS               GENMASK(7, 4)
+#define ZYNQMP_DMA_AWQOS_OFST          4
+#define ZYNQMP_DMA_AWLEN               GENMASK(3, 0)
+#define ZYNQMP_DMA_AWLEN_OFST          0
+
+/* Descriptor Attribute register bit field definitions */
+#define ZYNQMP_DMA_AXCOHRNT            BIT(8)
+#define ZYNQMP_DMA_AXCACHE             GENMASK(7, 4)
+#define ZYNQMP_DMA_AXCACHE_OFST                4
+#define ZYNQMP_DMA_AXQOS               GENMASK(3, 0)
+#define ZYNQMP_DMA_AXQOS_OFST          0
+
+/* Control register 2 bit field definitions */
+#define ZYNQMP_DMA_ENABLE              BIT(0)
+
+/* Buffer Descriptor definitions */
+#define ZYNQMP_DMA_DESC_CTRL_STOP      0x10
+#define ZYNQMP_DMA_DESC_CTRL_COMP_INT  0x4
+#define ZYNQMP_DMA_DESC_CTRL_SIZE_256  0x2
+#define ZYNQMP_DMA_DESC_CTRL_COHRNT    0x1
+
+/* Interrupt Mask specific definitions */
+#define ZYNQMP_DMA_INT_ERR     (ZYNQMP_DMA_AXI_RD_DATA | \
+                               ZYNQMP_DMA_AXI_WR_DATA | \
+                               ZYNQMP_DMA_AXI_RD_DST_DSCR | \
+                               ZYNQMP_DMA_AXI_RD_SRC_DSCR | \
+                               ZYNQMP_DMA_INV_APB)
+#define ZYNQMP_DMA_INT_OVRFL   (ZYNQMP_DMA_BYTE_CNT_OVRFL | \
+                               ZYNQMP_DMA_IRQ_SRC_ACCT_ERR | \
+                               ZYNQMP_DMA_IRQ_DST_ACCT_ERR)
+#define ZYNQMP_DMA_INT_DONE    (ZYNQMP_DMA_DONE | ZYNQMP_DMA_DST_DSCR_DONE)
+#define ZYNQMP_DMA_INT_EN_DEFAULT_MASK (ZYNQMP_DMA_INT_DONE | \
+                                       ZYNQMP_DMA_INT_ERR | \
+                                       ZYNQMP_DMA_INT_OVRFL | \
+                                       ZYNQMP_DMA_DST_DSCR_DONE)
+
+/* Max number of descriptors per channel */
+#define ZYNQMP_DMA_NUM_DESCS   32
+
+/* Max transfer size per descriptor */
+#define ZYNQMP_DMA_MAX_TRANS_LEN       0x40000000
+
+/* Reset values for data attributes */
+#define ZYNQMP_DMA_AXCACHE_VAL         0xF
+#define ZYNQMP_DMA_ARLEN_RST_VAL       0xF
+#define ZYNQMP_DMA_AWLEN_RST_VAL       0xF
+
+#define ZYNQMP_DMA_SRC_ISSUE_RST_VAL   0x1F
+
+#define ZYNQMP_DMA_IDS_DEFAULT_MASK    0xFFF
+
+/* Bus width in bits */
+#define ZYNQMP_DMA_BUS_WIDTH_64                64
+#define ZYNQMP_DMA_BUS_WIDTH_128       128
+
+#define ZYNQMP_DMA_DESC_SIZE(chan)     (chan->desc_size)
+
+#define to_chan(chan)          container_of(chan, struct zynqmp_dma_chan, \
+                                            common)
+#define tx_to_desc(tx)         container_of(tx, struct zynqmp_dma_desc_sw, \
+                                            async_tx)
+
+/**
+ * struct zynqmp_dma_desc_ll - Hw linked list descriptor
+ * @addr: Buffer address
+ * @size: Size of the buffer
+ * @ctrl: Control word
+ * @nxtdscraddr: Next descriptor base address
+ * @rsvd: Reserved field and for Hw internal use.
+ */
+struct zynqmp_dma_desc_ll {
+       u64 addr;
+       u32 size;
+       u32 ctrl;
+       u64 nxtdscraddr;
+       u64 rsvd;
+}; __aligned(64)
+
+/**
+ * struct zynqmp_dma_desc_sw - Per Transaction structure
+ * @src: Source address for simple mode dma
+ * @dst: Destination address for simple mode dma
+ * @len: Transfer length for simple mode dma
+ * @node: Node in the channel descriptor list
+ * @tx_list: List head for the current transfer
+ * @async_tx: Async transaction descriptor
+ * @src_v: Virtual address of the src descriptor
+ * @src_p: Physical address of the src descriptor
+ * @dst_v: Virtual address of the dst descriptor
+ * @dst_p: Physical address of the dst descriptor
+ */
+struct zynqmp_dma_desc_sw {
+       u64 src;
+       u64 dst;
+       u32 len;
+       struct list_head node;
+       struct list_head tx_list;
+       struct dma_async_tx_descriptor async_tx;
+       struct zynqmp_dma_desc_ll *src_v;
+       dma_addr_t src_p;
+       struct zynqmp_dma_desc_ll *dst_v;
+       dma_addr_t dst_p;
+};
+
+/**
+ * struct zynqmp_dma_chan - Driver specific DMA channel structure
+ * @zdev: Driver specific device structure
+ * @regs: Control registers offset
+ * @lock: Descriptor operation lock
+ * @pending_list: Descriptors waiting
+ * @free_list: Descriptors free
+ * @active_list: Descriptors active
+ * @sw_desc_pool: SW descriptor pool
+ * @done_list: Complete descriptors
+ * @common: DMA common channel
+ * @desc_pool_v: Statically allocated descriptor base
+ * @desc_pool_p: Physical allocated descriptor base
+ * @desc_free_cnt: Descriptor available count
+ * @dev: The dma device
+ * @irq: Channel IRQ
+ * @is_dmacoherent: Tells whether dma operations are coherent or not
+ * @tasklet: Cleanup work after irq
+ * @idle : Channel status;
+ * @desc_size: Size of the low level descriptor
+ * @err: Channel has errors
+ * @bus_width: Bus width
+ * @src_burst_len: Source burst length
+ * @dst_burst_len: Dest burst length
+ * @clk_main: Pointer to main clock
+ * @clk_apb: Pointer to apb clock
+ */
+struct zynqmp_dma_chan {
+       struct zynqmp_dma_device *zdev;
+       void __iomem *regs;
+       spinlock_t lock;
+       struct list_head pending_list;
+       struct list_head free_list;
+       struct list_head active_list;
+       struct zynqmp_dma_desc_sw *sw_desc_pool;
+       struct list_head done_list;
+       struct dma_chan common;
+       void *desc_pool_v;
+       dma_addr_t desc_pool_p;
+       u32 desc_free_cnt;
+       struct device *dev;
+       int irq;
+       bool is_dmacoherent;
+       struct tasklet_struct tasklet;
+       bool idle;
+       u32 desc_size;
+       bool err;
+       u32 bus_width;
+       u32 src_burst_len;
+       u32 dst_burst_len;
+       struct clk *clk_main;
+       struct clk *clk_apb;
+};
+
+/**
+ * struct zynqmp_dma_device - DMA device structure
+ * @dev: Device Structure
+ * @common: DMA device structure
+ * @chan: Driver specific DMA channel
+ */
+struct zynqmp_dma_device {
+       struct device *dev;
+       struct dma_device common;
+       struct zynqmp_dma_chan *chan;
+};
+
+static inline void zynqmp_dma_writeq(struct zynqmp_dma_chan *chan, u32 reg,
+                                    u64 value)
+{
+       lo_hi_writeq(value, chan->regs + reg);
+}
+
+/**
+ * zynqmp_dma_update_desc_to_ctrlr - Updates descriptor to the controller
+ * @chan: ZynqMP DMA DMA channel pointer
+ * @desc: Transaction descriptor pointer
+ */
+static void zynqmp_dma_update_desc_to_ctrlr(struct zynqmp_dma_chan *chan,
+                                     struct zynqmp_dma_desc_sw *desc)
+{
+       dma_addr_t addr;
+
+       addr = desc->src_p;
+       zynqmp_dma_writeq(chan, ZYNQMP_DMA_SRC_START_LSB, addr);
+       addr = desc->dst_p;
+       zynqmp_dma_writeq(chan, ZYNQMP_DMA_DST_START_LSB, addr);
+}
+
+/**
+ * zynqmp_dma_desc_config_eod - Mark the descriptor as end descriptor
+ * @chan: ZynqMP DMA channel pointer
+ * @desc: Hw descriptor pointer
+ */
+static void zynqmp_dma_desc_config_eod(struct zynqmp_dma_chan *chan,
+                                      void *desc)
+{
+       struct zynqmp_dma_desc_ll *hw = (struct zynqmp_dma_desc_ll *)desc;
+
+       hw->ctrl |= ZYNQMP_DMA_DESC_CTRL_STOP;
+       hw++;
+       hw->ctrl |= ZYNQMP_DMA_DESC_CTRL_COMP_INT | ZYNQMP_DMA_DESC_CTRL_STOP;
+}
+
+/**
+ * zynqmp_dma_config_sg_ll_desc - Configure the linked list descriptor
+ * @chan: ZynqMP DMA channel pointer
+ * @sdesc: Hw descriptor pointer
+ * @src: Source buffer address
+ * @dst: Destination buffer address
+ * @len: Transfer length
+ * @prev: Previous hw descriptor pointer
+ */
+static void zynqmp_dma_config_sg_ll_desc(struct zynqmp_dma_chan *chan,
+                                  struct zynqmp_dma_desc_ll *sdesc,
+                                  dma_addr_t src, dma_addr_t dst, size_t len,
+                                  struct zynqmp_dma_desc_ll *prev)
+{
+       struct zynqmp_dma_desc_ll *ddesc = sdesc + 1;
+
+       sdesc->size = ddesc->size = len;
+       sdesc->addr = src;
+       ddesc->addr = dst;
+
+       sdesc->ctrl = ddesc->ctrl = ZYNQMP_DMA_DESC_CTRL_SIZE_256;
+       if (chan->is_dmacoherent) {
+               sdesc->ctrl |= ZYNQMP_DMA_DESC_CTRL_COHRNT;
+               ddesc->ctrl |= ZYNQMP_DMA_DESC_CTRL_COHRNT;
+       }
+
+       if (prev) {
+               dma_addr_t addr = chan->desc_pool_p +
+                           ((uintptr_t)sdesc - (uintptr_t)chan->desc_pool_v);
+               ddesc = prev + 1;
+               prev->nxtdscraddr = addr;
+               ddesc->nxtdscraddr = addr + ZYNQMP_DMA_DESC_SIZE(chan);
+       }
+}
+
+/**
+ * zynqmp_dma_init - Initialize the channel
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_init(struct zynqmp_dma_chan *chan)
+{
+       u32 val;
+
+       writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS);
+       val = readl(chan->regs + ZYNQMP_DMA_ISR);
+       writel(val, chan->regs + ZYNQMP_DMA_ISR);
+
+       if (chan->is_dmacoherent) {
+               val = ZYNQMP_DMA_AXCOHRNT;
+               val = (val & ~ZYNQMP_DMA_AXCACHE) |
+                       (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_AXCACHE_OFST);
+               writel(val, chan->regs + ZYNQMP_DMA_DSCR_ATTR);
+       }
+
+       val = readl(chan->regs + ZYNQMP_DMA_DATA_ATTR);
+       if (chan->is_dmacoherent) {
+               val = (val & ~ZYNQMP_DMA_ARCACHE) |
+                       (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_ARCACHE_OFST);
+               val = (val & ~ZYNQMP_DMA_AWCACHE) |
+                       (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_AWCACHE_OFST);
+       }
+       writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR);
+
+       /* Clearing the interrupt account rgisters */
+       val = readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT);
+       val = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT);
+
+       chan->idle = true;
+}
+
+/**
+ * zynqmp_dma_tx_submit - Submit DMA transaction
+ * @tx: Async transaction descriptor pointer
+ *
+ * Return: cookie value
+ */
+static dma_cookie_t zynqmp_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct zynqmp_dma_chan *chan = to_chan(tx->chan);
+       struct zynqmp_dma_desc_sw *desc, *new;
+       dma_cookie_t cookie;
+
+       new = tx_to_desc(tx);
+       spin_lock_bh(&chan->lock);
+       cookie = dma_cookie_assign(tx);
+
+       if (!list_empty(&chan->pending_list)) {
+               desc = list_last_entry(&chan->pending_list,
+                                    struct zynqmp_dma_desc_sw, node);
+               if (!list_empty(&desc->tx_list))
+                       desc = list_last_entry(&desc->tx_list,
+                                              struct zynqmp_dma_desc_sw, node);
+               desc->src_v->nxtdscraddr = new->src_p;
+               desc->src_v->ctrl &= ~ZYNQMP_DMA_DESC_CTRL_STOP;
+               desc->dst_v->nxtdscraddr = new->dst_p;
+               desc->dst_v->ctrl &= ~ZYNQMP_DMA_DESC_CTRL_STOP;
+       }
+
+       list_add_tail(&new->node, &chan->pending_list);
+       spin_unlock_bh(&chan->lock);
+
+       return cookie;
+}
+
+/**
+ * zynqmp_dma_get_descriptor - Get the sw descriptor from the pool
+ * @chan: ZynqMP DMA channel pointer
+ *
+ * Return: The sw descriptor
+ */
+static struct zynqmp_dma_desc_sw *
+zynqmp_dma_get_descriptor(struct zynqmp_dma_chan *chan)
+{
+       struct zynqmp_dma_desc_sw *desc;
+
+       spin_lock_bh(&chan->lock);
+       desc = list_first_entry(&chan->free_list,
+                               struct zynqmp_dma_desc_sw, node);
+       list_del(&desc->node);
+       spin_unlock_bh(&chan->lock);
+
+       INIT_LIST_HEAD(&desc->tx_list);
+       /* Clear the src and dst descriptor memory */
+       memset((void *)desc->src_v, 0, ZYNQMP_DMA_DESC_SIZE(chan));
+       memset((void *)desc->dst_v, 0, ZYNQMP_DMA_DESC_SIZE(chan));
+
+       return desc;
+}
+
+/**
+ * zynqmp_dma_free_descriptor - Issue pending transactions
+ * @chan: ZynqMP DMA channel pointer
+ * @sdesc: Transaction descriptor pointer
+ */
+static void zynqmp_dma_free_descriptor(struct zynqmp_dma_chan *chan,
+                                struct zynqmp_dma_desc_sw *sdesc)
+{
+       struct zynqmp_dma_desc_sw *child, *next;
+
+       chan->desc_free_cnt++;
+       list_add_tail(&sdesc->node, &chan->free_list);
+       list_for_each_entry_safe(child, next, &sdesc->tx_list, node) {
+               chan->desc_free_cnt++;
+               list_move_tail(&child->node, &chan->free_list);
+       }
+}
+
+/**
+ * zynqmp_dma_free_desc_list - Free descriptors list
+ * @chan: ZynqMP DMA channel pointer
+ * @list: List to parse and delete the descriptor
+ */
+static void zynqmp_dma_free_desc_list(struct zynqmp_dma_chan *chan,
+                                     struct list_head *list)
+{
+       struct zynqmp_dma_desc_sw *desc, *next;
+
+       list_for_each_entry_safe(desc, next, list, node)
+               zynqmp_dma_free_descriptor(chan, desc);
+}
+
+/**
+ * zynqmp_dma_alloc_chan_resources - Allocate channel resources
+ * @dchan: DMA channel
+ *
+ * Return: Number of descriptors on success and failure value on error
+ */
+static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+       struct zynqmp_dma_desc_sw *desc;
+       int i;
+
+       chan->sw_desc_pool = kzalloc(sizeof(*desc) * ZYNQMP_DMA_NUM_DESCS,
+                                    GFP_KERNEL);
+       if (!chan->sw_desc_pool)
+               return -ENOMEM;
+
+       chan->idle = true;
+       chan->desc_free_cnt = ZYNQMP_DMA_NUM_DESCS;
+
+       INIT_LIST_HEAD(&chan->free_list);
+
+       for (i = 0; i < ZYNQMP_DMA_NUM_DESCS; i++) {
+               desc = chan->sw_desc_pool + i;
+               dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+               desc->async_tx.tx_submit = zynqmp_dma_tx_submit;
+               list_add_tail(&desc->node, &chan->free_list);
+       }
+
+       chan->desc_pool_v = dma_zalloc_coherent(chan->dev,
+                               (2 * chan->desc_size * ZYNQMP_DMA_NUM_DESCS),
+                               &chan->desc_pool_p, GFP_KERNEL);
+       if (!chan->desc_pool_v)
+               return -ENOMEM;
+
+       for (i = 0; i < ZYNQMP_DMA_NUM_DESCS; i++) {
+               desc = chan->sw_desc_pool + i;
+               desc->src_v = (struct zynqmp_dma_desc_ll *) (chan->desc_pool_v +
+                                       (i * ZYNQMP_DMA_DESC_SIZE(chan) * 2));
+               desc->dst_v = (struct zynqmp_dma_desc_ll *) (desc->src_v + 1);
+               desc->src_p = chan->desc_pool_p +
+                               (i * ZYNQMP_DMA_DESC_SIZE(chan) * 2);
+               desc->dst_p = desc->src_p + ZYNQMP_DMA_DESC_SIZE(chan);
+       }
+
+       return ZYNQMP_DMA_NUM_DESCS;
+}
+
+/**
+ * zynqmp_dma_start - Start DMA channel
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_start(struct zynqmp_dma_chan *chan)
+{
+       writel(ZYNQMP_DMA_INT_EN_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IER);
+       chan->idle = false;
+       writel(ZYNQMP_DMA_ENABLE, chan->regs + ZYNQMP_DMA_CTRL2);
+}
+
+/**
+ * zynqmp_dma_handle_ovfl_int - Process the overflow interrupt
+ * @chan: ZynqMP DMA channel pointer
+ * @status: Interrupt status value
+ */
+static void zynqmp_dma_handle_ovfl_int(struct zynqmp_dma_chan *chan, u32 status)
+{
+       u32 val;
+
+       if (status & ZYNQMP_DMA_IRQ_DST_ACCT_ERR)
+               val = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT);
+       if (status & ZYNQMP_DMA_IRQ_SRC_ACCT_ERR)
+               val = readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT);
+}
+
+static void zynqmp_dma_config(struct zynqmp_dma_chan *chan)
+{
+       u32 val;
+
+       val = readl(chan->regs + ZYNQMP_DMA_CTRL0);
+       val |= ZYNQMP_DMA_POINT_TYPE_SG;
+       writel(val, chan->regs + ZYNQMP_DMA_CTRL0);
+
+       val = readl(chan->regs + ZYNQMP_DMA_DATA_ATTR);
+       val = (val & ~ZYNQMP_DMA_ARLEN) |
+               (chan->src_burst_len << ZYNQMP_DMA_ARLEN_OFST);
+       val = (val & ~ZYNQMP_DMA_AWLEN) |
+               (chan->dst_burst_len << ZYNQMP_DMA_AWLEN_OFST);
+       writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR);
+}
+
+/**
+ * zynqmp_dma_device_config - Zynqmp dma device configuration
+ * @dchan: DMA channel
+ * @config: DMA device config
+ */
+static int zynqmp_dma_device_config(struct dma_chan *dchan,
+                                   struct dma_slave_config *config)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+
+       chan->src_burst_len = config->src_maxburst;
+       chan->dst_burst_len = config->dst_maxburst;
+
+       return 0;
+}
+
+/**
+ * zynqmp_dma_start_transfer - Initiate the new transfer
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_start_transfer(struct zynqmp_dma_chan *chan)
+{
+       struct zynqmp_dma_desc_sw *desc;
+
+       if (!chan->idle)
+               return;
+
+       zynqmp_dma_config(chan);
+
+       desc = list_first_entry_or_null(&chan->pending_list,
+                                       struct zynqmp_dma_desc_sw, node);
+       if (!desc)
+               return;
+
+       list_splice_tail_init(&chan->pending_list, &chan->active_list);
+       zynqmp_dma_update_desc_to_ctrlr(chan, desc);
+       zynqmp_dma_start(chan);
+}
+
+
+/**
+ * zynqmp_dma_chan_desc_cleanup - Cleanup the completed descriptors
+ * @chan: ZynqMP DMA channel
+ */
+static void zynqmp_dma_chan_desc_cleanup(struct zynqmp_dma_chan *chan)
+{
+       struct zynqmp_dma_desc_sw *desc, *next;
+
+       list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+               dma_async_tx_callback callback;
+               void *callback_param;
+
+               list_del(&desc->node);
+
+               callback = desc->async_tx.callback;
+               callback_param = desc->async_tx.callback_param;
+               if (callback) {
+                       spin_unlock(&chan->lock);
+                       callback(callback_param);
+                       spin_lock(&chan->lock);
+               }
+
+               /* Run any dependencies, then free the descriptor */
+               zynqmp_dma_free_descriptor(chan, desc);
+       }
+}
+
+/**
+ * zynqmp_dma_complete_descriptor - Mark the active descriptor as complete
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_complete_descriptor(struct zynqmp_dma_chan *chan)
+{
+       struct zynqmp_dma_desc_sw *desc;
+
+       desc = list_first_entry_or_null(&chan->active_list,
+                                       struct zynqmp_dma_desc_sw, node);
+       if (!desc)
+               return;
+       list_del(&desc->node);
+       dma_cookie_complete(&desc->async_tx);
+       list_add_tail(&desc->node, &chan->done_list);
+}
+
+/**
+ * zynqmp_dma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel pointer
+ */
+static void zynqmp_dma_issue_pending(struct dma_chan *dchan)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+
+       spin_lock_bh(&chan->lock);
+       zynqmp_dma_start_transfer(chan);
+       spin_unlock_bh(&chan->lock);
+}
+
+/**
+ * zynqmp_dma_free_descriptors - Free channel descriptors
+ * @dchan: DMA channel pointer
+ */
+static void zynqmp_dma_free_descriptors(struct zynqmp_dma_chan *chan)
+{
+       zynqmp_dma_free_desc_list(chan, &chan->active_list);
+       zynqmp_dma_free_desc_list(chan, &chan->pending_list);
+       zynqmp_dma_free_desc_list(chan, &chan->done_list);
+}
+
+/**
+ * zynqmp_dma_free_chan_resources - Free channel resources
+ * @dchan: DMA channel pointer
+ */
+static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+
+       spin_lock_bh(&chan->lock);
+       zynqmp_dma_free_descriptors(chan);
+       spin_unlock_bh(&chan->lock);
+       dma_free_coherent(chan->dev,
+               (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS),
+               chan->desc_pool_v, chan->desc_pool_p);
+       kfree(chan->sw_desc_pool);
+}
+
+/**
+ * zynqmp_dma_reset - Reset the channel
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_reset(struct zynqmp_dma_chan *chan)
+{
+       writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS);
+
+       zynqmp_dma_complete_descriptor(chan);
+       zynqmp_dma_chan_desc_cleanup(chan);
+       zynqmp_dma_free_descriptors(chan);
+       zynqmp_dma_init(chan);
+}
+
+/**
+ * zynqmp_dma_irq_handler - ZynqMP DMA Interrupt handler
+ * @irq: IRQ number
+ * @data: Pointer to the ZynqMP DMA channel structure
+ *
+ * Return: IRQ_HANDLED/IRQ_NONE
+ */
+static irqreturn_t zynqmp_dma_irq_handler(int irq, void *data)
+{
+       struct zynqmp_dma_chan *chan = (struct zynqmp_dma_chan *)data;
+       u32 isr, imr, status;
+       irqreturn_t ret = IRQ_NONE;
+
+       isr = readl(chan->regs + ZYNQMP_DMA_ISR);
+       imr = readl(chan->regs + ZYNQMP_DMA_IMR);
+       status = isr & ~imr;
+
+       writel(isr, chan->regs + ZYNQMP_DMA_ISR);
+       if (status & ZYNQMP_DMA_INT_DONE) {
+               tasklet_schedule(&chan->tasklet);
+               ret = IRQ_HANDLED;
+       }
+
+       if (status & ZYNQMP_DMA_DONE)
+               chan->idle = true;
+
+       if (status & ZYNQMP_DMA_INT_ERR) {
+               chan->err = true;
+               tasklet_schedule(&chan->tasklet);
+               dev_err(chan->dev, "Channel %p has errors\n", chan);
+               ret = IRQ_HANDLED;
+       }
+
+       if (status & ZYNQMP_DMA_INT_OVRFL) {
+               zynqmp_dma_handle_ovfl_int(chan, status);
+               dev_info(chan->dev, "Channel %p overflow interrupt\n", chan);
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+/**
+ * zynqmp_dma_do_tasklet - Schedule completion tasklet
+ * @data: Pointer to the ZynqMP DMA channel structure
+ */
+static void zynqmp_dma_do_tasklet(unsigned long data)
+{
+       struct zynqmp_dma_chan *chan = (struct zynqmp_dma_chan *)data;
+       u32 count;
+
+       spin_lock(&chan->lock);
+
+       if (chan->err) {
+               zynqmp_dma_reset(chan);
+               chan->err = false;
+               goto unlock;
+       }
+
+       count = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT);
+
+       while (count) {
+               zynqmp_dma_complete_descriptor(chan);
+               zynqmp_dma_chan_desc_cleanup(chan);
+               count--;
+       }
+
+       if (chan->idle)
+               zynqmp_dma_start_transfer(chan);
+
+unlock:
+       spin_unlock(&chan->lock);
+}
+
+/**
+ * zynqmp_dma_device_terminate_all - Aborts all transfers on a channel
+ * @dchan: DMA channel pointer
+ *
+ * Return: Always '0'
+ */
+static int zynqmp_dma_device_terminate_all(struct dma_chan *dchan)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+
+       spin_lock_bh(&chan->lock);
+       writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS);
+       zynqmp_dma_free_descriptors(chan);
+       spin_unlock_bh(&chan->lock);
+
+       return 0;
+}
+
+/**
+ * zynqmp_dma_prep_memcpy - prepare descriptors for memcpy transaction
+ * @dchan: DMA channel
+ * @dma_dst: Destination buffer address
+ * @dma_src: Source buffer address
+ * @len: Transfer length
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *zynqmp_dma_prep_memcpy(
+                               struct dma_chan *dchan, dma_addr_t dma_dst,
+                               dma_addr_t dma_src, size_t len, ulong flags)
+{
+       struct zynqmp_dma_chan *chan;
+       struct zynqmp_dma_desc_sw *new, *first = NULL;
+       void *desc = NULL, *prev = NULL;
+       size_t copy;
+       u32 desc_cnt;
+
+       chan = to_chan(dchan);
+
+       if (len > ZYNQMP_DMA_MAX_TRANS_LEN)
+               return NULL;
+
+       desc_cnt = DIV_ROUND_UP(len, ZYNQMP_DMA_MAX_TRANS_LEN);
+
+       spin_lock_bh(&chan->lock);
+       if (desc_cnt > chan->desc_free_cnt) {
+               spin_unlock_bh(&chan->lock);
+               dev_dbg(chan->dev, "chan %p descs are not available\n", chan);
+               return NULL;
+       }
+       chan->desc_free_cnt = chan->desc_free_cnt - desc_cnt;
+       spin_unlock_bh(&chan->lock);
+
+       do {
+               /* Allocate and populate the descriptor */
+               new = zynqmp_dma_get_descriptor(chan);
+
+               copy = min_t(size_t, len, ZYNQMP_DMA_MAX_TRANS_LEN);
+               desc = (struct zynqmp_dma_desc_ll *)new->src_v;
+               zynqmp_dma_config_sg_ll_desc(chan, desc, dma_src,
+                                            dma_dst, copy, prev);
+               prev = desc;
+               len -= copy;
+               dma_src += copy;
+               dma_dst += copy;
+               if (!first)
+                       first = new;
+               else
+                       list_add_tail(&new->node, &first->tx_list);
+       } while (len);
+
+       zynqmp_dma_desc_config_eod(chan, desc);
+       async_tx_ack(&first->async_tx);
+       first->async_tx.flags = flags;
+       return &first->async_tx;
+}
+
+/**
+ * zynqmp_dma_prep_slave_sg - prepare descriptors for a memory sg transaction
+ * @dchan: DMA channel
+ * @dst_sg: Destination scatter list
+ * @dst_sg_len: Number of entries in destination scatter list
+ * @src_sg: Source scatter list
+ * @src_sg_len: Number of entries in source scatter list
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *zynqmp_dma_prep_sg(
+                       struct dma_chan *dchan, struct scatterlist *dst_sg,
+                       unsigned int dst_sg_len, struct scatterlist *src_sg,
+                       unsigned int src_sg_len, unsigned long flags)
+{
+       struct zynqmp_dma_desc_sw *new, *first = NULL;
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+       void *desc = NULL, *prev = NULL;
+       size_t len, dst_avail, src_avail;
+       dma_addr_t dma_dst, dma_src;
+       u32 desc_cnt = 0, i;
+       struct scatterlist *sg;
+
+       for_each_sg(src_sg, sg, src_sg_len, i)
+               desc_cnt += DIV_ROUND_UP(sg_dma_len(sg),
+                                        ZYNQMP_DMA_MAX_TRANS_LEN);
+
+       spin_lock_bh(&chan->lock);
+       if (desc_cnt > chan->desc_free_cnt) {
+               spin_unlock_bh(&chan->lock);
+               dev_dbg(chan->dev, "chan %p descs are not available\n", chan);
+               return NULL;
+       }
+       chan->desc_free_cnt = chan->desc_free_cnt - desc_cnt;
+       spin_unlock_bh(&chan->lock);
+
+       dst_avail = sg_dma_len(dst_sg);
+       src_avail = sg_dma_len(src_sg);
+
+       /* Run until we are out of scatterlist entries */
+       while (true) {
+               /* Allocate and populate the descriptor */
+               new = zynqmp_dma_get_descriptor(chan);
+               desc = (struct zynqmp_dma_desc_ll *)new->src_v;
+               len = min_t(size_t, src_avail, dst_avail);
+               len = min_t(size_t, len, ZYNQMP_DMA_MAX_TRANS_LEN);
+               if (len == 0)
+                       goto fetch;
+               dma_dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) -
+                       dst_avail;
+               dma_src = sg_dma_address(src_sg) + sg_dma_len(src_sg) -
+                       src_avail;
+
+               zynqmp_dma_config_sg_ll_desc(chan, desc, dma_src, dma_dst,
+                                            len, prev);
+               prev = desc;
+               dst_avail -= len;
+               src_avail -= len;
+
+               if (!first)
+                       first = new;
+               else
+                       list_add_tail(&new->node, &first->tx_list);
+fetch:
+               /* Fetch the next dst scatterlist entry */
+               if (dst_avail == 0) {
+                       if (dst_sg_len == 0)
+                               break;
+                       dst_sg = sg_next(dst_sg);
+                       if (dst_sg == NULL)
+                               break;
+                       dst_sg_len--;
+                       dst_avail = sg_dma_len(dst_sg);
+               }
+               /* Fetch the next src scatterlist entry */
+               if (src_avail == 0) {
+                       if (src_sg_len == 0)
+                               break;
+                       src_sg = sg_next(src_sg);
+                       if (src_sg == NULL)
+                               break;
+                       src_sg_len--;
+                       src_avail = sg_dma_len(src_sg);
+               }
+       }
+
+       zynqmp_dma_desc_config_eod(chan, desc);
+       first->async_tx.flags = flags;
+       return &first->async_tx;
+}
+
+/**
+ * zynqmp_dma_chan_remove - Channel remove function
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan)
+{
+       if (!chan)
+               return;
+
+       devm_free_irq(chan->zdev->dev, chan->irq, chan);
+       tasklet_kill(&chan->tasklet);
+       list_del(&chan->common.device_node);
+       clk_disable_unprepare(chan->clk_apb);
+       clk_disable_unprepare(chan->clk_main);
+}
+
+/**
+ * zynqmp_dma_chan_probe - Per Channel Probing
+ * @zdev: Driver specific device structure
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
+                          struct platform_device *pdev)
+{
+       struct zynqmp_dma_chan *chan;
+       struct resource *res;
+       struct device_node *node = pdev->dev.of_node;
+       int err;
+
+       chan = devm_kzalloc(zdev->dev, sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               return -ENOMEM;
+       chan->dev = zdev->dev;
+       chan->zdev = zdev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       chan->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(chan->regs))
+               return PTR_ERR(chan->regs);
+
+       chan->bus_width = ZYNQMP_DMA_BUS_WIDTH_64;
+       chan->dst_burst_len = ZYNQMP_DMA_AWLEN_RST_VAL;
+       chan->src_burst_len = ZYNQMP_DMA_ARLEN_RST_VAL;
+       err = of_property_read_u32(node, "xlnx,bus-width", &chan->bus_width);
+       if (err < 0) {
+               dev_err(&pdev->dev, "missing xlnx,bus-width property\n");
+               return err;
+       }
+
+       if (chan->bus_width != ZYNQMP_DMA_BUS_WIDTH_64 &&
+           chan->bus_width != ZYNQMP_DMA_BUS_WIDTH_128) {
+               dev_err(zdev->dev, "invalid bus-width value");
+               return -EINVAL;
+       }
+
+       chan->is_dmacoherent =  of_property_read_bool(node, "dma-coherent");
+       zdev->chan = chan;
+       tasklet_init(&chan->tasklet, zynqmp_dma_do_tasklet, (ulong)chan);
+       spin_lock_init(&chan->lock);
+       INIT_LIST_HEAD(&chan->active_list);
+       INIT_LIST_HEAD(&chan->pending_list);
+       INIT_LIST_HEAD(&chan->done_list);
+       INIT_LIST_HEAD(&chan->free_list);
+
+       dma_cookie_init(&chan->common);
+       chan->common.device = &zdev->common;
+       list_add_tail(&chan->common.device_node, &zdev->common.channels);
+
+       zynqmp_dma_init(chan);
+       chan->irq = platform_get_irq(pdev, 0);
+       if (chan->irq < 0)
+               return -ENXIO;
+       err = devm_request_irq(&pdev->dev, chan->irq, zynqmp_dma_irq_handler, 0,
+                              "zynqmp-dma", chan);
+       if (err)
+               return err;
+       chan->clk_main = devm_clk_get(&pdev->dev, "clk_main");
+       if (IS_ERR(chan->clk_main)) {
+               dev_err(&pdev->dev, "main clock not found.\n");
+               return PTR_ERR(chan->clk_main);
+       }
+
+       chan->clk_apb = devm_clk_get(&pdev->dev, "clk_apb");
+       if (IS_ERR(chan->clk_apb)) {
+               dev_err(&pdev->dev, "apb clock not found.\n");
+               return PTR_ERR(chan->clk_apb);
+       }
+
+       err = clk_prepare_enable(chan->clk_main);
+       if (err) {
+               dev_err(&pdev->dev, "Unable to enable main clock.\n");
+               return err;
+       }
+
+       err = clk_prepare_enable(chan->clk_apb);
+       if (err) {
+               clk_disable_unprepare(chan->clk_main);
+               dev_err(&pdev->dev, "Unable to enable apb clock.\n");
+               return err;
+       }
+
+       chan->desc_size = sizeof(struct zynqmp_dma_desc_ll);
+       chan->idle = true;
+       return 0;
+}
+
+/**
+ * of_zynqmp_dma_xlate - Translation function
+ * @dma_spec: Pointer to DMA specifier as found in the device tree
+ * @ofdma: Pointer to DMA controller data
+ *
+ * Return: DMA channel pointer on success and NULL on error
+ */
+static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec,
+                                           struct of_dma *ofdma)
+{
+       struct zynqmp_dma_device *zdev = ofdma->of_dma_data;
+
+       return dma_get_slave_channel(&zdev->chan->common);
+}
+
+/**
+ * zynqmp_dma_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int zynqmp_dma_probe(struct platform_device *pdev)
+{
+       struct zynqmp_dma_device *zdev;
+       struct dma_device *p;
+       int ret;
+
+       zdev = devm_kzalloc(&pdev->dev, sizeof(*zdev), GFP_KERNEL);
+       if (!zdev)
+               return -ENOMEM;
+
+       zdev->dev = &pdev->dev;
+       INIT_LIST_HEAD(&zdev->common.channels);
+
+       dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+       dma_cap_set(DMA_SG, zdev->common.cap_mask);
+       dma_cap_set(DMA_MEMCPY, zdev->common.cap_mask);
+
+       p = &zdev->common;
+       p->device_prep_dma_sg = zynqmp_dma_prep_sg;
+       p->device_prep_dma_memcpy = zynqmp_dma_prep_memcpy;
+       p->device_terminate_all = zynqmp_dma_device_terminate_all;
+       p->device_issue_pending = zynqmp_dma_issue_pending;
+       p->device_alloc_chan_resources = zynqmp_dma_alloc_chan_resources;
+       p->device_free_chan_resources = zynqmp_dma_free_chan_resources;
+       p->device_tx_status = dma_cookie_status;
+       p->device_config = zynqmp_dma_device_config;
+       p->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, zdev);
+
+       ret = zynqmp_dma_chan_probe(zdev, pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Probing channel failed\n");
+               goto free_chan_resources;
+       }
+
+       p->dst_addr_widths = BIT(zdev->chan->bus_width / 8);
+       p->src_addr_widths = BIT(zdev->chan->bus_width / 8);
+
+       dma_async_device_register(&zdev->common);
+
+       ret = of_dma_controller_register(pdev->dev.of_node,
+                                        of_zynqmp_dma_xlate, zdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to register DMA to DT\n");
+               dma_async_device_unregister(&zdev->common);
+               goto free_chan_resources;
+       }
+
+       dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n");
+
+       return 0;
+
+free_chan_resources:
+       zynqmp_dma_chan_remove(zdev->chan);
+       return ret;
+}
+
+/**
+ * zynqmp_dma_remove - Driver remove function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: Always '0'
+ */
+static int zynqmp_dma_remove(struct platform_device *pdev)
+{
+       struct zynqmp_dma_device *zdev = platform_get_drvdata(pdev);
+
+       of_dma_controller_free(pdev->dev.of_node);
+       dma_async_device_unregister(&zdev->common);
+
+       zynqmp_dma_chan_remove(zdev->chan);
+
+       return 0;
+}
+
+static const struct of_device_id zynqmp_dma_of_match[] = {
+       { .compatible = "xlnx,zynqmp-dma-1.0", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, zynqmp_dma_of_match);
+
+static struct platform_driver zynqmp_dma_driver = {
+       .driver = {
+               .name = "xilinx-zynqmp-dma",
+               .of_match_table = zynqmp_dma_of_match,
+       },
+       .probe = zynqmp_dma_probe,
+       .remove = zynqmp_dma_remove,
+};
+
+module_platform_driver(zynqmp_dma_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx ZynqMP DMA driver");
index 88e7fc7977213d323869d990275a634a70db8bf2..cb8f0347b934d4be4b385796a03352dca5e7b381 100644 (file)
@@ -231,7 +231,7 @@ struct armada_gem_object *armada_gem_alloc_object(struct drm_device *dev,
 
        obj->dev_addr = DMA_ERROR_CODE;
 
-       mapping = file_inode(obj->obj.filp)->i_mapping;
+       mapping = obj->obj.filp->f_mapping;
        mapping_set_gfp_mask(mapping, GFP_HIGHUSER | __GFP_RECLAIMABLE);
 
        DRM_DEBUG_DRIVER("alloc obj %p size %zu\n", obj, size);
@@ -441,7 +441,7 @@ armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
                if (sg_alloc_table(sgt, count, GFP_KERNEL))
                        goto free_sgt;
 
-               mapping = file_inode(dobj->obj.filp)->i_mapping;
+               mapping = dobj->obj.filp->f_mapping;
 
                for_each_sg(sgt->sgl, sg, count, i) {
                        struct page *page;
index 32156060b9c96bb9ccfe0c0b06dc5057a0160fb6..ad89db36ca256dbe73e7c5b3e04ce42ad03e141c 100644 (file)
@@ -511,7 +511,7 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj)
        int i, npages;
 
        /* This is the shared memory object that backs the GEM resource */
-       mapping = file_inode(obj->filp)->i_mapping;
+       mapping = obj->filp->f_mapping;
 
        /* We already BUG_ON() for non-page-aligned sizes in
         * drm_gem_object_init(), so we should never hit this unless
index df9bcbab922f359bd1837f5b3a5fde457e827457..8c6f750634af4bd9ed56e073411575f9f397b4c5 100644 (file)
@@ -660,7 +660,7 @@ static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
                 * why this is required _and_ expected if you're
                 * going to pin these pages.
                 */
-               mapping = file_inode(obj->filp)->i_mapping;
+               mapping = obj->filp->f_mapping;
                mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
        }
 
index 103546834b60d9f9af9043a2c6881c5a08d1388d..2a6e12956baf8f285abe480cc100d0c6ff13e761 100644 (file)
@@ -2100,9 +2100,10 @@ static int i915_dump_lrc(struct seq_file *m, void *unused)
                return ret;
 
        list_for_each_entry(ctx, &dev_priv->context_list, link)
-               if (ctx != dev_priv->kernel_context)
+               if (ctx != dev_priv->kernel_context) {
                        for_each_engine(engine, dev_priv)
                                i915_dump_lrc_obj(m, ctx, engine);
+               }
 
        mutex_unlock(&dev->struct_mutex);
 
index aad26851cee3c87514fc9f4162a7bff2ac88ec75..ed6117a0ee84689137ee7ca6e6625b5b5b093d1f 100644 (file)
@@ -151,7 +151,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 static int
 i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
 {
-       struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
+       struct address_space *mapping = obj->base.filp->f_mapping;
        char *vaddr = obj->phys_handle->vaddr;
        struct sg_table *st;
        struct scatterlist *sg;
@@ -218,7 +218,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj)
                obj->dirty = 0;
 
        if (obj->dirty) {
-               struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
+               struct address_space *mapping = obj->base.filp->f_mapping;
                char *vaddr = obj->phys_handle->vaddr;
                int i;
 
@@ -2155,7 +2155,7 @@ i915_gem_object_invalidate(struct drm_i915_gem_object *obj)
        if (obj->base.filp == NULL)
                return;
 
-       mapping = file_inode(obj->base.filp)->i_mapping,
+       mapping = obj->base.filp->f_mapping,
        invalidate_mapping_pages(mapping, 0, (loff_t)-1);
 }
 
@@ -2271,7 +2271,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
         *
         * Fail silently without starting the shrinker
         */
-       mapping = file_inode(obj->base.filp)->i_mapping;
+       mapping = obj->base.filp->f_mapping;
        gfp = mapping_gfp_constraint(mapping, ~(__GFP_IO | __GFP_RECLAIM));
        gfp |= __GFP_NORETRY | __GFP_NOWARN;
        sg = st->sgl;
@@ -4522,7 +4522,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
                mask |= __GFP_DMA32;
        }
 
-       mapping = file_inode(obj->base.filp)->i_mapping;
+       mapping = obj->base.filp->f_mapping;
        mapping_set_gfp_mask(mapping, mask);
 
        i915_gem_object_init(obj, &i915_gem_object_ops);
index 03698b6c806c6c63eabc10b7b304f9fb1a3bb43c..0dbd0f03f9bd36963acd2b36bd64010df6bbd95f 100644 (file)
@@ -1407,7 +1407,7 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
                if (ret)
                        goto err_free;
 
-               mapping = file_inode(obj->filp)->i_mapping;
+               mapping = obj->filp->f_mapping;
                mapping_set_gfp_mask(mapping, GFP_USER | __GFP_DMA32);
        }
 
index 077ae9b2865dcda4bb8d9e774a8b4a5cf498bc84..97542c35d6efa4ab2adde3b19af61f20f95e31be 100644 (file)
@@ -298,7 +298,7 @@ int ttm_tt_swapin(struct ttm_tt *ttm)
        swap_storage = ttm->swap_storage;
        BUG_ON(swap_storage == NULL);
 
-       swap_space = file_inode(swap_storage)->i_mapping;
+       swap_space = swap_storage->f_mapping;
 
        for (i = 0; i < ttm->num_pages; ++i) {
                from_page = shmem_read_mapping_page(swap_space, i);
@@ -347,7 +347,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
        } else
                swap_storage = persistent_swap_storage;
 
-       swap_space = file_inode(swap_storage)->i_mapping;
+       swap_space = swap_storage->f_mapping;
 
        for (i = 0; i < ttm->num_pages; ++i) {
                from_page = ttm->pages[i];
index 5646ca4b95de1cc616be21e163374f1473d41478..78ac4811bd3c0c0683e62bfe424c43c0fba4c8a9 100644 (file)
@@ -388,6 +388,21 @@ config HID_LCPOWER
        ---help---
        Support for LC-Power RC1000MCE RF remote control.
 
+config HID_LED
+       tristate "Simple RGB LED support"
+       depends on HID
+       depends on LEDS_CLASS
+       ---help---
+       Support for simple RGB LED devices. Currently supported are:
+       - Riso Kagaku Webmail Notifier
+       - Dream Cheeky Webmail Notifier and Friends Alert
+       - ThingM blink(1)
+       - Delcom Visual Signal Indicator Generation 2
+       - Greynut Luxafor
+
+       To compile this driver as a module, choose M here: the
+       module will be called hid-led.
+
 config HID_LENOVO
        tristate "Lenovo / Thinkpad devices"
        depends on HID
@@ -819,11 +834,11 @@ config HID_THINGM
        tristate "ThingM blink(1) USB RGB LED"
        depends on HID
        depends on LEDS_CLASS
+       select HID_LED
        ---help---
-       Support for the ThingM blink(1) USB RGB LED. This driver registers a
-       Linux LED class instance, plus additional sysfs attributes to control
-       RGB colors, fade time and playing. The device is exposed through hidraw
-       to access other functions.
+       Support for the ThingM blink(1) USB RGB LED. This driver has been
+       merged into the generic hid led driver. Config symbol HID_THINGM
+       just selects HID_LED and will be removed soon.
 
 config HID_THRUSTMASTER
        tristate "ThrustMaster devices support"
@@ -936,6 +951,14 @@ config HID_SENSOR_CUSTOM_SENSOR
          standard sensors.
          Select this config option for custom/generic sensor support.
 
+config HID_ALPS
+       tristate "Alps HID device support"
+       depends on HID
+       ---help---
+       Support for Alps I2C HID touchpads and StickPointer.
+       Say Y here if you have a Alps touchpads over i2c-hid or usbhid
+       and want support for its special functionalities.
+
 endmenu
 
 endif # HID
index a2fb562de7489f868a1c39f7f0eedcab6a9063a7..fc4b2aa47f2e7bb5dcbf8c71e65777d5ba785fe5 100644 (file)
@@ -21,6 +21,7 @@ hid-wiimote-y         := hid-wiimote-core.o hid-wiimote-modules.o
 hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
 
 obj-$(CONFIG_HID_A4TECH)       += hid-a4tech.o
+obj-$(CONFIG_HID_ALPS)         += hid-alps.o
 obj-$(CONFIG_HID_ACRUX)                += hid-axff.o
 obj-$(CONFIG_HID_APPLE)                += hid-apple.o
 obj-$(CONFIG_HID_APPLEIR)      += hid-appleir.o
@@ -90,12 +91,12 @@ obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o
 obj-$(CONFIG_HID_STEELSERIES)  += hid-steelseries.o
 obj-$(CONFIG_HID_SUNPLUS)      += hid-sunplus.o
 obj-$(CONFIG_HID_GREENASIA)    += hid-gaff.o
-obj-$(CONFIG_HID_THINGM)       += hid-thingm.o
 obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
 obj-$(CONFIG_HID_TIVO)         += hid-tivo.o
 obj-$(CONFIG_HID_TOPSEED)      += hid-topseed.o
 obj-$(CONFIG_HID_TWINHAN)      += hid-twinhan.o
 obj-$(CONFIG_HID_UCLOGIC)      += hid-uclogic.o
+obj-$(CONFIG_HID_LED)          += hid-led.o
 obj-$(CONFIG_HID_XINMO)                += hid-xinmo.o
 obj-$(CONFIG_HID_ZEROPLUS)     += hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)     += hid-zydacron.o
diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c
new file mode 100644 (file)
index 0000000..048befd
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ *  Copyright (c) 2016 Masaki Ota <masaki.ota@jp.alps.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+#include "hid-ids.h"
+
+/* ALPS Device Product ID */
+#define HID_PRODUCT_ID_T3_BTNLESS      0xD0C0
+#define HID_PRODUCT_ID_COSMO           0x1202
+#define HID_PRODUCT_ID_U1_PTP_1                0x1207
+#define HID_PRODUCT_ID_U1                      0x1209
+#define HID_PRODUCT_ID_U1_PTP_2                0x120A
+#define HID_PRODUCT_ID_U1_DUAL         0x120B
+#define HID_PRODUCT_ID_T4_BTNLESS      0x120C
+
+#define DEV_SINGLEPOINT                                0x01
+#define DEV_DUALPOINT                          0x02
+
+#define U1_MOUSE_REPORT_ID                     0x01 /* Mouse data ReportID */
+#define U1_ABSOLUTE_REPORT_ID          0x03 /* Absolute data ReportID */
+#define U1_FEATURE_REPORT_ID           0x05 /* Feature ReportID */
+#define U1_SP_ABSOLUTE_REPORT_ID       0x06 /* Feature ReportID */
+
+#define U1_FEATURE_REPORT_LEN          0x08 /* Feature Report Length */
+#define U1_FEATURE_REPORT_LEN_ALL      0x0A
+#define U1_CMD_REGISTER_READ           0xD1
+#define U1_CMD_REGISTER_WRITE          0xD2
+
+#define        U1_DEVTYPE_SP_SUPPORT           0x10 /* SP Support */
+#define        U1_DISABLE_DEV                          0x01
+#define U1_TP_ABS_MODE                         0x02
+#define        U1_SP_ABS_MODE                          0x80
+
+#define ADDRESS_U1_DEV_CTRL_1  0x00800040
+#define ADDRESS_U1_DEVICE_TYP  0x00800043
+#define ADDRESS_U1_NUM_SENS_X  0x00800047
+#define ADDRESS_U1_NUM_SENS_Y  0x00800048
+#define ADDRESS_U1_PITCH_SENS_X        0x00800049
+#define ADDRESS_U1_PITCH_SENS_Y        0x0080004A
+#define ADDRESS_U1_RESO_DWN_ABS 0x0080004E
+#define ADDRESS_U1_PAD_BTN             0x00800052
+#define ADDRESS_U1_SP_BTN              0x0080009F
+
+#define MAX_TOUCHES    5
+
+/**
+ * struct u1_data
+ *
+ * @input: pointer to the kernel input device
+ * @input2: pointer to the kernel input2 device
+ * @hdev: pointer to the struct hid_device
+ *
+ * @dev_ctrl: device control parameter
+ * @dev_type: device type
+ * @sen_line_num_x: number of sensor line of X
+ * @sen_line_num_y: number of sensor line of Y
+ * @pitch_x: sensor pitch of X
+ * @pitch_y: sensor pitch of Y
+ * @resolution: resolution
+ * @btn_info: button information
+ * @x_active_len_mm: active area length of X (mm)
+ * @y_active_len_mm: active area length of Y (mm)
+ * @x_max: maximum x coordinate value
+ * @y_max: maximum y coordinate value
+ * @btn_cnt: number of buttons
+ * @sp_btn_cnt: number of stick buttons
+ */
+struct u1_dev {
+       struct input_dev *input;
+       struct input_dev *input2;
+       struct hid_device *hdev;
+
+       u8      dev_ctrl;
+       u8      dev_type;
+       u8      sen_line_num_x;
+       u8      sen_line_num_y;
+       u8      pitch_x;
+       u8      pitch_y;
+       u8      resolution;
+       u8      btn_info;
+       u8      sp_btn_info;
+       u32     x_active_len_mm;
+       u32     y_active_len_mm;
+       u32     x_max;
+       u32     y_max;
+       u32     btn_cnt;
+       u32     sp_btn_cnt;
+};
+
+static int u1_read_write_register(struct hid_device *hdev, u32 address,
+       u8 *read_val, u8 write_val, bool read_flag)
+{
+       int ret, i;
+       u8 check_sum;
+       u8 *input;
+       u8 *readbuf;
+
+       input = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
+       if (!input)
+               return -ENOMEM;
+
+       input[0] = U1_FEATURE_REPORT_ID;
+       if (read_flag) {
+               input[1] = U1_CMD_REGISTER_READ;
+               input[6] = 0x00;
+       } else {
+               input[1] = U1_CMD_REGISTER_WRITE;
+               input[6] = write_val;
+       }
+
+       put_unaligned_le32(address, input + 2);
+
+       /* Calculate the checksum */
+       check_sum = U1_FEATURE_REPORT_LEN_ALL;
+       for (i = 0; i < U1_FEATURE_REPORT_LEN - 1; i++)
+               check_sum += input[i];
+
+       input[7] = check_sum;
+       ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, input,
+                       U1_FEATURE_REPORT_LEN,
+                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed to read command (%d)\n", ret);
+               goto exit;
+       }
+
+       if (read_flag) {
+               readbuf = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
+               if (!readbuf) {
+                       kfree(input);
+                       return -ENOMEM;
+               }
+
+               ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, readbuf,
+                               U1_FEATURE_REPORT_LEN,
+                               HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+
+               if (ret < 0) {
+                       dev_err(&hdev->dev, "failed read register (%d)\n", ret);
+                       goto exit;
+               }
+
+               *read_val = readbuf[6];
+
+               kfree(readbuf);
+       }
+
+       ret = 0;
+
+exit:
+       kfree(input);
+       return ret;
+}
+
+static int alps_raw_event(struct hid_device *hdev,
+               struct hid_report *report, u8 *data, int size)
+{
+       unsigned int x, y, z;
+       int i;
+       short sp_x, sp_y;
+       struct u1_dev *hdata = hid_get_drvdata(hdev);
+
+       switch (data[0]) {
+       case U1_MOUSE_REPORT_ID:
+               break;
+       case U1_FEATURE_REPORT_ID:
+               break;
+       case U1_ABSOLUTE_REPORT_ID:
+               for (i = 0; i < MAX_TOUCHES; i++) {
+                       u8 *contact = &data[i * 5];
+
+                       x = get_unaligned_le16(contact + 3);
+                       y = get_unaligned_le16(contact + 5);
+                       z = contact[7] & 0x7F;
+
+                       input_mt_slot(hdata->input, i);
+
+                       if (z != 0) {
+                               input_mt_report_slot_state(hdata->input,
+                                       MT_TOOL_FINGER, 1);
+                       } else {
+                               input_mt_report_slot_state(hdata->input,
+                                       MT_TOOL_FINGER, 0);
+                               break;
+                       }
+
+                       input_report_abs(hdata->input, ABS_MT_POSITION_X, x);
+                       input_report_abs(hdata->input, ABS_MT_POSITION_Y, y);
+                       input_report_abs(hdata->input, ABS_MT_PRESSURE, z);
+
+               }
+
+               input_mt_sync_frame(hdata->input);
+
+               input_report_key(hdata->input, BTN_LEFT,
+                       data[1] & 0x1);
+               input_report_key(hdata->input, BTN_RIGHT,
+                       (data[1] & 0x2));
+               input_report_key(hdata->input, BTN_MIDDLE,
+                       (data[1] & 0x4));
+
+               input_sync(hdata->input);
+
+               return 1;
+
+       case U1_SP_ABSOLUTE_REPORT_ID:
+               sp_x = get_unaligned_le16(data+2);
+               sp_y = get_unaligned_le16(data+4);
+
+               sp_x = sp_x / 8;
+               sp_y = sp_y / 8;
+
+               input_report_rel(hdata->input2, REL_X, sp_x);
+               input_report_rel(hdata->input2, REL_Y, sp_y);
+
+               input_report_key(hdata->input2, BTN_LEFT,
+                       data[1] & 0x1);
+               input_report_key(hdata->input2, BTN_RIGHT,
+                       (data[1] & 0x2));
+               input_report_key(hdata->input2, BTN_MIDDLE,
+                       (data[1] & 0x4));
+
+               input_sync(hdata->input2);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int alps_post_reset(struct hid_device *hdev)
+{
+       return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                               NULL, U1_TP_ABS_MODE, false);
+}
+
+static int alps_post_resume(struct hid_device *hdev)
+{
+       return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                               NULL, U1_TP_ABS_MODE, false);
+}
+#endif /* CONFIG_PM */
+
+static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
+{
+       struct u1_dev *data = hid_get_drvdata(hdev);
+       struct input_dev *input = hi->input, *input2;
+       struct u1_dev devInfo;
+       int ret;
+       int res_x, res_y, i;
+
+       data->input = input;
+
+       hid_dbg(hdev, "Opening low level driver\n");
+       ret = hid_hw_open(hdev);
+       if (ret)
+               return ret;
+
+       /* Allow incoming hid reports */
+       hid_device_io_start(hdev);
+
+       /* Device initialization */
+       ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                       &devInfo.dev_ctrl, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret);
+               goto exit;
+       }
+
+       devInfo.dev_ctrl &= ~U1_DISABLE_DEV;
+       devInfo.dev_ctrl |= U1_TP_ABS_MODE;
+       ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                       NULL, devInfo.dev_ctrl, false);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X,
+                       &devInfo.sen_line_num_x, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y,
+                       &devInfo.sen_line_num_y, 0, true);
+               if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X,
+                       &devInfo.pitch_x, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y,
+                       &devInfo.pitch_y, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS,
+               &devInfo.resolution, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN,
+                       &devInfo.btn_info, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret);
+               goto exit;
+       }
+
+       /* Check StickPointer device */
+       ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP,
+                       &devInfo.dev_type, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret);
+               goto exit;
+       }
+
+       devInfo.x_active_len_mm =
+               (devInfo.pitch_x * (devInfo.sen_line_num_x - 1)) / 10;
+       devInfo.y_active_len_mm =
+               (devInfo.pitch_y * (devInfo.sen_line_num_y - 1)) / 10;
+
+       devInfo.x_max =
+               (devInfo.resolution << 2) * (devInfo.sen_line_num_x - 1);
+       devInfo.y_max =
+               (devInfo.resolution << 2) * (devInfo.sen_line_num_y - 1);
+
+       __set_bit(EV_ABS, input->evbit);
+       input_set_abs_params(input, ABS_MT_POSITION_X, 1, devInfo.x_max, 0, 0);
+       input_set_abs_params(input, ABS_MT_POSITION_Y, 1, devInfo.y_max, 0, 0);
+
+       if (devInfo.x_active_len_mm && devInfo.y_active_len_mm) {
+               res_x = (devInfo.x_max - 1) / devInfo.x_active_len_mm;
+               res_y = (devInfo.y_max - 1) / devInfo.y_active_len_mm;
+
+               input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
+               input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
+       }
+
+       input_set_abs_params(input, ABS_MT_PRESSURE, 0, 64, 0, 0);
+
+       input_mt_init_slots(input, MAX_TOUCHES, INPUT_MT_POINTER);
+
+       __set_bit(EV_KEY, input->evbit);
+       if ((devInfo.btn_info & 0x0F) == (devInfo.btn_info & 0xF0) >> 4) {
+               devInfo.btn_cnt = (devInfo.btn_info & 0x0F);
+       } else {
+               /* Button pad */
+               devInfo.btn_cnt = 1;
+               __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+       }
+
+       for (i = 0; i < devInfo.btn_cnt; i++)
+               __set_bit(BTN_LEFT + i, input->keybit);
+
+
+       /* Stick device initialization */
+       if (devInfo.dev_type & U1_DEVTYPE_SP_SUPPORT) {
+
+               input2 = input_allocate_device();
+               if (!input2) {
+                       input_free_device(input2);
+                       goto exit;
+               }
+
+               data->input2 = input2;
+
+               devInfo.dev_ctrl |= U1_SP_ABS_MODE;
+               ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                       NULL, devInfo.dev_ctrl, false);
+               if (ret < 0) {
+                       dev_err(&hdev->dev, "failed SP mode (%d)\n", ret);
+                       input_free_device(input2);
+                       goto exit;
+               }
+
+               ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN,
+                       &devInfo.sp_btn_info, 0, true);
+               if (ret < 0) {
+                       dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret);
+                       input_free_device(input2);
+                       goto exit;
+               }
+
+               input2->phys = input->phys;
+               input2->name = "DualPoint Stick";
+               input2->id.bustype = BUS_I2C;
+               input2->id.vendor  = input->id.vendor;
+               input2->id.product = input->id.product;
+               input2->id.version = input->id.version;
+               input2->dev.parent = input->dev.parent;
+
+               __set_bit(EV_KEY, input2->evbit);
+               devInfo.sp_btn_cnt = (devInfo.sp_btn_info & 0x0F);
+               for (i = 0; i < devInfo.sp_btn_cnt; i++)
+                       __set_bit(BTN_LEFT + i, input2->keybit);
+
+               __set_bit(EV_REL, input2->evbit);
+               __set_bit(REL_X, input2->relbit);
+               __set_bit(REL_Y, input2->relbit);
+               __set_bit(INPUT_PROP_POINTER, input2->propbit);
+               __set_bit(INPUT_PROP_POINTING_STICK, input2->propbit);
+
+               if (input_register_device(data->input2)) {
+                       input_free_device(input2);
+                       goto exit;
+               }
+       }
+
+exit:
+       hid_device_io_stop(hdev);
+       hid_hw_close(hdev);
+       return ret;
+}
+
+static int alps_input_mapping(struct hid_device *hdev,
+               struct hid_input *hi, struct hid_field *field,
+               struct hid_usage *usage, unsigned long **bit, int *max)
+{
+       return -1;
+}
+
+static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       struct u1_dev *data = NULL;
+       int ret;
+
+       data = devm_kzalloc(&hdev->dev, sizeof(struct u1_dev), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->hdev = hdev;
+       hid_set_drvdata(hdev, data);
+
+       hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               hid_err(hdev, "parse failed\n");
+               return ret;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               hid_err(hdev, "hw start failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void alps_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id alps_id[] = {
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
+               USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, alps_id);
+
+static struct hid_driver alps_driver = {
+       .name = "hid-alps",
+       .id_table               = alps_id,
+       .probe                  = alps_probe,
+       .remove                 = alps_remove,
+       .raw_event              = alps_raw_event,
+       .input_mapping          = alps_input_mapping,
+       .input_configured       = alps_input_configured,
+#ifdef CONFIG_PM
+       .resume                 = alps_post_resume,
+       .reset_resume           = alps_post_reset,
+#endif
+};
+
+module_hid_driver(alps_driver);
+
+MODULE_AUTHOR("Masaki Ota <masaki.ota@jp.alps.com>");
+MODULE_DESCRIPTION("ALPS HID driver");
+MODULE_LICENSE("GPL");
index 884d82f9190e214636a539cb2db884a1d175c945..2e046082210f9fd452aaa7fb6f2a79a2c278728a 100644 (file)
@@ -474,6 +474,8 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI),
+               .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
index 8ea3a26360e941614efd496a2d8435322e0ff567..08f53c7fd5132f86123f15fc2b5c3cadf12604b7 100644 (file)
@@ -1772,6 +1772,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) },
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
@@ -1851,6 +1852,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) },
@@ -1877,8 +1879,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
@@ -1962,6 +1967,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_LUXAFOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
@@ -2008,6 +2014,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
 #if IS_ENABLED(CONFIG_HID_ROCCAT)
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
@@ -2348,8 +2355,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
@@ -2486,7 +2491,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) },
 #endif
        { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
        { }
 };
 
index 3eec09a134cb66ac1b9e03f89e3c201cd1b48adb..4ed9a4fdfea789ff94da728555b6c9ca7d802bd8 100644 (file)
@@ -70,6 +70,9 @@
 #define USB_VENDOR_ID_ALPS             0x0433
 #define USB_DEVICE_ID_IBM_GAMEPAD      0x1101
 
+#define USB_VENDOR_ID_ALPS_JP          0x044E
+#define HID_DEVICE_ID_ALPS_U1_DUAL     0x120B
+
 #define USB_VENDOR_ID_ANTON            0x1130
 #define USB_DEVICE_ID_ANTON_TOUCH_PAD  0x3101
 
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI  0x0255
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO   0x0256
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS   0x0257
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI   0x0267
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI   0x0290
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO    0x0291
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS    0x0292
 #define USB_VENDOR_ID_DEALEXTREAME     0x10c5
 #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701        0x819a
 
+#define USB_VENDOR_ID_DELCOM           0x0fc5
+#define USB_DEVICE_ID_DELCOM_VISUAL_IND        0xb080
+
 #define USB_VENDOR_ID_DELORME          0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE        0x0100
 #define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
 #define USB_DEVICE_ID_ELECOM_BM084     0x0061
 
 #define USB_VENDOR_ID_DREAM_CHEEKY     0x1d34
+#define USB_DEVICE_ID_DREAM_CHEEKY_WN  0x0004
+#define USB_DEVICE_ID_DREAM_CHEEKY_FA  0x000a
 
 #define USB_VENDOR_ID_ELITEGROUP       0x03fc
 #define USB_DEVICE_ID_ELITEGROUP_05D8  0x05d8
 #define USB_DEVICE_ID_PICOLCD_BOOTLOADER       0xf002
 #define USB_DEVICE_ID_PICK16F1454      0x0042
 #define USB_DEVICE_ID_PICK16F1454_V2   0xf2f7
+#define USB_DEVICE_ID_LUXAFOR          0xf372
 
 #define USB_VENDOR_ID_MICROSOFT                0x045e
 #define USB_DEVICE_ID_SIDEWINDER_GV    0x003b
diff --git a/drivers/hid/hid-led.c b/drivers/hid/hid-led.c
new file mode 100644 (file)
index 0000000..d8d55f3
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Simple USB RGB LED driver
+ *
+ * Copyright 2016 Heiner Kallweit <hkallweit1@gmail.com>
+ * Based on drivers/hid/hid-thingm.c and
+ * drivers/usb/misc/usbled.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/hid.h>
+#include <linux/hidraw.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include "hid-ids.h"
+
+enum hidled_report_type {
+       RAW_REQUEST,
+       OUTPUT_REPORT
+};
+
+enum hidled_type {
+       RISO_KAGAKU,
+       DREAM_CHEEKY,
+       THINGM,
+       DELCOM,
+       LUXAFOR,
+};
+
+static unsigned const char riso_kagaku_tbl[] = {
+/* R+2G+4B -> riso kagaku color index */
+       [0] = 0, /* black   */
+       [1] = 2, /* red     */
+       [2] = 1, /* green   */
+       [3] = 5, /* yellow  */
+       [4] = 3, /* blue    */
+       [5] = 6, /* magenta */
+       [6] = 4, /* cyan    */
+       [7] = 7  /* white   */
+};
+
+#define RISO_KAGAKU_IX(r, g, b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
+
+union delcom_packet {
+       __u8 data[8];
+       struct {
+               __u8 major_cmd;
+               __u8 minor_cmd;
+               __u8 data_lsb;
+               __u8 data_msb;
+       } tx;
+       struct {
+               __u8 cmd;
+       } rx;
+       struct {
+               __le16 family_code;
+               __le16 security_code;
+               __u8 fw_version;
+       } fw;
+};
+
+#define DELCOM_GREEN_LED       0
+#define DELCOM_RED_LED         1
+#define DELCOM_BLUE_LED                2
+
+struct hidled_device;
+struct hidled_rgb;
+
+struct hidled_config {
+       enum hidled_type        type;
+       const char              *name;
+       const char              *short_name;
+       enum led_brightness     max_brightness;
+       int                     num_leds;
+       size_t                  report_size;
+       enum hidled_report_type report_type;
+       int (*init)(struct hidled_device *ldev);
+       int (*write)(struct led_classdev *cdev, enum led_brightness br);
+};
+
+struct hidled_led {
+       struct led_classdev     cdev;
+       struct hidled_rgb       *rgb;
+       char                    name[32];
+};
+
+struct hidled_rgb {
+       struct hidled_device    *ldev;
+       struct hidled_led       red;
+       struct hidled_led       green;
+       struct hidled_led       blue;
+       u8                      num;
+};
+
+struct hidled_device {
+       const struct hidled_config *config;
+       struct hid_device       *hdev;
+       struct hidled_rgb       *rgb;
+       struct mutex            lock;
+};
+
+#define MAX_REPORT_SIZE                16
+
+#define to_hidled_led(arg) container_of(arg, struct hidled_led, cdev)
+
+static bool riso_kagaku_switch_green_blue;
+module_param(riso_kagaku_switch_green_blue, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(riso_kagaku_switch_green_blue,
+       "switch green and blue RGB component for Riso Kagaku devices");
+
+static int hidled_send(struct hidled_device *ldev, __u8 *buf)
+{
+       int ret;
+
+       mutex_lock(&ldev->lock);
+
+       if (ldev->config->report_type == RAW_REQUEST)
+               ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+                                        ldev->config->report_size,
+                                        HID_FEATURE_REPORT,
+                                        HID_REQ_SET_REPORT);
+       else if (ldev->config->report_type == OUTPUT_REPORT)
+               ret = hid_hw_output_report(ldev->hdev, buf,
+                                          ldev->config->report_size);
+       else
+               ret = -EINVAL;
+
+       mutex_unlock(&ldev->lock);
+
+       if (ret < 0)
+               return ret;
+
+       return ret == ldev->config->report_size ? 0 : -EMSGSIZE;
+}
+
+/* reading data is supported for report type RAW_REQUEST only */
+static int hidled_recv(struct hidled_device *ldev, __u8 *buf)
+{
+       int ret;
+
+       if (ldev->config->report_type != RAW_REQUEST)
+               return -EINVAL;
+
+       mutex_lock(&ldev->lock);
+
+       ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+                                ldev->config->report_size,
+                                HID_FEATURE_REPORT,
+                                HID_REQ_SET_REPORT);
+       if (ret < 0)
+               goto err;
+
+       ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+                                ldev->config->report_size,
+                                HID_FEATURE_REPORT,
+                                HID_REQ_GET_REPORT);
+err:
+       mutex_unlock(&ldev->lock);
+
+       return ret < 0 ? ret : 0;
+}
+
+static u8 riso_kagaku_index(struct hidled_rgb *rgb)
+{
+       enum led_brightness r, g, b;
+
+       r = rgb->red.cdev.brightness;
+       g = rgb->green.cdev.brightness;
+       b = rgb->blue.cdev.brightness;
+
+       if (riso_kagaku_switch_green_blue)
+               return RISO_KAGAKU_IX(r, b, g);
+       else
+               return RISO_KAGAKU_IX(r, g, b);
+}
+
+static int riso_kagaku_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       struct hidled_rgb *rgb = led->rgb;
+       __u8 buf[MAX_REPORT_SIZE] = {};
+
+       buf[1] = riso_kagaku_index(rgb);
+
+       return hidled_send(rgb->ldev, buf);
+}
+
+static int dream_cheeky_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       struct hidled_rgb *rgb = led->rgb;
+       __u8 buf[MAX_REPORT_SIZE] = {};
+
+       buf[1] = rgb->red.cdev.brightness;
+       buf[2] = rgb->green.cdev.brightness;
+       buf[3] = rgb->blue.cdev.brightness;
+       buf[7] = 0x1a;
+       buf[8] = 0x05;
+
+       return hidled_send(rgb->ldev, buf);
+}
+
+static int dream_cheeky_init(struct hidled_device *ldev)
+{
+       __u8 buf[MAX_REPORT_SIZE] = {};
+
+       /* Dream Cheeky magic */
+       buf[1] = 0x1f;
+       buf[2] = 0x02;
+       buf[4] = 0x5f;
+       buf[7] = 0x1a;
+       buf[8] = 0x03;
+
+       return hidled_send(ldev, buf);
+}
+
+static int _thingm_write(struct led_classdev *cdev, enum led_brightness br,
+                        u8 offset)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       __u8 buf[MAX_REPORT_SIZE] = { 1, 'c' };
+
+       buf[2] = led->rgb->red.cdev.brightness;
+       buf[3] = led->rgb->green.cdev.brightness;
+       buf[4] = led->rgb->blue.cdev.brightness;
+       buf[7] = led->rgb->num + offset;
+
+       return hidled_send(led->rgb->ldev, buf);
+}
+
+static int thingm_write_v1(struct led_classdev *cdev, enum led_brightness br)
+{
+       return _thingm_write(cdev, br, 0);
+}
+
+static int thingm_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       return _thingm_write(cdev, br, 1);
+}
+
+static const struct hidled_config hidled_config_thingm_v1 = {
+       .name = "ThingM blink(1) v1",
+       .short_name = "thingm",
+       .max_brightness = 255,
+       .num_leds = 1,
+       .report_size = 9,
+       .report_type = RAW_REQUEST,
+       .write = thingm_write_v1,
+};
+
+static int thingm_init(struct hidled_device *ldev)
+{
+       __u8 buf[MAX_REPORT_SIZE] = { 1, 'v' };
+       int ret;
+
+       ret = hidled_recv(ldev, buf);
+       if (ret)
+               return ret;
+
+       /* Check for firmware major version 1 */
+       if (buf[3] == '1')
+               ldev->config = &hidled_config_thingm_v1;
+
+       return 0;
+}
+
+static inline int delcom_get_lednum(const struct hidled_led *led)
+{
+       if (led == &led->rgb->red)
+               return DELCOM_RED_LED;
+       else if (led == &led->rgb->green)
+               return DELCOM_GREEN_LED;
+       else
+               return DELCOM_BLUE_LED;
+}
+
+static int delcom_enable_led(struct hidled_led *led)
+{
+       union delcom_packet dp = { .tx.major_cmd = 101, .tx.minor_cmd = 12 };
+
+       dp.tx.data_lsb = 1 << delcom_get_lednum(led);
+       dp.tx.data_msb = 0;
+
+       return hidled_send(led->rgb->ldev, dp.data);
+}
+
+static int delcom_set_pwm(struct hidled_led *led)
+{
+       union delcom_packet dp = { .tx.major_cmd = 101, .tx.minor_cmd = 34 };
+
+       dp.tx.data_lsb = delcom_get_lednum(led);
+       dp.tx.data_msb = led->cdev.brightness;
+
+       return hidled_send(led->rgb->ldev, dp.data);
+}
+
+static int delcom_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       int ret;
+
+       /*
+        * enable LED
+        * We can't do this in the init function already because the device
+        * is internally reset later.
+        */
+       ret = delcom_enable_led(led);
+       if (ret)
+               return ret;
+
+       return delcom_set_pwm(led);
+}
+
+static int delcom_init(struct hidled_device *ldev)
+{
+       union delcom_packet dp = { .rx.cmd = 104 };
+       int ret;
+
+       ret = hidled_recv(ldev, dp.data);
+       if (ret)
+               return ret;
+       /*
+        * Several Delcom devices share the same USB VID/PID
+        * Check for family id 2 for Visual Signal Indicator
+        */
+       return le16_to_cpu(dp.fw.family_code) == 2 ? 0 : -ENODEV;
+}
+
+static int luxafor_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       __u8 buf[MAX_REPORT_SIZE] = { [1] = 1 };
+
+       buf[2] = led->rgb->num + 1;
+       buf[3] = led->rgb->red.cdev.brightness;
+       buf[4] = led->rgb->green.cdev.brightness;
+       buf[5] = led->rgb->blue.cdev.brightness;
+
+       return hidled_send(led->rgb->ldev, buf);
+}
+
+static const struct hidled_config hidled_configs[] = {
+       {
+               .type = RISO_KAGAKU,
+               .name = "Riso Kagaku Webmail Notifier",
+               .short_name = "riso_kagaku",
+               .max_brightness = 1,
+               .num_leds = 1,
+               .report_size = 6,
+               .report_type = OUTPUT_REPORT,
+               .write = riso_kagaku_write,
+       },
+       {
+               .type = DREAM_CHEEKY,
+               .name = "Dream Cheeky Webmail Notifier",
+               .short_name = "dream_cheeky",
+               .max_brightness = 31,
+               .num_leds = 1,
+               .report_size = 9,
+               .report_type = RAW_REQUEST,
+               .init = dream_cheeky_init,
+               .write = dream_cheeky_write,
+       },
+       {
+               .type = THINGM,
+               .name = "ThingM blink(1)",
+               .short_name = "thingm",
+               .max_brightness = 255,
+               .num_leds = 2,
+               .report_size = 9,
+               .report_type = RAW_REQUEST,
+               .init = thingm_init,
+               .write = thingm_write,
+       },
+       {
+               .type = DELCOM,
+               .name = "Delcom Visual Signal Indicator G2",
+               .short_name = "delcom",
+               .max_brightness = 100,
+               .num_leds = 1,
+               .report_size = 8,
+               .report_type = RAW_REQUEST,
+               .init = delcom_init,
+               .write = delcom_write,
+       },
+       {
+               .type = LUXAFOR,
+               .name = "Greynut Luxafor",
+               .short_name = "luxafor",
+               .max_brightness = 255,
+               .num_leds = 6,
+               .report_size = 9,
+               .report_type = OUTPUT_REPORT,
+               .write = luxafor_write,
+       },
+};
+
+static int hidled_init_led(struct hidled_led *led, const char *color_name,
+                          struct hidled_rgb *rgb, unsigned int minor)
+{
+       const struct hidled_config *config = rgb->ldev->config;
+
+       if (config->num_leds > 1)
+               snprintf(led->name, sizeof(led->name), "%s%u:%s:led%u",
+                        config->short_name, minor, color_name, rgb->num);
+       else
+               snprintf(led->name, sizeof(led->name), "%s%u:%s",
+                        config->short_name, minor, color_name);
+       led->cdev.name = led->name;
+       led->cdev.max_brightness = config->max_brightness;
+       led->cdev.brightness_set_blocking = config->write;
+       led->cdev.flags = LED_HW_PLUGGABLE;
+       led->rgb = rgb;
+
+       return devm_led_classdev_register(&rgb->ldev->hdev->dev, &led->cdev);
+}
+
+static int hidled_init_rgb(struct hidled_rgb *rgb, unsigned int minor)
+{
+       int ret;
+
+       /* Register the red diode */
+       ret = hidled_init_led(&rgb->red, "red", rgb, minor);
+       if (ret)
+               return ret;
+
+       /* Register the green diode */
+       ret = hidled_init_led(&rgb->green, "green", rgb, minor);
+       if (ret)
+               return ret;
+
+       /* Register the blue diode */
+       return hidled_init_led(&rgb->blue, "blue", rgb, minor);
+}
+
+static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       struct hidled_device *ldev;
+       unsigned int minor;
+       int ret, i;
+
+       ldev = devm_kzalloc(&hdev->dev, sizeof(*ldev), GFP_KERNEL);
+       if (!ldev)
+               return -ENOMEM;
+
+       ret = hid_parse(hdev);
+       if (ret)
+               return ret;
+
+       ldev->hdev = hdev;
+       mutex_init(&ldev->lock);
+
+       for (i = 0; !ldev->config && i < ARRAY_SIZE(hidled_configs); i++)
+               if (hidled_configs[i].type == id->driver_data)
+                       ldev->config = &hidled_configs[i];
+
+       if (!ldev->config)
+               return -EINVAL;
+
+       if (ldev->config->init) {
+               ret = ldev->config->init(ldev);
+               if (ret)
+                       return ret;
+       }
+
+       ldev->rgb = devm_kcalloc(&hdev->dev, ldev->config->num_leds,
+                                sizeof(struct hidled_rgb), GFP_KERNEL);
+       if (!ldev->rgb)
+               return -ENOMEM;
+
+       ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+       if (ret)
+               return ret;
+
+       minor = ((struct hidraw *) hdev->hidraw)->minor;
+
+       for (i = 0; i < ldev->config->num_leds; i++) {
+               ldev->rgb[i].ldev = ldev;
+               ldev->rgb[i].num = i;
+               ret = hidled_init_rgb(&ldev->rgb[i], minor);
+               if (ret) {
+                       hid_hw_stop(hdev);
+                       return ret;
+               }
+       }
+
+       hid_info(hdev, "%s initialized\n", ldev->config->name);
+
+       return 0;
+}
+
+static const struct hid_device_id hidled_table[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU,
+         USB_DEVICE_ID_RI_KA_WEBMAIL), .driver_data = RISO_KAGAKU },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY,
+         USB_DEVICE_ID_DREAM_CHEEKY_WN), .driver_data = DREAM_CHEEKY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY,
+         USB_DEVICE_ID_DREAM_CHEEKY_FA), .driver_data = DREAM_CHEEKY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THINGM,
+         USB_DEVICE_ID_BLINK1), .driver_data = THINGM },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM,
+         USB_DEVICE_ID_DELCOM_VISUAL_IND), .driver_data = DELCOM },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP,
+         USB_DEVICE_ID_LUXAFOR), .driver_data = LUXAFOR },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, hidled_table);
+
+static struct hid_driver hidled_driver = {
+       .name = "hid-led",
+       .probe = hidled_probe,
+       .id_table = hidled_table,
+};
+
+module_hid_driver(hidled_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Heiner Kallweit <hkallweit1@gmail.com>");
+MODULE_DESCRIPTION("Simple USB RGB LED driver");
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
deleted file mode 100644 (file)
index 9ad9c6e..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * ThingM blink(1) USB RGB LED driver
- *
- * Copyright 2013-2014 Savoir-faire Linux Inc.
- *     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2.
- */
-
-#include <linux/hid.h>
-#include <linux/hidraw.h>
-#include <linux/leds.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-
-#include "hid-ids.h"
-
-#define REPORT_ID      1
-#define REPORT_SIZE    9
-
-/* Firmware major number of supported devices */
-#define THINGM_MAJOR_MK1       '1'
-#define THINGM_MAJOR_MK2       '2'
-
-struct thingm_fwinfo {
-       char major;
-       unsigned numrgb;
-       unsigned first;
-};
-
-static const struct thingm_fwinfo thingm_fwinfo[] = {
-       {
-               .major = THINGM_MAJOR_MK1,
-               .numrgb = 1,
-               .first = 0,
-       }, {
-               .major = THINGM_MAJOR_MK2,
-               .numrgb = 2,
-               .first = 1,
-       }
-};
-
-/* A red, green or blue channel, part of an RGB chip */
-struct thingm_led {
-       struct thingm_rgb *rgb;
-       struct led_classdev ldev;
-       char name[32];
-};
-
-/* Basically a WS2812 5050 RGB LED chip */
-struct thingm_rgb {
-       struct thingm_device *tdev;
-       struct thingm_led red;
-       struct thingm_led green;
-       struct thingm_led blue;
-       u8 num;
-};
-
-struct thingm_device {
-       struct hid_device *hdev;
-       struct {
-               char major;
-               char minor;
-       } version;
-       const struct thingm_fwinfo *fwinfo;
-       struct mutex lock;
-       struct thingm_rgb *rgb;
-};
-
-static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
-{
-       int ret;
-
-       hid_dbg(tdev->hdev, "-> %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
-                       buf[0], buf[1], buf[2], buf[3], buf[4],
-                       buf[5], buf[6], buf[7], buf[8]);
-
-       mutex_lock(&tdev->lock);
-
-       ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
-                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-
-       mutex_unlock(&tdev->lock);
-
-       return ret < 0 ? ret : 0;
-}
-
-static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
-{
-       int ret;
-
-       /*
-        * A read consists of two operations: sending the read command
-        * and the actual read from the device. Use the mutex to protect
-        * the full sequence of both operations.
-        */
-       mutex_lock(&tdev->lock);
-
-       ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
-                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-       if (ret < 0)
-               goto err;
-
-       ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
-                       HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
-       if (ret < 0)
-               goto err;
-
-       ret = 0;
-
-       hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
-                       buf[0], buf[1], buf[2], buf[3], buf[4],
-                       buf[5], buf[6], buf[7], buf[8]);
-err:
-       mutex_unlock(&tdev->lock);
-       return ret;
-}
-
-static int thingm_version(struct thingm_device *tdev)
-{
-       u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
-       int err;
-
-       err = thingm_recv(tdev, buf);
-       if (err)
-               return err;
-
-       tdev->version.major = buf[3];
-       tdev->version.minor = buf[4];
-
-       return 0;
-}
-
-static int thingm_write_color(struct thingm_rgb *rgb)
-{
-       u8 buf[REPORT_SIZE] = { REPORT_ID, 'c', 0, 0, 0, 0, 0, rgb->num, 0 };
-
-       buf[2] = rgb->red.ldev.brightness;
-       buf[3] = rgb->green.ldev.brightness;
-       buf[4] = rgb->blue.ldev.brightness;
-
-       return thingm_send(rgb->tdev, buf);
-}
-
-static int thingm_led_set(struct led_classdev *ldev,
-                         enum led_brightness brightness)
-{
-       struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
-
-       return thingm_write_color(led->rgb);
-}
-
-static int thingm_init_led(struct thingm_led *led, const char *color_name,
-                          struct thingm_rgb *rgb, int minor)
-{
-       snprintf(led->name, sizeof(led->name), "thingm%d:%s:led%d",
-                minor, color_name, rgb->num);
-       led->ldev.name = led->name;
-       led->ldev.max_brightness = 255;
-       led->ldev.brightness_set_blocking = thingm_led_set;
-       led->ldev.flags = LED_HW_PLUGGABLE;
-       led->rgb = rgb;
-       return devm_led_classdev_register(&rgb->tdev->hdev->dev, &led->ldev);
-}
-
-static int thingm_init_rgb(struct thingm_rgb *rgb)
-{
-       const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor;
-       int err;
-
-       /* Register the red diode */
-       err = thingm_init_led(&rgb->red, "red", rgb, minor);
-       if (err)
-               return err;
-
-       /* Register the green diode */
-       err = thingm_init_led(&rgb->green, "green", rgb, minor);
-       if (err)
-               return err;
-
-       /* Register the blue diode */
-       return thingm_init_led(&rgb->blue, "blue", rgb, minor);
-}
-
-static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
-       struct thingm_device *tdev;
-       int i, err;
-
-       tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device),
-                       GFP_KERNEL);
-       if (!tdev)
-               return -ENOMEM;
-
-       tdev->hdev = hdev;
-       hid_set_drvdata(hdev, tdev);
-
-       err = hid_parse(hdev);
-       if (err)
-               return err;
-
-       mutex_init(&tdev->lock);
-
-       err = thingm_version(tdev);
-       if (err)
-               return err;
-
-       hid_dbg(hdev, "firmware version: %c.%c\n",
-                       tdev->version.major, tdev->version.minor);
-
-       for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i)
-               if (thingm_fwinfo[i].major == tdev->version.major)
-                       tdev->fwinfo = &thingm_fwinfo[i];
-
-       if (!tdev->fwinfo) {
-               hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
-               return -ENODEV;
-       }
-
-       tdev->rgb = devm_kzalloc(&hdev->dev,
-                       sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
-                       GFP_KERNEL);
-       if (!tdev->rgb)
-               return -ENOMEM;
-
-       err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
-       if (err)
-               return err;
-
-       for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
-               struct thingm_rgb *rgb = tdev->rgb + i;
-
-               rgb->tdev = tdev;
-               rgb->num = tdev->fwinfo->first + i;
-               err = thingm_init_rgb(rgb);
-               if (err) {
-                       hid_hw_stop(hdev);
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static const struct hid_device_id thingm_table[] = {
-       { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
-       { }
-};
-MODULE_DEVICE_TABLE(hid, thingm_table);
-
-static struct hid_driver thingm_driver = {
-       .name = "thingm",
-       .probe = thingm_probe,
-       .id_table = thingm_table,
-};
-
-module_hid_driver(thingm_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Vivien Didelot <vivien.didelot@savoirfairelinux.com>");
-MODULE_DESCRIPTION("ThingM blink(1) USB RGB LED driver");
index 2e021ba8ff052eacdf1dda7bf68af24d9d628543..b3ec4f2de875e3e0e9626fd1296778089cb2b226 100644 (file)
@@ -1020,6 +1020,7 @@ static int i2c_hid_probe(struct i2c_client *client,
        pm_runtime_get_noresume(&client->dev);
        pm_runtime_set_active(&client->dev);
        pm_runtime_enable(&client->dev);
+       device_enable_async_suspend(&client->dev);
 
        ret = i2c_hid_fetch_hid_descriptor(ihid);
        if (ret < 0)
@@ -1106,6 +1107,14 @@ static int i2c_hid_remove(struct i2c_client *client)
        return 0;
 }
 
+static void i2c_hid_shutdown(struct i2c_client *client)
+{
+       struct i2c_hid *ihid = i2c_get_clientdata(client);
+
+       i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+       free_irq(client->irq, ihid);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int i2c_hid_suspend(struct device *dev)
 {
@@ -1230,7 +1239,7 @@ static struct i2c_driver i2c_hid_driver = {
 
        .probe          = i2c_hid_probe,
        .remove         = i2c_hid_remove,
-
+       .shutdown       = i2c_hid_shutdown,
        .id_table       = i2c_hid_id_table,
 };
 
index 16b6f11a07001c7831a987e6bd891b7d00868f65..99ec3ff7563b3e75ce0c050ba7d28064d445c7af 100644 (file)
@@ -51,10 +51,26 @@ struct uhid_device {
        u32 report_id;
        u32 report_type;
        struct uhid_event report_buf;
+       struct work_struct worker;
 };
 
 static struct miscdevice uhid_misc;
 
+static void uhid_device_add_worker(struct work_struct *work)
+{
+       struct uhid_device *uhid = container_of(work, struct uhid_device, worker);
+       int ret;
+
+       ret = hid_add_device(uhid->hid);
+       if (ret) {
+               hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret);
+
+               hid_destroy_device(uhid->hid);
+               uhid->hid = NULL;
+               uhid->running = false;
+       }
+}
+
 static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
 {
        __u8 newhead;
@@ -498,18 +514,14 @@ static int uhid_dev_create2(struct uhid_device *uhid,
        uhid->hid = hid;
        uhid->running = true;
 
-       ret = hid_add_device(hid);
-       if (ret) {
-               hid_err(hid, "Cannot register HID device\n");
-               goto err_hid;
-       }
+       /* Adding of a HID device is done through a worker, to allow HID drivers
+        * which use feature requests during .probe to work, without they would
+        * be blocked on devlock, which is held by uhid_char_write.
+        */
+       schedule_work(&uhid->worker);
 
        return 0;
 
-err_hid:
-       hid_destroy_device(hid);
-       uhid->hid = NULL;
-       uhid->running = false;
 err_free:
        kfree(uhid->rd_data);
        uhid->rd_data = NULL;
@@ -550,6 +562,8 @@ static int uhid_dev_destroy(struct uhid_device *uhid)
        uhid->running = false;
        wake_up_interruptible(&uhid->report_wait);
 
+       cancel_work_sync(&uhid->worker);
+
        hid_destroy_device(uhid->hid);
        kfree(uhid->rd_data);
 
@@ -612,6 +626,7 @@ static int uhid_char_open(struct inode *inode, struct file *file)
        init_waitqueue_head(&uhid->waitq);
        init_waitqueue_head(&uhid->report_wait);
        uhid->running = false;
+       INIT_WORK(&uhid->worker, uhid_device_add_worker);
 
        file->private_data = uhid;
        nonseekable_open(inode, file);
index c752447fbac7883f96290889e382639033975b53..fa6880b8060a050cf2ef01d8a79b762e1cb2272c 100644 (file)
@@ -98,6 +98,7 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev)
        }
 
        regmap = syscon_node_to_regmap(syscon);
+       of_node_put(syscon);
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
index 6a86b5d1defa0513f6bc5cc8e88e125aecfaf629..7330a66e2b7ef4d9b88222df3153c07c8f83b1d7 100644 (file)
@@ -1871,10 +1871,11 @@ static int dmar_hp_remove_drhd(struct acpi_dmar_header *header, void *arg)
        /*
         * All PCI devices managed by this unit should have been destroyed.
         */
-       if (!dmaru->include_all && dmaru->devices && dmaru->devices_cnt)
+       if (!dmaru->include_all && dmaru->devices && dmaru->devices_cnt) {
                for_each_active_dev_scope(dmaru->devices,
                                          dmaru->devices_cnt, i, dev)
                        return -EBUSY;
+       }
 
        ret = dmar_ir_hotplug(dmaru, false);
        if (ret == 0)
index 323dac9900ba3cc0a0c1351dfc39de86b4cb06ab..4b9040bb2f1ca5129a90e4d5cce17433fef55daf 100644 (file)
@@ -4272,10 +4272,11 @@ int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg)
        if (!atsru)
                return 0;
 
-       if (!atsru->include_all && atsru->devices && atsru->devices_cnt)
+       if (!atsru->include_all && atsru->devices && atsru->devices_cnt) {
                for_each_active_dev_scope(atsru->devices, atsru->devices_cnt,
                                          i, dev)
                        return -EBUSY;
+       }
 
        return 0;
 }
index 6d35dd4e9efbe45384dca916bf447396a30fe02e..4788b0b989a9bac661f07a8deb2c7a86a96c8677 100644 (file)
@@ -142,7 +142,7 @@ static int linear_iterate_devices(struct dm_target *ti,
 }
 
 static long linear_direct_access(struct dm_target *ti, sector_t sector,
-                                void __pmem **kaddr, pfn_t *pfn, long size)
+                                void **kaddr, pfn_t *pfn, long size)
 {
        struct linear_c *lc = ti->private;
        struct block_device *bdev = lc->dev->bdev;
index 731e1f5bd89574deb711419ebe8eaf7a544e605d..ce2a910709f722ce065e365fd53a9ee326b6477e 100644 (file)
@@ -2303,7 +2303,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio)
 }
 
 static long origin_direct_access(struct dm_target *ti, sector_t sector,
-               void __pmem **kaddr, pfn_t *pfn, long size)
+               void **kaddr, pfn_t *pfn, long size)
 {
        DMWARN("device does not support dax.");
        return -EIO;
index 01bb9cf2a8c2318e1b5cf704728637acf95665c9..83f1d46671953323bd7390d57a6eef4099b61d5d 100644 (file)
@@ -309,7 +309,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio)
 }
 
 static long stripe_direct_access(struct dm_target *ti, sector_t sector,
-                                void __pmem **kaddr, pfn_t *pfn, long size)
+                                void **kaddr, pfn_t *pfn, long size)
 {
        struct stripe_c *sc = ti->private;
        uint32_t stripe;
index 6eecd6b36f768fb0ea4e056b5742afce02089e28..710ae28fd618256ea0b1da6fc34c40ae6e473066 100644 (file)
@@ -149,7 +149,7 @@ static void io_err_release_clone_rq(struct request *clone)
 }
 
 static long io_err_direct_access(struct dm_target *ti, sector_t sector,
-                                void __pmem **kaddr, pfn_t *pfn, long size)
+                                void **kaddr, pfn_t *pfn, long size)
 {
        return -EIO;
 }
index ceb69fc0b10b32773bd41d3c0b8beadf442571f7..25d1d97154a8b68c0f847acdfdc74cca4aa711f1 100644 (file)
@@ -906,7 +906,7 @@ int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
 EXPORT_SYMBOL_GPL(dm_set_target_max_io_len);
 
 static long dm_blk_direct_access(struct block_device *bdev, sector_t sector,
-                                void __pmem **kaddr, pfn_t *pfn, long size)
+                                void **kaddr, pfn_t *pfn, long size)
 {
        struct mapped_device *md = bdev->bd_disk->private_data;
        struct dm_table *map;
index 1f123f5a29da2cb4859060fab44d69e32c388606..2c3ab6f5e6bef01f0b358b65daf78a51442cc07a 100644 (file)
@@ -2482,8 +2482,7 @@ static int add_bound_rdev(struct md_rdev *rdev)
                if (add_journal)
                        mddev_resume(mddev);
                if (err) {
-                       unbind_rdev_from_array(rdev);
-                       export_rdev(rdev);
+                       md_kick_rdev_from_array(rdev);
                        return err;
                }
        }
@@ -2600,6 +2599,10 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
                else
                        err = -EBUSY;
        } else if (cmd_match(buf, "remove")) {
+               if (rdev->mddev->pers) {
+                       clear_bit(Blocked, &rdev->flags);
+                       remove_and_add_spares(rdev->mddev, rdev);
+               }
                if (rdev->raid_disk >= 0)
                        err = -EBUSY;
                else {
@@ -3176,8 +3179,7 @@ int md_rdev_init(struct md_rdev *rdev)
        rdev->data_offset = 0;
        rdev->new_data_offset = 0;
        rdev->sb_events = 0;
-       rdev->last_read_error.tv_sec  = 0;
-       rdev->last_read_error.tv_nsec = 0;
+       rdev->last_read_error = 0;
        rdev->sb_loaded = 0;
        rdev->bb_page = NULL;
        atomic_set(&rdev->nr_pending, 0);
@@ -3583,6 +3585,8 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
                        mddev->to_remove = &md_redundancy_group;
        }
 
+       module_put(oldpers->owner);
+
        rdev_for_each(rdev, mddev) {
                if (rdev->raid_disk < 0)
                        continue;
@@ -3940,6 +3944,8 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
                        } else
                                err = -EBUSY;
                }
+               if (!err)
+                       sysfs_notify_dirent_safe(mddev->sysfs_state);
                spin_unlock(&mddev->lock);
                return err ?: len;
        }
@@ -4191,7 +4197,8 @@ size_store(struct mddev *mddev, const char *buf, size_t len)
                return err;
        if (mddev->pers) {
                err = update_size(mddev, sectors);
-               md_update_sb(mddev, 1);
+               if (err == 0)
+                       md_update_sb(mddev, 1);
        } else {
                if (mddev->dev_sectors == 0 ||
                    mddev->dev_sectors > sectors)
@@ -7813,6 +7820,7 @@ void md_do_sync(struct md_thread *thread)
                if (ret)
                        goto skip;
 
+               set_bit(MD_CLUSTER_RESYNC_LOCKED, &mddev->flags);
                if (!(test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
                        test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) ||
                        test_bit(MD_RECOVERY_RECOVER, &mddev->recovery))
@@ -8151,18 +8159,11 @@ void md_do_sync(struct md_thread *thread)
                }
        }
  skip:
-       if (mddev_is_clustered(mddev) &&
-           ret == 0) {
-               /* set CHANGE_PENDING here since maybe another
-                * update is needed, so other nodes are informed */
-               set_mask_bits(&mddev->flags, 0,
-                             BIT(MD_CHANGE_PENDING) | BIT(MD_CHANGE_DEVS));
-               md_wakeup_thread(mddev->thread);
-               wait_event(mddev->sb_wait,
-                          !test_bit(MD_CHANGE_PENDING, &mddev->flags));
-               md_cluster_ops->resync_finish(mddev);
-       } else
-               set_bit(MD_CHANGE_DEVS, &mddev->flags);
+       /* set CHANGE_PENDING here since maybe another update is needed,
+        * so other nodes are informed. It should be harmless for normal
+        * raid */
+       set_mask_bits(&mddev->flags, 0,
+                     BIT(MD_CHANGE_PENDING) | BIT(MD_CHANGE_DEVS));
 
        spin_lock(&mddev->lock);
        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
@@ -8188,15 +8189,34 @@ static int remove_and_add_spares(struct mddev *mddev,
        struct md_rdev *rdev;
        int spares = 0;
        int removed = 0;
+       bool remove_some = false;
 
-       rdev_for_each(rdev, mddev)
+       rdev_for_each(rdev, mddev) {
+               if ((this == NULL || rdev == this) &&
+                   rdev->raid_disk >= 0 &&
+                   !test_bit(Blocked, &rdev->flags) &&
+                   test_bit(Faulty, &rdev->flags) &&
+                   atomic_read(&rdev->nr_pending)==0) {
+                       /* Faulty non-Blocked devices with nr_pending == 0
+                        * never get nr_pending incremented,
+                        * never get Faulty cleared, and never get Blocked set.
+                        * So we can synchronize_rcu now rather than once per device
+                        */
+                       remove_some = true;
+                       set_bit(RemoveSynchronized, &rdev->flags);
+               }
+       }
+
+       if (remove_some)
+               synchronize_rcu();
+       rdev_for_each(rdev, mddev) {
                if ((this == NULL || rdev == this) &&
                    rdev->raid_disk >= 0 &&
                    !test_bit(Blocked, &rdev->flags) &&
-                   (test_bit(Faulty, &rdev->flags) ||
+                   ((test_bit(RemoveSynchronized, &rdev->flags) ||
                     (!test_bit(In_sync, &rdev->flags) &&
                      !test_bit(Journal, &rdev->flags))) &&
-                   atomic_read(&rdev->nr_pending)==0) {
+                   atomic_read(&rdev->nr_pending)==0)) {
                        if (mddev->pers->hot_remove_disk(
                                    mddev, rdev) == 0) {
                                sysfs_unlink_rdev(mddev, rdev);
@@ -8204,6 +8224,10 @@ static int remove_and_add_spares(struct mddev *mddev,
                                removed++;
                        }
                }
+               if (remove_some && test_bit(RemoveSynchronized, &rdev->flags))
+                       clear_bit(RemoveSynchronized, &rdev->flags);
+       }
+
        if (removed && mddev->kobj.sd)
                sysfs_notify(&mddev->kobj, NULL, "degraded");
 
@@ -8506,6 +8530,11 @@ void md_reap_sync_thread(struct mddev *mddev)
                        rdev->saved_raid_disk = -1;
 
        md_update_sb(mddev, 1);
+       /* MD_CHANGE_PENDING should be cleared by md_update_sb, so we can
+        * call resync_finish here if MD_CLUSTER_RESYNC_LOCKED is set by
+        * clustered raid */
+       if (test_and_clear_bit(MD_CLUSTER_RESYNC_LOCKED, &mddev->flags))
+               md_cluster_ops->resync_finish(mddev);
        clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
        clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
        clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
@@ -8803,6 +8832,7 @@ EXPORT_SYMBOL(md_reload_sb);
  * at boot time.
  */
 
+static DEFINE_MUTEX(detected_devices_mutex);
 static LIST_HEAD(all_detected_devices);
 struct detected_devices_node {
        struct list_head list;
@@ -8816,7 +8846,9 @@ void md_autodetect_dev(dev_t dev)
        node_detected_dev = kzalloc(sizeof(*node_detected_dev), GFP_KERNEL);
        if (node_detected_dev) {
                node_detected_dev->dev = dev;
+               mutex_lock(&detected_devices_mutex);
                list_add_tail(&node_detected_dev->list, &all_detected_devices);
+               mutex_unlock(&detected_devices_mutex);
        } else {
                printk(KERN_CRIT "md: md_autodetect_dev: kzalloc failed"
                        ", skipping dev(%d,%d)\n", MAJOR(dev), MINOR(dev));
@@ -8835,6 +8867,7 @@ static void autostart_arrays(int part)
 
        printk(KERN_INFO "md: Autodetecting RAID arrays.\n");
 
+       mutex_lock(&detected_devices_mutex);
        while (!list_empty(&all_detected_devices) && i_scanned < INT_MAX) {
                i_scanned++;
                node_detected_dev = list_entry(all_detected_devices.next,
@@ -8853,6 +8886,7 @@ static void autostart_arrays(int part)
                list_add(&rdev->same_set, &pending_raid_disks);
                i_passed++;
        }
+       mutex_unlock(&detected_devices_mutex);
 
        printk(KERN_INFO "md: Scanned %d and added %d devices.\n",
                                                i_scanned, i_passed);
index b4f335245bd60f851fac610592bd447dcfe434b4..20c667579ede413ae20438dc50aed4c095246494 100644 (file)
@@ -99,7 +99,7 @@ struct md_rdev {
        atomic_t        read_errors;    /* number of consecutive read errors that
                                         * we have tried to ignore.
                                         */
-       struct timespec last_read_error;        /* monotonic time since our
+       time64_t        last_read_error;        /* monotonic time since our
                                                 * last read error
                                                 */
        atomic_t        corrected_errors; /* number of corrected read errors,
@@ -163,6 +163,11 @@ enum flag_bits {
                                 * than other devices in the array
                                 */
        ClusterRemove,
+       RemoveSynchronized,     /* synchronize_rcu() was called after
+                                * this device was known to be faulty,
+                                * so it is safe to remove without
+                                * another synchronize_rcu() call.
+                                */
 };
 
 static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
@@ -204,6 +209,9 @@ struct mddev {
 #define MD_RELOAD_SB   7       /* Reload the superblock because another node
                                 * updated it.
                                 */
+#define MD_CLUSTER_RESYNC_LOCKED 8 /* cluster raid only, which means node
+                                   * already took resync lock, need to
+                                   * release the lock */
 
        int                             suspended;
        atomic_t                        active_io;
index 72ea98e89e5787fd96b7ebfef2cc68cbf1a02107..4974682842aece2aae18ae3257a2955183854dfd 100644 (file)
@@ -43,7 +43,8 @@ static int multipath_map (struct mpconf *conf)
        rcu_read_lock();
        for (i = 0; i < disks; i++) {
                struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev);
-               if (rdev && test_bit(In_sync, &rdev->flags)) {
+               if (rdev && test_bit(In_sync, &rdev->flags) &&
+                   !test_bit(Faulty, &rdev->flags)) {
                        atomic_inc(&rdev->nr_pending);
                        rcu_read_unlock();
                        return i;
@@ -141,17 +142,19 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
        return;
 }
 
-static void multipath_status (struct seq_file *seq, struct mddev *mddev)
+static void multipath_status(struct seq_file *seq, struct mddev *mddev)
 {
        struct mpconf *conf = mddev->private;
        int i;
 
        seq_printf (seq, " [%d/%d] [", conf->raid_disks,
                    conf->raid_disks - mddev->degraded);
-       for (i = 0; i < conf->raid_disks; i++)
-               seq_printf (seq, "%s",
-                              conf->multipaths[i].rdev &&
-                              test_bit(In_sync, &conf->multipaths[i].rdev->flags) ? "U" : "_");
+       rcu_read_lock();
+       for (i = 0; i < conf->raid_disks; i++) {
+               struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev);
+               seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_");
+       }
+       rcu_read_unlock();
        seq_printf (seq, "]");
 }
 
@@ -295,12 +298,14 @@ static int multipath_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
                        goto abort;
                }
                p->rdev = NULL;
-               synchronize_rcu();
-               if (atomic_read(&rdev->nr_pending)) {
-                       /* lost the race, try later */
-                       err = -EBUSY;
-                       p->rdev = rdev;
-                       goto abort;
+               if (!test_bit(RemoveSynchronized, &rdev->flags)) {
+                       synchronize_rcu();
+                       if (atomic_read(&rdev->nr_pending)) {
+                               /* lost the race, try later */
+                               err = -EBUSY;
+                               p->rdev = rdev;
+                               goto abort;
+                       }
                }
                err = md_integrity_register(mddev);
        }
index 4e6da4497553cde35149daa63caf74e4ecbe843b..46168ef2e279e353215f520a8527b4ed3b157801 100644 (file)
@@ -319,14 +319,13 @@ static void raid1_end_read_request(struct bio *bio)
 {
        int uptodate = !bio->bi_error;
        struct r1bio *r1_bio = bio->bi_private;
-       int mirror;
        struct r1conf *conf = r1_bio->mddev->private;
+       struct md_rdev *rdev = conf->mirrors[r1_bio->read_disk].rdev;
 
-       mirror = r1_bio->read_disk;
        /*
         * this branch is our 'one mirror IO has finished' event handler:
         */
-       update_head_pos(mirror, r1_bio);
+       update_head_pos(r1_bio->read_disk, r1_bio);
 
        if (uptodate)
                set_bit(R1BIO_Uptodate, &r1_bio->state);
@@ -339,14 +338,14 @@ static void raid1_end_read_request(struct bio *bio)
                spin_lock_irqsave(&conf->device_lock, flags);
                if (r1_bio->mddev->degraded == conf->raid_disks ||
                    (r1_bio->mddev->degraded == conf->raid_disks-1 &&
-                    test_bit(In_sync, &conf->mirrors[mirror].rdev->flags)))
+                    test_bit(In_sync, &rdev->flags)))
                        uptodate = 1;
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
 
        if (uptodate) {
                raid_end_bio_io(r1_bio);
-               rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
+               rdev_dec_pending(rdev, conf->mddev);
        } else {
                /*
                 * oops, read error:
@@ -356,7 +355,7 @@ static void raid1_end_read_request(struct bio *bio)
                        KERN_ERR "md/raid1:%s: %s: "
                        "rescheduling sector %llu\n",
                        mdname(conf->mddev),
-                       bdevname(conf->mirrors[mirror].rdev->bdev,
+                       bdevname(rdev->bdev,
                                 b),
                        (unsigned long long)r1_bio->sector);
                set_bit(R1BIO_ReadError, &r1_bio->state);
@@ -403,20 +402,18 @@ static void r1_bio_write_done(struct r1bio *r1_bio)
 static void raid1_end_write_request(struct bio *bio)
 {
        struct r1bio *r1_bio = bio->bi_private;
-       int mirror, behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
+       int behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
        struct r1conf *conf = r1_bio->mddev->private;
        struct bio *to_put = NULL;
-
-       mirror = find_bio_disk(r1_bio, bio);
+       int mirror = find_bio_disk(r1_bio, bio);
+       struct md_rdev *rdev = conf->mirrors[mirror].rdev;
 
        /*
         * 'one mirror IO has finished' event handler:
         */
        if (bio->bi_error) {
-               set_bit(WriteErrorSeen,
-                       &conf->mirrors[mirror].rdev->flags);
-               if (!test_and_set_bit(WantReplacement,
-                                     &conf->mirrors[mirror].rdev->flags))
+               set_bit(WriteErrorSeen, &rdev->flags);
+               if (!test_and_set_bit(WantReplacement, &rdev->flags))
                        set_bit(MD_RECOVERY_NEEDED, &
                                conf->mddev->recovery);
 
@@ -445,13 +442,12 @@ static void raid1_end_write_request(struct bio *bio)
                 * before rdev->recovery_offset, but for simplicity we don't
                 * check this here.
                 */
-               if (test_bit(In_sync, &conf->mirrors[mirror].rdev->flags) &&
-                   !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags))
+               if (test_bit(In_sync, &rdev->flags) &&
+                   !test_bit(Faulty, &rdev->flags))
                        set_bit(R1BIO_Uptodate, &r1_bio->state);
 
                /* Maybe we can clear some bad blocks. */
-               if (is_badblock(conf->mirrors[mirror].rdev,
-                               r1_bio->sector, r1_bio->sectors,
+               if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors,
                                &first_bad, &bad_sectors)) {
                        r1_bio->bios[mirror] = IO_MADE_GOOD;
                        set_bit(R1BIO_MadeGood, &r1_bio->state);
@@ -459,7 +455,7 @@ static void raid1_end_write_request(struct bio *bio)
        }
 
        if (behind) {
-               if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags))
+               if (test_bit(WriteMostly, &rdev->flags))
                        atomic_dec(&r1_bio->behind_remaining);
 
                /*
@@ -483,8 +479,7 @@ static void raid1_end_write_request(struct bio *bio)
                }
        }
        if (r1_bio->bios[mirror] == NULL)
-               rdev_dec_pending(conf->mirrors[mirror].rdev,
-                                conf->mddev);
+               rdev_dec_pending(rdev, conf->mddev);
 
        /*
         * Let's see if all mirrored write operations have finished
@@ -689,13 +684,6 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                if (!rdev)
                        goto retry;
                atomic_inc(&rdev->nr_pending);
-               if (test_bit(Faulty, &rdev->flags)) {
-                       /* cannot risk returning a device that failed
-                        * before we inc'ed nr_pending
-                        */
-                       rdev_dec_pending(rdev, conf->mddev);
-                       goto retry;
-               }
                sectors = best_good_sectors;
 
                if (conf->mirrors[best_disk].next_seq_sect != this_sector)
@@ -1666,13 +1654,16 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
                        goto abort;
                }
                p->rdev = NULL;
-               synchronize_rcu();
-               if (atomic_read(&rdev->nr_pending)) {
-                       /* lost the race, try later */
-                       err = -EBUSY;
-                       p->rdev = rdev;
-                       goto abort;
-               } else if (conf->mirrors[conf->raid_disks + number].rdev) {
+               if (!test_bit(RemoveSynchronized, &rdev->flags)) {
+                       synchronize_rcu();
+                       if (atomic_read(&rdev->nr_pending)) {
+                               /* lost the race, try later */
+                               err = -EBUSY;
+                               p->rdev = rdev;
+                               goto abort;
+                       }
+               }
+               if (conf->mirrors[conf->raid_disks + number].rdev) {
                        /* We just removed a device that is being replaced.
                         * Move down the replacement.  We drain all IO before
                         * doing this to avoid confusion.
@@ -1719,11 +1710,9 @@ static void end_sync_write(struct bio *bio)
        struct r1bio *r1_bio = bio->bi_private;
        struct mddev *mddev = r1_bio->mddev;
        struct r1conf *conf = mddev->private;
-       int mirror=0;
        sector_t first_bad;
        int bad_sectors;
-
-       mirror = find_bio_disk(r1_bio, bio);
+       struct md_rdev *rdev = conf->mirrors[find_bio_disk(r1_bio, bio)].rdev;
 
        if (!uptodate) {
                sector_t sync_blocks = 0;
@@ -1736,16 +1725,12 @@ static void end_sync_write(struct bio *bio)
                        s += sync_blocks;
                        sectors_to_go -= sync_blocks;
                } while (sectors_to_go > 0);
-               set_bit(WriteErrorSeen,
-                       &conf->mirrors[mirror].rdev->flags);
-               if (!test_and_set_bit(WantReplacement,
-                                     &conf->mirrors[mirror].rdev->flags))
+               set_bit(WriteErrorSeen, &rdev->flags);
+               if (!test_and_set_bit(WantReplacement, &rdev->flags))
                        set_bit(MD_RECOVERY_NEEDED, &
                                mddev->recovery);
                set_bit(R1BIO_WriteError, &r1_bio->state);
-       } else if (is_badblock(conf->mirrors[mirror].rdev,
-                              r1_bio->sector,
-                              r1_bio->sectors,
+       } else if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors,
                               &first_bad, &bad_sectors) &&
                   !is_badblock(conf->mirrors[r1_bio->read_disk].rdev,
                                r1_bio->sector,
@@ -2072,29 +2057,30 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
                        s = PAGE_SIZE >> 9;
 
                do {
-                       /* Note: no rcu protection needed here
-                        * as this is synchronous in the raid1d thread
-                        * which is the thread that might remove
-                        * a device.  If raid1d ever becomes multi-threaded....
-                        */
                        sector_t first_bad;
                        int bad_sectors;
 
-                       rdev = conf->mirrors[d].rdev;
+                       rcu_read_lock();
+                       rdev = rcu_dereference(conf->mirrors[d].rdev);
                        if (rdev &&
                            (test_bit(In_sync, &rdev->flags) ||
                             (!test_bit(Faulty, &rdev->flags) &&
                              rdev->recovery_offset >= sect + s)) &&
                            is_badblock(rdev, sect, s,
-                                       &first_bad, &bad_sectors) == 0 &&
-                           sync_page_io(rdev, sect, s<<9,
+                                       &first_bad, &bad_sectors) == 0) {
+                               atomic_inc(&rdev->nr_pending);
+                               rcu_read_unlock();
+                               if (sync_page_io(rdev, sect, s<<9,
                                         conf->tmppage, REQ_OP_READ, 0, false))
-                               success = 1;
-                       else {
-                               d++;
-                               if (d == conf->raid_disks * 2)
-                                       d = 0;
-                       }
+                                       success = 1;
+                               rdev_dec_pending(rdev, mddev);
+                               if (success)
+                                       break;
+                       } else
+                               rcu_read_unlock();
+                       d++;
+                       if (d == conf->raid_disks * 2)
+                               d = 0;
                } while (!success && d != read_disk);
 
                if (!success) {
@@ -2110,11 +2096,17 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
                        if (d==0)
                                d = conf->raid_disks * 2;
                        d--;
-                       rdev = conf->mirrors[d].rdev;
+                       rcu_read_lock();
+                       rdev = rcu_dereference(conf->mirrors[d].rdev);
                        if (rdev &&
-                           !test_bit(Faulty, &rdev->flags))
+                           !test_bit(Faulty, &rdev->flags)) {
+                               atomic_inc(&rdev->nr_pending);
+                               rcu_read_unlock();
                                r1_sync_page_io(rdev, sect, s,
                                                conf->tmppage, WRITE);
+                               rdev_dec_pending(rdev, mddev);
+                       } else
+                               rcu_read_unlock();
                }
                d = start;
                while (d != read_disk) {
@@ -2122,9 +2114,12 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
                        if (d==0)
                                d = conf->raid_disks * 2;
                        d--;
-                       rdev = conf->mirrors[d].rdev;
+                       rcu_read_lock();
+                       rdev = rcu_dereference(conf->mirrors[d].rdev);
                        if (rdev &&
                            !test_bit(Faulty, &rdev->flags)) {
+                               atomic_inc(&rdev->nr_pending);
+                               rcu_read_unlock();
                                if (r1_sync_page_io(rdev, sect, s,
                                                    conf->tmppage, READ)) {
                                        atomic_add(s, &rdev->corrected_errors);
@@ -2133,10 +2128,12 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
                                               "(%d sectors at %llu on %s)\n",
                                               mdname(mddev), s,
                                               (unsigned long long)(sect +
-                                                  rdev->data_offset),
+                                                                   rdev->data_offset),
                                               bdevname(rdev->bdev, b));
                                }
-                       }
+                               rdev_dec_pending(rdev, mddev);
+                       } else
+                               rcu_read_unlock();
                }
                sectors -= s;
                sect += s;
@@ -2534,6 +2531,13 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
                return sync_blocks;
        }
 
+       /*
+        * If there is non-resync activity waiting for a turn, then let it
+        * though before starting on this new sync request.
+        */
+       if (conf->nr_waiting)
+               schedule_timeout_uninterruptible(1);
+
        /* we are incrementing sector_nr below. To be safe, we check against
         * sector_nr + two times RESYNC_SECTORS
         */
index 26ae74fd0d01319aca8c8fbea08dc7c7d3d48ebf..ed29fc899f068943203480d01e1401b6adabe167 100644 (file)
@@ -707,7 +707,6 @@ static struct md_rdev *read_balance(struct r10conf *conf,
 
        raid10_find_phys(conf, r10_bio);
        rcu_read_lock();
-retry:
        sectors = r10_bio->sectors;
        best_slot = -1;
        best_rdev = NULL;
@@ -804,13 +803,6 @@ retry:
 
        if (slot >= 0) {
                atomic_inc(&rdev->nr_pending);
-               if (test_bit(Faulty, &rdev->flags)) {
-                       /* Cannot risk returning a device that failed
-                        * before we inc'ed nr_pending
-                        */
-                       rdev_dec_pending(rdev, conf->mddev);
-                       goto retry;
-               }
                r10_bio->read_slot = slot;
        } else
                rdev = NULL;
@@ -913,7 +905,7 @@ static void raise_barrier(struct r10conf *conf, int force)
 
        /* Now wait for all pending IO to complete */
        wait_event_lock_irq(conf->wait_barrier,
-                           !conf->nr_pending && conf->barrier < RESYNC_DEPTH,
+                           !atomic_read(&conf->nr_pending) && conf->barrier < RESYNC_DEPTH,
                            conf->resync_lock);
 
        spin_unlock_irq(&conf->resync_lock);
@@ -944,23 +936,23 @@ static void wait_barrier(struct r10conf *conf)
                 */
                wait_event_lock_irq(conf->wait_barrier,
                                    !conf->barrier ||
-                                   (conf->nr_pending &&
+                                   (atomic_read(&conf->nr_pending) &&
                                     current->bio_list &&
                                     !bio_list_empty(current->bio_list)),
                                    conf->resync_lock);
                conf->nr_waiting--;
+               if (!conf->nr_waiting)
+                       wake_up(&conf->wait_barrier);
        }
-       conf->nr_pending++;
+       atomic_inc(&conf->nr_pending);
        spin_unlock_irq(&conf->resync_lock);
 }
 
 static void allow_barrier(struct r10conf *conf)
 {
-       unsigned long flags;
-       spin_lock_irqsave(&conf->resync_lock, flags);
-       conf->nr_pending--;
-       spin_unlock_irqrestore(&conf->resync_lock, flags);
-       wake_up(&conf->wait_barrier);
+       if ((atomic_dec_and_test(&conf->nr_pending)) ||
+                       (conf->array_freeze_pending))
+               wake_up(&conf->wait_barrier);
 }
 
 static void freeze_array(struct r10conf *conf, int extra)
@@ -978,13 +970,15 @@ static void freeze_array(struct r10conf *conf, int extra)
         * we continue.
         */
        spin_lock_irq(&conf->resync_lock);
+       conf->array_freeze_pending++;
        conf->barrier++;
        conf->nr_waiting++;
        wait_event_lock_irq_cmd(conf->wait_barrier,
-                               conf->nr_pending == conf->nr_queued+extra,
+                               atomic_read(&conf->nr_pending) == conf->nr_queued+extra,
                                conf->resync_lock,
                                flush_pending_writes(conf));
 
+       conf->array_freeze_pending--;
        spin_unlock_irq(&conf->resync_lock);
 }
 
@@ -1499,10 +1493,12 @@ static void raid10_status(struct seq_file *seq, struct mddev *mddev)
        }
        seq_printf(seq, " [%d/%d] [", conf->geo.raid_disks,
                                        conf->geo.raid_disks - mddev->degraded);
-       for (i = 0; i < conf->geo.raid_disks; i++)
-               seq_printf(seq, "%s",
-                             conf->mirrors[i].rdev &&
-                             test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
+       rcu_read_lock();
+       for (i = 0; i < conf->geo.raid_disks; i++) {
+               struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
+               seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_");
+       }
+       rcu_read_unlock();
        seq_printf(seq, "]");
 }
 
@@ -1600,7 +1596,7 @@ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev)
 static void print_conf(struct r10conf *conf)
 {
        int i;
-       struct raid10_info *tmp;
+       struct md_rdev *rdev;
 
        printk(KERN_DEBUG "RAID10 conf printout:\n");
        if (!conf) {
@@ -1610,14 +1606,16 @@ static void print_conf(struct r10conf *conf)
        printk(KERN_DEBUG " --- wd:%d rd:%d\n", conf->geo.raid_disks - conf->mddev->degraded,
                conf->geo.raid_disks);
 
+       /* This is only called with ->reconfix_mutex held, so
+        * rcu protection of rdev is not needed */
        for (i = 0; i < conf->geo.raid_disks; i++) {
                char b[BDEVNAME_SIZE];
-               tmp = conf->mirrors + i;
-               if (tmp->rdev)
+               rdev = conf->mirrors[i].rdev;
+               if (rdev)
                        printk(KERN_DEBUG " disk %d, wo:%d, o:%d, dev:%s\n",
-                               i, !test_bit(In_sync, &tmp->rdev->flags),
-                               !test_bit(Faulty, &tmp->rdev->flags),
-                               bdevname(tmp->rdev->bdev,b));
+                               i, !test_bit(In_sync, &rdev->flags),
+                               !test_bit(Faulty, &rdev->flags),
+                               bdevname(rdev->bdev,b));
        }
 }
 
@@ -1766,7 +1764,7 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
                err = -EBUSY;
                goto abort;
        }
-       /* Only remove faulty devices if recovery
+       /* Only remove non-faulty devices if recovery
         * is not possible.
         */
        if (!test_bit(Faulty, &rdev->flags) &&
@@ -1778,13 +1776,16 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
                goto abort;
        }
        *rdevp = NULL;
-       synchronize_rcu();
-       if (atomic_read(&rdev->nr_pending)) {
-               /* lost the race, try later */
-               err = -EBUSY;
-               *rdevp = rdev;
-               goto abort;
-       } else if (p->replacement) {
+       if (!test_bit(RemoveSynchronized, &rdev->flags)) {
+               synchronize_rcu();
+               if (atomic_read(&rdev->nr_pending)) {
+                       /* lost the race, try later */
+                       err = -EBUSY;
+                       *rdevp = rdev;
+                       goto abort;
+               }
+       }
+       if (p->replacement) {
                /* We must have just cleared 'rdev' */
                p->rdev = p->replacement;
                clear_bit(Replacement, &p->replacement->flags);
@@ -2171,21 +2172,20 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio)
  */
 static void check_decay_read_errors(struct mddev *mddev, struct md_rdev *rdev)
 {
-       struct timespec cur_time_mon;
+       long cur_time_mon;
        unsigned long hours_since_last;
        unsigned int read_errors = atomic_read(&rdev->read_errors);
 
-       ktime_get_ts(&cur_time_mon);
+       cur_time_mon = ktime_get_seconds();
 
-       if (rdev->last_read_error.tv_sec == 0 &&
-           rdev->last_read_error.tv_nsec == 0) {
+       if (rdev->last_read_error == 0) {
                /* first time we've seen a read error */
                rdev->last_read_error = cur_time_mon;
                return;
        }
 
-       hours_since_last = (cur_time_mon.tv_sec -
-                           rdev->last_read_error.tv_sec) / 3600;
+       hours_since_last = (long)(cur_time_mon -
+                           rdev->last_read_error) / 3600;
 
        rdev->last_read_error = cur_time_mon;
 
@@ -2264,7 +2264,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                printk(KERN_NOTICE
                       "md/raid10:%s: %s: Failing raid device\n",
                       mdname(mddev), b);
-               md_error(mddev, conf->mirrors[d].rdev);
+               md_error(mddev, rdev);
                r10_bio->devs[r10_bio->read_slot].bio = IO_BLOCKED;
                return;
        }
@@ -2287,6 +2287,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                        rdev = rcu_dereference(conf->mirrors[d].rdev);
                        if (rdev &&
                            test_bit(In_sync, &rdev->flags) &&
+                           !test_bit(Faulty, &rdev->flags) &&
                            is_badblock(rdev, r10_bio->devs[sl].addr + sect, s,
                                        &first_bad, &bad_sectors) == 0) {
                                atomic_inc(&rdev->nr_pending);
@@ -2340,6 +2341,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                        d = r10_bio->devs[sl].devnum;
                        rdev = rcu_dereference(conf->mirrors[d].rdev);
                        if (!rdev ||
+                           test_bit(Faulty, &rdev->flags) ||
                            !test_bit(In_sync, &rdev->flags))
                                continue;
 
@@ -2379,6 +2381,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                        d = r10_bio->devs[sl].devnum;
                        rdev = rcu_dereference(conf->mirrors[d].rdev);
                        if (!rdev ||
+                           test_bit(Faulty, &rdev->flags) ||
                            !test_bit(In_sync, &rdev->flags))
                                continue;
 
@@ -2876,11 +2879,14 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                /* Completed a full sync so the replacements
                                 * are now fully recovered.
                                 */
-                               for (i = 0; i < conf->geo.raid_disks; i++)
-                                       if (conf->mirrors[i].replacement)
-                                               conf->mirrors[i].replacement
-                                                       ->recovery_offset
-                                                       = MaxSector;
+                               rcu_read_lock();
+                               for (i = 0; i < conf->geo.raid_disks; i++) {
+                                       struct md_rdev *rdev =
+                                               rcu_dereference(conf->mirrors[i].replacement);
+                                       if (rdev)
+                                               rdev->recovery_offset = MaxSector;
+                               }
+                               rcu_read_unlock();
                        }
                        conf->fullsync = 0;
                }
@@ -2911,6 +2917,13 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
            max_sector > (sector_nr | chunk_mask))
                max_sector = (sector_nr | chunk_mask) + 1;
 
+       /*
+        * If there is non-resync activity waiting for a turn, then let it
+        * though before starting on this new sync request.
+        */
+       if (conf->nr_waiting)
+               schedule_timeout_uninterruptible(1);
+
        /* Again, very different code for resync and recovery.
         * Both must result in an r10bio with a list of bios that
         * have bi_end_io, bi_sector, bi_bdev set,
@@ -2939,14 +2952,20 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                        int must_sync;
                        int any_working;
                        struct raid10_info *mirror = &conf->mirrors[i];
+                       struct md_rdev *mrdev, *mreplace;
 
-                       if ((mirror->rdev == NULL ||
-                            test_bit(In_sync, &mirror->rdev->flags))
-                           &&
-                           (mirror->replacement == NULL ||
-                            test_bit(Faulty,
-                                     &mirror->replacement->flags)))
+                       rcu_read_lock();
+                       mrdev = rcu_dereference(mirror->rdev);
+                       mreplace = rcu_dereference(mirror->replacement);
+
+                       if ((mrdev == NULL ||
+                            test_bit(Faulty, &mrdev->flags) ||
+                            test_bit(In_sync, &mrdev->flags)) &&
+                           (mreplace == NULL ||
+                            test_bit(Faulty, &mreplace->flags))) {
+                               rcu_read_unlock();
                                continue;
+                       }
 
                        still_degraded = 0;
                        /* want to reconstruct this device */
@@ -2956,8 +2975,11 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                /* last stripe is not complete - don't
                                 * try to recover this sector.
                                 */
+                               rcu_read_unlock();
                                continue;
                        }
+                       if (mreplace && test_bit(Faulty, &mreplace->flags))
+                               mreplace = NULL;
                        /* Unless we are doing a full sync, or a replacement
                         * we only need to recover the block if it is set in
                         * the bitmap
@@ -2967,14 +2989,19 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                        if (sync_blocks < max_sync)
                                max_sync = sync_blocks;
                        if (!must_sync &&
-                           mirror->replacement == NULL &&
+                           mreplace == NULL &&
                            !conf->fullsync) {
                                /* yep, skip the sync_blocks here, but don't assume
                                 * that there will never be anything to do here
                                 */
                                chunks_skipped = -1;
+                               rcu_read_unlock();
                                continue;
                        }
+                       atomic_inc(&mrdev->nr_pending);
+                       if (mreplace)
+                               atomic_inc(&mreplace->nr_pending);
+                       rcu_read_unlock();
 
                        r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
                        r10_bio->state = 0;
@@ -2993,12 +3020,15 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                        /* Need to check if the array will still be
                         * degraded
                         */
-                       for (j = 0; j < conf->geo.raid_disks; j++)
-                               if (conf->mirrors[j].rdev == NULL ||
-                                   test_bit(Faulty, &conf->mirrors[j].rdev->flags)) {
+                       rcu_read_lock();
+                       for (j = 0; j < conf->geo.raid_disks; j++) {
+                               struct md_rdev *rdev = rcu_dereference(
+                                       conf->mirrors[j].rdev);
+                               if (rdev == NULL || test_bit(Faulty, &rdev->flags)) {
                                        still_degraded = 1;
                                        break;
                                }
+                       }
 
                        must_sync = bitmap_start_sync(mddev->bitmap, sect,
                                                      &sync_blocks, still_degraded);
@@ -3008,15 +3038,15 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                int k;
                                int d = r10_bio->devs[j].devnum;
                                sector_t from_addr, to_addr;
-                               struct md_rdev *rdev;
+                               struct md_rdev *rdev =
+                                       rcu_dereference(conf->mirrors[d].rdev);
                                sector_t sector, first_bad;
                                int bad_sectors;
-                               if (!conf->mirrors[d].rdev ||
-                                   !test_bit(In_sync, &conf->mirrors[d].rdev->flags))
+                               if (!rdev ||
+                                   !test_bit(In_sync, &rdev->flags))
                                        continue;
                                /* This is where we read from */
                                any_working = 1;
-                               rdev = conf->mirrors[d].rdev;
                                sector = r10_bio->devs[j].addr;
 
                                if (is_badblock(rdev, sector, max_sync,
@@ -3055,8 +3085,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                r10_bio->devs[1].devnum = i;
                                r10_bio->devs[1].addr = to_addr;
 
-                               rdev = mirror->rdev;
-                               if (!test_bit(In_sync, &rdev->flags)) {
+                               if (!test_bit(In_sync, &mrdev->flags)) {
                                        bio = r10_bio->devs[1].bio;
                                        bio_reset(bio);
                                        bio->bi_next = biolist;
@@ -3065,8 +3094,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                        bio->bi_end_io = end_sync_write;
                                        bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
                                        bio->bi_iter.bi_sector = to_addr
-                                               + rdev->data_offset;
-                                       bio->bi_bdev = rdev->bdev;
+                                               + mrdev->data_offset;
+                                       bio->bi_bdev = mrdev->bdev;
                                        atomic_inc(&r10_bio->remaining);
                                } else
                                        r10_bio->devs[1].bio->bi_end_io = NULL;
@@ -3075,8 +3104,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                bio = r10_bio->devs[1].repl_bio;
                                if (bio)
                                        bio->bi_end_io = NULL;
-                               rdev = mirror->replacement;
-                               /* Note: if rdev != NULL, then bio
+                               /* Note: if mreplace != NULL, then bio
                                 * cannot be NULL as r10buf_pool_alloc will
                                 * have allocated it.
                                 * So the second test here is pointless.
@@ -3084,8 +3112,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                 * this comment keeps human reviewers
                                 * happy.
                                 */
-                               if (rdev == NULL || bio == NULL ||
-                                   test_bit(Faulty, &rdev->flags))
+                               if (mreplace == NULL || bio == NULL ||
+                                   test_bit(Faulty, &mreplace->flags))
                                        break;
                                bio_reset(bio);
                                bio->bi_next = biolist;
@@ -3094,11 +3122,12 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                bio->bi_end_io = end_sync_write;
                                bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
                                bio->bi_iter.bi_sector = to_addr +
-                                       rdev->data_offset;
-                               bio->bi_bdev = rdev->bdev;
+                                       mreplace->data_offset;
+                               bio->bi_bdev = mreplace->bdev;
                                atomic_inc(&r10_bio->remaining);
                                break;
                        }
+                       rcu_read_unlock();
                        if (j == conf->copies) {
                                /* Cannot recover, so abort the recovery or
                                 * record a bad block */
@@ -3111,15 +3140,15 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                                if (r10_bio->devs[k].devnum == i)
                                                        break;
                                        if (!test_bit(In_sync,
-                                                     &mirror->rdev->flags)
+                                                     &mrdev->flags)
                                            && !rdev_set_badblocks(
-                                                   mirror->rdev,
+                                                   mrdev,
                                                    r10_bio->devs[k].addr,
                                                    max_sync, 0))
                                                any_working = 0;
-                                       if (mirror->replacement &&
+                                       if (mreplace &&
                                            !rdev_set_badblocks(
-                                                   mirror->replacement,
+                                                   mreplace,
                                                    r10_bio->devs[k].addr,
                                                    max_sync, 0))
                                                any_working = 0;
@@ -3137,8 +3166,14 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                if (rb2)
                                        atomic_dec(&rb2->remaining);
                                r10_bio = rb2;
+                               rdev_dec_pending(mrdev, mddev);
+                               if (mreplace)
+                                       rdev_dec_pending(mreplace, mddev);
                                break;
                        }
+                       rdev_dec_pending(mrdev, mddev);
+                       if (mreplace)
+                               rdev_dec_pending(mreplace, mddev);
                }
                if (biolist == NULL) {
                        while (r10_bio) {
@@ -3183,6 +3218,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                        int d = r10_bio->devs[i].devnum;
                        sector_t first_bad, sector;
                        int bad_sectors;
+                       struct md_rdev *rdev;
 
                        if (r10_bio->devs[i].repl_bio)
                                r10_bio->devs[i].repl_bio->bi_end_io = NULL;
@@ -3190,12 +3226,14 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                        bio = r10_bio->devs[i].bio;
                        bio_reset(bio);
                        bio->bi_error = -EIO;
-                       if (conf->mirrors[d].rdev == NULL ||
-                           test_bit(Faulty, &conf->mirrors[d].rdev->flags))
+                       rcu_read_lock();
+                       rdev = rcu_dereference(conf->mirrors[d].rdev);
+                       if (rdev == NULL || test_bit(Faulty, &rdev->flags)) {
+                               rcu_read_unlock();
                                continue;
+                       }
                        sector = r10_bio->devs[i].addr;
-                       if (is_badblock(conf->mirrors[d].rdev,
-                                       sector, max_sync,
+                       if (is_badblock(rdev, sector, max_sync,
                                        &first_bad, &bad_sectors)) {
                                if (first_bad > sector)
                                        max_sync = first_bad - sector;
@@ -3203,25 +3241,28 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                        bad_sectors -= (sector - first_bad);
                                        if (max_sync > bad_sectors)
                                                max_sync = bad_sectors;
+                                       rcu_read_unlock();
                                        continue;
                                }
                        }
-                       atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+                       atomic_inc(&rdev->nr_pending);
                        atomic_inc(&r10_bio->remaining);
                        bio->bi_next = biolist;
                        biolist = bio;
                        bio->bi_private = r10_bio;
                        bio->bi_end_io = end_sync_read;
                        bio_set_op_attrs(bio, REQ_OP_READ, 0);
-                       bio->bi_iter.bi_sector = sector +
-                               conf->mirrors[d].rdev->data_offset;
-                       bio->bi_bdev = conf->mirrors[d].rdev->bdev;
+                       bio->bi_iter.bi_sector = sector + rdev->data_offset;
+                       bio->bi_bdev = rdev->bdev;
                        count++;
 
-                       if (conf->mirrors[d].replacement == NULL ||
-                           test_bit(Faulty,
-                                    &conf->mirrors[d].replacement->flags))
+                       rdev = rcu_dereference(conf->mirrors[d].replacement);
+                       if (rdev == NULL || test_bit(Faulty, &rdev->flags)) {
+                               rcu_read_unlock();
                                continue;
+                       }
+                       atomic_inc(&rdev->nr_pending);
+                       rcu_read_unlock();
 
                        /* Need to set up for writing to the replacement */
                        bio = r10_bio->devs[i].repl_bio;
@@ -3229,15 +3270,13 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                        bio->bi_error = -EIO;
 
                        sector = r10_bio->devs[i].addr;
-                       atomic_inc(&conf->mirrors[d].rdev->nr_pending);
                        bio->bi_next = biolist;
                        biolist = bio;
                        bio->bi_private = r10_bio;
                        bio->bi_end_io = end_sync_write;
                        bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
-                       bio->bi_iter.bi_sector = sector +
-                               conf->mirrors[d].replacement->data_offset;
-                       bio->bi_bdev = conf->mirrors[d].replacement->bdev;
+                       bio->bi_iter.bi_sector = sector + rdev->data_offset;
+                       bio->bi_bdev = rdev->bdev;
                        count++;
                }
 
@@ -3504,6 +3543,7 @@ static struct r10conf *setup_conf(struct mddev *mddev)
 
        spin_lock_init(&conf->resync_lock);
        init_waitqueue_head(&conf->wait_barrier);
+       atomic_set(&conf->nr_pending, 0);
 
        conf->thread = md_register_thread(raid10d, mddev, "raid10");
        if (!conf->thread)
@@ -4333,15 +4373,16 @@ read_more:
        blist = read_bio;
        read_bio->bi_next = NULL;
 
+       rcu_read_lock();
        for (s = 0; s < conf->copies*2; s++) {
                struct bio *b;
                int d = r10_bio->devs[s/2].devnum;
                struct md_rdev *rdev2;
                if (s&1) {
-                       rdev2 = conf->mirrors[d].replacement;
+                       rdev2 = rcu_dereference(conf->mirrors[d].replacement);
                        b = r10_bio->devs[s/2].repl_bio;
                } else {
-                       rdev2 = conf->mirrors[d].rdev;
+                       rdev2 = rcu_dereference(conf->mirrors[d].rdev);
                        b = r10_bio->devs[s/2].bio;
                }
                if (!rdev2 || test_bit(Faulty, &rdev2->flags))
@@ -4386,6 +4427,7 @@ read_more:
                nr_sectors += len >> 9;
        }
 bio_full:
+       rcu_read_unlock();
        r10_bio->sectors = nr_sectors;
 
        /* Now submit the read */
@@ -4437,16 +4479,20 @@ static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio)
                struct bio *b;
                int d = r10_bio->devs[s/2].devnum;
                struct md_rdev *rdev;
+               rcu_read_lock();
                if (s&1) {
-                       rdev = conf->mirrors[d].replacement;
+                       rdev = rcu_dereference(conf->mirrors[d].replacement);
                        b = r10_bio->devs[s/2].repl_bio;
                } else {
-                       rdev = conf->mirrors[d].rdev;
+                       rdev = rcu_dereference(conf->mirrors[d].rdev);
                        b = r10_bio->devs[s/2].bio;
                }
-               if (!rdev || test_bit(Faulty, &rdev->flags))
+               if (!rdev || test_bit(Faulty, &rdev->flags)) {
+                       rcu_read_unlock();
                        continue;
+               }
                atomic_inc(&rdev->nr_pending);
+               rcu_read_unlock();
                md_sync_acct(b->bi_bdev, r10_bio->sectors);
                atomic_inc(&r10_bio->remaining);
                b->bi_next = NULL;
@@ -4507,9 +4553,10 @@ static int handle_reshape_read_error(struct mddev *mddev,
                if (s > (PAGE_SIZE >> 9))
                        s = PAGE_SIZE >> 9;
 
+               rcu_read_lock();
                while (!success) {
                        int d = r10b->devs[slot].devnum;
-                       struct md_rdev *rdev = conf->mirrors[d].rdev;
+                       struct md_rdev *rdev = rcu_dereference(conf->mirrors[d].rdev);
                        sector_t addr;
                        if (rdev == NULL ||
                            test_bit(Faulty, &rdev->flags) ||
@@ -4517,11 +4564,15 @@ static int handle_reshape_read_error(struct mddev *mddev,
                                goto failed;
 
                        addr = r10b->devs[slot].addr + idx * PAGE_SIZE;
+                       atomic_inc(&rdev->nr_pending);
+                       rcu_read_unlock();
                        success = sync_page_io(rdev,
                                               addr,
                                               s << 9,
                                               bvec[idx].bv_page,
                                               REQ_OP_READ, 0, false);
+                       rdev_dec_pending(rdev, mddev);
+                       rcu_read_lock();
                        if (success)
                                break;
                failed:
@@ -4531,6 +4582,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
                        if (slot == first_slot)
                                break;
                }
+               rcu_read_unlock();
                if (!success) {
                        /* couldn't read this block, must give up */
                        set_bit(MD_RECOVERY_INTR,
@@ -4600,16 +4652,18 @@ static void raid10_finish_reshape(struct mddev *mddev)
                }
        } else {
                int d;
+               rcu_read_lock();
                for (d = conf->geo.raid_disks ;
                     d < conf->geo.raid_disks - mddev->delta_disks;
                     d++) {
-                       struct md_rdev *rdev = conf->mirrors[d].rdev;
+                       struct md_rdev *rdev = rcu_dereference(conf->mirrors[d].rdev);
                        if (rdev)
                                clear_bit(In_sync, &rdev->flags);
-                       rdev = conf->mirrors[d].replacement;
+                       rdev = rcu_dereference(conf->mirrors[d].replacement);
                        if (rdev)
                                clear_bit(In_sync, &rdev->flags);
                }
+               rcu_read_unlock();
        }
        mddev->layout = mddev->new_layout;
        mddev->chunk_sectors = 1 << conf->geo.chunk_shift;
index 6fc2c75759bf28eacaa2d93bbbb4041fb10bbd6d..18ec1f7a98bf77c98da88eaaa7ff0a95da2ac30a 100644 (file)
@@ -64,10 +64,11 @@ struct r10conf {
        int                     pending_count;
 
        spinlock_t              resync_lock;
-       int                     nr_pending;
+       atomic_t                nr_pending;
        int                     nr_waiting;
        int                     nr_queued;
        int                     barrier;
+       int                     array_freeze_pending;
        sector_t                next_resync;
        int                     fullsync;  /* set to 1 if a full sync is needed,
                                            * (fresh device added).
index 6953d78297b0ccf633abeb7591ed23fdb469f639..d189e894b921700d74fab3fb836f770b23ff14bd 100644 (file)
@@ -3080,7 +3080,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
                        struct md_rdev *rdev;
                        rcu_read_lock();
                        rdev = rcu_dereference(conf->disks[i].rdev);
-                       if (rdev && test_bit(In_sync, &rdev->flags))
+                       if (rdev && test_bit(In_sync, &rdev->flags) &&
+                           !test_bit(Faulty, &rdev->flags))
                                atomic_inc(&rdev->nr_pending);
                        else
                                rdev = NULL;
@@ -3210,15 +3211,16 @@ handle_failed_sync(struct r5conf *conf, struct stripe_head *sh,
                /* During recovery devices cannot be removed, so
                 * locking and refcounting of rdevs is not needed
                 */
+               rcu_read_lock();
                for (i = 0; i < conf->raid_disks; i++) {
-                       struct md_rdev *rdev = conf->disks[i].rdev;
+                       struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev);
                        if (rdev
                            && !test_bit(Faulty, &rdev->flags)
                            && !test_bit(In_sync, &rdev->flags)
                            && !rdev_set_badblocks(rdev, sh->sector,
                                                   STRIPE_SECTORS, 0))
                                abort = 1;
-                       rdev = conf->disks[i].replacement;
+                       rdev = rcu_dereference(conf->disks[i].replacement);
                        if (rdev
                            && !test_bit(Faulty, &rdev->flags)
                            && !test_bit(In_sync, &rdev->flags)
@@ -3226,6 +3228,7 @@ handle_failed_sync(struct r5conf *conf, struct stripe_head *sh,
                                                   STRIPE_SECTORS, 0))
                                abort = 1;
                }
+               rcu_read_unlock();
                if (abort)
                        conf->recovery_disabled =
                                conf->mddev->recovery_disabled;
@@ -3237,15 +3240,16 @@ static int want_replace(struct stripe_head *sh, int disk_idx)
 {
        struct md_rdev *rdev;
        int rv = 0;
-       /* Doing recovery so rcu locking not required */
-       rdev = sh->raid_conf->disks[disk_idx].replacement;
+
+       rcu_read_lock();
+       rdev = rcu_dereference(sh->raid_conf->disks[disk_idx].replacement);
        if (rdev
            && !test_bit(Faulty, &rdev->flags)
            && !test_bit(In_sync, &rdev->flags)
            && (rdev->recovery_offset <= sh->sector
                || rdev->mddev->recovery_cp <= sh->sector))
                rv = 1;
-
+       rcu_read_unlock();
        return rv;
 }
 
@@ -3600,7 +3604,7 @@ static void handle_stripe_dirtying(struct r5conf *conf,
        pr_debug("for sector %llu, rmw=%d rcw=%d\n",
                (unsigned long long)sh->sector, rmw, rcw);
        set_bit(STRIPE_HANDLE, &sh->state);
-       if ((rmw < rcw || (rmw == rcw && conf->rmw_level == PARITY_ENABLE_RMW)) && rmw > 0) {
+       if ((rmw < rcw || (rmw == rcw && conf->rmw_level == PARITY_PREFER_RMW)) && rmw > 0) {
                /* prefer read-modify-write, but need to get some data */
                if (conf->mddev->queue)
                        blk_add_trace_msg(conf->mddev->queue,
@@ -3627,7 +3631,7 @@ static void handle_stripe_dirtying(struct r5conf *conf,
                        }
                }
        }
-       if ((rcw < rmw || (rcw == rmw && conf->rmw_level != PARITY_ENABLE_RMW)) && rcw > 0) {
+       if ((rcw < rmw || (rcw == rmw && conf->rmw_level != PARITY_PREFER_RMW)) && rcw > 0) {
                /* want reconstruct write, but need to get some data */
                int qread =0;
                rcw = 0;
@@ -7066,10 +7070,12 @@ static void raid5_status(struct seq_file *seq, struct mddev *mddev)
        seq_printf(seq, " level %d, %dk chunk, algorithm %d", mddev->level,
                conf->chunk_sectors / 2, mddev->layout);
        seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded);
-       for (i = 0; i < conf->raid_disks; i++)
-               seq_printf (seq, "%s",
-                              conf->disks[i].rdev &&
-                              test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
+       rcu_read_lock();
+       for (i = 0; i < conf->raid_disks; i++) {
+               struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev);
+               seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_");
+       }
+       rcu_read_unlock();
        seq_printf (seq, "]");
 }
 
@@ -7191,12 +7197,15 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
                goto abort;
        }
        *rdevp = NULL;
-       synchronize_rcu();
-       if (atomic_read(&rdev->nr_pending)) {
-               /* lost the race, try later */
-               err = -EBUSY;
-               *rdevp = rdev;
-       } else if (p->replacement) {
+       if (!test_bit(RemoveSynchronized, &rdev->flags)) {
+               synchronize_rcu();
+               if (atomic_read(&rdev->nr_pending)) {
+                       /* lost the race, try later */
+                       err = -EBUSY;
+                       *rdevp = rdev;
+               }
+       }
+       if (p->replacement) {
                /* We must have just cleared 'rdev' */
                p->rdev = p->replacement;
                clear_bit(Replacement, &p->replacement->flags);
index 7c8a3bf078846ac0bb1410f93e5a91ff3ca4c985..124c2432ac9cb3d6e0a696023507f5131774c282 100644 (file)
@@ -1,6 +1,7 @@
 menuconfig LIBNVDIMM
        tristate "NVDIMM (Non-Volatile Memory Device) Support"
        depends on PHYS_ADDR_T_64BIT
+       depends on HAS_IOMEM
        depends on BLK_DEV
        help
          Generic support for non-volatile memory devices including
@@ -19,7 +20,6 @@ if LIBNVDIMM
 config BLK_DEV_PMEM
        tristate "PMEM: Persistent memory block device support"
        default LIBNVDIMM
-       depends on HAS_IOMEM
        select ND_BTT if BTT
        select ND_PFN if NVDIMM_PFN
        help
index 7e262ef06ede793ebb378770977fd12fefaf79a6..9faaa9694d8741adb64b5aae8754f44d24a01e13 100644 (file)
@@ -267,10 +267,8 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        q = blk_alloc_queue(GFP_KERNEL);
        if (!q)
                return -ENOMEM;
-       if (devm_add_action(dev, nd_blk_release_queue, q)) {
-               blk_cleanup_queue(q);
+       if (devm_add_action_or_reset(dev, nd_blk_release_queue, q))
                return -ENOMEM;
-       }
 
        blk_queue_make_request(q, nd_blk_make_request);
        blk_queue_max_hw_sectors(q, UINT_MAX);
@@ -282,10 +280,6 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        disk = alloc_disk(0);
        if (!disk)
                return -ENOMEM;
-       if (devm_add_action(dev, nd_blk_release_disk, disk)) {
-               put_disk(disk);
-               return -ENOMEM;
-       }
 
        disk->first_minor       = 0;
        disk->fops              = &nd_blk_fops;
@@ -295,6 +289,9 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        set_capacity(disk, 0);
        device_add_disk(dev, disk);
 
+       if (devm_add_action_or_reset(dev, nd_blk_release_disk, disk))
+               return -ENOMEM;
+
        if (nsblk_meta_size(nsblk)) {
                int rc = nd_integrity_init(disk, nsblk_meta_size(nsblk));
 
index 816d0dae63983c8ccf2c4f288e2d841dc74d843d..3fa7919f94a8785860afd3487d803f5b3010acd9 100644 (file)
@@ -198,8 +198,7 @@ struct device *nd_btt_create(struct nd_region *nd_region)
 {
        struct device *dev = __nd_btt_create(nd_region, 0, NULL, NULL);
 
-       if (dev)
-               __nd_device_register(dev);
+       __nd_device_register(dev);
        return dev;
 }
 
index 5e4e5c772ea54ff9f5696a1f7d2816d0ebff4d5c..458daf9273362a19cc26d6a4f2c9113764f493b8 100644 (file)
@@ -31,6 +31,7 @@
 int nvdimm_major;
 static int nvdimm_bus_major;
 static struct class *nd_class;
+static DEFINE_IDA(nd_ida);
 
 static int to_nd_device_type(struct device *dev)
 {
@@ -60,20 +61,13 @@ static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
                        to_nd_device_type(dev));
 }
 
-static int nvdimm_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct nd_device_driver *nd_drv = to_nd_device_driver(drv);
-
-       return !!test_bit(to_nd_device_type(dev), &nd_drv->type);
-}
-
 static struct module *to_bus_provider(struct device *dev)
 {
        /* pin bus providers while regions are enabled */
        if (is_nd_pmem(dev) || is_nd_blk(dev)) {
                struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
 
-               return nvdimm_bus->module;
+               return nvdimm_bus->nd_desc->module;
        }
        return NULL;
 }
@@ -136,6 +130,21 @@ static int nvdimm_bus_remove(struct device *dev)
        return rc;
 }
 
+static void nvdimm_bus_shutdown(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+       struct nd_device_driver *nd_drv = NULL;
+
+       if (dev->driver)
+               nd_drv = to_nd_device_driver(dev->driver);
+
+       if (nd_drv && nd_drv->shutdown) {
+               nd_drv->shutdown(dev);
+               dev_dbg(&nvdimm_bus->dev, "%s.shutdown(%s)\n",
+                               dev->driver->name, dev_name(dev));
+       }
+}
+
 void nd_device_notify(struct device *dev, enum nvdimm_event event)
 {
        device_lock(dev);
@@ -208,14 +217,187 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
 }
 EXPORT_SYMBOL_GPL(nvdimm_clear_poison);
 
+static int nvdimm_bus_match(struct device *dev, struct device_driver *drv);
+
 static struct bus_type nvdimm_bus_type = {
        .name = "nd",
        .uevent = nvdimm_bus_uevent,
        .match = nvdimm_bus_match,
        .probe = nvdimm_bus_probe,
        .remove = nvdimm_bus_remove,
+       .shutdown = nvdimm_bus_shutdown,
+};
+
+static void nvdimm_bus_release(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus;
+
+       nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
+       ida_simple_remove(&nd_ida, nvdimm_bus->id);
+       kfree(nvdimm_bus);
+}
+
+static bool is_nvdimm_bus(struct device *dev)
+{
+       return dev->release == nvdimm_bus_release;
+}
+
+struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev)
+{
+       struct device *dev;
+
+       for (dev = nd_dev; dev; dev = dev->parent)
+               if (is_nvdimm_bus(dev))
+                       break;
+       dev_WARN_ONCE(nd_dev, !dev, "invalid dev, not on nd bus\n");
+       if (dev)
+               return to_nvdimm_bus(dev);
+       return NULL;
+}
+
+struct nvdimm_bus *to_nvdimm_bus(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus;
+
+       nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
+       WARN_ON(!is_nvdimm_bus(dev));
+       return nvdimm_bus;
+}
+EXPORT_SYMBOL_GPL(to_nvdimm_bus);
+
+struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
+               struct nvdimm_bus_descriptor *nd_desc)
+{
+       struct nvdimm_bus *nvdimm_bus;
+       int rc;
+
+       nvdimm_bus = kzalloc(sizeof(*nvdimm_bus), GFP_KERNEL);
+       if (!nvdimm_bus)
+               return NULL;
+       INIT_LIST_HEAD(&nvdimm_bus->list);
+       INIT_LIST_HEAD(&nvdimm_bus->mapping_list);
+       INIT_LIST_HEAD(&nvdimm_bus->poison_list);
+       init_waitqueue_head(&nvdimm_bus->probe_wait);
+       nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
+       mutex_init(&nvdimm_bus->reconfig_mutex);
+       if (nvdimm_bus->id < 0) {
+               kfree(nvdimm_bus);
+               return NULL;
+       }
+       nvdimm_bus->nd_desc = nd_desc;
+       nvdimm_bus->dev.parent = parent;
+       nvdimm_bus->dev.release = nvdimm_bus_release;
+       nvdimm_bus->dev.groups = nd_desc->attr_groups;
+       nvdimm_bus->dev.bus = &nvdimm_bus_type;
+       dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
+       rc = device_register(&nvdimm_bus->dev);
+       if (rc) {
+               dev_dbg(&nvdimm_bus->dev, "registration failed: %d\n", rc);
+               goto err;
+       }
+
+       return nvdimm_bus;
+ err:
+       put_device(&nvdimm_bus->dev);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(nvdimm_bus_register);
+
+void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
+{
+       if (!nvdimm_bus)
+               return;
+       device_unregister(&nvdimm_bus->dev);
+}
+EXPORT_SYMBOL_GPL(nvdimm_bus_unregister);
+
+static int child_unregister(struct device *dev, void *data)
+{
+       /*
+        * the singular ndctl class device per bus needs to be
+        * "device_destroy"ed, so skip it here
+        *
+        * i.e. remove classless children
+        */
+       if (dev->class)
+               /* pass */;
+       else
+               nd_device_unregister(dev, ND_SYNC);
+       return 0;
+}
+
+static void free_poison_list(struct list_head *poison_list)
+{
+       struct nd_poison *pl, *next;
+
+       list_for_each_entry_safe(pl, next, poison_list, list) {
+               list_del(&pl->list);
+               kfree(pl);
+       }
+       list_del_init(poison_list);
+}
+
+static int nd_bus_remove(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+
+       mutex_lock(&nvdimm_bus_list_mutex);
+       list_del_init(&nvdimm_bus->list);
+       mutex_unlock(&nvdimm_bus_list_mutex);
+
+       nd_synchronize();
+       device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
+
+       nvdimm_bus_lock(&nvdimm_bus->dev);
+       free_poison_list(&nvdimm_bus->poison_list);
+       nvdimm_bus_unlock(&nvdimm_bus->dev);
+
+       nvdimm_bus_destroy_ndctl(nvdimm_bus);
+
+       return 0;
+}
+
+static int nd_bus_probe(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+       int rc;
+
+       rc = nvdimm_bus_create_ndctl(nvdimm_bus);
+       if (rc)
+               return rc;
+
+       mutex_lock(&nvdimm_bus_list_mutex);
+       list_add_tail(&nvdimm_bus->list, &nvdimm_bus_list);
+       mutex_unlock(&nvdimm_bus_list_mutex);
+
+       /* enable bus provider attributes to look up their local context */
+       dev_set_drvdata(dev, nvdimm_bus->nd_desc);
+
+       return 0;
+}
+
+static struct nd_device_driver nd_bus_driver = {
+       .probe = nd_bus_probe,
+       .remove = nd_bus_remove,
+       .drv = {
+               .name = "nd_bus",
+               .suppress_bind_attrs = true,
+               .bus = &nvdimm_bus_type,
+               .owner = THIS_MODULE,
+               .mod_name = KBUILD_MODNAME,
+       },
 };
 
+static int nvdimm_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct nd_device_driver *nd_drv = to_nd_device_driver(drv);
+
+       if (is_nvdimm_bus(dev) && nd_drv == &nd_bus_driver)
+               return true;
+
+       return !!test_bit(to_nd_device_type(dev), &nd_drv->type);
+}
+
 static ASYNC_DOMAIN_EXCLUSIVE(nd_async_domain);
 
 void nd_synchronize(void)
@@ -395,12 +577,10 @@ int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus)
        dev = device_create(nd_class, &nvdimm_bus->dev, devt, nvdimm_bus,
                        "ndctl%d", nvdimm_bus->id);
 
-       if (IS_ERR(dev)) {
+       if (IS_ERR(dev))
                dev_dbg(&nvdimm_bus->dev, "failed to register ndctl%d: %ld\n",
                                nvdimm_bus->id, PTR_ERR(dev));
-               return PTR_ERR(dev);
-       }
-       return 0;
+       return PTR_ERR_OR_ZERO(dev);
 }
 
 void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus)
@@ -850,8 +1030,14 @@ int __init nvdimm_bus_init(void)
                goto err_class;
        }
 
+       rc = driver_register(&nd_bus_driver.drv);
+       if (rc)
+               goto err_nd_bus;
+
        return 0;
 
+ err_nd_bus:
+       class_destroy(nd_class);
  err_class:
        unregister_chrdev(nvdimm_major, "dimmctl");
  err_dimm_chrdev:
@@ -864,8 +1050,10 @@ int __init nvdimm_bus_init(void)
 
 void nvdimm_bus_exit(void)
 {
+       driver_unregister(&nd_bus_driver.drv);
        class_destroy(nd_class);
        unregister_chrdev(nvdimm_bus_major, "ndctl");
        unregister_chrdev(nvdimm_major, "dimmctl");
        bus_unregister(&nvdimm_bus_type);
+       ida_destroy(&nd_ida);
 }
index 8b2e3c4fb0add718d2dbf167b499516a94612c80..d5dc80c48b4cb36a55c54a2383ce9812ae068260 100644 (file)
@@ -240,7 +240,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
                return memcpy_from_pmem(buf, nsio->addr + offset, size);
        } else {
                memcpy_to_pmem(nsio->addr + offset, buf, size);
-               wmb_pmem();
+               nvdimm_flush(to_nd_region(ndns->dev.parent));
        }
 
        return 0;
@@ -266,9 +266,8 @@ int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
 
        nsio->addr = devm_memremap(dev, res->start, resource_size(res),
                        ARCH_MEMREMAP_PMEM);
-       if (IS_ERR(nsio->addr))
-               return PTR_ERR(nsio->addr);
-       return 0;
+
+       return PTR_ERR_OR_ZERO(nsio->addr);
 }
 EXPORT_SYMBOL_GPL(devm_nsio_enable);
 
index be89764315c2b54d9bbe9548fc3f6183d6032ea4..715583f69d28ae2f413768c81c141e1dd3019d75 100644 (file)
 #include <linux/ndctl.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include "nd-core.h"
 #include "nd.h"
 
 LIST_HEAD(nvdimm_bus_list);
 DEFINE_MUTEX(nvdimm_bus_list_mutex);
-static DEFINE_IDA(nd_ida);
 
 void nvdimm_bus_lock(struct device *dev)
 {
@@ -57,6 +57,127 @@ bool is_nvdimm_bus_locked(struct device *dev)
 }
 EXPORT_SYMBOL(is_nvdimm_bus_locked);
 
+struct nvdimm_map {
+       struct nvdimm_bus *nvdimm_bus;
+       struct list_head list;
+       resource_size_t offset;
+       unsigned long flags;
+       size_t size;
+       union {
+               void *mem;
+               void __iomem *iomem;
+       };
+       struct kref kref;
+};
+
+static struct nvdimm_map *find_nvdimm_map(struct device *dev,
+               resource_size_t offset)
+{
+       struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+       struct nvdimm_map *nvdimm_map;
+
+       list_for_each_entry(nvdimm_map, &nvdimm_bus->mapping_list, list)
+               if (nvdimm_map->offset == offset)
+                       return nvdimm_map;
+       return NULL;
+}
+
+static struct nvdimm_map *alloc_nvdimm_map(struct device *dev,
+               resource_size_t offset, size_t size, unsigned long flags)
+{
+       struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+       struct nvdimm_map *nvdimm_map;
+
+       nvdimm_map = kzalloc(sizeof(*nvdimm_map), GFP_KERNEL);
+       if (!nvdimm_map)
+               return NULL;
+
+       INIT_LIST_HEAD(&nvdimm_map->list);
+       nvdimm_map->nvdimm_bus = nvdimm_bus;
+       nvdimm_map->offset = offset;
+       nvdimm_map->flags = flags;
+       nvdimm_map->size = size;
+       kref_init(&nvdimm_map->kref);
+
+       if (!request_mem_region(offset, size, dev_name(&nvdimm_bus->dev)))
+               goto err_request_region;
+
+       if (flags)
+               nvdimm_map->mem = memremap(offset, size, flags);
+       else
+               nvdimm_map->iomem = ioremap(offset, size);
+
+       if (!nvdimm_map->mem)
+               goto err_map;
+
+       dev_WARN_ONCE(dev, !is_nvdimm_bus_locked(dev), "%s: bus unlocked!",
+                       __func__);
+       list_add(&nvdimm_map->list, &nvdimm_bus->mapping_list);
+
+       return nvdimm_map;
+
+ err_map:
+       release_mem_region(offset, size);
+ err_request_region:
+       kfree(nvdimm_map);
+       return NULL;
+}
+
+static void nvdimm_map_release(struct kref *kref)
+{
+       struct nvdimm_bus *nvdimm_bus;
+       struct nvdimm_map *nvdimm_map;
+
+       nvdimm_map = container_of(kref, struct nvdimm_map, kref);
+       nvdimm_bus = nvdimm_map->nvdimm_bus;
+
+       dev_dbg(&nvdimm_bus->dev, "%s: %pa\n", __func__, &nvdimm_map->offset);
+       list_del(&nvdimm_map->list);
+       if (nvdimm_map->flags)
+               memunmap(nvdimm_map->mem);
+       else
+               iounmap(nvdimm_map->iomem);
+       release_mem_region(nvdimm_map->offset, nvdimm_map->size);
+       kfree(nvdimm_map);
+}
+
+static void nvdimm_map_put(void *data)
+{
+       struct nvdimm_map *nvdimm_map = data;
+       struct nvdimm_bus *nvdimm_bus = nvdimm_map->nvdimm_bus;
+
+       nvdimm_bus_lock(&nvdimm_bus->dev);
+       kref_put(&nvdimm_map->kref, nvdimm_map_release);
+       nvdimm_bus_unlock(&nvdimm_bus->dev);
+}
+
+/**
+ * devm_nvdimm_memremap - map a resource that is shared across regions
+ * @dev: device that will own a reference to the shared mapping
+ * @offset: physical base address of the mapping
+ * @size: mapping size
+ * @flags: memremap flags, or, if zero, perform an ioremap instead
+ */
+void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset,
+               size_t size, unsigned long flags)
+{
+       struct nvdimm_map *nvdimm_map;
+
+       nvdimm_bus_lock(dev);
+       nvdimm_map = find_nvdimm_map(dev, offset);
+       if (!nvdimm_map)
+               nvdimm_map = alloc_nvdimm_map(dev, offset, size, flags);
+       else
+               kref_get(&nvdimm_map->kref);
+       nvdimm_bus_unlock(dev);
+
+       if (devm_add_action_or_reset(dev, nvdimm_map_put, nvdimm_map))
+               return NULL;
+
+       return nvdimm_map->mem;
+}
+EXPORT_SYMBOL_GPL(devm_nvdimm_memremap);
+
 u64 nd_fletcher64(void *addr, size_t len, bool le)
 {
        u32 *buf = addr;
@@ -73,25 +194,6 @@ u64 nd_fletcher64(void *addr, size_t len, bool le)
 }
 EXPORT_SYMBOL_GPL(nd_fletcher64);
 
-static void nvdimm_bus_release(struct device *dev)
-{
-       struct nvdimm_bus *nvdimm_bus;
-
-       nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
-       ida_simple_remove(&nd_ida, nvdimm_bus->id);
-       kfree(nvdimm_bus);
-}
-
-struct nvdimm_bus *to_nvdimm_bus(struct device *dev)
-{
-       struct nvdimm_bus *nvdimm_bus;
-
-       nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
-       WARN_ON(nvdimm_bus->dev.release != nvdimm_bus_release);
-       return nvdimm_bus;
-}
-EXPORT_SYMBOL_GPL(to_nvdimm_bus);
-
 struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus)
 {
        /* struct nvdimm_bus definition is private to libnvdimm */
@@ -99,18 +201,12 @@ struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus)
 }
 EXPORT_SYMBOL_GPL(to_nd_desc);
 
-struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev)
+struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus)
 {
-       struct device *dev;
-
-       for (dev = nd_dev; dev; dev = dev->parent)
-               if (dev->release == nvdimm_bus_release)
-                       break;
-       dev_WARN_ONCE(nd_dev, !dev, "invalid dev, not on nd bus\n");
-       if (dev)
-               return to_nvdimm_bus(dev);
-       return NULL;
+       /* struct nvdimm_bus definition is private to libnvdimm */
+       return &nvdimm_bus->dev;
 }
+EXPORT_SYMBOL_GPL(to_nvdimm_bus_dev);
 
 static bool is_uuid_sep(char sep)
 {
@@ -325,51 +421,6 @@ struct attribute_group nvdimm_bus_attribute_group = {
 };
 EXPORT_SYMBOL_GPL(nvdimm_bus_attribute_group);
 
-struct nvdimm_bus *__nvdimm_bus_register(struct device *parent,
-               struct nvdimm_bus_descriptor *nd_desc, struct module *module)
-{
-       struct nvdimm_bus *nvdimm_bus;
-       int rc;
-
-       nvdimm_bus = kzalloc(sizeof(*nvdimm_bus), GFP_KERNEL);
-       if (!nvdimm_bus)
-               return NULL;
-       INIT_LIST_HEAD(&nvdimm_bus->list);
-       INIT_LIST_HEAD(&nvdimm_bus->poison_list);
-       init_waitqueue_head(&nvdimm_bus->probe_wait);
-       nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
-       mutex_init(&nvdimm_bus->reconfig_mutex);
-       if (nvdimm_bus->id < 0) {
-               kfree(nvdimm_bus);
-               return NULL;
-       }
-       nvdimm_bus->nd_desc = nd_desc;
-       nvdimm_bus->module = module;
-       nvdimm_bus->dev.parent = parent;
-       nvdimm_bus->dev.release = nvdimm_bus_release;
-       nvdimm_bus->dev.groups = nd_desc->attr_groups;
-       dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
-       rc = device_register(&nvdimm_bus->dev);
-       if (rc) {
-               dev_dbg(&nvdimm_bus->dev, "registration failed: %d\n", rc);
-               goto err;
-       }
-
-       rc = nvdimm_bus_create_ndctl(nvdimm_bus);
-       if (rc)
-               goto err;
-
-       mutex_lock(&nvdimm_bus_list_mutex);
-       list_add_tail(&nvdimm_bus->list, &nvdimm_bus_list);
-       mutex_unlock(&nvdimm_bus_list_mutex);
-
-       return nvdimm_bus;
- err:
-       put_device(&nvdimm_bus->dev);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(__nvdimm_bus_register);
-
 static void set_badblock(struct badblocks *bb, sector_t s, int num)
 {
        dev_dbg(bb->dev, "Found a poison range (0x%llx, 0x%llx)\n",
@@ -545,54 +596,6 @@ int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
 }
 EXPORT_SYMBOL_GPL(nvdimm_bus_add_poison);
 
-static void free_poison_list(struct list_head *poison_list)
-{
-       struct nd_poison *pl, *next;
-
-       list_for_each_entry_safe(pl, next, poison_list, list) {
-               list_del(&pl->list);
-               kfree(pl);
-       }
-       list_del_init(poison_list);
-}
-
-static int child_unregister(struct device *dev, void *data)
-{
-       /*
-        * the singular ndctl class device per bus needs to be
-        * "device_destroy"ed, so skip it here
-        *
-        * i.e. remove classless children
-        */
-       if (dev->class)
-               /* pass */;
-       else
-               nd_device_unregister(dev, ND_SYNC);
-       return 0;
-}
-
-void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
-{
-       if (!nvdimm_bus)
-               return;
-
-       mutex_lock(&nvdimm_bus_list_mutex);
-       list_del_init(&nvdimm_bus->list);
-       mutex_unlock(&nvdimm_bus_list_mutex);
-
-       nd_synchronize();
-       device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
-
-       nvdimm_bus_lock(&nvdimm_bus->dev);
-       free_poison_list(&nvdimm_bus->poison_list);
-       nvdimm_bus_unlock(&nvdimm_bus->dev);
-
-       nvdimm_bus_destroy_ndctl(nvdimm_bus);
-
-       device_unregister(&nvdimm_bus->dev);
-}
-EXPORT_SYMBOL_GPL(nvdimm_bus_unregister);
-
 #ifdef CONFIG_BLK_DEV_INTEGRITY
 int nd_integrity_init(struct gendisk *disk, unsigned long meta_size)
 {
@@ -601,7 +604,8 @@ int nd_integrity_init(struct gendisk *disk, unsigned long meta_size)
        if (meta_size == 0)
                return 0;
 
-       bi.profile = NULL;
+       memset(&bi, 0, sizeof(bi));
+
        bi.tuple_size = meta_size;
        bi.tag_size = meta_size;
 
@@ -650,7 +654,6 @@ static __exit void libnvdimm_exit(void)
        nvdimm_bus_exit();
        nd_region_devs_exit();
        nvdimm_devs_exit();
-       ida_destroy(&nd_ida);
 }
 
 MODULE_LICENSE("GPL v2");
index bbde28d3dec5cd4bbbb283847d2f736bc81148c9..d9bba5edd8dcf0646cad13a0160534648c52ce8d 100644 (file)
@@ -346,7 +346,8 @@ EXPORT_SYMBOL_GPL(nvdimm_attribute_group);
 
 struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
                const struct attribute_group **groups, unsigned long flags,
-               unsigned long cmd_mask)
+               unsigned long cmd_mask, int num_flush,
+               struct resource *flush_wpq)
 {
        struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL);
        struct device *dev;
@@ -362,6 +363,8 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
        nvdimm->provider_data = provider_data;
        nvdimm->flags = flags;
        nvdimm->cmd_mask = cmd_mask;
+       nvdimm->num_flush = num_flush;
+       nvdimm->flush_wpq = flush_wpq;
        atomic_set(&nvdimm->busy, 0);
        dev = &nvdimm->dev;
        dev_set_name(dev, "nmem%d", nvdimm->id);
index 95825b38559addb8a0dc5cca22bc305e228e65f6..11ea90120542dcbec8410147efca7a502eea9a77 100644 (file)
@@ -47,6 +47,7 @@ static int e820_pmem_probe(struct platform_device *pdev)
 
        nd_desc.attr_groups = e820_pmem_attribute_groups;
        nd_desc.provider_name = "e820";
+       nd_desc.module = THIS_MODULE;
        nvdimm_bus = nvdimm_bus_register(dev, &nd_desc);
        if (!nvdimm_bus)
                goto err;
index 284cdaa268cfd8132bc7fcd7299d66eaa4256217..38ce6bbbc170bcdc40982d5f49473bab181e2071 100644 (file)
@@ -26,11 +26,11 @@ extern int nvdimm_major;
 struct nvdimm_bus {
        struct nvdimm_bus_descriptor *nd_desc;
        wait_queue_head_t probe_wait;
-       struct module *module;
        struct list_head list;
        struct device dev;
        int id, probe_active;
        struct list_head poison_list;
+       struct list_head mapping_list;
        struct mutex reconfig_mutex;
 };
 
@@ -40,7 +40,8 @@ struct nvdimm {
        unsigned long cmd_mask;
        struct device dev;
        atomic_t busy;
-       int id;
+       int id, num_flush;
+       struct resource *flush_wpq;
 };
 
 bool is_nvdimm(struct device *dev);
index d0ac93c31dda6adcd01a4be288b3963d5f09f084..40476399d22793aece0438da0f5a0976cef063ab 100644 (file)
@@ -49,9 +49,11 @@ struct nvdimm_drvdata {
        struct kref kref;
 };
 
-struct nd_region_namespaces {
-       int count;
-       int active;
+struct nd_region_data {
+       int ns_count;
+       int ns_active;
+       unsigned int flush_mask;
+       void __iomem *flush_wpq[0][0];
 };
 
 static inline struct nd_namespace_index *to_namespace_index(
@@ -119,7 +121,6 @@ struct nd_region {
 
 struct nd_blk_region {
        int (*enable)(struct nvdimm_bus *nvdimm_bus, struct device *dev);
-       void (*disable)(struct nvdimm_bus *nvdimm_bus, struct device *dev);
        int (*do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
                        void *iobuf, u64 len, int rw);
        void *blk_provider_data;
@@ -325,6 +326,7 @@ static inline void devm_nsio_disable(struct device *dev,
 }
 #endif
 int nd_blk_region_init(struct nd_region *nd_region);
+int nd_region_activate(struct nd_region *nd_region);
 void __nd_iostat_start(struct bio *bio, unsigned long *start);
 static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
 {
index 36cb39047d5b77b17eb3d04980b82b36980e7ce4..b511099457db5cbb155e5b6270bc9bb8a3677cc6 100644 (file)
 #include <linux/slab.h>
 #include <linux/pmem.h>
 #include <linux/nd.h>
+#include "pmem.h"
 #include "pfn.h"
 #include "nd.h"
 
-struct pmem_device {
-       /* One contiguous memory region per device */
-       phys_addr_t             phys_addr;
-       /* when non-zero this device is hosting a 'pfn' instance */
-       phys_addr_t             data_offset;
-       u64                     pfn_flags;
-       void __pmem             *virt_addr;
-       /* immutable base size of the namespace */
-       size_t                  size;
-       /* trim size when namespace capacity has been section aligned */
-       u32                     pfn_pad;
-       struct badblocks        bb;
-};
+static struct device *to_dev(struct pmem_device *pmem)
+{
+       /*
+        * nvdimm bus services need a 'dev' parameter, and we record the device
+        * at init in bb.dev.
+        */
+       return pmem->bb.dev;
+}
+
+static struct nd_region *to_region(struct pmem_device *pmem)
+{
+       return to_nd_region(to_dev(pmem)->parent);
+}
 
 static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
                unsigned int len)
 {
-       struct device *dev = pmem->bb.dev;
+       struct device *dev = to_dev(pmem);
        sector_t sector;
        long cleared;
 
@@ -57,7 +58,7 @@ static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
        cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
 
        if (cleared > 0 && cleared / 512) {
-               dev_dbg(dev, "%s: %llx clear %ld sector%s\n",
+               dev_dbg(dev, "%s: %#llx clear %ld sector%s\n",
                                __func__, (unsigned long long) sector,
                                cleared / 512, cleared / 512 > 1 ? "s" : "");
                badblocks_clear(&pmem->bb, sector, cleared / 512);
@@ -73,7 +74,7 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
        bool bad_pmem = false;
        void *mem = kmap_atomic(page);
        phys_addr_t pmem_off = sector * 512 + pmem->data_offset;
-       void __pmem *pmem_addr = pmem->virt_addr + pmem_off;
+       void *pmem_addr = pmem->virt_addr + pmem_off;
 
        if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
                bad_pmem = true;
@@ -112,6 +113,11 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
        return rc;
 }
 
+/* account for REQ_FLUSH rename, replace with REQ_PREFLUSH after v4.8-rc1 */
+#ifndef REQ_FLUSH
+#define REQ_FLUSH REQ_PREFLUSH
+#endif
+
 static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
 {
        int rc = 0;
@@ -120,6 +126,10 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
        struct bio_vec bvec;
        struct bvec_iter iter;
        struct pmem_device *pmem = q->queuedata;
+       struct nd_region *nd_region = to_region(pmem);
+
+       if (bio->bi_rw & REQ_FLUSH)
+               nvdimm_flush(nd_region);
 
        do_acct = nd_iostat_start(bio, &start);
        bio_for_each_segment(bvec, bio, iter) {
@@ -134,8 +144,8 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
        if (do_acct)
                nd_iostat_end(bio, start);
 
-       if (bio_data_dir(bio))
-               wmb_pmem();
+       if (bio->bi_rw & REQ_FUA)
+               nvdimm_flush(nd_region);
 
        bio_endio(bio);
        return BLK_QC_T_NONE;
@@ -148,8 +158,6 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
        int rc;
 
        rc = pmem_do_bvec(pmem, page, PAGE_SIZE, 0, rw, sector);
-       if (rw & WRITE)
-               wmb_pmem();
 
        /*
         * The ->rw_page interface is subtle and tricky.  The core
@@ -163,8 +171,9 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
        return rc;
 }
 
-static long pmem_direct_access(struct block_device *bdev, sector_t sector,
-                     void __pmem **kaddr, pfn_t *pfn, long size)
+/* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */
+__weak long pmem_direct_access(struct block_device *bdev, sector_t sector,
+                     void **kaddr, pfn_t *pfn, long size)
 {
        struct pmem_device *pmem = bdev->bd_queue->queuedata;
        resource_size_t offset = sector * 512 + pmem->data_offset;
@@ -195,7 +204,7 @@ static void pmem_release_queue(void *q)
        blk_cleanup_queue(q);
 }
 
-void pmem_release_disk(void *disk)
+static void pmem_release_disk(void *disk)
 {
        del_gendisk(disk);
        put_disk(disk);
@@ -205,6 +214,7 @@ static int pmem_attach_disk(struct device *dev,
                struct nd_namespace_common *ndns)
 {
        struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+       struct nd_region *nd_region = to_nd_region(dev->parent);
        struct vmem_altmap __altmap, *altmap = NULL;
        struct resource *res = &nsio->res;
        struct nd_pfn *nd_pfn = NULL;
@@ -234,7 +244,7 @@ static int pmem_attach_disk(struct device *dev,
        dev_set_drvdata(dev, pmem);
        pmem->phys_addr = res->start;
        pmem->size = resource_size(res);
-       if (!arch_has_wmb_pmem())
+       if (nvdimm_has_flush(nd_region) < 0)
                dev_warn(dev, "unable to guarantee persistence of writes\n");
 
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
@@ -269,15 +279,14 @@ static int pmem_attach_disk(struct device *dev,
         * At release time the queue must be dead before
         * devm_memremap_pages is unwound
         */
-       if (devm_add_action(dev, pmem_release_queue, q)) {
-               blk_cleanup_queue(q);
+       if (devm_add_action_or_reset(dev, pmem_release_queue, q))
                return -ENOMEM;
-       }
 
        if (IS_ERR(addr))
                return PTR_ERR(addr);
-       pmem->virt_addr = (void __pmem *) addr;
+       pmem->virt_addr = addr;
 
+       blk_queue_write_cache(q, true, true);
        blk_queue_make_request(q, pmem_make_request);
        blk_queue_physical_block_size(q, PAGE_SIZE);
        blk_queue_max_hw_sectors(q, UINT_MAX);
@@ -289,10 +298,6 @@ static int pmem_attach_disk(struct device *dev,
        disk = alloc_disk_node(0, nid);
        if (!disk)
                return -ENOMEM;
-       if (devm_add_action(dev, pmem_release_disk, disk)) {
-               put_disk(disk);
-               return -ENOMEM;
-       }
 
        disk->fops              = &pmem_fops;
        disk->queue             = q;
@@ -302,9 +307,13 @@ static int pmem_attach_disk(struct device *dev,
                        / 512);
        if (devm_init_badblocks(dev, &pmem->bb))
                return -ENOMEM;
-       nvdimm_badblocks_populate(to_nd_region(dev->parent), &pmem->bb, res);
+       nvdimm_badblocks_populate(nd_region, &pmem->bb, res);
        disk->bb = &pmem->bb;
        device_add_disk(dev, disk);
+
+       if (devm_add_action_or_reset(dev, pmem_release_disk, disk))
+               return -ENOMEM;
+
        revalidate_disk(disk);
 
        return 0;
@@ -340,13 +349,20 @@ static int nd_pmem_remove(struct device *dev)
 {
        if (is_nd_btt(dev))
                nvdimm_namespace_detach_btt(to_nd_btt(dev));
+       nvdimm_flush(to_nd_region(dev->parent));
+
        return 0;
 }
 
+static void nd_pmem_shutdown(struct device *dev)
+{
+       nvdimm_flush(to_nd_region(dev->parent));
+}
+
 static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
 {
-       struct nd_region *nd_region = to_nd_region(dev->parent);
        struct pmem_device *pmem = dev_get_drvdata(dev);
+       struct nd_region *nd_region = to_region(pmem);
        resource_size_t offset = 0, end_trunc = 0;
        struct nd_namespace_common *ndns;
        struct nd_namespace_io *nsio;
@@ -382,6 +398,7 @@ static struct nd_device_driver nd_pmem_driver = {
        .probe = nd_pmem_probe,
        .remove = nd_pmem_remove,
        .notify = nd_pmem_notify,
+       .shutdown = nd_pmem_shutdown,
        .drv = {
                .name = "nd_pmem",
        },
diff --git a/drivers/nvdimm/pmem.h b/drivers/nvdimm/pmem.h
new file mode 100644 (file)
index 0000000..b4ee4f7
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __NVDIMM_PMEM_H__
+#define __NVDIMM_PMEM_H__
+#include <linux/badblocks.h>
+#include <linux/types.h>
+#include <linux/pfn_t.h>
+#include <linux/fs.h>
+
+long pmem_direct_access(struct block_device *bdev, sector_t sector,
+                     void **kaddr, pfn_t *pfn, long size);
+/* this definition is in it's own header for tools/testing/nvdimm to consume */
+struct pmem_device {
+       /* One contiguous memory region per device */
+       phys_addr_t             phys_addr;
+       /* when non-zero this device is hosting a 'pfn' instance */
+       phys_addr_t             data_offset;
+       u64                     pfn_flags;
+       void                    *virt_addr;
+       /* immutable base size of the namespace */
+       size_t                  size;
+       /* trim size when namespace capacity has been section aligned */
+       u32                     pfn_pad;
+       struct badblocks        bb;
+};
+#endif /* __NVDIMM_PMEM_H__ */
index 05a91235993969752a8e1edad056a036847923e5..8f241772ec0b24d0a2d297a7549ceac9e072872a 100644 (file)
@@ -20,7 +20,7 @@ static int nd_region_probe(struct device *dev)
 {
        int err, rc;
        static unsigned long once;
-       struct nd_region_namespaces *num_ns;
+       struct nd_region_data *ndrd;
        struct nd_region *nd_region = to_nd_region(dev);
 
        if (nd_region->num_lanes > num_online_cpus()
@@ -33,21 +33,21 @@ static int nd_region_probe(struct device *dev)
                                nd_region->num_lanes);
        }
 
+       rc = nd_region_activate(nd_region);
+       if (rc)
+               return rc;
+
        rc = nd_blk_region_init(nd_region);
        if (rc)
                return rc;
 
        rc = nd_region_register_namespaces(nd_region, &err);
-       num_ns = devm_kzalloc(dev, sizeof(*num_ns), GFP_KERNEL);
-       if (!num_ns)
-               return -ENOMEM;
-
        if (rc < 0)
                return rc;
 
-       num_ns->active = rc;
-       num_ns->count = rc + err;
-       dev_set_drvdata(dev, num_ns);
+       ndrd = dev_get_drvdata(dev);
+       ndrd->ns_active = rc;
+       ndrd->ns_count = rc + err;
 
        if (rc && err && rc == err)
                return -ENODEV;
@@ -82,6 +82,8 @@ static int nd_region_remove(struct device *dev)
 {
        struct nd_region *nd_region = to_nd_region(dev);
 
+       device_for_each_child(dev, NULL, child_unregister);
+
        /* flush attribute readers and disable */
        nvdimm_bus_lock(dev);
        nd_region->ns_seed = NULL;
@@ -91,7 +93,6 @@ static int nd_region_remove(struct device *dev)
        dev_set_drvdata(dev, NULL);
        nvdimm_bus_unlock(dev);
 
-       device_for_each_child(dev, NULL, child_unregister);
        return 0;
 }
 
index 40fcfea26fbbc387a3ecbf235b1d4b011022f1aa..e8d5ba7b29af98f647b119640e79e581996cfdc0 100644 (file)
 #include <linux/highmem.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/hash.h>
+#include <linux/pmem.h>
 #include <linux/sort.h>
 #include <linux/io.h>
 #include <linux/nd.h>
 #include "nd-core.h"
 #include "nd.h"
 
+/*
+ * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
+ * irrelevant.
+ */
+#include <linux/io-64-nonatomic-hi-lo.h>
+
 static DEFINE_IDA(region_ida);
+static DEFINE_PER_CPU(int, flush_idx);
+
+static int nvdimm_map_flush(struct device *dev, struct nvdimm *nvdimm, int dimm,
+               struct nd_region_data *ndrd)
+{
+       int i, j;
+
+       dev_dbg(dev, "%s: map %d flush address%s\n", nvdimm_name(nvdimm),
+                       nvdimm->num_flush, nvdimm->num_flush == 1 ? "" : "es");
+       for (i = 0; i < nvdimm->num_flush; i++) {
+               struct resource *res = &nvdimm->flush_wpq[i];
+               unsigned long pfn = PHYS_PFN(res->start);
+               void __iomem *flush_page;
+
+               /* check if flush hints share a page */
+               for (j = 0; j < i; j++) {
+                       struct resource *res_j = &nvdimm->flush_wpq[j];
+                       unsigned long pfn_j = PHYS_PFN(res_j->start);
+
+                       if (pfn == pfn_j)
+                               break;
+               }
+
+               if (j < i)
+                       flush_page = (void __iomem *) ((unsigned long)
+                                       ndrd->flush_wpq[dimm][j] & PAGE_MASK);
+               else
+                       flush_page = devm_nvdimm_ioremap(dev,
+                                       PHYS_PFN(pfn), PAGE_SIZE);
+               if (!flush_page)
+                       return -ENXIO;
+               ndrd->flush_wpq[dimm][i] = flush_page
+                       + (res->start & ~PAGE_MASK);
+       }
+
+       return 0;
+}
+
+int nd_region_activate(struct nd_region *nd_region)
+{
+       int i, num_flush = 0;
+       struct nd_region_data *ndrd;
+       struct device *dev = &nd_region->dev;
+       size_t flush_data_size = sizeof(void *);
+
+       nvdimm_bus_lock(&nd_region->dev);
+       for (i = 0; i < nd_region->ndr_mappings; i++) {
+               struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+               /* at least one null hint slot per-dimm for the "no-hint" case */
+               flush_data_size += sizeof(void *);
+               num_flush = min_not_zero(num_flush, nvdimm->num_flush);
+               if (!nvdimm->num_flush)
+                       continue;
+               flush_data_size += nvdimm->num_flush * sizeof(void *);
+       }
+       nvdimm_bus_unlock(&nd_region->dev);
+
+       ndrd = devm_kzalloc(dev, sizeof(*ndrd) + flush_data_size, GFP_KERNEL);
+       if (!ndrd)
+               return -ENOMEM;
+       dev_set_drvdata(dev, ndrd);
+
+       ndrd->flush_mask = (1 << ilog2(num_flush)) - 1;
+       for (i = 0; i < nd_region->ndr_mappings; i++) {
+               struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+               int rc = nvdimm_map_flush(&nd_region->dev, nvdimm, i, ndrd);
+
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
 
 static void nd_region_release(struct device *dev)
 {
@@ -242,12 +326,12 @@ static DEVICE_ATTR_RO(available_size);
 static ssize_t init_namespaces_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct nd_region_namespaces *num_ns = dev_get_drvdata(dev);
+       struct nd_region_data *ndrd = dev_get_drvdata(dev);
        ssize_t rc;
 
        nvdimm_bus_lock(dev);
-       if (num_ns)
-               rc = sprintf(buf, "%d/%d\n", num_ns->active, num_ns->count);
+       if (ndrd)
+               rc = sprintf(buf, "%d/%d\n", ndrd->ns_active, ndrd->ns_count);
        else
                rc = -ENXIO;
        nvdimm_bus_unlock(dev);
@@ -433,8 +517,6 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus,
 
                if (is_nd_pmem(dev))
                        return;
-
-               to_nd_blk_region(dev)->disable(nvdimm_bus, dev);
        }
        if (dev->parent && is_nd_blk(dev->parent) && probe) {
                nd_region = to_nd_region(dev->parent);
@@ -698,7 +780,6 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
                if (ndbr) {
                        nd_region = &ndbr->nd_region;
                        ndbr->enable = ndbr_desc->enable;
-                       ndbr->disable = ndbr_desc->disable;
                        ndbr->do_io = ndbr_desc->do_io;
                }
                region_buf = ndbr;
@@ -794,6 +875,67 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
 }
 EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
 
+/**
+ * nvdimm_flush - flush any posted write queues between the cpu and pmem media
+ * @nd_region: blk or interleaved pmem region
+ */
+void nvdimm_flush(struct nd_region *nd_region)
+{
+       struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
+       int i, idx;
+
+       /*
+        * Try to encourage some diversity in flush hint addresses
+        * across cpus assuming a limited number of flush hints.
+        */
+       idx = this_cpu_read(flush_idx);
+       idx = this_cpu_add_return(flush_idx, hash_32(current->pid + idx, 8));
+
+       /*
+        * The first wmb() is needed to 'sfence' all previous writes
+        * such that they are architecturally visible for the platform
+        * buffer flush.  Note that we've already arranged for pmem
+        * writes to avoid the cache via arch_memcpy_to_pmem().  The
+        * final wmb() ensures ordering for the NVDIMM flush write.
+        */
+       wmb();
+       for (i = 0; i < nd_region->ndr_mappings; i++)
+               if (ndrd->flush_wpq[i][0])
+                       writeq(1, ndrd->flush_wpq[i][idx & ndrd->flush_mask]);
+       wmb();
+}
+EXPORT_SYMBOL_GPL(nvdimm_flush);
+
+/**
+ * nvdimm_has_flush - determine write flushing requirements
+ * @nd_region: blk or interleaved pmem region
+ *
+ * Returns 1 if writes require flushing
+ * Returns 0 if writes do not require flushing
+ * Returns -ENXIO if flushing capability can not be determined
+ */
+int nvdimm_has_flush(struct nd_region *nd_region)
+{
+       struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
+       int i;
+
+       /* no nvdimm == flushing capability unknown */
+       if (nd_region->ndr_mappings == 0)
+               return -ENXIO;
+
+       for (i = 0; i < nd_region->ndr_mappings; i++)
+               /* flush hints present, flushing required */
+               if (ndrd->flush_wpq[i][0])
+                       return 1;
+
+       /*
+        * The platform defines dimm devices without hints, assume
+        * platform persistence mechanism like ADR
+        */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nvdimm_has_flush);
+
 void __exit nd_region_devs_exit(void)
 {
        ida_destroy(&region_ida);
index fb8200b8e8ec60911ddad766b740e879202d0b94..b3fe1d33963287c4883c0396e9a16764c62e1983 100644 (file)
@@ -35,7 +35,7 @@ config PINCTRL_ADI2
          machine and arch are selected to build.
 
 config PINCTRL_AS3722
-       bool "Pinctrl and GPIO driver for ams AS3722 PMIC"
+       tristate "Pinctrl and GPIO driver for ams AS3722 PMIC"
        depends on MFD_AS3722 && GPIOLIB
        select PINMUX
        select GENERIC_PINCONF
@@ -129,6 +129,17 @@ config PINCTRL_MESON
        select OF_GPIO
        select REGMAP_MMIO
 
+config PINCTRL_OXNAS
+       bool
+       depends on OF
+       select PINMUX
+       select PINCONF
+       select GENERIC_PINCONF
+       select GPIOLIB
+       select OF_GPIO
+       select GPIOLIB_IRQCHIP
+       select MFD_SYSCON
+
 config PINCTRL_ROCKCHIP
        bool
        select PINMUX
@@ -196,8 +207,19 @@ config PINCTRL_COH901
          COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
          ports of 8 GPIO pins each.
 
+config PINCTRL_MAX77620
+       tristate "MAX77620/MAX20024 Pincontrol support"
+       depends on MFD_MAX77620
+       select PINMUX
+       select GENERIC_PINCONF
+       help
+         Say Yes here to enable Pin control support for Maxim PMIC MAX77620.
+         This PMIC has 8 GPIO pins that work as GPIO as well as special
+         function in alternate mode. This driver also configure push-pull,
+         open drain, FPS slots etc.
+
 config PINCTRL_PALMAS
-       bool "Pinctrl driver for the PALMAS Series MFD devices"
+       tristate "Pinctrl driver for the PALMAS Series MFD devices"
        depends on OF && MFD_PALMAS
        select PINMUX
        select GENERIC_PINCONF
index 42a5c1dddfefaf7414eca1809ef7d1bf75a11628..8ebd7b8e16214ecf56f93e535caef91b54cecc9e 100644 (file)
@@ -16,7 +16,9 @@ obj-$(CONFIG_PINCTRL_AT91PIO4)        += pinctrl-at91-pio4.o
 obj-$(CONFIG_PINCTRL_AMD)      += pinctrl-amd.o
 obj-$(CONFIG_PINCTRL_DIGICOLOR)        += pinctrl-digicolor.o
 obj-$(CONFIG_PINCTRL_FALCON)   += pinctrl-falcon.o
+obj-$(CONFIG_PINCTRL_MAX77620) += pinctrl-max77620.o
 obj-$(CONFIG_PINCTRL_MESON)    += meson/
+obj-$(CONFIG_PINCTRL_OXNAS)    += pinctrl-oxnas.o
 obj-$(CONFIG_PINCTRL_PALMAS)   += pinctrl-palmas.o
 obj-$(CONFIG_PINCTRL_PIC32)    += pinctrl-pic32.o
 obj-$(CONFIG_PINCTRL_PISTACHIO)        += pinctrl-pistachio.o
@@ -35,7 +37,7 @@ obj-$(CONFIG_PINCTRL_TB10X)   += pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_ZYNQ)     += pinctrl-zynq.o
 
-obj-$(CONFIG_ARCH_BCM)         += bcm/
+obj-y                          += bcm/
 obj-$(CONFIG_PINCTRL_BERLIN)   += berlin/
 obj-y                          += freescale/
 obj-$(CONFIG_X86)              += intel/
index c356223e1c9c4d2c6252aa26be27f3ccb1a21fec..63246770bd74b9dcd3804cee66a960f2404b7092 100644 (file)
@@ -60,6 +60,7 @@ config PINCTRL_IPROC_GPIO
 config PINCTRL_CYGNUS_MUX
        bool "Broadcom Cygnus IOMUX driver"
        depends on (ARCH_BCM_CYGNUS || COMPILE_TEST)
+       depends on OF
        select PINMUX
        select GENERIC_PINCONF
        default ARCH_BCM_CYGNUS
@@ -99,3 +100,17 @@ config PINCTRL_NS2_MUX
 
          The Broadcom Northstar2 IOMUX driver supports group based IOMUX
          configuration.
+
+config PINCTRL_NSP_MUX
+       bool "Broadcom NSP IOMUX driver"
+       depends on (ARCH_BCM_NSP || COMPILE_TEST)
+       depends on OF
+       select PINMUX
+       select GENERIC_PINCONF
+       default ARCH_BCM_NSP
+       help
+         Say yes here to enable the Broadcom NSP SOC IOMUX driver.
+
+         The Broadcom Northstar Plus IOMUX driver supports pin based IOMUX
+         configuration, with certain individual pins can be overridden
+         to GPIO function.
index 3861a1c1f8ffebaf753c80a8a2fba09036496697..2a65111f3c7098c2f4e8d91bd6e1e9784e5c0573 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_PINCTRL_IPROC_GPIO)        += pinctrl-iproc-gpio.o
 obj-$(CONFIG_PINCTRL_CYGNUS_MUX)       += pinctrl-cygnus-mux.o
 obj-$(CONFIG_PINCTRL_NSP_GPIO)         += pinctrl-nsp-gpio.o
 obj-$(CONFIG_PINCTRL_NS2_MUX)          += pinctrl-ns2-mux.o
+obj-$(CONFIG_PINCTRL_NSP_MUX)          += pinctrl-nsp-mux.o
index 3670f5ea7a12ff3958c1e16105e03c848077778e..7f77007163985762abc6110f282eec762bdc8a92 100644 (file)
 #define GPIO_DRV_STRENGTH_BITS       3
 #define GPIO_DRV_STRENGTH_BIT_MASK   ((1 << GPIO_DRV_STRENGTH_BITS) - 1)
 
+enum iproc_pinconf_param {
+       IPROC_PINCONF_DRIVE_STRENGTH = 0,
+       IPROC_PINCONF_BIAS_DISABLE,
+       IPROC_PINCONF_BIAS_PULL_UP,
+       IPROC_PINCONF_BIAS_PULL_DOWN,
+       IPROC_PINCON_MAX,
+};
+
 /*
  * Iproc GPIO core
  *
  * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs
  * @pinmux_is_supported: flag to indicate this GPIO controller contains pins
  * that can be individually muxed to GPIO
+ * @pinconf_disable: contains a list of PINCONF parameters that need to be
+ * disabled
+ * @nr_pinconf_disable: total number of PINCONF parameters that need to be
+ * disabled
  * @pctl: pointer to pinctrl_dev
  * @pctldesc: pinctrl descriptor
  */
@@ -94,6 +106,9 @@ struct iproc_gpio {
 
        bool pinmux_is_supported;
 
+       enum pin_config_param *pinconf_disable;
+       unsigned int nr_pinconf_disable;
+
        struct pinctrl_dev *pctl;
        struct pinctrl_desc pctldesc;
 };
@@ -360,6 +375,65 @@ static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio)
        return !!(readl(chip->base + offset) & BIT(shift));
 }
 
+/*
+ * Mapping of the iProc PINCONF parameters to the generic pin configuration
+ * parameters
+ */
+static const enum pin_config_param iproc_pinconf_disable_map[] = {
+       [IPROC_PINCONF_DRIVE_STRENGTH] = PIN_CONFIG_DRIVE_STRENGTH,
+       [IPROC_PINCONF_BIAS_DISABLE] = PIN_CONFIG_BIAS_DISABLE,
+       [IPROC_PINCONF_BIAS_PULL_UP] = PIN_CONFIG_BIAS_PULL_UP,
+       [IPROC_PINCONF_BIAS_PULL_DOWN] = PIN_CONFIG_BIAS_PULL_DOWN,
+};
+
+static bool iproc_pinconf_param_is_disabled(struct iproc_gpio *chip,
+                                           enum pin_config_param param)
+{
+       unsigned int i;
+
+       if (!chip->nr_pinconf_disable)
+               return false;
+
+       for (i = 0; i < chip->nr_pinconf_disable; i++)
+               if (chip->pinconf_disable[i] == param)
+                       return true;
+
+       return false;
+}
+
+static int iproc_pinconf_disable_map_create(struct iproc_gpio *chip,
+                                           unsigned long disable_mask)
+{
+       unsigned int map_size = ARRAY_SIZE(iproc_pinconf_disable_map);
+       unsigned int bit, nbits = 0;
+
+       /* figure out total number of PINCONF parameters to disable */
+       for_each_set_bit(bit, &disable_mask, map_size)
+               nbits++;
+
+       if (!nbits)
+               return 0;
+
+       /*
+        * Allocate an array to store PINCONF parameters that need to be
+        * disabled
+        */
+       chip->pinconf_disable = devm_kcalloc(chip->dev, nbits,
+                                            sizeof(*chip->pinconf_disable),
+                                            GFP_KERNEL);
+       if (!chip->pinconf_disable)
+               return -ENOMEM;
+
+       chip->nr_pinconf_disable = nbits;
+
+       /* now store these parameters */
+       nbits = 0;
+       for_each_set_bit(bit, &disable_mask, map_size)
+               chip->pinconf_disable[nbits++] = iproc_pinconf_disable_map[bit];
+
+       return 0;
+}
+
 static int iproc_get_groups_count(struct pinctrl_dev *pctldev)
 {
        return 1;
@@ -500,6 +574,9 @@ static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
        bool disable, pull_up;
        int ret;
 
+       if (iproc_pinconf_param_is_disabled(chip, param))
+               return -ENOTSUPP;
+
        switch (param) {
        case PIN_CONFIG_BIAS_DISABLE:
                iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
@@ -548,6 +625,10 @@ static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
 
        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
+
+               if (iproc_pinconf_param_is_disabled(chip, param))
+                       return -ENOTSUPP;
+
                arg = pinconf_to_config_argument(configs[i]);
 
                switch (param) {
@@ -633,11 +714,13 @@ static int iproc_gpio_register_pinconf(struct iproc_gpio *chip)
 }
 
 static const struct of_device_id iproc_gpio_of_match[] = {
+       { .compatible = "brcm,iproc-gpio" },
        { .compatible = "brcm,cygnus-ccm-gpio" },
        { .compatible = "brcm,cygnus-asiu-gpio" },
        { .compatible = "brcm,cygnus-crmu-gpio" },
-       { .compatible = "brcm,iproc-gpio" },
-       { }
+       { .compatible = "brcm,iproc-nsp-gpio" },
+       { .compatible = "brcm,iproc-stingray-gpio" },
+       { /* sentinel */ }
 };
 
 static int iproc_gpio_probe(struct platform_device *pdev)
@@ -646,8 +729,17 @@ static int iproc_gpio_probe(struct platform_device *pdev)
        struct resource *res;
        struct iproc_gpio *chip;
        struct gpio_chip *gc;
-       u32 ngpios;
+       u32 ngpios, pinconf_disable_mask = 0;
        int irq, ret;
+       bool no_pinconf = false;
+
+       /* NSP does not support drive strength config */
+       if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
+               pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH);
+       /* Stingray does not support pinconf in this controller */
+       else if (of_device_is_compatible(dev->of_node,
+                                        "brcm,iproc-stingray-gpio"))
+               no_pinconf = true;
 
        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
@@ -702,10 +794,22 @@ static int iproc_gpio_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = iproc_gpio_register_pinconf(chip);
-       if (ret) {
-               dev_err(dev, "unable to register pinconf\n");
-               goto err_rm_gpiochip;
+       if (!no_pinconf) {
+               ret = iproc_gpio_register_pinconf(chip);
+               if (ret) {
+                       dev_err(dev, "unable to register pinconf\n");
+                       goto err_rm_gpiochip;
+               }
+
+               if (pinconf_disable_mask) {
+                       ret = iproc_pinconf_disable_map_create(chip,
+                                                        pinconf_disable_mask);
+                       if (ret) {
+                               dev_err(dev,
+                                       "unable to create pinconf disable map\n");
+                               goto err_rm_gpiochip;
+                       }
+               }
        }
 
        /* optional GPIO interrupt support */
index 3fefd14acc3eebf33323035eeb3211abb8482e44..ca817896ed241e3909c2aad8b77f2a23fb29913a 100644 (file)
@@ -1044,10 +1044,8 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        pinctrl->base0 = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(pinctrl->base0)) {
-               dev_err(&pdev->dev, "unable to map I/O space\n");
+       if (IS_ERR(pinctrl->base0))
                return PTR_ERR(pinctrl->base0);
-       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        pinctrl->base1 = devm_ioremap_nocache(&pdev->dev, res->start,
@@ -1059,10 +1057,8 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
        pinctrl->pinconf_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(pinctrl->pinconf_base)) {
-               dev_err(&pdev->dev, "unable to map I/O space\n");
+       if (IS_ERR(pinctrl->pinconf_base))
                return PTR_ERR(pinctrl->pinconf_base);
-       }
 
        ret = ns2_mux_log_init(pinctrl);
        if (ret) {
@@ -1089,9 +1085,9 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
 
        pinctrl->pctl = pinctrl_register(&ns2_pinctrl_desc, &pdev->dev,
                        pinctrl);
-       if (!pinctrl->pctl) {
+       if (IS_ERR(pinctrl->pctl)) {
                dev_err(&pdev->dev, "unable to register IOMUX pinctrl\n");
-               return -EINVAL;
+               return PTR_ERR(pinctrl->pctl);
        }
 
        return 0;
index a8b37a9a82301a9d6b82e57a9f716416f0d60247..35783db1c10bad5f50bb8ac41a59307dc97b852e 100644 (file)
@@ -458,13 +458,15 @@ static int nsp_gpio_get_strength(struct nsp_gpio *chip, unsigned gpio,
        return 0;
 }
 
-int nsp_pin_config_group_get(struct pinctrl_dev *pctldev, unsigned selector,
+static int nsp_pin_config_group_get(struct pinctrl_dev *pctldev,
+                                   unsigned selector,
                             unsigned long *config)
 {
        return 0;
 }
 
-int nsp_pin_config_group_set(struct pinctrl_dev *pctldev, unsigned selector,
+static int nsp_pin_config_group_set(struct pinctrl_dev *pctldev,
+                                   unsigned selector,
                             unsigned long *configs, unsigned num_configs)
 {
        return 0;
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c
new file mode 100644 (file)
index 0000000..4149db3
--- /dev/null
@@ -0,0 +1,642 @@
+/* Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This file contains the Northstar plus (NSP) IOMUX driver that supports
+ * group based PINMUX configuration. The Northstar plus IOMUX controller
+ * allows pins to be individually muxed to GPIO function. The NAND and MMC is
+ * a group based selection. The gpio_a 8 - 11 are muxed with gpio_b and pwm.
+ * To select PWM, one need to enable the corresponding gpio_b as well.
+ *
+ *                             gpio_a (8 - 11)
+ *                             +----------
+ *                             |
+ *             gpio_a (8-11)   |       gpio_b (0 - 3)
+ *     ------------------------+-------+----------
+ *                                     |
+ *                                     |       pwm (0 - 3)
+ *                                     +----------
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define NSP_MUX_BASE0  0x00
+#define NSP_MUX_BASE1  0x01
+#define NSP_MUX_BASE2  0x02
+/*
+ * nsp IOMUX register description
+ *
+ * @base: base 0 or base 1
+ * @shift: bit shift for mux configuration of a group
+ * @mask: bit mask of the function
+ * @alt: alternate function to set to
+ */
+struct nsp_mux {
+       unsigned int base;
+       unsigned int shift;
+       unsigned int mask;
+       unsigned int alt;
+};
+
+/*
+ * Keep track of nsp IOMUX configuration and prevent double configuration
+ *
+ * @nsp_mux: nsp IOMUX register description
+ * @is_configured: flag to indicate whether a mux setting has already been
+ * configured
+ */
+struct nsp_mux_log {
+       struct nsp_mux mux;
+       bool is_configured;
+};
+
+/*
+ * Group based IOMUX configuration
+ *
+ * @name: name of the group
+ * @pins: array of pins used by this group
+ * @num_pins: total number of pins used by this group
+ * @mux: nsp group based IOMUX configuration
+ */
+struct nsp_pin_group {
+       const char *name;
+       const unsigned int *pins;
+       const unsigned int num_pins;
+       const struct nsp_mux mux;
+};
+
+/*
+ * nsp mux function and supported pin groups
+ *
+ * @name: name of the function
+ * @groups: array of groups that can be supported by this function
+ * @num_groups: total number of groups that can be supported by this function
+ */
+struct nsp_pin_function {
+       const char *name;
+       const char * const *groups;
+       const unsigned int num_groups;
+};
+
+/*
+ * nsp IOMUX pinctrl core
+ *
+ * @pctl: pointer to pinctrl_dev
+ * @dev: pointer to device
+ * @base0: first mux register
+ * @base1: second mux register
+ * @base2: third mux register
+ * @groups: pointer to array of groups
+ * @num_groups: total number of groups
+ * @functions: pointer to array of functions
+ * @num_functions: total number of functions
+ * @mux_log: pointer to the array of mux logs
+ * @lock: lock to protect register access
+ */
+struct nsp_pinctrl {
+       struct pinctrl_dev *pctl;
+       struct device *dev;
+       void __iomem *base0;
+       void __iomem *base1;
+       void __iomem *base2;
+       const struct nsp_pin_group *groups;
+       unsigned int num_groups;
+       const struct nsp_pin_function *functions;
+       unsigned int num_functions;
+       struct nsp_mux_log *mux_log;
+       spinlock_t lock;
+};
+
+/*
+ * Description of a pin in nsp
+ *
+ * @pin: pin number
+ * @name: pin name
+ * @gpio_select: reg data to select GPIO
+ */
+struct nsp_pin {
+       unsigned int pin;
+       char *name;
+       unsigned int gpio_select;
+};
+
+#define NSP_PIN_DESC(p, n, g)          \
+{                                      \
+       .pin = p,                       \
+       .name = n,                      \
+       .gpio_select = g,               \
+}
+
+/*
+ * List of muxable pins in nsp
+ */
+static struct nsp_pin nsp_pins[] = {
+       NSP_PIN_DESC(0, "spi_clk", 1),
+       NSP_PIN_DESC(1, "spi_ss", 1),
+       NSP_PIN_DESC(2, "spi_mosi", 1),
+       NSP_PIN_DESC(3, "spi_miso", 1),
+       NSP_PIN_DESC(4, "scl", 1),
+       NSP_PIN_DESC(5, "sda", 1),
+       NSP_PIN_DESC(6, "mdc", 1),
+       NSP_PIN_DESC(7, "mdio", 1),
+       NSP_PIN_DESC(8, "pwm0", 1),
+       NSP_PIN_DESC(9, "pwm1", 1),
+       NSP_PIN_DESC(10, "pwm2", 1),
+       NSP_PIN_DESC(11, "pwm3", 1),
+       NSP_PIN_DESC(12, "uart1_rx", 1),
+       NSP_PIN_DESC(13, "uart1_tx", 1),
+       NSP_PIN_DESC(14, "uart1_cts", 1),
+       NSP_PIN_DESC(15, "uart1_rts", 1),
+       NSP_PIN_DESC(16, "uart2_rx", 1),
+       NSP_PIN_DESC(17, "uart2_tx", 1),
+       NSP_PIN_DESC(18, "synce", 0),
+       NSP_PIN_DESC(19, "sata0_led", 0),
+       NSP_PIN_DESC(20, "sata1_led", 0),
+       NSP_PIN_DESC(21, "xtal_out", 1),
+       NSP_PIN_DESC(22, "sdio_pwr", 1),
+       NSP_PIN_DESC(23, "sdio_en_1p8v", 1),
+       NSP_PIN_DESC(24, "gpio_24", 1),
+       NSP_PIN_DESC(25, "gpio_25", 1),
+       NSP_PIN_DESC(26, "p5_led0", 0),
+       NSP_PIN_DESC(27, "p5_led1", 0),
+       NSP_PIN_DESC(28, "gpio_28", 1),
+       NSP_PIN_DESC(29, "gpio_29", 1),
+       NSP_PIN_DESC(30, "gpio_30", 1),
+       NSP_PIN_DESC(31, "gpio_31", 1),
+       NSP_PIN_DESC(32, "nand_ale", 0),
+       NSP_PIN_DESC(33, "nand_ce0", 0),
+       NSP_PIN_DESC(34, "nand_r/b", 0),
+       NSP_PIN_DESC(35, "nand_dq0", 0),
+       NSP_PIN_DESC(36, "nand_dq1", 0),
+       NSP_PIN_DESC(37, "nand_dq2", 0),
+       NSP_PIN_DESC(38, "nand_dq3", 0),
+       NSP_PIN_DESC(39, "nand_dq4", 0),
+       NSP_PIN_DESC(40, "nand_dq5", 0),
+       NSP_PIN_DESC(41, "nand_dq6", 0),
+       NSP_PIN_DESC(42, "nand_dq7", 0),
+};
+
+/*
+ * List of groups of pins
+ */
+
+static const unsigned int spi_pins[] = {0, 1, 2, 3};
+static const unsigned int i2c_pins[] = {4, 5};
+static const unsigned int mdio_pins[] = {6, 7};
+static const unsigned int pwm0_pins[] = {8};
+static const unsigned int gpio_b_0_pins[] = {8};
+static const unsigned int pwm1_pins[] = {9};
+static const unsigned int gpio_b_1_pins[] = {9};
+static const unsigned int pwm2_pins[] = {10};
+static const unsigned int gpio_b_2_pins[] = {10};
+static const unsigned int pwm3_pins[] = {11};
+static const unsigned int gpio_b_3_pins[] = {11};
+static const unsigned int uart1_pins[] = {12, 13, 14, 15};
+static const unsigned int uart2_pins[] = {16, 17};
+static const unsigned int synce_pins[] = {18};
+static const unsigned int sata0_led_pins[] = {19};
+static const unsigned int sata1_led_pins[] = {20};
+static const unsigned int xtal_out_pins[] = {21};
+static const unsigned int sdio_pwr_pins[] = {22};
+static const unsigned int sdio_1p8v_pins[] = {23};
+static const unsigned int switch_p05_led0_pins[] = {26};
+static const unsigned int switch_p05_led1_pins[] = {27};
+static const unsigned int nand_pins[] = {32, 33, 34, 35, 36, 37, 38, 39,
+                                                       40, 41, 42};
+static const unsigned int emmc_pins[] = {32, 33, 34, 35, 36, 37, 38, 39,
+                                                       40, 41, 42};
+
+#define NSP_PIN_GROUP(group_name, ba, sh, ma, al)      \
+{                                                      \
+       .name = __stringify(group_name) "_grp",         \
+       .pins = group_name ## _pins,                    \
+       .num_pins = ARRAY_SIZE(group_name ## _pins),    \
+       .mux = {                                        \
+               .base = ba,                             \
+               .shift = sh,                            \
+               .mask = ma,                             \
+               .alt = al,                              \
+       }                                               \
+}
+
+/*
+ * List of nsp pin groups
+ */
+static const struct nsp_pin_group nsp_pin_groups[] = {
+       NSP_PIN_GROUP(spi, NSP_MUX_BASE0, 0, 0x0f, 0x00),
+       NSP_PIN_GROUP(i2c, NSP_MUX_BASE0, 3, 0x03, 0x00),
+       NSP_PIN_GROUP(mdio, NSP_MUX_BASE0, 5, 0x03, 0x00),
+       NSP_PIN_GROUP(gpio_b_0, NSP_MUX_BASE0, 7, 0x01, 0x00),
+       NSP_PIN_GROUP(pwm0, NSP_MUX_BASE1, 0, 0x01, 0x01),
+       NSP_PIN_GROUP(gpio_b_1, NSP_MUX_BASE0, 8, 0x01, 0x00),
+       NSP_PIN_GROUP(pwm1, NSP_MUX_BASE1, 1, 0x01, 0x01),
+       NSP_PIN_GROUP(gpio_b_2, NSP_MUX_BASE0, 9, 0x01, 0x00),
+       NSP_PIN_GROUP(pwm2, NSP_MUX_BASE1, 2, 0x01, 0x01),
+       NSP_PIN_GROUP(gpio_b_3, NSP_MUX_BASE0, 10, 0x01, 0x00),
+       NSP_PIN_GROUP(pwm3, NSP_MUX_BASE1, 3, 0x01, 0x01),
+       NSP_PIN_GROUP(uart1, NSP_MUX_BASE0, 11, 0x0f, 0x00),
+       NSP_PIN_GROUP(uart2, NSP_MUX_BASE0, 15, 0x03, 0x00),
+       NSP_PIN_GROUP(synce, NSP_MUX_BASE0, 17, 0x01, 0x01),
+       NSP_PIN_GROUP(sata0_led, NSP_MUX_BASE0, 18, 0x01, 0x01),
+       NSP_PIN_GROUP(sata1_led, NSP_MUX_BASE0, 19, 0x01, 0x01),
+       NSP_PIN_GROUP(xtal_out, NSP_MUX_BASE0, 20, 0x01, 0x00),
+       NSP_PIN_GROUP(sdio_pwr, NSP_MUX_BASE0, 21, 0x01, 0x00),
+       NSP_PIN_GROUP(sdio_1p8v, NSP_MUX_BASE0, 22, 0x01, 0x00),
+       NSP_PIN_GROUP(switch_p05_led0, NSP_MUX_BASE0, 26, 0x01, 0x01),
+       NSP_PIN_GROUP(switch_p05_led1, NSP_MUX_BASE0, 27, 0x01, 0x01),
+       NSP_PIN_GROUP(nand, NSP_MUX_BASE2, 0, 0x01, 0x00),
+       NSP_PIN_GROUP(emmc, NSP_MUX_BASE2, 0, 0x01, 0x01)
+};
+
+/*
+ * List of groups supported by functions
+ */
+
+static const char * const spi_grps[] = {"spi_grp"};
+static const char * const i2c_grps[] = {"i2c_grp"};
+static const char * const mdio_grps[] = {"mdio_grp"};
+static const char * const pwm_grps[] = {"pwm0_grp", "pwm1_grp", "pwm2_grp"
+                                               , "pwm3_grp"};
+static const char * const gpio_b_grps[] = {"gpio_b_0_grp", "gpio_b_1_grp",
+                                       "gpio_b_2_grp", "gpio_b_3_grp"};
+static const char * const uart1_grps[] = {"uart1_grp"};
+static const char * const uart2_grps[] = {"uart2_grp"};
+static const char * const synce_grps[] = {"synce_grp"};
+static const char * const sata_led_grps[] = {"sata0_led_grp", "sata1_led_grp"};
+static const char * const xtal_out_grps[] = {"xtal_out_grp"};
+static const char * const sdio_grps[] = {"sdio_pwr_grp", "sdio_1p8v_grp"};
+static const char * const switch_led_grps[] = {"switch_p05_led0_grp",
+                                               "switch_p05_led1_grp"};
+static const char * const nand_grps[] = {"nand_grp"};
+static const char * const emmc_grps[] = {"emmc_grp"};
+
+#define NSP_PIN_FUNCTION(func)                         \
+{                                                      \
+       .name = #func,                                  \
+       .groups = func ## _grps,                        \
+       .num_groups = ARRAY_SIZE(func ## _grps),        \
+}
+
+/*
+ * List of supported functions in nsp
+ */
+static const struct nsp_pin_function nsp_pin_functions[] = {
+       NSP_PIN_FUNCTION(spi),
+       NSP_PIN_FUNCTION(i2c),
+       NSP_PIN_FUNCTION(mdio),
+       NSP_PIN_FUNCTION(pwm),
+       NSP_PIN_FUNCTION(gpio_b),
+       NSP_PIN_FUNCTION(uart1),
+       NSP_PIN_FUNCTION(uart2),
+       NSP_PIN_FUNCTION(synce),
+       NSP_PIN_FUNCTION(sata_led),
+       NSP_PIN_FUNCTION(xtal_out),
+       NSP_PIN_FUNCTION(sdio),
+       NSP_PIN_FUNCTION(switch_led),
+       NSP_PIN_FUNCTION(nand),
+       NSP_PIN_FUNCTION(emmc)
+};
+
+static int nsp_get_groups_count(struct pinctrl_dev *pctrl_dev)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       return pinctrl->num_groups;
+}
+
+static const char *nsp_get_group_name(struct pinctrl_dev *pctrl_dev,
+                                     unsigned int selector)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       return pinctrl->groups[selector].name;
+}
+
+static int nsp_get_group_pins(struct pinctrl_dev *pctrl_dev,
+                             unsigned int selector, const unsigned int **pins,
+                             unsigned int *num_pins)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       *pins = pinctrl->groups[selector].pins;
+       *num_pins = pinctrl->groups[selector].num_pins;
+
+       return 0;
+}
+
+static void nsp_pin_dbg_show(struct pinctrl_dev *pctrl_dev,
+                            struct seq_file *s, unsigned int offset)
+{
+       seq_printf(s, " %s", dev_name(pctrl_dev->dev));
+}
+
+static struct pinctrl_ops nsp_pinctrl_ops = {
+       .get_groups_count = nsp_get_groups_count,
+       .get_group_name = nsp_get_group_name,
+       .get_group_pins = nsp_get_group_pins,
+       .pin_dbg_show = nsp_pin_dbg_show,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+       .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int nsp_get_functions_count(struct pinctrl_dev *pctrl_dev)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       return pinctrl->num_functions;
+}
+
+static const char *nsp_get_function_name(struct pinctrl_dev *pctrl_dev,
+                                        unsigned int selector)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       return pinctrl->functions[selector].name;
+}
+
+static int nsp_get_function_groups(struct pinctrl_dev *pctrl_dev,
+                                  unsigned int selector,
+                                  const char * const **groups,
+                                  unsigned * const num_groups)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       *groups = pinctrl->functions[selector].groups;
+       *num_groups = pinctrl->functions[selector].num_groups;
+
+       return 0;
+}
+
+static int nsp_pinmux_set(struct nsp_pinctrl *pinctrl,
+                         const struct nsp_pin_function *func,
+                         const struct nsp_pin_group *grp,
+                         struct nsp_mux_log *mux_log)
+{
+       const struct nsp_mux *mux = &grp->mux;
+       int i;
+       u32 val, mask;
+       unsigned long flags;
+       void __iomem *base_address;
+
+       for (i = 0; i < pinctrl->num_groups; i++) {
+               if ((mux->shift != mux_log[i].mux.shift) ||
+                       (mux->base != mux_log[i].mux.base))
+                       continue;
+
+               /* if this is a new configuration, just do it! */
+               if (!mux_log[i].is_configured)
+                       break;
+
+               /*
+                * IOMUX has been configured previously and one is trying to
+                * configure it to a different function
+                */
+               if (mux_log[i].mux.alt != mux->alt) {
+                       dev_err(pinctrl->dev,
+                               "double configuration error detected!\n");
+                       dev_err(pinctrl->dev, "func:%s grp:%s\n",
+                               func->name, grp->name);
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
+       if (i == pinctrl->num_groups)
+               return -EINVAL;
+
+       mask = mux->mask;
+       mux_log[i].mux.alt = mux->alt;
+       mux_log[i].is_configured = true;
+
+       switch (mux->base) {
+       case NSP_MUX_BASE0:
+               base_address = pinctrl->base0;
+               break;
+
+       case NSP_MUX_BASE1:
+               base_address = pinctrl->base1;
+               break;
+
+       case NSP_MUX_BASE2:
+               base_address = pinctrl->base2;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&pinctrl->lock, flags);
+       val = readl(base_address);
+       val &= ~(mask << grp->mux.shift);
+       val |= grp->mux.alt << grp->mux.shift;
+       writel(val, base_address);
+       spin_unlock_irqrestore(&pinctrl->lock, flags);
+
+       return 0;
+}
+
+static int nsp_pinmux_enable(struct pinctrl_dev *pctrl_dev,
+                            unsigned int func_select, unsigned int grp_select)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+       const struct nsp_pin_function *func;
+       const struct nsp_pin_group *grp;
+
+       if (grp_select > pinctrl->num_groups ||
+               func_select > pinctrl->num_functions)
+               return -EINVAL;
+
+       func = &pinctrl->functions[func_select];
+       grp = &pinctrl->groups[grp_select];
+
+       dev_dbg(pctrl_dev->dev, "func:%u name:%s grp:%u name:%s\n",
+               func_select, func->name, grp_select, grp->name);
+
+       dev_dbg(pctrl_dev->dev, "shift:%u alt:%u\n", grp->mux.shift,
+               grp->mux.alt);
+
+       return nsp_pinmux_set(pinctrl, func, grp, pinctrl->mux_log);
+}
+
+
+static int nsp_gpio_request_enable(struct pinctrl_dev *pctrl_dev,
+                                  struct pinctrl_gpio_range *range,
+                                  unsigned int pin)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+       u32 *gpio_select = pctrl_dev->desc->pins[pin].drv_data;
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pinctrl->lock, flags);
+       val = readl(pinctrl->base0);
+       if ((val & BIT(pin)) != (*gpio_select << pin)) {
+               val &= ~BIT(pin);
+               val |= *gpio_select << pin;
+               writel(val, pinctrl->base0);
+       }
+       spin_unlock_irqrestore(&pinctrl->lock, flags);
+
+       return 0;
+}
+
+static void nsp_gpio_disable_free(struct pinctrl_dev *pctrl_dev,
+                                 struct pinctrl_gpio_range *range,
+                                 unsigned int pin)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+       u32 *gpio_select = pctrl_dev->desc->pins[pin].drv_data;
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pinctrl->lock, flags);
+       val = readl(pinctrl->base0);
+       if ((val & (1 << pin)) == (*gpio_select << pin)) {
+               val &= ~(1 << pin);
+               if (!(*gpio_select))
+                       val |= (1 << pin);
+               writel(val, pinctrl->base0);
+       }
+       spin_unlock_irqrestore(&pinctrl->lock, flags);
+}
+
+static struct pinmux_ops nsp_pinmux_ops = {
+       .get_functions_count = nsp_get_functions_count,
+       .get_function_name = nsp_get_function_name,
+       .get_function_groups = nsp_get_function_groups,
+       .set_mux = nsp_pinmux_enable,
+       .gpio_request_enable = nsp_gpio_request_enable,
+       .gpio_disable_free = nsp_gpio_disable_free,
+};
+
+static struct pinctrl_desc nsp_pinctrl_desc = {
+       .name = "nsp-pinmux",
+       .pctlops = &nsp_pinctrl_ops,
+       .pmxops = &nsp_pinmux_ops,
+};
+
+static int nsp_mux_log_init(struct nsp_pinctrl *pinctrl)
+{
+       struct nsp_mux_log *log;
+       unsigned int i;
+       u32 no_of_groups = ARRAY_SIZE(nsp_pin_groups);
+
+       pinctrl->mux_log = devm_kcalloc(pinctrl->dev, no_of_groups,
+                                       sizeof(struct nsp_mux_log),
+                                       GFP_KERNEL);
+       if (!pinctrl->mux_log)
+               return -ENOMEM;
+
+       for (i = 0; i < no_of_groups; i++) {
+               log = &pinctrl->mux_log[i];
+               log->mux.base = nsp_pin_groups[i].mux.base;
+               log->mux.shift = nsp_pin_groups[i].mux.shift;
+               log->mux.alt = 0;
+               log->is_configured = false;
+       }
+
+       return 0;
+}
+
+static int nsp_pinmux_probe(struct platform_device *pdev)
+{
+       struct nsp_pinctrl *pinctrl;
+       struct resource *res;
+       int i, ret;
+       struct pinctrl_pin_desc *pins;
+       unsigned int num_pins = ARRAY_SIZE(nsp_pins);
+
+       pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
+       if (!pinctrl)
+               return -ENOMEM;
+       pinctrl->dev = &pdev->dev;
+       platform_set_drvdata(pdev, pinctrl);
+       spin_lock_init(&pinctrl->lock);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pinctrl->base0 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pinctrl->base0))
+               return PTR_ERR(pinctrl->base0);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       pinctrl->base1 = devm_ioremap_nocache(&pdev->dev, res->start,
+                                             resource_size(res));
+       if (!pinctrl->base1) {
+               dev_err(&pdev->dev, "unable to map I/O space\n");
+               return -ENOMEM;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       pinctrl->base2 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pinctrl->base2))
+               return PTR_ERR(pinctrl->base2);
+
+       ret = nsp_mux_log_init(pinctrl);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to initialize IOMUX log\n");
+               return ret;
+       }
+
+       pins = devm_kcalloc(&pdev->dev, num_pins, sizeof(*pins), GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       for (i = 0; i < num_pins; i++) {
+               pins[i].number = nsp_pins[i].pin;
+               pins[i].name = nsp_pins[i].name;
+               pins[i].drv_data = &nsp_pins[i].gpio_select;
+       }
+
+       pinctrl->groups = nsp_pin_groups;
+       pinctrl->num_groups = ARRAY_SIZE(nsp_pin_groups);
+       pinctrl->functions = nsp_pin_functions;
+       pinctrl->num_functions = ARRAY_SIZE(nsp_pin_functions);
+       nsp_pinctrl_desc.pins = pins;
+       nsp_pinctrl_desc.npins = num_pins;
+
+       pinctrl->pctl = devm_pinctrl_register(&pdev->dev, &nsp_pinctrl_desc,
+                                        pinctrl);
+       if (IS_ERR(pinctrl->pctl)) {
+               dev_err(&pdev->dev, "unable to register nsp IOMUX pinctrl\n");
+               return PTR_ERR(pinctrl->pctl);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id nsp_pinmux_of_match[] = {
+       { .compatible = "brcm,nsp-pinmux" },
+       { }
+};
+
+static struct platform_driver nsp_pinmux_driver = {
+       .driver = {
+               .name = "nsp-pinmux",
+               .of_match_table = nsp_pinmux_of_match,
+       },
+       .probe = nsp_pinmux_probe,
+};
+
+static int __init nsp_pinmux_init(void)
+{
+       return platform_driver_register(&nsp_pinmux_driver);
+}
+arch_initcall(nsp_pinmux_init);
index 98d2a1bb44cb2a2c979ce8d428325f47da354f5b..fb38e208f32dd2199f427207fe6a0e19d3987a5a 100644 (file)
@@ -225,13 +225,14 @@ static void pinctrl_free_pindescs(struct pinctrl_dev *pctldev,
 }
 
 static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
-                                   unsigned number, const char *name)
+                                   const struct pinctrl_pin_desc *pin)
 {
        struct pin_desc *pindesc;
 
-       pindesc = pin_desc_get(pctldev, number);
+       pindesc = pin_desc_get(pctldev, pin->number);
        if (pindesc != NULL) {
-               dev_err(pctldev->dev, "pin %d already registered\n", number);
+               dev_err(pctldev->dev, "pin %d already registered\n",
+                       pin->number);
                return -EINVAL;
        }
 
@@ -245,10 +246,10 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
        pindesc->pctldev = pctldev;
 
        /* Copy basic pin info */
-       if (name) {
-               pindesc->name = name;
+       if (pin->name) {
+               pindesc->name = pin->name;
        } else {
-               pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", number);
+               pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", pin->number);
                if (pindesc->name == NULL) {
                        kfree(pindesc);
                        return -ENOMEM;
@@ -256,9 +257,11 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
                pindesc->dynamic_name = true;
        }
 
-       radix_tree_insert(&pctldev->pin_desc_tree, number, pindesc);
+       pindesc->drv_data = pin->drv_data;
+
+       radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
        pr_debug("registered pin %d (%s) on %s\n",
-                number, pindesc->name, pctldev->desc->name);
+                pin->number, pindesc->name, pctldev->desc->name);
        return 0;
 }
 
@@ -270,8 +273,7 @@ static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
        int ret = 0;
 
        for (i = 0; i < num_descs; i++) {
-               ret = pinctrl_register_one_pin(pctldev,
-                                              pins[i].number, pins[i].name);
+               ret = pinctrl_register_one_pin(pctldev, &pins[i]);
                if (ret)
                        return ret;
        }
@@ -1367,8 +1369,7 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
                if (desc == NULL)
                        continue;
 
-               seq_printf(s, "pin %d (%s) ", pin,
-                          desc->name ? desc->name : "unnamed");
+               seq_printf(s, "pin %d (%s) ", pin, desc->name);
 
                /* Driver-specific info per pin */
                if (ops->pin_dbg_show)
index ca08723b9ee1e90fdfc792666cc7491ad5fc492e..747c423c11f34ab65a491b3d76fddff7d15e0049 100644 (file)
@@ -134,6 +134,7 @@ struct pinctrl_setting {
  * @name: a name for the pin, e.g. the name of the pin/pad/finger on a
  *     datasheet or such
  * @dynamic_name: if the name of this pin was dynamically allocated
+ * @drv_data: driver-defined per-pin data. pinctrl core does not touch this
  * @mux_usecount: If zero, the pin is not claimed, and @owner should be NULL.
  *     If non-zero, this pin is claimed by @owner. This field is an integer
  *     rather than a boolean, since pinctrl_get() might process multiple
@@ -148,6 +149,7 @@ struct pin_desc {
        struct pinctrl_dev *pctldev;
        const char *name;
        bool dynamic_name;
+       void *drv_data;
        /* These fields only added when supporting pinmux drivers */
 #ifdef CONFIG_PINMUX
        unsigned mux_usecount;
index fe04e748dfe4b5cf036af6e9e2af7ba7c0868b19..54dad89fc9bfe60b23938cc21f1f198311b7f28a 100644 (file)
@@ -195,8 +195,13 @@ int pinctrl_dt_to_map(struct pinctrl *p)
                propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
                prop = of_find_property(np, propname, &size);
                kfree(propname);
-               if (!prop)
+               if (!prop) {
+                       if (state == 0) {
+                               of_node_put(np);
+                               return -ENODEV;
+                       }
                        break;
+               }
                list = prop->value;
                size /= sizeof(*list);
 
index eccb47480e1db12d0212ea54c47b94d4b79d5cc8..71391757938b79b85bf109e6dead4319384c0e7b 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
@@ -46,7 +45,7 @@ struct imx_pinctrl {
        const struct imx_pinctrl_soc_info *info;
 };
 
-static const inline struct imx_pin_group *imx_pinctrl_find_group_by_name(
+static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name(
                                const struct imx_pinctrl_soc_info *info,
                                const char *name)
 {
@@ -513,13 +512,6 @@ static const struct pinconf_ops imx_pinconf_ops = {
        .pin_config_group_dbg_show = imx_pinconf_group_dbg_show,
 };
 
-static struct pinctrl_desc imx_pinctrl_desc = {
-       .pctlops = &imx_pctrl_ops,
-       .pmxops = &imx_pmx_ops,
-       .confops = &imx_pinconf_ops,
-       .owner = THIS_MODULE,
-};
-
 /*
  * Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
  * 1 u32 CONFIG, so 24 types in total for each pin.
@@ -722,6 +714,7 @@ int imx_pinctrl_probe(struct platform_device *pdev,
 {
        struct regmap_config config = { .name = "gpr" };
        struct device_node *dev_np = pdev->dev.of_node;
+       struct pinctrl_desc *imx_pinctrl_desc;
        struct device_node *np;
        struct imx_pinctrl *ipctl;
        struct resource *res;
@@ -776,9 +769,18 @@ int imx_pinctrl_probe(struct platform_device *pdev,
                }
        }
 
-       imx_pinctrl_desc.name = dev_name(&pdev->dev);
-       imx_pinctrl_desc.pins = info->pins;
-       imx_pinctrl_desc.npins = info->npins;
+       imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),
+                                       GFP_KERNEL);
+       if (!imx_pinctrl_desc)
+               return -ENOMEM;
+
+       imx_pinctrl_desc->name = dev_name(&pdev->dev);
+       imx_pinctrl_desc->pins = info->pins;
+       imx_pinctrl_desc->npins = info->npins;
+       imx_pinctrl_desc->pctlops = &imx_pctrl_ops,
+       imx_pinctrl_desc->pmxops = &imx_pmx_ops,
+       imx_pinctrl_desc->confops = &imx_pinconf_ops,
+       imx_pinctrl_desc->owner = THIS_MODULE,
 
        ret = imx_pinctrl_probe_dt(pdev, info);
        if (ret) {
@@ -789,7 +791,8 @@ int imx_pinctrl_probe(struct platform_device *pdev,
        ipctl->info = info;
        ipctl->dev = info->dev;
        platform_set_drvdata(pdev, ipctl);
-       ipctl->pctl = devm_pinctrl_register(&pdev->dev, &imx_pinctrl_desc, ipctl);
+       ipctl->pctl = devm_pinctrl_register(&pdev->dev,
+                                           imx_pinctrl_desc, ipctl);
        if (IS_ERR(ipctl->pctl)) {
                dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
                return PTR_ERR(ipctl->pctl);
index b4400cb19b61be5bc629077875ae19e517cb0f68..a4e9f430d45269c45367cacc1010087971c5596b 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/machine.h>
@@ -157,7 +156,7 @@ static int imx1_read_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
        return !!(readl(reg) & BIT(offset));
 }
 
-static const inline struct imx1_pin_group *imx1_pinctrl_find_group_by_name(
+static inline const struct imx1_pin_group *imx1_pinctrl_find_group_by_name(
                                const struct imx1_pinctrl_soc_info *info,
                                const char *name)
 {
index 04723455db5898656f9ac9712d62c283c9f330fc..fc8efc74873422a2cac3be2d3dabb0b4c4a662b6 100644 (file)
@@ -9,7 +9,7 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -262,7 +262,6 @@ static const struct of_device_id imx1_pinctrl_of_match[] = {
        { .compatible = "fsl,imx1-iomuxc", },
        { }
 };
-MODULE_DEVICE_TABLE(of, imx1_pinctrl_of_match);
 
 static struct platform_driver imx1_pinctrl_driver = {
        .driver = {
@@ -270,8 +269,4 @@ static struct platform_driver imx1_pinctrl_driver = {
                .of_match_table = imx1_pinctrl_of_match,
        },
 };
-module_platform_driver_probe(imx1_pinctrl_driver, imx1_pinctrl_probe);
-
-MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
-MODULE_DESCRIPTION("Freescale i.MX1 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver_probe(imx1_pinctrl_driver, imx1_pinctrl_probe);
index aa1221f4dbb78bce3d6e2ee1b2254b5532a2fd73..73e26bc12f09743ff2837ff6a18b78c2489fa640 100644 (file)
@@ -9,7 +9,7 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -325,7 +325,6 @@ static const struct of_device_id imx21_pinctrl_of_match[] = {
        { .compatible = "fsl,imx21-iomuxc", },
        { }
 };
-MODULE_DEVICE_TABLE(of, imx21_pinctrl_of_match);
 
 static struct platform_driver imx21_pinctrl_driver = {
        .driver = {
@@ -333,8 +332,4 @@ static struct platform_driver imx21_pinctrl_driver = {
                .of_match_table = imx21_pinctrl_of_match,
        },
 };
-module_platform_driver_probe(imx21_pinctrl_driver, imx21_pinctrl_probe);
-
-MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
-MODULE_DESCRIPTION("Freescale i.MX21 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver_probe(imx21_pinctrl_driver, imx21_pinctrl_probe);
index 955cbf4f094f8e8c6f554ba0b69b01fe37a390da..89b4f160138f63379ddcd7985d71580414f80660 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale i.MX23 pinctrl driver
+ *
+ * Author: Shawn Guo <shawn.guo@linaro.org>
  * Copyright 2012 Freescale Semiconductor, Inc.
  *
  * The code contained herein is licensed under the GNU General Public
@@ -10,7 +13,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include "pinctrl-mxs.h"
@@ -276,15 +278,14 @@ static const struct of_device_id imx23_pinctrl_of_match[] = {
        { .compatible = "fsl,imx23-pinctrl", },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, imx23_pinctrl_of_match);
 
 static struct platform_driver imx23_pinctrl_driver = {
        .driver = {
                .name = "imx23-pinctrl",
+               .suppress_bind_attrs = true,
                .of_match_table = imx23_pinctrl_of_match,
        },
        .probe = imx23_pinctrl_probe,
-       .remove = mxs_pinctrl_remove,
 };
 
 static int __init imx23_pinctrl_init(void)
@@ -292,13 +293,3 @@ static int __init imx23_pinctrl_init(void)
        return platform_driver_register(&imx23_pinctrl_driver);
 }
 postcore_initcall(imx23_pinctrl_init);
-
-static void __exit imx23_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx23_pinctrl_driver);
-}
-module_exit(imx23_pinctrl_exit);
-
-MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
-MODULE_DESCRIPTION("Freescale i.MX23 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 81ad546d74bb14ffc46105a8ccf90334872d0ff7..d7367fabe7123063564d474521453498f8288d83 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -338,12 +337,3 @@ static int __init imx25_pinctrl_init(void)
        return platform_driver_register(&imx25_pinctrl_driver);
 }
 arch_initcall(imx25_pinctrl_init);
-
-static void __exit imx25_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx25_pinctrl_driver);
-}
-module_exit(imx25_pinctrl_exit);
-MODULE_AUTHOR("Denis Carikli <denis@eukrea.com>");
-MODULE_DESCRIPTION("Freescale IMX25 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index f828fbbba4b901ca31f518701588cf9283774bf3..e5992036fc6c02b2e6a352bfc20356d8df30ba22 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -412,12 +411,3 @@ static int __init imx27_pinctrl_init(void)
        return platform_driver_register(&imx27_pinctrl_driver);
 }
 arch_initcall(imx27_pinctrl_init);
-
-static void __exit imx27_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx27_pinctrl_driver);
-}
-module_exit(imx27_pinctrl_exit);
-MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
-MODULE_DESCRIPTION("Freescale IMX27 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 5082efec4f7241598f9863209494cfc19672ded1..295236dfb0bc214dc3f335bf650921e8e715a9c1 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale i.MX28 pinctrl driver
+ *
+ * Author: Shawn Guo <shawn.guo@linaro.org>
  * Copyright 2012 Freescale Semiconductor, Inc.
  *
  * The code contained herein is licensed under the GNU General Public
@@ -10,7 +13,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include "pinctrl-mxs.h"
@@ -392,15 +394,14 @@ static const struct of_device_id imx28_pinctrl_of_match[] = {
        { .compatible = "fsl,imx28-pinctrl", },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, imx28_pinctrl_of_match);
 
 static struct platform_driver imx28_pinctrl_driver = {
        .driver = {
                .name = "imx28-pinctrl",
+               .suppress_bind_attrs = true,
                .of_match_table = imx28_pinctrl_of_match,
        },
        .probe = imx28_pinctrl_probe,
-       .remove = mxs_pinctrl_remove,
 };
 
 static int __init imx28_pinctrl_init(void)
@@ -408,13 +409,3 @@ static int __init imx28_pinctrl_init(void)
        return platform_driver_register(&imx28_pinctrl_driver);
 }
 postcore_initcall(imx28_pinctrl_init);
-
-static void __exit imx28_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx28_pinctrl_driver);
-}
-module_exit(imx28_pinctrl_exit);
-
-MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
-MODULE_DESCRIPTION("Freescale i.MX28 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 13eb224a29a920e4b93413e5570163e17b978010..6315ba6af431dc4cf208e921b6b75107b51a5442 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -1028,12 +1027,3 @@ static int __init imx35_pinctrl_init(void)
        return platform_driver_register(&imx35_pinctrl_driver);
 }
 arch_initcall(imx35_pinctrl_init);
-
-static void __exit imx35_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx35_pinctrl_driver);
-}
-module_exit(imx35_pinctrl_exit);
-MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
-MODULE_DESCRIPTION("Freescale IMX35 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 95a36c88b66a0ccb27f2ae8a641b234c093d0712..8e3a17df5c5da2a8220ae0cec87d81d1e162f400 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -415,11 +414,3 @@ static int __init imx50_pinctrl_init(void)
        return platform_driver_register(&imx50_pinctrl_driver);
 }
 arch_initcall(imx50_pinctrl_init);
-
-static void __exit imx50_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx50_pinctrl_driver);
-}
-module_exit(imx50_pinctrl_exit);
-MODULE_DESCRIPTION("Freescale IMX50 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 0863e5279896c52e392abc73aceaf93c6429a1bf..eeac64ba270934feb727702555477fefc0784f49 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -791,12 +790,3 @@ static int __init imx51_pinctrl_init(void)
        return platform_driver_register(&imx51_pinctrl_driver);
 }
 arch_initcall(imx51_pinctrl_init);
-
-static void __exit imx51_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx51_pinctrl_driver);
-}
-module_exit(imx51_pinctrl_exit);
-MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
-MODULE_DESCRIPTION("Freescale IMX51 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 64c9cbe2a5df723fe885b73761209f0f851c6b0a..46a9572f3473a763e5c7f3fcd06af22301effedb 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -478,12 +477,3 @@ static int __init imx53_pinctrl_init(void)
        return platform_driver_register(&imx53_pinctrl_driver);
 }
 arch_initcall(imx53_pinctrl_init);
-
-static void __exit imx53_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx53_pinctrl_driver);
-}
-module_exit(imx53_pinctrl_exit);
-MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
-MODULE_DESCRIPTION("Freescale IMX53 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index de17bac8ad89dfd29a58e5e06472350614543fab..3f25ca5867cc60c9fcad2342210001de35a1a7d1 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx6dl pinctrl driver
+ *
+ * Author: Shawn Guo <shawn.guo@linaro.org>
  * Copyright (C) 2013 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -484,13 +486,3 @@ static int __init imx6dl_pinctrl_init(void)
        return platform_driver_register(&imx6dl_pinctrl_driver);
 }
 arch_initcall(imx6dl_pinctrl_init);
-
-static void __exit imx6dl_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6dl_pinctrl_driver);
-}
-module_exit(imx6dl_pinctrl_exit);
-
-MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
-MODULE_DESCRIPTION("Freescale imx6dl pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 55cd8a0e367d5d73aca3360e48887b9ffc206d50..d61651c40458b8bbf1adc76285921918f9ab93df 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -490,12 +489,3 @@ static int __init imx6q_pinctrl_init(void)
        return platform_driver_register(&imx6q_pinctrl_driver);
 }
 arch_initcall(imx6q_pinctrl_init);
-
-static void __exit imx6q_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6q_pinctrl_driver);
-}
-module_exit(imx6q_pinctrl_exit);
-MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
-MODULE_DESCRIPTION("Freescale IMX6Q pinctrl driver");
-MODULE_LICENSE("GPL v2");
index bf455b8e73fcaba2da51b94a1707419e1b72a090..d023f6b006235ec2ffc803acc8158611b5b9de2b 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx6sl pinctrl driver
+ *
+ * Author: Shawn Guo <shawn.guo@linaro.org>
  * Copyright (C) 2013 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -371,7 +373,6 @@ static const struct of_device_id imx6sl_pinctrl_of_match[] = {
        { .compatible = "fsl,imx6sl-iomuxc", },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, imx6sl_pinctrl_of_match);
 
 static int imx6sl_pinctrl_probe(struct platform_device *pdev)
 {
@@ -391,13 +392,3 @@ static int __init imx6sl_pinctrl_init(void)
        return platform_driver_register(&imx6sl_pinctrl_driver);
 }
 arch_initcall(imx6sl_pinctrl_init);
-
-static void __exit imx6sl_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6sl_pinctrl_driver);
-}
-module_exit(imx6sl_pinctrl_exit);
-
-MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
-MODULE_DESCRIPTION("Freescale imx6sl pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 84118c388cc5d4f4de9372b4ff42b2d0bb91a013..898b781701e64162e6d7bbe300dc2473aba7ea5d 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx6sx pinctrl driver
+ *
+ * Author: Anson Huang <Anson.Huang@freescale.com>
  * Copyright (C) 2014 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -394,13 +396,3 @@ static int __init imx6sx_pinctrl_init(void)
        return platform_driver_register(&imx6sx_pinctrl_driver);
 }
 arch_initcall(imx6sx_pinctrl_init);
-
-static void __exit imx6sx_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6sx_pinctrl_driver);
-}
-module_exit(imx6sx_pinctrl_exit);
-
-MODULE_AUTHOR("Anson Huang <Anson.Huang@freescale.com>");
-MODULE_DESCRIPTION("Freescale imx6sx pinctrl driver");
-MODULE_LICENSE("GPL v2");
index c707fdd933ecace46d23d68418c8fb00623c89dc..1aeb840aae1d88a4ec8a6ced72f51459d9cff955 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx6ul pinctrl driver
+ *
+ * Author: Anson Huang <Anson.Huang@freescale.com>
  * Copyright (C) 2015 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -310,13 +312,3 @@ static int __init imx6ul_pinctrl_init(void)
        return platform_driver_register(&imx6ul_pinctrl_driver);
 }
 arch_initcall(imx6ul_pinctrl_init);
-
-static void __exit imx6ul_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6ul_pinctrl_driver);
-}
-module_exit(imx6ul_pinctrl_exit);
-
-MODULE_AUTHOR("Anson Huang <Anson.Huang@freescale.com>");
-MODULE_DESCRIPTION("Freescale imx6ul pinctrl driver");
-MODULE_LICENSE("GPL v2");
index d30d91f80dfdb695db646cc475f036f6f7df351c..a465a66c3ef446d6772a7b4effcbdd62dce1704f 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx7d pinctrl driver
+ *
+ * Author: Anson Huang <Anson.Huang@freescale.com>
  * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -402,13 +404,3 @@ static int __init imx7d_pinctrl_init(void)
        return platform_driver_register(&imx7d_pinctrl_driver);
 }
 arch_initcall(imx7d_pinctrl_init);
-
-static void __exit imx7d_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx7d_pinctrl_driver);
-}
-module_exit(imx7d_pinctrl_exit);
-
-MODULE_AUTHOR("Anson Huang <Anson.Huang@freescale.com>");
-MODULE_DESCRIPTION("Freescale imx7d pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 6bbda6b4ab50d9e930544e4bfd72a67904261f85..41b5b07d5a2bf51f6b0623597c294862910de78c 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/pinctrl/machine.h>
@@ -553,14 +552,3 @@ err:
        return ret;
 }
 EXPORT_SYMBOL_GPL(mxs_pinctrl_probe);
-
-int mxs_pinctrl_remove(struct platform_device *pdev)
-{
-       struct mxs_pinctrl_data *d = platform_get_drvdata(pdev);
-
-       pinctrl_unregister(d->pctl);
-       iounmap(d->base);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(mxs_pinctrl_remove);
index fdd88d0bae22c843898b5240267fa6047ea5dc1b..34dbf75208dc7beb854e82607b59d2ed1030c71a 100644 (file)
@@ -86,6 +86,5 @@ struct mxs_pinctrl_soc_data {
 
 int mxs_pinctrl_probe(struct platform_device *pdev,
                      struct mxs_pinctrl_soc_data *soc);
-int mxs_pinctrl_remove(struct platform_device *pdev);
 
 #endif /* __PINCTRL_MXS_H */
index 6d81be096bc0d9bc3949c86b5edbdfa924a6b249..2b1e198e30927addc01e623cb2fa3abb4438bc57 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -325,12 +324,3 @@ static int __init vf610_pinctrl_init(void)
        return platform_driver_register(&vf610_pinctrl_driver);
 }
 arch_initcall(vf610_pinctrl_init);
-
-static void __exit vf610_pinctrl_exit(void)
-{
-       platform_driver_unregister(&vf610_pinctrl_driver);
-}
-module_exit(vf610_pinctrl_exit);
-
-MODULE_DESCRIPTION("Freescale VF610 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 1c74e038b7b0066164fe874dd1e9cba1bd25f7e6..00fb055a489794597c6abf45b6909c4a2907db88 100644 (file)
@@ -29,6 +29,17 @@ config PINCTRL_CHERRYVIEW
          Cherryview/Braswell pinctrl driver provides an interface that
          allows configuring of SoC pins and using them as GPIOs.
 
+config PINCTRL_MERRIFIELD
+       tristate "Intel Merrifield pinctrl driver"
+       depends on X86_INTEL_MID
+       select PINMUX
+       select PINCONF
+       select GENERIC_PINCONF
+       help
+         Merrifield Family-Level Interface Shim (FLIS) driver provides an
+         interface that allows configuring of SoC pins and using them as
+         GPIOs.
+
 config PINCTRL_INTEL
        tristate
        select PINMUX
index 03bc68e3546cad35f8aa765222bb10a240735778..30803078f09eeb6865cb1cf9ffac886c3d9ca6e0 100644 (file)
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_PINCTRL_BAYTRAIL)         += pinctrl-baytrail.o
 obj-$(CONFIG_PINCTRL_CHERRYVIEW)       += pinctrl-cherryview.o
+obj-$(CONFIG_PINCTRL_MERRIFIELD)       += pinctrl-merrifield.o
 obj-$(CONFIG_PINCTRL_INTEL)            += pinctrl-intel.o
 obj-$(CONFIG_PINCTRL_BROXTON)          += pinctrl-broxton.o
 obj-$(CONFIG_PINCTRL_SUNRISEPOINT)     += pinctrl-sunrisepoint.o
index 7abfd42e8ffdf86953764ad2fa2c1c9bf70fcc57..d22a9fe2e6dfc36d63f9e493b61f2f35c2e21f97 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
@@ -1822,17 +1821,6 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int byt_pinctrl_remove(struct platform_device *pdev)
-{
-       struct byt_gpio *vg = platform_get_drvdata(pdev);
-
-       pm_runtime_disable(&pdev->dev);
-       gpiochip_remove(&vg->chip);
-       pinctrl_unregister(vg->pctl_dev);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int byt_gpio_suspend(struct device *dev)
 {
@@ -1930,10 +1918,11 @@ static const struct dev_pm_ops byt_gpio_pm_ops = {
 
 static struct platform_driver byt_gpio_driver = {
        .probe          = byt_pinctrl_probe,
-       .remove         = byt_pinctrl_remove,
        .driver         = {
-               .name   = "byt_gpio",
-               .pm     = &byt_gpio_pm_ops,
+               .name                   = "byt_gpio",
+               .pm                     = &byt_gpio_pm_ops,
+               .suppress_bind_attrs    = true,
+
                .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match),
        },
 };
@@ -1943,9 +1932,3 @@ static int __init byt_gpio_init(void)
        return platform_driver_register(&byt_gpio_driver);
 }
 subsys_initcall(byt_gpio_init);
-
-static void __exit byt_gpio_exit(void)
-{
-       platform_driver_unregister(&byt_gpio_driver);
-}
-module_exit(byt_gpio_exit);
index 5979d38c46b254965e8a7782de9a6c902894ce9a..59cb7a6fc5bef316d042f93da72792edca2ea8d9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Intel Broxton SoC pinctrl/GPIO driver
  *
- * Copyright (C) 2015, Intel Corporation
+ * Copyright (C) 2015, 2016 Intel Corporation
  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -1003,29 +1003,46 @@ static const struct acpi_device_id bxt_pinctrl_acpi_match[] = {
 };
 MODULE_DEVICE_TABLE(acpi, bxt_pinctrl_acpi_match);
 
+static const struct platform_device_id bxt_pinctrl_platform_ids[] = {
+       { "apl-pinctrl", (kernel_ulong_t)&apl_pinctrl_soc_data },
+       { "broxton-pinctrl", (kernel_ulong_t)&bxt_pinctrl_soc_data },
+       { },
+};
+
 static int bxt_pinctrl_probe(struct platform_device *pdev)
 {
        const struct intel_pinctrl_soc_data *soc_data = NULL;
        const struct intel_pinctrl_soc_data **soc_table;
-       const struct acpi_device_id *id;
        struct acpi_device *adev;
        int i;
 
        adev = ACPI_COMPANION(&pdev->dev);
-       if (!adev)
-               return -ENODEV;
+       if (adev) {
+               const struct acpi_device_id *id;
 
-       id = acpi_match_device(bxt_pinctrl_acpi_match, &pdev->dev);
-       if (!id)
-               return -ENODEV;
+               id = acpi_match_device(bxt_pinctrl_acpi_match, &pdev->dev);
+               if (!id)
+                       return -ENODEV;
 
-       soc_table = (const struct intel_pinctrl_soc_data **)id->driver_data;
+               soc_table = (const struct intel_pinctrl_soc_data **)
+                       id->driver_data;
 
-       for (i = 0; soc_table[i]; i++) {
-               if (!strcmp(adev->pnp.unique_id, soc_table[i]->uid)) {
-                       soc_data = soc_table[i];
-                       break;
+               for (i = 0; soc_table[i]; i++) {
+                       if (!strcmp(adev->pnp.unique_id, soc_table[i]->uid)) {
+                               soc_data = soc_table[i];
+                               break;
+                       }
                }
+       } else {
+               const struct platform_device_id *pid;
+
+               pid = platform_get_device_id(pdev);
+               if (!pid)
+                       return -ENODEV;
+
+               soc_table = (const struct intel_pinctrl_soc_data **)
+                       pid->driver_data;
+               soc_data = soc_table[pdev->id];
        }
 
        if (!soc_data)
@@ -1047,6 +1064,7 @@ static struct platform_driver bxt_pinctrl_driver = {
                .acpi_match_table = bxt_pinctrl_acpi_match,
                .pm = &bxt_pinctrl_pm_ops,
        },
+       .id_table = bxt_pinctrl_platform_ids,
 };
 
 static int __init bxt_pinctrl_init(void)
@@ -1064,3 +1082,4 @@ module_exit(bxt_pinctrl_exit);
 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
 MODULE_DESCRIPTION("Intel Broxton SoC pinctrl/GPIO driver");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:broxton-pinctrl");
index ac4f564f1c3ef3b6ab46c9ec8e51e4d1cab2d7f4..5749a4eee746da45fdef1d4f39cabab607160408 100644 (file)
@@ -160,7 +160,6 @@ struct chv_pin_context {
  * @pctldev: Pointer to the pin controller device
  * @chip: GPIO chip in this pin controller
  * @regs: MMIO registers
- * @lock: Lock to serialize register accesses
  * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO
  *             offset (in GPIO number space)
  * @community: Community this pinctrl instance represents
@@ -174,7 +173,6 @@ struct chv_pinctrl {
        struct pinctrl_dev *pctldev;
        struct gpio_chip chip;
        void __iomem *regs;
-       raw_spinlock_t lock;
        unsigned intr_lines[16];
        const struct chv_community *community;
        u32 saved_intmask;
@@ -657,6 +655,17 @@ static const struct chv_community *chv_communities[] = {
        &southeast_community,
 };
 
+/*
+ * Lock to serialize register accesses
+ *
+ * Due to a silicon issue, a shared lock must be used to prevent
+ * concurrent accesses across the 4 GPIO controllers.
+ *
+ * See Intel Atom Z8000 Processor Series Specification Update (Rev. 005),
+ * errata #CHT34, for further information.
+ */
+static DEFINE_RAW_SPINLOCK(chv_lock);
+
 static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset,
                                unsigned reg)
 {
@@ -718,13 +727,13 @@ static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
        u32 ctrl0, ctrl1;
        bool locked;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
        ctrl1 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL1));
        locked = chv_pad_locked(pctrl, offset);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        if (ctrl0 & CHV_PADCTRL0_GPIOEN) {
                seq_puts(s, "GPIO ");
@@ -787,14 +796,14 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
 
        grp = &pctrl->community->groups[group];
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        /* Check first that the pad is not locked */
        for (i = 0; i < grp->npins; i++) {
                if (chv_pad_locked(pctrl, grp->pins[i])) {
                        dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n",
                                 grp->pins[i]);
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EBUSY;
                }
        }
@@ -837,7 +846,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
                        pin, altfunc->mode, altfunc->invert_oe ? "" : "not ");
        }
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -851,13 +860,13 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
        void __iomem *reg;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        if (chv_pad_locked(pctrl, offset)) {
                value = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
                if (!(value & CHV_PADCTRL0_GPIOEN)) {
                        /* Locked so cannot enable */
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EBUSY;
                }
        } else {
@@ -897,7 +906,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
                chv_writel(value, reg);
        }
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -911,13 +920,13 @@ static void chv_gpio_disable_free(struct pinctrl_dev *pctldev,
        void __iomem *reg;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        reg = chv_padreg(pctrl, offset, CHV_PADCTRL0);
        value = readl(reg) & ~CHV_PADCTRL0_GPIOEN;
        chv_writel(value, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -929,7 +938,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
        unsigned long flags;
        u32 ctrl0;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        ctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIOCFG_MASK;
        if (input)
@@ -938,7 +947,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
                ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT;
        chv_writel(ctrl0, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -963,10 +972,10 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin,
        u16 arg = 0;
        u32 term;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        ctrl1 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT;
 
@@ -1040,7 +1049,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
        unsigned long flags;
        u32 ctrl0, pull;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(reg);
 
        switch (param) {
@@ -1063,7 +1072,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                        pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
                        break;
                default:
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EINVAL;
                }
 
@@ -1081,7 +1090,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                        pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
                        break;
                default:
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EINVAL;
                }
 
@@ -1089,12 +1098,33 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                break;
 
        default:
-               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&chv_lock, flags);
                return -EINVAL;
        }
 
        chv_writel(ctrl0, reg);
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
+
+       return 0;
+}
+
+static int chv_config_set_oden(struct chv_pinctrl *pctrl, unsigned int pin,
+                              bool enable)
+{
+       void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL1);
+       unsigned long flags;
+       u32 ctrl1;
+
+       raw_spin_lock_irqsave(&chv_lock, flags);
+       ctrl1 = readl(reg);
+
+       if (enable)
+               ctrl1 |= CHV_PADCTRL1_ODEN;
+       else
+               ctrl1 &= ~CHV_PADCTRL1_ODEN;
+
+       chv_writel(ctrl1, reg);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -1123,6 +1153,18 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin,
                                return ret;
                        break;
 
+               case PIN_CONFIG_DRIVE_PUSH_PULL:
+                       ret = chv_config_set_oden(pctrl, pin, false);
+                       if (ret)
+                               return ret;
+                       break;
+
+               case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+                       ret = chv_config_set_oden(pctrl, pin, true);
+                       if (ret)
+                               return ret;
+                       break;
+
                default:
                        return -ENOTSUPP;
                }
@@ -1134,10 +1176,52 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin,
        return 0;
 }
 
+static int chv_config_group_get(struct pinctrl_dev *pctldev,
+                               unsigned int group,
+                               unsigned long *config)
+{
+       const unsigned int *pins;
+       unsigned int npins;
+       int ret;
+
+       ret = chv_get_group_pins(pctldev, group, &pins, &npins);
+       if (ret)
+               return ret;
+
+       ret = chv_config_get(pctldev, pins[0], config);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int chv_config_group_set(struct pinctrl_dev *pctldev,
+                               unsigned int group, unsigned long *configs,
+                               unsigned int num_configs)
+{
+       const unsigned int *pins;
+       unsigned int npins;
+       int i, ret;
+
+       ret = chv_get_group_pins(pctldev, group, &pins, &npins);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < npins; i++) {
+               ret = chv_config_set(pctldev, pins[i], configs, num_configs);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static const struct pinconf_ops chv_pinconf_ops = {
        .is_generic = true,
        .pin_config_set = chv_config_set,
        .pin_config_get = chv_config_get,
+       .pin_config_group_get = chv_config_group_get,
+       .pin_config_group_set = chv_config_group_set,
 };
 
 static struct pinctrl_desc chv_pinctrl_desc = {
@@ -1160,9 +1244,9 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
        unsigned long flags;
        u32 ctrl0, cfg;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
        cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
@@ -1180,7 +1264,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        void __iomem *reg;
        u32 ctrl0;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
        ctrl0 = readl(reg);
@@ -1192,7 +1276,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 
        chv_writel(ctrl0, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -1202,9 +1286,9 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
        u32 ctrl0, direction;
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
        direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
@@ -1242,14 +1326,14 @@ static void chv_gpio_irq_ack(struct irq_data *d)
        int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
        u32 intr_line;
 
-       raw_spin_lock(&pctrl->lock);
+       raw_spin_lock(&chv_lock);
 
        intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        intr_line &= CHV_PADCTRL0_INTSEL_MASK;
        intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT;
        chv_writel(BIT(intr_line), pctrl->regs + CHV_INTSTAT);
 
-       raw_spin_unlock(&pctrl->lock);
+       raw_spin_unlock(&chv_lock);
 }
 
 static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
@@ -1260,7 +1344,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
        u32 value, intr_line;
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        intr_line &= CHV_PADCTRL0_INTSEL_MASK;
@@ -1273,7 +1357,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
                value |= BIT(intr_line);
        chv_writel(value, pctrl->regs + CHV_INTMASK);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static void chv_gpio_irq_mask(struct irq_data *d)
@@ -1307,7 +1391,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
                unsigned long flags;
                u32 intsel, value;
 
-               raw_spin_lock_irqsave(&pctrl->lock, flags);
+               raw_spin_lock_irqsave(&chv_lock, flags);
                intsel = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
                intsel &= CHV_PADCTRL0_INTSEL_MASK;
                intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
@@ -1322,7 +1406,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
                        irq_set_handler_locked(d, handler);
                        pctrl->intr_lines[intsel] = offset;
                }
-               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&chv_lock, flags);
        }
 
        chv_gpio_irq_unmask(d);
@@ -1338,7 +1422,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
        unsigned long flags;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        /*
         * Pins which can be used as shared interrupt are configured in
@@ -1387,7 +1471,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
        else if (type & IRQ_TYPE_LEVEL_MASK)
                irq_set_handler_locked(d, handle_level_irq);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -1499,7 +1583,6 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
        if (i == ARRAY_SIZE(chv_communities))
                return -ENODEV;
 
-       raw_spin_lock_init(&pctrl->lock);
        pctrl->dev = &pdev->dev;
 
 #ifdef CONFIG_PM_SLEEP
index 3584e50fa2c6908d32419395679774158f13f0b6..257cab12969257d44c2e8bad1993575034e82aa8 100644 (file)
@@ -89,7 +89,7 @@ struct intel_pinctrl_context {
  */
 struct intel_pinctrl {
        struct device *dev;
-       spinlock_t lock;
+       raw_spinlock_t lock;
        struct pinctrl_desc pctldesc;
        struct pinctrl_dev *pctldev;
        struct gpio_chip chip;
@@ -318,7 +318,7 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
        unsigned long flags;
        int i;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        /*
         * All pins in the groups needs to be accessible and writable
@@ -326,7 +326,7 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
         */
        for (i = 0; i < grp->npins; i++) {
                if (!intel_pad_usable(pctrl, grp->pins[i])) {
-                       spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
                        return -EBUSY;
                }
        }
@@ -345,7 +345,7 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
                writel(value, padcfg0);
        }
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -359,10 +359,10 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
        unsigned long flags;
        u32 value;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        if (!intel_pad_usable(pctrl, pin)) {
-               spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
                return -EBUSY;
        }
 
@@ -377,7 +377,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
        value |= PADCFG0_GPIOTXDIS;
        writel(value, padcfg0);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -391,7 +391,7 @@ static int intel_gpio_set_direction(struct pinctrl_dev *pctldev,
        unsigned long flags;
        u32 value;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
 
@@ -402,7 +402,7 @@ static int intel_gpio_set_direction(struct pinctrl_dev *pctldev,
                value &= ~PADCFG0_GPIOTXDIS;
        writel(value, padcfg0);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -490,7 +490,7 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
        int ret = 0;
        u32 value;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1);
        value = readl(padcfg1);
@@ -544,7 +544,7 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
        if (!ret)
                writel(value, padcfg1);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return ret;
 }
@@ -611,14 +611,14 @@ static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                unsigned long flags;
                u32 padcfg0;
 
-               spin_lock_irqsave(&pctrl->lock, flags);
+               raw_spin_lock_irqsave(&pctrl->lock, flags);
                padcfg0 = readl(reg);
                if (value)
                        padcfg0 |= PADCFG0_GPIOTXSTATE;
                else
                        padcfg0 &= ~PADCFG0_GPIOTXSTATE;
                writel(padcfg0, reg);
-               spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
        }
 }
 
@@ -651,7 +651,7 @@ static void intel_gpio_irq_ack(struct irq_data *d)
        const struct intel_community *community;
        unsigned pin = irqd_to_hwirq(d);
 
-       spin_lock(&pctrl->lock);
+       raw_spin_lock(&pctrl->lock);
 
        community = intel_get_community(pctrl, pin);
        if (community) {
@@ -662,7 +662,7 @@ static void intel_gpio_irq_ack(struct irq_data *d)
                writel(BIT(gpp_offset), community->regs + GPI_IS + gpp * 4);
        }
 
-       spin_unlock(&pctrl->lock);
+       raw_spin_unlock(&pctrl->lock);
 }
 
 static void intel_gpio_irq_enable(struct irq_data *d)
@@ -673,7 +673,7 @@ static void intel_gpio_irq_enable(struct irq_data *d)
        unsigned pin = irqd_to_hwirq(d);
        unsigned long flags;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        community = intel_get_community(pctrl, pin);
        if (community) {
@@ -691,7 +691,7 @@ static void intel_gpio_irq_enable(struct irq_data *d)
                writel(value, community->regs + community->ie_offset + gpp * 4);
        }
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
 static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
@@ -702,7 +702,7 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
        unsigned pin = irqd_to_hwirq(d);
        unsigned long flags;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        community = intel_get_community(pctrl, pin);
        if (community) {
@@ -721,7 +721,7 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
                writel(value, reg);
        }
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
 static void intel_gpio_irq_mask(struct irq_data *d)
@@ -757,7 +757,7 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
                return -EPERM;
        }
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        value = readl(reg);
 
@@ -784,7 +784,7 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
        else if (type & IRQ_TYPE_LEVEL_MASK)
                irq_set_handler_locked(d, handle_level_irq);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -796,12 +796,15 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
        const struct intel_community *community;
        unsigned pin = irqd_to_hwirq(d);
        unsigned padno, gpp, gpp_offset;
+       unsigned long flags;
        u32 gpe_en;
 
        community = intel_get_community(pctrl, pin);
        if (!community)
                return -EINVAL;
 
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+
        padno = pin_to_padno(community, pin);
        gpp = padno / community->gpp_size;
        gpp_offset = padno % community->gpp_size;
@@ -821,6 +824,8 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
                gpe_en &= ~BIT(gpp_offset);
        writel(gpe_en, community->regs + GPI_GPE_EN + gpp * 4);
 
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
        dev_dbg(pctrl->dev, "%sable wake for pin %u\n", on ? "en" : "dis", pin);
        return 0;
 }
@@ -919,7 +924,8 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
         * to the irq directly) because on some platforms several GPIO
         * controllers share the same interrupt line.
         */
-       ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq, IRQF_SHARED,
+       ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq,
+                              IRQF_SHARED | IRQF_NO_THREAD,
                               dev_name(pctrl->dev), pctrl);
        if (ret) {
                dev_err(pctrl->dev, "failed to request interrupt\n");
@@ -995,7 +1001,7 @@ int intel_pinctrl_probe(struct platform_device *pdev,
 
        pctrl->dev = &pdev->dev;
        pctrl->soc = soc_data;
-       spin_lock_init(&pctrl->lock);
+       raw_spin_lock_init(&pctrl->lock);
 
        /*
         * Make a copy of the communities which we can use to hold pointers
diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c
new file mode 100644 (file)
index 0000000..eb4990f
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * Intel Merrifield SoC pinctrl driver
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-intel.h"
+
+#define MRFLD_FAMILY_NR                        64
+#define MRFLD_FAMILY_LEN               0x400
+
+#define SLEW_OFFSET                    0x000
+#define BUFCFG_OFFSET                  0x100
+#define MISC_OFFSET                    0x300
+
+#define BUFCFG_PINMODE_SHIFT           0
+#define BUFCFG_PINMODE_MASK            GENMASK(2, 0)
+#define BUFCFG_PINMODE_GPIO            0
+#define BUFCFG_PUPD_VAL_SHIFT          4
+#define BUFCFG_PUPD_VAL_MASK           GENMASK(5, 4)
+#define BUFCFG_PUPD_VAL_2K             0
+#define BUFCFG_PUPD_VAL_20K            1
+#define BUFCFG_PUPD_VAL_50K            2
+#define BUFCFG_PUPD_VAL_910            3
+#define BUFCFG_PU_EN                   BIT(8)
+#define BUFCFG_PD_EN                   BIT(9)
+#define BUFCFG_Px_EN_MASK              GENMASK(9, 8)
+#define BUFCFG_SLEWSEL                 BIT(10)
+#define BUFCFG_OVINEN                  BIT(12)
+#define BUFCFG_OVINEN_EN               BIT(13)
+#define BUFCFG_OVINEN_MASK             GENMASK(13, 12)
+#define BUFCFG_OVOUTEN                 BIT(14)
+#define BUFCFG_OVOUTEN_EN              BIT(15)
+#define BUFCFG_OVOUTEN_MASK            GENMASK(15, 14)
+#define BUFCFG_INDATAOV_VAL            BIT(16)
+#define BUFCFG_INDATAOV_EN             BIT(17)
+#define BUFCFG_INDATAOV_MASK           GENMASK(17, 16)
+#define BUFCFG_OUTDATAOV_VAL           BIT(18)
+#define BUFCFG_OUTDATAOV_EN            BIT(19)
+#define BUFCFG_OUTDATAOV_MASK          GENMASK(19, 18)
+#define BUFCFG_OD_EN                   BIT(21)
+
+/**
+ * struct mrfld_family - Intel pin family description
+ * @barno: MMIO BAR number where registers for this family reside
+ * @pin_base: Starting pin of pins in this family
+ * @npins: Number of pins in this family
+ * @protected: True if family is protected by access
+ * @regs: family specific common registers
+ */
+struct mrfld_family {
+       unsigned int barno;
+       unsigned int pin_base;
+       size_t npins;
+       bool protected;
+       void __iomem *regs;
+};
+
+#define MRFLD_FAMILY(b, s, e)                          \
+       {                                               \
+               .barno = (b),                           \
+               .pin_base = (s),                        \
+               .npins = (e) - (s) + 1,                 \
+       }
+
+#define MRFLD_FAMILY_PROTECTED(b, s, e)                        \
+       {                                               \
+               .barno = (b),                           \
+               .pin_base = (s),                        \
+               .npins = (e) - (s) + 1,                 \
+               .protected = true,                      \
+       }
+
+static const struct pinctrl_pin_desc mrfld_pins[] = {
+       /* Family 0: OCP2SSC (0 pins) */
+       /* Family 1: ULPI (13 pins) */
+       PINCTRL_PIN(0, "ULPI_CLK"),
+       PINCTRL_PIN(1, "ULPI_D0"),
+       PINCTRL_PIN(2, "ULPI_D1"),
+       PINCTRL_PIN(3, "ULPI_D2"),
+       PINCTRL_PIN(4, "ULPI_D3"),
+       PINCTRL_PIN(5, "ULPI_D4"),
+       PINCTRL_PIN(6, "ULPI_D5"),
+       PINCTRL_PIN(7, "ULPI_D6"),
+       PINCTRL_PIN(8, "ULPI_D7"),
+       PINCTRL_PIN(9, "ULPI_DIR"),
+       PINCTRL_PIN(10, "ULPI_NXT"),
+       PINCTRL_PIN(11, "ULPI_REFCLK"),
+       PINCTRL_PIN(12, "ULPI_STP"),
+       /* Family 2: eMMC (24 pins) */
+       PINCTRL_PIN(13, "EMMC_CLK"),
+       PINCTRL_PIN(14, "EMMC_CMD"),
+       PINCTRL_PIN(15, "EMMC_D0"),
+       PINCTRL_PIN(16, "EMMC_D1"),
+       PINCTRL_PIN(17, "EMMC_D2"),
+       PINCTRL_PIN(18, "EMMC_D3"),
+       PINCTRL_PIN(19, "EMMC_D4"),
+       PINCTRL_PIN(20, "EMMC_D5"),
+       PINCTRL_PIN(21, "EMMC_D6"),
+       PINCTRL_PIN(22, "EMMC_D7"),
+       PINCTRL_PIN(23, "EMMC_RST_N"),
+       PINCTRL_PIN(24, "GP154"),
+       PINCTRL_PIN(25, "GP155"),
+       PINCTRL_PIN(26, "GP156"),
+       PINCTRL_PIN(27, "GP157"),
+       PINCTRL_PIN(28, "GP158"),
+       PINCTRL_PIN(29, "GP159"),
+       PINCTRL_PIN(30, "GP160"),
+       PINCTRL_PIN(31, "GP161"),
+       PINCTRL_PIN(32, "GP162"),
+       PINCTRL_PIN(33, "GP163"),
+       PINCTRL_PIN(34, "GP97"),
+       PINCTRL_PIN(35, "GP14"),
+       PINCTRL_PIN(36, "GP15"),
+       /* Family 3: SDIO (20 pins) */
+       PINCTRL_PIN(37, "GP77_SD_CD"),
+       PINCTRL_PIN(38, "GP78_SD_CLK"),
+       PINCTRL_PIN(39, "GP79_SD_CMD"),
+       PINCTRL_PIN(40, "GP80_SD_D0"),
+       PINCTRL_PIN(41, "GP81_SD_D1"),
+       PINCTRL_PIN(42, "GP82_SD_D2"),
+       PINCTRL_PIN(43, "GP83_SD_D3"),
+       PINCTRL_PIN(44, "GP84_SD_LS_CLK_FB"),
+       PINCTRL_PIN(45, "GP85_SD_LS_CMD_DIR"),
+       PINCTRL_PIN(46, "GP86_SD_LVL_D_DIR"),
+       PINCTRL_PIN(47, "GP88_SD_LS_SEL"),
+       PINCTRL_PIN(48, "GP87_SD_PD"),
+       PINCTRL_PIN(49, "GP89_SD_WP"),
+       PINCTRL_PIN(50, "GP90_SDIO_CLK"),
+       PINCTRL_PIN(51, "GP91_SDIO_CMD"),
+       PINCTRL_PIN(52, "GP92_SDIO_D0"),
+       PINCTRL_PIN(53, "GP93_SDIO_D1"),
+       PINCTRL_PIN(54, "GP94_SDIO_D2"),
+       PINCTRL_PIN(55, "GP95_SDIO_D3"),
+       PINCTRL_PIN(56, "GP96_SDIO_PD"),
+       /* Family 4: HSI (8 pins) */
+       PINCTRL_PIN(57, "HSI_ACDATA"),
+       PINCTRL_PIN(58, "HSI_ACFLAG"),
+       PINCTRL_PIN(59, "HSI_ACREADY"),
+       PINCTRL_PIN(60, "HSI_ACWAKE"),
+       PINCTRL_PIN(61, "HSI_CADATA"),
+       PINCTRL_PIN(62, "HSI_CAFLAG"),
+       PINCTRL_PIN(63, "HSI_CAREADY"),
+       PINCTRL_PIN(64, "HSI_CAWAKE"),
+       /* Family 5: SSP Audio (14 pins) */
+       PINCTRL_PIN(65, "GP70"),
+       PINCTRL_PIN(66, "GP71"),
+       PINCTRL_PIN(67, "GP32_I2S_0_CLK"),
+       PINCTRL_PIN(68, "GP33_I2S_0_FS"),
+       PINCTRL_PIN(69, "GP34_I2S_0_RXD"),
+       PINCTRL_PIN(70, "GP35_I2S_0_TXD"),
+       PINCTRL_PIN(71, "GP36_I2S_1_CLK"),
+       PINCTRL_PIN(72, "GP37_I2S_1_FS"),
+       PINCTRL_PIN(73, "GP38_I2S_1_RXD"),
+       PINCTRL_PIN(74, "GP39_I2S_1_TXD"),
+       PINCTRL_PIN(75, "GP40_I2S_2_CLK"),
+       PINCTRL_PIN(76, "GP41_I2S_2_FS"),
+       PINCTRL_PIN(77, "GP42_I2S_2_RXD"),
+       PINCTRL_PIN(78, "GP43_I2S_2_TXD"),
+       /* Family 6: GP SSP (22 pins) */
+       PINCTRL_PIN(79, "GP120_SPI_3_CLK"),
+       PINCTRL_PIN(80, "GP121_SPI_3_SS"),
+       PINCTRL_PIN(81, "GP122_SPI_3_RXD"),
+       PINCTRL_PIN(82, "GP123_SPI_3_TXD"),
+       PINCTRL_PIN(83, "GP102_SPI_4_CLK"),
+       PINCTRL_PIN(84, "GP103_SPI_4_SS_0"),
+       PINCTRL_PIN(85, "GP104_SPI_4_SS_1"),
+       PINCTRL_PIN(86, "GP105_SPI_4_SS_2"),
+       PINCTRL_PIN(87, "GP106_SPI_4_SS_3"),
+       PINCTRL_PIN(88, "GP107_SPI_4_RXD"),
+       PINCTRL_PIN(89, "GP108_SPI_4_TXD"),
+       PINCTRL_PIN(90, "GP109_SPI_5_CLK"),
+       PINCTRL_PIN(91, "GP110_SPI_5_SS_0"),
+       PINCTRL_PIN(92, "GP111_SPI_5_SS_1"),
+       PINCTRL_PIN(93, "GP112_SPI_5_SS_2"),
+       PINCTRL_PIN(94, "GP113_SPI_5_SS_3"),
+       PINCTRL_PIN(95, "GP114_SPI_5_RXD"),
+       PINCTRL_PIN(96, "GP115_SPI_5_TXD"),
+       PINCTRL_PIN(97, "GP116_SPI_6_CLK"),
+       PINCTRL_PIN(98, "GP117_SPI_6_SS"),
+       PINCTRL_PIN(99, "GP118_SPI_6_RXD"),
+       PINCTRL_PIN(100, "GP119_SPI_6_TXD"),
+       /* Family 7: I2C (14 pins) */
+       PINCTRL_PIN(101, "GP19_I2C_1_SCL"),
+       PINCTRL_PIN(102, "GP20_I2C_1_SDA"),
+       PINCTRL_PIN(103, "GP21_I2C_2_SCL"),
+       PINCTRL_PIN(104, "GP22_I2C_2_SDA"),
+       PINCTRL_PIN(105, "GP17_I2C_3_SCL_HDMI"),
+       PINCTRL_PIN(106, "GP18_I2C_3_SDA_HDMI"),
+       PINCTRL_PIN(107, "GP23_I2C_4_SCL"),
+       PINCTRL_PIN(108, "GP24_I2C_4_SDA"),
+       PINCTRL_PIN(109, "GP25_I2C_5_SCL"),
+       PINCTRL_PIN(110, "GP26_I2C_5_SDA"),
+       PINCTRL_PIN(111, "GP27_I2C_6_SCL"),
+       PINCTRL_PIN(112, "GP28_I2C_6_SDA"),
+       PINCTRL_PIN(113, "GP29_I2C_7_SCL"),
+       PINCTRL_PIN(114, "GP30_I2C_7_SDA"),
+       /* Family 8: UART (12 pins) */
+       PINCTRL_PIN(115, "GP124_UART_0_CTS"),
+       PINCTRL_PIN(116, "GP125_UART_0_RTS"),
+       PINCTRL_PIN(117, "GP126_UART_0_RX"),
+       PINCTRL_PIN(118, "GP127_UART_0_TX"),
+       PINCTRL_PIN(119, "GP128_UART_1_CTS"),
+       PINCTRL_PIN(120, "GP129_UART_1_RTS"),
+       PINCTRL_PIN(121, "GP130_UART_1_RX"),
+       PINCTRL_PIN(122, "GP131_UART_1_TX"),
+       PINCTRL_PIN(123, "GP132_UART_2_CTS"),
+       PINCTRL_PIN(124, "GP133_UART_2_RTS"),
+       PINCTRL_PIN(125, "GP134_UART_2_RX"),
+       PINCTRL_PIN(126, "GP135_UART_2_TX"),
+       /* Family 9: GPIO South (19 pins) */
+       PINCTRL_PIN(127, "GP177"),
+       PINCTRL_PIN(128, "GP178"),
+       PINCTRL_PIN(129, "GP179"),
+       PINCTRL_PIN(130, "GP180"),
+       PINCTRL_PIN(131, "GP181"),
+       PINCTRL_PIN(132, "GP182_PWM2"),
+       PINCTRL_PIN(133, "GP183_PWM3"),
+       PINCTRL_PIN(134, "GP184"),
+       PINCTRL_PIN(135, "GP185"),
+       PINCTRL_PIN(136, "GP186"),
+       PINCTRL_PIN(137, "GP187"),
+       PINCTRL_PIN(138, "GP188"),
+       PINCTRL_PIN(139, "GP189"),
+       PINCTRL_PIN(140, "GP64_FAST_INT0"),
+       PINCTRL_PIN(141, "GP65_FAST_INT1"),
+       PINCTRL_PIN(142, "GP66_FAST_INT2"),
+       PINCTRL_PIN(143, "GP67_FAST_INT3"),
+       PINCTRL_PIN(144, "GP12_PWM0"),
+       PINCTRL_PIN(145, "GP13_PWM1"),
+       /* Family 10: Camera Sideband (12 pins) */
+       PINCTRL_PIN(146, "GP0"),
+       PINCTRL_PIN(147, "GP1"),
+       PINCTRL_PIN(148, "GP2"),
+       PINCTRL_PIN(149, "GP3"),
+       PINCTRL_PIN(150, "GP4"),
+       PINCTRL_PIN(151, "GP5"),
+       PINCTRL_PIN(152, "GP6"),
+       PINCTRL_PIN(153, "GP7"),
+       PINCTRL_PIN(154, "GP8"),
+       PINCTRL_PIN(155, "GP9"),
+       PINCTRL_PIN(156, "GP10"),
+       PINCTRL_PIN(157, "GP11"),
+       /* Family 11: Clock (22 pins) */
+       PINCTRL_PIN(158, "GP137"),
+       PINCTRL_PIN(159, "GP138"),
+       PINCTRL_PIN(160, "GP139"),
+       PINCTRL_PIN(161, "GP140"),
+       PINCTRL_PIN(162, "GP141"),
+       PINCTRL_PIN(163, "GP142"),
+       PINCTRL_PIN(164, "GP16_HDMI_HPD"),
+       PINCTRL_PIN(165, "GP68_DSI_A_TE"),
+       PINCTRL_PIN(166, "GP69_DSI_C_TE"),
+       PINCTRL_PIN(167, "OSC_CLK_CTRL0"),
+       PINCTRL_PIN(168, "OSC_CLK_CTRL1"),
+       PINCTRL_PIN(169, "OSC_CLK0"),
+       PINCTRL_PIN(170, "OSC_CLK1"),
+       PINCTRL_PIN(171, "OSC_CLK2"),
+       PINCTRL_PIN(172, "OSC_CLK3"),
+       PINCTRL_PIN(173, "OSC_CLK4"),
+       PINCTRL_PIN(174, "RESETOUT"),
+       PINCTRL_PIN(175, "PMODE"),
+       PINCTRL_PIN(176, "PRDY"),
+       PINCTRL_PIN(177, "PREQ"),
+       PINCTRL_PIN(178, "GP190"),
+       PINCTRL_PIN(179, "GP191"),
+       /* Family 12: MSIC (15 pins) */
+       PINCTRL_PIN(180, "I2C_0_SCL"),
+       PINCTRL_PIN(181, "I2C_0_SDA"),
+       PINCTRL_PIN(182, "IERR"),
+       PINCTRL_PIN(183, "JTAG_TCK"),
+       PINCTRL_PIN(184, "JTAG_TDI"),
+       PINCTRL_PIN(185, "JTAG_TDO"),
+       PINCTRL_PIN(186, "JTAG_TMS"),
+       PINCTRL_PIN(187, "JTAG_TRST"),
+       PINCTRL_PIN(188, "PROCHOT"),
+       PINCTRL_PIN(189, "RTC_CLK"),
+       PINCTRL_PIN(190, "SVID_ALERT"),
+       PINCTRL_PIN(191, "SVID_CLK"),
+       PINCTRL_PIN(192, "SVID_D"),
+       PINCTRL_PIN(193, "THERMTRIP"),
+       PINCTRL_PIN(194, "STANDBY"),
+       /* Family 13: Keyboard (20 pins) */
+       PINCTRL_PIN(195, "GP44"),
+       PINCTRL_PIN(196, "GP45"),
+       PINCTRL_PIN(197, "GP46"),
+       PINCTRL_PIN(198, "GP47"),
+       PINCTRL_PIN(199, "GP48"),
+       PINCTRL_PIN(200, "GP49"),
+       PINCTRL_PIN(201, "GP50"),
+       PINCTRL_PIN(202, "GP51"),
+       PINCTRL_PIN(203, "GP52"),
+       PINCTRL_PIN(204, "GP53"),
+       PINCTRL_PIN(205, "GP54"),
+       PINCTRL_PIN(206, "GP55"),
+       PINCTRL_PIN(207, "GP56"),
+       PINCTRL_PIN(208, "GP57"),
+       PINCTRL_PIN(209, "GP58"),
+       PINCTRL_PIN(210, "GP59"),
+       PINCTRL_PIN(211, "GP60"),
+       PINCTRL_PIN(212, "GP61"),
+       PINCTRL_PIN(213, "GP62"),
+       PINCTRL_PIN(214, "GP63"),
+       /* Family 14: GPIO North (13 pins) */
+       PINCTRL_PIN(215, "GP164"),
+       PINCTRL_PIN(216, "GP165"),
+       PINCTRL_PIN(217, "GP166"),
+       PINCTRL_PIN(218, "GP167"),
+       PINCTRL_PIN(219, "GP168_MJTAG_TCK"),
+       PINCTRL_PIN(220, "GP169_MJTAG_TDI"),
+       PINCTRL_PIN(221, "GP170_MJTAG_TDO"),
+       PINCTRL_PIN(222, "GP171_MJTAG_TMS"),
+       PINCTRL_PIN(223, "GP172_MJTAG_TRST"),
+       PINCTRL_PIN(224, "GP173"),
+       PINCTRL_PIN(225, "GP174"),
+       PINCTRL_PIN(226, "GP175"),
+       PINCTRL_PIN(227, "GP176"),
+       /* Family 15: PTI (5 pins) */
+       PINCTRL_PIN(228, "GP72_PTI_CLK"),
+       PINCTRL_PIN(229, "GP73_PTI_D0"),
+       PINCTRL_PIN(230, "GP74_PTI_D1"),
+       PINCTRL_PIN(231, "GP75_PTI_D2"),
+       PINCTRL_PIN(232, "GP76_PTI_D3"),
+       /* Family 16: USB3 (0 pins) */
+       /* Family 17: HSIC (0 pins) */
+       /* Family 18: Broadcast (0 pins) */
+};
+
+static const unsigned int mrfld_sdio_pins[] = { 50, 51, 52, 53, 54, 55, 56 };
+static const unsigned int mrfld_spi5_pins[] = { 90, 91, 92, 93, 94, 95, 96 };
+static const unsigned int mrfld_uart0_pins[] = { 124, 125, 126, 127 };
+static const unsigned int mrfld_uart1_pins[] = { 128, 129, 130, 131 };
+static const unsigned int mrfld_uart2_pins[] = { 132, 133, 134, 135 };
+static const unsigned int mrfld_pwm0_pins[] = { 144 };
+static const unsigned int mrfld_pwm1_pins[] = { 145 };
+static const unsigned int mrfld_pwm2_pins[] = { 132 };
+static const unsigned int mrfld_pwm3_pins[] = { 133 };
+
+static const struct intel_pingroup mrfld_groups[] = {
+       PIN_GROUP("sdio_grp", mrfld_sdio_pins, 1),
+       PIN_GROUP("spi5_grp", mrfld_spi5_pins, 1),
+       PIN_GROUP("uart0_grp", mrfld_uart0_pins, 1),
+       PIN_GROUP("uart1_grp", mrfld_uart1_pins, 1),
+       PIN_GROUP("uart2_grp", mrfld_uart2_pins, 1),
+       PIN_GROUP("pwm0_grp", mrfld_pwm0_pins, 1),
+       PIN_GROUP("pwm1_grp", mrfld_pwm1_pins, 1),
+       PIN_GROUP("pwm2_grp", mrfld_pwm2_pins, 1),
+       PIN_GROUP("pwm3_grp", mrfld_pwm3_pins, 1),
+};
+
+static const char * const mrfld_sdio_groups[] = { "sdio_grp" };
+static const char * const mrfld_spi5_groups[] = { "spi5_grp" };
+static const char * const mrfld_uart0_groups[] = { "uart0_grp" };
+static const char * const mrfld_uart1_groups[] = { "uart1_grp" };
+static const char * const mrfld_uart2_groups[] = { "uart2_grp" };
+static const char * const mrfld_pwm0_groups[] = { "pwm0_grp" };
+static const char * const mrfld_pwm1_groups[] = { "pwm1_grp" };
+static const char * const mrfld_pwm2_groups[] = { "pwm2_grp" };
+static const char * const mrfld_pwm3_groups[] = { "pwm3_grp" };
+
+static const struct intel_function mrfld_functions[] = {
+       FUNCTION("sdio", mrfld_sdio_groups),
+       FUNCTION("spi5", mrfld_spi5_groups),
+       FUNCTION("uart0", mrfld_uart0_groups),
+       FUNCTION("uart1", mrfld_uart1_groups),
+       FUNCTION("uart2", mrfld_uart2_groups),
+       FUNCTION("pwm0", mrfld_pwm0_groups),
+       FUNCTION("pwm1", mrfld_pwm1_groups),
+       FUNCTION("pwm2", mrfld_pwm2_groups),
+       FUNCTION("pwm3", mrfld_pwm3_groups),
+};
+
+static const struct mrfld_family mrfld_families[] = {
+       MRFLD_FAMILY(1, 0, 12),
+       MRFLD_FAMILY(2, 13, 36),
+       MRFLD_FAMILY(3, 37, 56),
+       MRFLD_FAMILY(4, 57, 64),
+       MRFLD_FAMILY(5, 65, 78),
+       MRFLD_FAMILY(6, 79, 100),
+       MRFLD_FAMILY_PROTECTED(7, 101, 114),
+       MRFLD_FAMILY(8, 115, 126),
+       MRFLD_FAMILY(9, 127, 145),
+       MRFLD_FAMILY(10, 146, 157),
+       MRFLD_FAMILY(11, 158, 179),
+       MRFLD_FAMILY_PROTECTED(12, 180, 194),
+       MRFLD_FAMILY(13, 195, 214),
+       MRFLD_FAMILY(14, 215, 227),
+       MRFLD_FAMILY(15, 228, 232),
+};
+
+/**
+ * struct mrfld_pinctrl - Intel Merrifield pinctrl private structure
+ * @dev: Pointer to the device structure
+ * @lock: Lock to serialize register access
+ * @pctldesc: Pin controller description
+ * @pctldev: Pointer to the pin controller device
+ * @families: Array of families this pinctrl handles
+ * @nfamilies: Number of families in the array
+ * @functions: Array of functions
+ * @nfunctions: Number of functions in the array
+ * @groups: Array of pin groups
+ * @ngroups: Number of groups in the array
+ * @pins: Array of pins this pinctrl controls
+ * @npins: Number of pins in the array
+ */
+struct mrfld_pinctrl {
+       struct device *dev;
+       raw_spinlock_t lock;
+       struct pinctrl_desc pctldesc;
+       struct pinctrl_dev *pctldev;
+
+       /* Pin controller configuration */
+       const struct mrfld_family *families;
+       size_t nfamilies;
+       const struct intel_function *functions;
+       size_t nfunctions;
+       const struct intel_pingroup *groups;
+       size_t ngroups;
+       const struct pinctrl_pin_desc *pins;
+       size_t npins;
+};
+
+#define pin_to_bufno(f, p)             ((p) - (f)->pin_base)
+
+static const struct mrfld_family *mrfld_get_family(struct mrfld_pinctrl *mp,
+                                                  unsigned int pin)
+{
+       const struct mrfld_family *family;
+       unsigned int i;
+
+       for (i = 0; i < mp->nfamilies; i++) {
+               family = &mp->families[i];
+               if (pin >= family->pin_base &&
+                   pin < family->pin_base + family->npins)
+                       return family;
+       }
+
+       dev_warn(mp->dev, "failed to find family for pin %u\n", pin);
+       return NULL;
+}
+
+static bool mrfld_buf_available(struct mrfld_pinctrl *mp, unsigned int pin)
+{
+       const struct mrfld_family *family;
+
+       family = mrfld_get_family(mp, pin);
+       if (!family)
+               return false;
+
+       return !family->protected;
+}
+
+static void __iomem *mrfld_get_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin)
+{
+       const struct mrfld_family *family;
+       unsigned int bufno;
+
+       family = mrfld_get_family(mp, pin);
+       if (!family)
+               return NULL;
+
+       bufno = pin_to_bufno(family, pin);
+       return family->regs + BUFCFG_OFFSET + bufno * 4;
+}
+
+static int mrfld_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       return mp->ngroups;
+}
+
+static const char *mrfld_get_group_name(struct pinctrl_dev *pctldev,
+                                       unsigned int group)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       return mp->groups[group].name;
+}
+
+static int mrfld_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
+                               const unsigned int **pins, unsigned int *npins)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       *pins = mp->groups[group].pins;
+       *npins = mp->groups[group].npins;
+       return 0;
+}
+
+static void mrfld_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+                              unsigned int pin)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       void __iomem *bufcfg;
+       u32 value, mode;
+
+       if (!mrfld_buf_available(mp, pin)) {
+               seq_puts(s, "not available");
+               return;
+       }
+
+       bufcfg = mrfld_get_bufcfg(mp, pin);
+       value = readl(bufcfg);
+
+       mode = (value & BUFCFG_PINMODE_MASK) >> BUFCFG_PINMODE_SHIFT;
+       if (!mode)
+               seq_puts(s, "GPIO ");
+       else
+               seq_printf(s, "mode %d ", mode);
+
+       seq_printf(s, "0x%08x", value);
+}
+
+static const struct pinctrl_ops mrfld_pinctrl_ops = {
+       .get_groups_count = mrfld_get_groups_count,
+       .get_group_name = mrfld_get_group_name,
+       .get_group_pins = mrfld_get_group_pins,
+       .pin_dbg_show = mrfld_pin_dbg_show,
+};
+
+static int mrfld_get_functions_count(struct pinctrl_dev *pctldev)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       return mp->nfunctions;
+}
+
+static const char *mrfld_get_function_name(struct pinctrl_dev *pctldev,
+                                          unsigned int function)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       return mp->functions[function].name;
+}
+
+static int mrfld_get_function_groups(struct pinctrl_dev *pctldev,
+                                    unsigned int function,
+                                    const char * const **groups,
+                                    unsigned int * const ngroups)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = mp->functions[function].groups;
+       *ngroups = mp->functions[function].ngroups;
+       return 0;
+}
+
+static void mrfld_update_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin,
+                               u32 bits, u32 mask)
+{
+       void __iomem *bufcfg;
+       u32 value;
+
+       bufcfg = mrfld_get_bufcfg(mp, pin);
+       value = readl(bufcfg);
+
+       value &= ~mask;
+       value |= bits & mask;
+
+       writel(value, bufcfg);
+}
+
+static int mrfld_pinmux_set_mux(struct pinctrl_dev *pctldev,
+                               unsigned int function,
+                               unsigned int group)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       const struct intel_pingroup *grp = &mp->groups[group];
+       u32 bits = grp->mode << BUFCFG_PINMODE_SHIFT;
+       u32 mask = BUFCFG_PINMODE_MASK;
+       unsigned long flags;
+       unsigned int i;
+
+       /*
+        * All pins in the groups needs to be accessible and writable
+        * before we can enable the mux for this group.
+        */
+       for (i = 0; i < grp->npins; i++) {
+               if (!mrfld_buf_available(mp, grp->pins[i]))
+                       return -EBUSY;
+       }
+
+       /* Now enable the mux setting for each pin in the group */
+       raw_spin_lock_irqsave(&mp->lock, flags);
+       for (i = 0; i < grp->npins; i++)
+               mrfld_update_bufcfg(mp, grp->pins[i], bits, mask);
+       raw_spin_unlock_irqrestore(&mp->lock, flags);
+
+       return 0;
+}
+
+static int mrfld_gpio_request_enable(struct pinctrl_dev *pctldev,
+                                    struct pinctrl_gpio_range *range,
+                                    unsigned int pin)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       u32 bits = BUFCFG_PINMODE_GPIO << BUFCFG_PINMODE_SHIFT;
+       u32 mask = BUFCFG_PINMODE_MASK;
+       unsigned long flags;
+
+       if (!mrfld_buf_available(mp, pin))
+               return -EBUSY;
+
+       raw_spin_lock_irqsave(&mp->lock, flags);
+       mrfld_update_bufcfg(mp, pin, bits, mask);
+       raw_spin_unlock_irqrestore(&mp->lock, flags);
+
+       return 0;
+}
+
+static const struct pinmux_ops mrfld_pinmux_ops = {
+       .get_functions_count = mrfld_get_functions_count,
+       .get_function_name = mrfld_get_function_name,
+       .get_function_groups = mrfld_get_function_groups,
+       .set_mux = mrfld_pinmux_set_mux,
+       .gpio_request_enable = mrfld_gpio_request_enable,
+};
+
+static int mrfld_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                           unsigned long *config)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       u32 value, term;
+       u16 arg = 0;
+
+       if (!mrfld_buf_available(mp, pin))
+               return -ENOTSUPP;
+
+       value = readl(mrfld_get_bufcfg(mp, pin));
+       term = (value & BUFCFG_PUPD_VAL_MASK) >> BUFCFG_PUPD_VAL_SHIFT;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               if (value & BUFCFG_Px_EN_MASK)
+                       return -EINVAL;
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               if ((value & BUFCFG_Px_EN_MASK) != BUFCFG_PU_EN)
+                       return -EINVAL;
+
+               switch (term) {
+               case BUFCFG_PUPD_VAL_910:
+                       arg = 910;
+                       break;
+               case BUFCFG_PUPD_VAL_2K:
+                       arg = 2000;
+                       break;
+               case BUFCFG_PUPD_VAL_20K:
+                       arg = 20000;
+                       break;
+               case BUFCFG_PUPD_VAL_50K:
+                       arg = 50000;
+                       break;
+               }
+
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               if ((value & BUFCFG_Px_EN_MASK) != BUFCFG_PD_EN)
+                       return -EINVAL;
+
+               switch (term) {
+               case BUFCFG_PUPD_VAL_910:
+                       arg = 910;
+                       break;
+               case BUFCFG_PUPD_VAL_2K:
+                       arg = 2000;
+                       break;
+               case BUFCFG_PUPD_VAL_20K:
+                       arg = 20000;
+                       break;
+               case BUFCFG_PUPD_VAL_50K:
+                       arg = 50000;
+                       break;
+               }
+
+               break;
+
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               if (!(value & BUFCFG_OD_EN))
+                       return -EINVAL;
+               break;
+
+       case PIN_CONFIG_SLEW_RATE:
+               if (!(value & BUFCFG_SLEWSEL))
+                       arg = 0;
+               else
+                       arg = 1;
+               break;
+
+       default:
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, arg);
+       return 0;
+}
+
+static int mrfld_config_set_pin(struct mrfld_pinctrl *mp, unsigned int pin,
+                               unsigned long config)
+{
+       unsigned int param = pinconf_to_config_param(config);
+       unsigned int arg = pinconf_to_config_argument(config);
+       u32 bits = 0, mask = 0;
+       unsigned long flags;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               mask |= BUFCFG_Px_EN_MASK | BUFCFG_PUPD_VAL_MASK;
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               mask |= BUFCFG_Px_EN_MASK | BUFCFG_PUPD_VAL_MASK;
+               bits |= BUFCFG_PU_EN;
+
+               switch (arg) {
+               case 50000:
+                       bits |= BUFCFG_PUPD_VAL_50K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               case 20000:
+                       bits |= BUFCFG_PUPD_VAL_20K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               case 2000:
+                       bits |= BUFCFG_PUPD_VAL_2K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               mask |= BUFCFG_Px_EN_MASK | BUFCFG_PUPD_VAL_MASK;
+               bits |= BUFCFG_PD_EN;
+
+               switch (arg) {
+               case 50000:
+                       bits |= BUFCFG_PUPD_VAL_50K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               case 20000:
+                       bits |= BUFCFG_PUPD_VAL_20K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               case 2000:
+                       bits |= BUFCFG_PUPD_VAL_2K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               break;
+
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               mask |= BUFCFG_OD_EN;
+               if (arg)
+                       bits |= BUFCFG_OD_EN;
+               break;
+
+       case PIN_CONFIG_SLEW_RATE:
+               mask |= BUFCFG_SLEWSEL;
+               if (arg)
+                       bits |= BUFCFG_SLEWSEL;
+               break;
+       }
+
+       raw_spin_lock_irqsave(&mp->lock, flags);
+       mrfld_update_bufcfg(mp, pin, bits, mask);
+       raw_spin_unlock_irqrestore(&mp->lock, flags);
+
+       return 0;
+}
+
+static int mrfld_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                           unsigned long *configs, unsigned int nconfigs)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < nconfigs; i++) {
+               switch (pinconf_to_config_param(configs[i])) {
+               case PIN_CONFIG_BIAS_DISABLE:
+               case PIN_CONFIG_BIAS_PULL_UP:
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+               case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               case PIN_CONFIG_SLEW_RATE:
+                       ret = mrfld_config_set_pin(mp, pin, configs[i]);
+                       if (ret)
+                               return ret;
+                       break;
+
+               default:
+                       return -ENOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops mrfld_pinconf_ops = {
+       .is_generic = true,
+       .pin_config_get = mrfld_config_get,
+       .pin_config_set = mrfld_config_set,
+};
+
+static const struct pinctrl_desc mrfld_pinctrl_desc = {
+       .pctlops = &mrfld_pinctrl_ops,
+       .pmxops = &mrfld_pinmux_ops,
+       .confops = &mrfld_pinconf_ops,
+       .owner = THIS_MODULE,
+};
+
+static int mrfld_pinctrl_probe(struct platform_device *pdev)
+{
+       struct mrfld_family *families;
+       struct mrfld_pinctrl *mp;
+       struct resource *mem;
+       void __iomem *regs;
+       size_t nfamilies;
+       unsigned int i;
+
+       mp = devm_kzalloc(&pdev->dev, sizeof(*mp), GFP_KERNEL);
+       if (!mp)
+               return -ENOMEM;
+
+       mp->dev = &pdev->dev;
+       raw_spin_lock_init(&mp->lock);
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       /*
+        * Make a copy of the families which we can use to hold pointers
+        * to the registers.
+        */
+       nfamilies = ARRAY_SIZE(mrfld_families),
+       families = devm_kmemdup(&pdev->dev, mrfld_families,
+                                           nfamilies * sizeof(mrfld_families),
+                                           GFP_KERNEL);
+       if (!families)
+               return -ENOMEM;
+
+       /* Splice memory resource by chunk per family */
+       for (i = 0; i < nfamilies; i++) {
+               struct mrfld_family *family = &families[i];
+
+               family->regs = regs + family->barno * MRFLD_FAMILY_LEN;
+       }
+
+       mp->families = families;
+       mp->nfamilies = nfamilies;
+       mp->functions = mrfld_functions;
+       mp->nfunctions = ARRAY_SIZE(mrfld_functions);
+       mp->groups = mrfld_groups;
+       mp->ngroups = ARRAY_SIZE(mrfld_groups);
+       mp->pctldesc = mrfld_pinctrl_desc;
+       mp->pctldesc.name = dev_name(&pdev->dev);
+       mp->pctldesc.pins = mrfld_pins;
+       mp->pctldesc.npins = ARRAY_SIZE(mrfld_pins);
+
+       mp->pctldev = devm_pinctrl_register(&pdev->dev, &mp->pctldesc, mp);
+       if (IS_ERR(mp->pctldev)) {
+               dev_err(&pdev->dev, "failed to register pinctrl driver\n");
+               return PTR_ERR(mp->pctldev);
+       }
+
+       platform_set_drvdata(pdev, mp);
+       return 0;
+}
+
+static struct platform_driver mrfld_pinctrl_driver = {
+       .probe = mrfld_pinctrl_probe,
+       .driver = {
+               .name = "pinctrl-merrifield",
+       },
+};
+
+static int __init mrfld_pinctrl_init(void)
+{
+       return platform_driver_register(&mrfld_pinctrl_driver);
+}
+subsys_initcall(mrfld_pinctrl_init);
+
+static void __exit mrfld_pinctrl_exit(void)
+{
+       platform_driver_unregister(&mrfld_pinctrl_driver);
+}
+module_exit(mrfld_pinctrl_exit);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Merrifield SoC pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:pinctrl-merrifield");
index a607655d78309c23c1b1373103f93f307311248f..ce554e0d69795cc9e9ded0dd31bedafc357ba523 100644 (file)
@@ -1183,8 +1183,8 @@ static int mtk_eint_resume(struct device *device)
 }
 
 const struct dev_pm_ops mtk_eint_pm_ops = {
-       .suspend = mtk_eint_suspend,
-       .resume = mtk_eint_resume,
+       .suspend_noirq = mtk_eint_suspend,
+       .resume_noirq = mtk_eint_resume,
 };
 
 static void mtk_eint_ack(struct irq_data *d)
index eeabafbbf5988e9b83461ae316266fb20fa64023..cb4d6ad3053079af678d2222de90183c667ee5c8 100644 (file)
@@ -147,6 +147,52 @@ static const struct pinctrl_pin_desc meson_gxbb_periphs_pins[] = {
        MESON_PIN(GPIO_TEST_N, EE_OFF),
 };
 
+static const unsigned int emmc_nand_d07_pins[] = {
+       PIN(BOOT_0, EE_OFF), PIN(BOOT_1, EE_OFF), PIN(BOOT_2, EE_OFF),
+       PIN(BOOT_3, EE_OFF), PIN(BOOT_4, EE_OFF), PIN(BOOT_5, EE_OFF),
+       PIN(BOOT_6, EE_OFF), PIN(BOOT_7, EE_OFF),
+};
+static const unsigned int emmc_clk_pins[] = { PIN(BOOT_8, EE_OFF) };
+static const unsigned int emmc_cmd_pins[] = { PIN(BOOT_10, EE_OFF) };
+static const unsigned int emmc_ds_pins[] = { PIN(BOOT_15, EE_OFF) };
+
+static const unsigned int sdcard_d0_pins[] = { PIN(CARD_1, EE_OFF) };
+static const unsigned int sdcard_d1_pins[] = { PIN(CARD_0, EE_OFF) };
+static const unsigned int sdcard_d2_pins[] = { PIN(CARD_5, EE_OFF) };
+static const unsigned int sdcard_d3_pins[] = { PIN(CARD_4, EE_OFF) };
+static const unsigned int sdcard_cmd_pins[] = { PIN(CARD_3, EE_OFF) };
+static const unsigned int sdcard_clk_pins[] = { PIN(CARD_2, EE_OFF) };
+
+static const unsigned int uart_tx_a_pins[]     = { PIN(GPIOX_12, EE_OFF) };
+static const unsigned int uart_rx_a_pins[]     = { PIN(GPIOX_13, EE_OFF) };
+static const unsigned int uart_cts_a_pins[]    = { PIN(GPIOX_14, EE_OFF) };
+static const unsigned int uart_rts_a_pins[]    = { PIN(GPIOX_15, EE_OFF) };
+
+static const unsigned int uart_tx_b_pins[]     = { PIN(GPIODV_24, EE_OFF) };
+static const unsigned int uart_rx_b_pins[]     = { PIN(GPIODV_25, EE_OFF) };
+static const unsigned int uart_cts_b_pins[]    = { PIN(GPIODV_26, EE_OFF) };
+static const unsigned int uart_rts_b_pins[]    = { PIN(GPIODV_27, EE_OFF) };
+
+static const unsigned int uart_tx_c_pins[]     = { PIN(GPIOY_13, EE_OFF) };
+static const unsigned int uart_rx_c_pins[]     = { PIN(GPIOY_14, EE_OFF) };
+static const unsigned int uart_cts_c_pins[]    = { PIN(GPIOX_11, EE_OFF) };
+static const unsigned int uart_rts_c_pins[]    = { PIN(GPIOX_12, EE_OFF) };
+
+static const unsigned int eth_mdio_pins[]      = { PIN(GPIOZ_0, EE_OFF) };
+static const unsigned int eth_mdc_pins[]       = { PIN(GPIOZ_1, EE_OFF) };
+static const unsigned int eth_clk_rx_clk_pins[]        = { PIN(GPIOZ_2, EE_OFF) };
+static const unsigned int eth_rx_dv_pins[]     = { PIN(GPIOZ_3, EE_OFF) };
+static const unsigned int eth_rxd0_pins[]      = { PIN(GPIOZ_4, EE_OFF) };
+static const unsigned int eth_rxd1_pins[]      = { PIN(GPIOZ_5, EE_OFF) };
+static const unsigned int eth_rxd2_pins[]      = { PIN(GPIOZ_6, EE_OFF) };
+static const unsigned int eth_rxd3_pins[]      = { PIN(GPIOZ_7, EE_OFF) };
+static const unsigned int eth_rgmii_tx_clk_pins[] = { PIN(GPIOZ_8, EE_OFF) };
+static const unsigned int eth_tx_en_pins[]     = { PIN(GPIOZ_9, EE_OFF) };
+static const unsigned int eth_txd0_pins[]      = { PIN(GPIOZ_10, EE_OFF) };
+static const unsigned int eth_txd1_pins[]      = { PIN(GPIOZ_11, EE_OFF) };
+static const unsigned int eth_txd2_pins[]      = { PIN(GPIOZ_12, EE_OFF) };
+static const unsigned int eth_txd3_pins[]      = { PIN(GPIOZ_13, EE_OFF) };
+
 static const struct pinctrl_pin_desc meson_gxbb_aobus_pins[] = {
        MESON_PIN(GPIOAO_0, 0),
        MESON_PIN(GPIOAO_1, 0),
@@ -168,6 +214,16 @@ static const unsigned int uart_tx_ao_a_pins[]      = { PIN(GPIOAO_0, 0) };
 static const unsigned int uart_rx_ao_a_pins[]  = { PIN(GPIOAO_1, 0) };
 static const unsigned int uart_cts_ao_a_pins[] = { PIN(GPIOAO_2, 0) };
 static const unsigned int uart_rts_ao_a_pins[] = { PIN(GPIOAO_3, 0) };
+static const unsigned int uart_tx_ao_b_pins[]  = { PIN(GPIOAO_0, 0) };
+static const unsigned int uart_rx_ao_b_pins[]  = { PIN(GPIOAO_1, 0),
+                                                   PIN(GPIOAO_5, 0) };
+static const unsigned int uart_cts_ao_b_pins[] = { PIN(GPIOAO_2, 0) };
+static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, 0) };
+
+static const unsigned int i2c_sck_ao_pins[] = {PIN(GPIOAO_4, 0) };
+static const unsigned int i2c_sda_ao_pins[] = {PIN(GPIOAO_5, 0) };
+static const unsigned int i2c_slave_sck_ao_pins[] = {PIN(GPIOAO_4, 0) };
+static const unsigned int i2c_slave_sda_ao_pins[] = {PIN(GPIOAO_5, 0) };
 
 static struct meson_pmx_group meson_gxbb_periphs_groups[] = {
        GPIO_GROUP(GPIOZ_0, EE_OFF),
@@ -297,6 +353,54 @@ static struct meson_pmx_group meson_gxbb_periphs_groups[] = {
        GPIO_GROUP(GPIOCLK_3, EE_OFF),
 
        GPIO_GROUP(GPIO_TEST_N, EE_OFF),
+
+       /* Bank X */
+       GROUP(uart_tx_a,        4,      13),
+       GROUP(uart_rx_a,        4,      12),
+       GROUP(uart_cts_a,       4,      11),
+       GROUP(uart_rts_a,       4,      10),
+
+       /* Bank Y */
+       GROUP(uart_cts_c,       1,      19),
+       GROUP(uart_rts_c,       1,      18),
+       GROUP(uart_tx_c,        1,      17),
+       GROUP(uart_rx_c,        1,      16),
+
+       /* Bank Z */
+       GROUP(eth_mdio,         6,      1),
+       GROUP(eth_mdc,          6,      0),
+       GROUP(eth_clk_rx_clk,   6,      13),
+       GROUP(eth_rx_dv,        6,      12),
+       GROUP(eth_rxd0,         6,      11),
+       GROUP(eth_rxd1,         6,      10),
+       GROUP(eth_rxd2,         6,      9),
+       GROUP(eth_rxd3,         6,      8),
+       GROUP(eth_rgmii_tx_clk, 6,      7),
+       GROUP(eth_tx_en,        6,      6),
+       GROUP(eth_txd0,         6,      5),
+       GROUP(eth_txd1,         6,      4),
+       GROUP(eth_txd2,         6,      3),
+       GROUP(eth_txd3,         6,      2),
+
+       /* Bank DV */
+       GROUP(uart_tx_b,        2,      29),
+       GROUP(uart_rx_b,        2,      28),
+       GROUP(uart_cts_b,       2,      27),
+       GROUP(uart_rts_b,       2,      26),
+
+       /* Bank BOOT */
+       GROUP(emmc_nand_d07,    4,      30),
+       GROUP(emmc_clk,         4,      18),
+       GROUP(emmc_cmd,         4,      19),
+       GROUP(emmc_ds,          4,      31),
+
+       /* Bank CARD */
+       GROUP(sdcard_d1,        2,      14),
+       GROUP(sdcard_d0,        2,      15),
+       GROUP(sdcard_d3,        2,      12),
+       GROUP(sdcard_d2,        2,      13),
+       GROUP(sdcard_cmd,       2,      10),
+       GROUP(sdcard_clk,       2,      11),
 };
 
 static struct meson_pmx_group meson_gxbb_aobus_groups[] = {
@@ -316,10 +420,18 @@ static struct meson_pmx_group meson_gxbb_aobus_groups[] = {
        GPIO_GROUP(GPIOAO_13, 0),
 
        /* bank AO */
+       GROUP(uart_tx_ao_b,     0,      26),
+       GROUP(uart_rx_ao_b,     0,      25),
        GROUP(uart_tx_ao_a,     0,      12),
        GROUP(uart_rx_ao_a,     0,      11),
        GROUP(uart_cts_ao_a,    0,      10),
        GROUP(uart_rts_ao_a,    0,      9),
+       GROUP(uart_cts_ao_b,    0,      8),
+       GROUP(uart_rts_ao_b,    0,      7),
+       GROUP(i2c_sck_ao,       0,      6),
+       GROUP(i2c_sda_ao,       0,      5),
+       GROUP(i2c_slave_sck_ao, 0,      2),
+       GROUP(i2c_slave_sda_ao, 0,      1),
 };
 
 static const char * const gpio_periphs_groups[] = {
@@ -359,6 +471,34 @@ static const char * const gpio_periphs_groups[] = {
        "GPIO_TEST_N",
 };
 
+static const char * const emmc_groups[] = {
+       "emmc_nand_d07", "emmc_clk", "emmc_cmd", "emmc_ds",
+};
+
+static const char * const sdcard_groups[] = {
+       "sdcard_d0", "sdcard_d1", "sdcard_d2", "sdcard_d3",
+       "sdcard_cmd", "sdcard_clk",
+};
+
+static const char * const uart_a_groups[] = {
+       "uart_tx_a", "uart_rx_a", "uart_cts_a", "uart_rts_a",
+};
+
+static const char * const uart_b_groups[] = {
+       "uart_tx_b", "uart_rx_b", "uart_cts_b", "uart_rts_b",
+};
+
+static const char * const uart_c_groups[] = {
+       "uart_tx_c", "uart_rx_c", "uart_cts_c", "uart_rts_c",
+};
+
+static const char * const eth_groups[] = {
+       "eth_mdio", "eth_mdc", "eth_clk_rx_clk", "eth_rx_dv",
+       "eth_rxd0", "eth_rxd1", "eth_rxd2", "eth_rxd3",
+       "eth_rgmii_tx_clk", "eth_tx_en",
+       "eth_txd0", "eth_txd1", "eth_txd2", "eth_txd3",
+};
+
 static const char * const gpio_aobus_groups[] = {
        "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
        "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
@@ -366,16 +506,37 @@ static const char * const gpio_aobus_groups[] = {
 };
 
 static const char * const uart_ao_groups[] = {
-       "uart_tx_ao_a", "uart_rx_ao_a", "uart_cts_ao_a", "uart_rts_ao_a"
+       "uart_tx_ao_a", "uart_rx_ao_a", "uart_cts_ao_a", "uart_rts_ao_a",
+};
+
+static const char * const uart_ao_b_groups[] = {
+       "uart_tx_ao_b", "uart_rx_ao_b", "uart_cts_ao_b", "uart_rts_ao_b",
+};
+
+static const char * const i2c_ao_groups[] = {
+       "i2c_sdk_ao", "i2c_sda_ao",
+};
+
+static const char * const i2c_slave_ao_groups[] = {
+       "i2c_slave_sdk_ao", "i2c_slave_sda_ao",
 };
 
 static struct meson_pmx_func meson_gxbb_periphs_functions[] = {
        FUNCTION(gpio_periphs),
+       FUNCTION(emmc),
+       FUNCTION(sdcard),
+       FUNCTION(uart_a),
+       FUNCTION(uart_b),
+       FUNCTION(uart_c),
+       FUNCTION(eth),
 };
 
 static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
        FUNCTION(gpio_aobus),
        FUNCTION(uart_ao),
+       FUNCTION(uart_ao_b),
+       FUNCTION(i2c_ao),
+       FUNCTION(i2c_slave_ao),
 };
 
 static struct meson_bank meson_gxbb_periphs_banks[] = {
index a78e9a4997baa2645c5251f9b1d141979e5948a6..5f89c26f3292c87c094922a314a45452478c17e5 100644 (file)
@@ -168,87 +168,87 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
                MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "nand", "io1",     V(1, 1, 1, 1, 1, 1))),
        MPP_MODE(20,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txd0",     V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d0",       V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(1, 0, 0, 0, 0, 0))),
+               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(0, 0, 0, 0, 0, 0))),
        MPP_MODE(21,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txd1",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d1",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(22,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txd2",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d2",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(23,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txd3",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",  V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d3",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(24,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxd0",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d4",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(25,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxd1",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d5",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(26,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxd2",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d6",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(27,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxd3",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d7",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(28,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "col",      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d8",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(29,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txclk",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d9",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(30,
                MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
@@ -280,65 +280,65 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
                MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d14",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(35,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxerr",    V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d15",      V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(0, 1, 1, 1, 1, 0))),
+               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(1, 1, 1, 1, 1, 0))),
        MPP_MODE(36,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "twsi1", "sda",    V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(37,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "twsi1", "sck",    V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(38,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d18",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(39,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d19",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(40,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d20",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(41,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d21",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(42,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d22",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(43,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d23",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(44,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "clk",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(45,
                MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
@@ -371,11 +371,12 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
 };
 
 static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 29, NULL, kirkwood_mpp_ctrl),
+       MPP_FUNC_CTRL(0, 44, NULL, kirkwood_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
-       MPP_GPIO_RANGE(0, 0, 0, 30),
+       MPP_GPIO_RANGE(0,  0,  0, 20),
+       MPP_GPIO_RANGE(1, 35, 35, 10),
 };
 
 static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = {
index 38faceff2f084202e035e1a0c122073eb5f456c9..35f62180db4e0427393f715ba5ba450d5c6fbeef 100644 (file)
@@ -1033,102 +1033,6 @@ static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
 #define nmk_gpio_dbg_show      NULL
 #endif
 
-void nmk_gpio_clocks_enable(void)
-{
-       int i;
-
-       for (i = 0; i < NUM_BANKS; i++) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-               if (!chip)
-                       continue;
-
-               clk_enable(chip->clk);
-       }
-}
-
-void nmk_gpio_clocks_disable(void)
-{
-       int i;
-
-       for (i = 0; i < NUM_BANKS; i++) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-               if (!chip)
-                       continue;
-
-               clk_disable(chip->clk);
-       }
-}
-
-/*
- * Called from the suspend/resume path to only keep the real wakeup interrupts
- * (those that have had set_irq_wake() called on them) as wakeup interrupts,
- * and not the rest of the interrupts which we needed to have as wakeups for
- * cpuidle.
- *
- * PM ops are not used since this needs to be done at the end, after all the
- * other drivers are done with their suspend callbacks.
- */
-void nmk_gpio_wakeups_suspend(void)
-{
-       int i;
-
-       for (i = 0; i < NUM_BANKS; i++) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-               if (!chip)
-                       break;
-
-               clk_enable(chip->clk);
-
-               writel(chip->rwimsc & chip->real_wake,
-                      chip->addr + NMK_GPIO_RWIMSC);
-               writel(chip->fwimsc & chip->real_wake,
-                      chip->addr + NMK_GPIO_FWIMSC);
-
-               clk_disable(chip->clk);
-       }
-}
-
-void nmk_gpio_wakeups_resume(void)
-{
-       int i;
-
-       for (i = 0; i < NUM_BANKS; i++) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-               if (!chip)
-                       break;
-
-               clk_enable(chip->clk);
-
-               writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
-               writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
-
-               clk_disable(chip->clk);
-       }
-}
-
-/*
- * Read the pull up/pull down status.
- * A bit set in 'pull_up' means that pull up
- * is selected if pull is enabled in PDIS register.
- * Note: only pull up/down set via this driver can
- * be detected due to HW limitations.
- */
-void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
-{
-       if (gpio_bank < NUM_BANKS) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[gpio_bank];
-
-               if (!chip)
-                       return;
-
-               *pull_up = chip->pull_up;
-       }
-}
-
 /*
  * We will allocate memory for the state container using devm* allocators
  * binding to the first device reaching this point, it doesn't matter if
index d5bf9fae2ddd425cf32570b668a2c0a5b3aec59f..5020ae5344794da4a64c571bc72e46243c853749 100644 (file)
@@ -53,7 +53,7 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
                                     struct seq_file *s, const char *gname,
                                     unsigned pin,
                                     const struct pin_config_item *items,
-                                    int nitems)
+                                    int nitems, int *print_sep)
 {
        int i;
 
@@ -75,8 +75,10 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
                        seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
                        continue;
                }
-               /* Space between multiple configs */
-               seq_puts(s, " ");
+               /* comma between multiple configs */
+               if (*print_sep)
+                       seq_puts(s, ", ");
+               *print_sep = 1;
                seq_puts(s, items[i].display);
                /* Print unit if available */
                if (items[i].has_arg) {
@@ -105,19 +107,21 @@ void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s,
                               const char *gname, unsigned pin)
 {
        const struct pinconf_ops *ops = pctldev->desc->confops;
+       int print_sep = 0;
 
        if (!ops->is_generic)
                return;
 
        /* generic parameters */
        pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items,
-                                ARRAY_SIZE(conf_items));
+                                ARRAY_SIZE(conf_items), &print_sep);
        /* driver-specific parameters */
        if (pctldev->desc->num_custom_params &&
            pctldev->desc->custom_conf_items)
                pinconf_generic_dump_one(pctldev, s, gname, pin,
                                         pctldev->desc->custom_conf_items,
-                                        pctldev->desc->num_custom_params);
+                                        pctldev->desc->num_custom_params,
+                                        &print_sep);
 }
 
 void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
@@ -391,4 +395,12 @@ exit:
 }
 EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
 
+void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev,
+                                struct pinctrl_map *map,
+                                unsigned num_maps)
+{
+       pinctrl_utils_free_map(pctldev, map, num_maps);
+}
+EXPORT_SYMBOL_GPL(pinconf_generic_dt_free_map);
+
 #endif
index 4dd7722f993552a4c8cd698cdc2f8d224dc337c4..799048f3c8d4ec271c5c8849d3a8f17c8ac4e1ff 100644 (file)
@@ -258,8 +258,7 @@ void pinconf_show_setting(struct seq_file *s,
        case PIN_MAP_TYPE_CONFIGS_PIN:
                desc = pin_desc_get(setting->pctldev,
                                    setting->data.configs.group_or_pin);
-               seq_printf(s, "pin %s (%d)",
-                          desc->name ? desc->name : "unnamed",
+               seq_printf(s, "pin %s (%d)", desc->name,
                           setting->data.configs.group_or_pin);
                break;
        case PIN_MAP_TYPE_CONFIGS_GROUP:
@@ -311,8 +310,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what)
                if (desc == NULL)
                        continue;
 
-               seq_printf(s, "pin %d (%s):", pin,
-                          desc->name ? desc->name : "unnamed");
+               seq_printf(s, "pin %d (%s): ", pin, desc->name);
 
                pinconf_dump_pin(pctldev, s, pin);
 
@@ -349,7 +347,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
        while (selector < ngroups) {
                const char *gname = pctlops->get_group_name(pctldev, selector);
 
-               seq_printf(s, "%u (%s):", selector, gname);
+               seq_printf(s, "%u (%s): ", selector, gname);
                pinconf_dump_group(pctldev, s, selector, gname);
                seq_printf(s, "\n");
 
index a025b40d246bdb66b9556d4fdb306d4cbe3fe8ca..28bbc1bb9e6c4c959c39c9711a170251ad77e274 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinconf.h>
@@ -421,8 +421,8 @@ static int atmel_pctl_get_group_pins(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-struct atmel_group *atmel_pctl_find_group_by_pin(struct pinctrl_dev *pctldev,
-                                                unsigned pin)
+static struct atmel_group *
+atmel_pctl_find_group_by_pin(struct pinctrl_dev *pctldev, unsigned pin)
 {
        struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev);
        int i;
@@ -879,7 +879,6 @@ static const struct of_device_id atmel_pctrl_of_match[] = {
                /* sentinel */
        }
 };
-MODULE_DEVICE_TABLE(of, atmel_pctrl_of_match);
 
 static int atmel_pinctrl_probe(struct platform_device *pdev)
 {
@@ -1074,28 +1073,13 @@ clk_prepare_enable_error:
        return ret;
 }
 
-int atmel_pinctrl_remove(struct platform_device *pdev)
-{
-       struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev);
-
-       irq_domain_remove(atmel_pioctrl->irq_domain);
-       clk_disable_unprepare(atmel_pioctrl->clk);
-       gpiochip_remove(atmel_pioctrl->gpio_chip);
-
-       return 0;
-}
-
 static struct platform_driver atmel_pinctrl_driver = {
        .driver = {
                .name = "pinctrl-at91-pio4",
                .of_match_table = atmel_pctrl_of_match,
                .pm = &atmel_pctrl_pm_ops,
+               .suppress_bind_attrs = true,
        },
        .probe = atmel_pinctrl_probe,
-       .remove = atmel_pinctrl_remove,
 };
-module_platform_driver(atmel_pinctrl_driver);
-
-MODULE_AUTHOR(Ludovic Desroches <ludovic.desroches@atmel.com>);
-MODULE_DESCRIPTION("Atmel PIO4 pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(atmel_pinctrl_driver);
index b7c0d6f7c04631c937530292ee5dec7ecc650f61..80daead3a5a175a0085d05ed4e65f24dbcd465be 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
@@ -189,7 +188,7 @@ struct at91_pinctrl {
        struct at91_pinctrl_mux_ops *ops;
 };
 
-static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name(
+static inline const struct at91_pin_group *at91_pinctrl_find_group_by_name(
                                const struct at91_pinctrl *info,
                                const char *name)
 {
@@ -1818,13 +1817,3 @@ static int __init at91_pinctrl_init(void)
        return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
 }
 arch_initcall(at91_pinctrl_init);
-
-static void __exit at91_pinctrl_exit(void)
-{
-       platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
-}
-
-module_exit(at91_pinctrl_exit);
-MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>");
-MODULE_DESCRIPTION("Atmel AT91 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 30ee56427f560e6d816631c43e148de242ec216a..639a57ecc7c25c23890fc066f18ea37aa5d4c5b0 100644 (file)
@@ -15,7 +15,7 @@
  * - Pin pad configuration (pull up/down, strength)
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -335,27 +335,17 @@ static int dc_pinctrl_probe(struct platform_device *pdev)
        return dc_gpiochip_add(pmap, pdev->dev.of_node);
 }
 
-static int dc_pinctrl_remove(struct platform_device *pdev)
-{
-       struct dc_pinmap *pmap = platform_get_drvdata(pdev);
-
-       gpiochip_remove(&pmap->chip);
-
-       return 0;
-}
-
 static const struct of_device_id dc_pinctrl_ids[] = {
        { .compatible = "cnxt,cx92755-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, dc_pinctrl_ids);
 
 static struct platform_driver dc_pinctrl_driver = {
        .driver = {
                .name = DRIVER_NAME,
                .of_match_table = dc_pinctrl_ids,
+               .suppress_bind_attrs = true,
        },
        .probe = dc_pinctrl_probe,
-       .remove = dc_pinctrl_remove,
 };
-module_platform_driver(dc_pinctrl_driver);
+builtin_platform_driver(dc_pinctrl_driver);
index 8a931c7ba2ffd8e75b917bc05e240bb460399838..e053f1fa551203cdf6e2fdeb2e3d8b78e75bdc0f 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -1365,31 +1365,17 @@ static int lpc18xx_scu_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int lpc18xx_scu_remove(struct platform_device *pdev)
-{
-       struct lpc18xx_scu_data *scu = platform_get_drvdata(pdev);
-
-       clk_disable_unprepare(scu->clk);
-
-       return 0;
-}
-
 static const struct of_device_id lpc18xx_scu_match[] = {
        { .compatible = "nxp,lpc1850-scu" },
        {},
 };
-MODULE_DEVICE_TABLE(of, lpc18xx_scu_match);
 
 static struct platform_driver lpc18xx_scu_driver = {
        .probe          = lpc18xx_scu_probe,
-       .remove         = lpc18xx_scu_remove,
        .driver = {
                .name           = "lpc18xx-scu",
                .of_match_table = lpc18xx_scu_match,
+               .suppress_bind_attrs = true,
        },
 };
-module_platform_driver(lpc18xx_scu_driver);
-
-MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
-MODULE_DESCRIPTION("Pinctrl driver for NXP LPC18xx/43xx SCU");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(lpc18xx_scu_driver);
diff --git a/drivers/pinctrl/pinctrl-max77620.c b/drivers/pinctrl/pinctrl-max77620.c
new file mode 100644 (file)
index 0000000..d9ff53e
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * MAX77620 pin control driver.
+ *
+ * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author:
+ *     Chaitanya Bandi <bandik@nvidia.com>
+ *     Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/mfd/max77620.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinctrl-utils.h"
+
+#define MAX77620_PIN_NUM 8
+
+enum max77620_pin_ppdrv {
+       MAX77620_PIN_UNCONFIG_DRV,
+       MAX77620_PIN_OD_DRV,
+       MAX77620_PIN_PP_DRV,
+};
+
+enum max77620_pinconf_param {
+       MAX77620_ACTIVE_FPS_SOURCE = PIN_CONFIG_END + 1,
+       MAX77620_ACTIVE_FPS_POWER_ON_SLOTS,
+       MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS,
+       MAX77620_SUSPEND_FPS_SOURCE,
+       MAX77620_SUSPEND_FPS_POWER_ON_SLOTS,
+       MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS,
+};
+
+struct max77620_pin_function {
+       const char *name;
+       const char * const *groups;
+       unsigned int ngroups;
+       int mux_option;
+};
+
+static const struct pinconf_generic_params max77620_cfg_params[] = {
+       {
+               .property = "maxim,active-fps-source",
+               .param = MAX77620_ACTIVE_FPS_SOURCE,
+       }, {
+               .property = "maxim,active-fps-power-up-slot",
+               .param = MAX77620_ACTIVE_FPS_POWER_ON_SLOTS,
+       }, {
+               .property = "maxim,active-fps-power-down-slot",
+               .param = MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS,
+       }, {
+               .property = "maxim,suspend-fps-source",
+               .param = MAX77620_SUSPEND_FPS_SOURCE,
+       }, {
+               .property = "maxim,suspend-fps-power-up-slot",
+               .param = MAX77620_SUSPEND_FPS_POWER_ON_SLOTS,
+       }, {
+               .property = "maxim,suspend-fps-power-down-slot",
+               .param = MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS,
+       },
+};
+
+enum max77620_alternate_pinmux_option {
+       MAX77620_PINMUX_GPIO                            = 0,
+       MAX77620_PINMUX_LOW_POWER_MODE_CONTROL_IN       = 1,
+       MAX77620_PINMUX_FLEXIBLE_POWER_SEQUENCER_OUT    = 2,
+       MAX77620_PINMUX_32K_OUT1                        = 3,
+       MAX77620_PINMUX_SD0_DYNAMIC_VOLTAGE_SCALING_IN  = 4,
+       MAX77620_PINMUX_SD1_DYNAMIC_VOLTAGE_SCALING_IN  = 5,
+       MAX77620_PINMUX_REFERENCE_OUT                   = 6,
+};
+
+struct max77620_pingroup {
+       const char *name;
+       const unsigned int pins[1];
+       unsigned int npins;
+       enum max77620_alternate_pinmux_option alt_option;
+};
+
+struct max77620_pin_info {
+       enum max77620_pin_ppdrv drv_type;
+       int pull_config;
+};
+
+struct max77620_fps_config {
+       int active_fps_src;
+       int active_power_up_slots;
+       int active_power_down_slots;
+       int suspend_fps_src;
+       int suspend_power_up_slots;
+       int suspend_power_down_slots;
+};
+
+struct max77620_pctrl_info {
+       struct device *dev;
+       struct pinctrl_dev *pctl;
+       struct regmap *rmap;
+       int pins_current_opt[MAX77620_GPIO_NR];
+       const struct max77620_pin_function *functions;
+       unsigned int num_functions;
+       const struct max77620_pingroup *pin_groups;
+       int num_pin_groups;
+       const struct pinctrl_pin_desc *pins;
+       unsigned int num_pins;
+       struct max77620_pin_info pin_info[MAX77620_PIN_NUM];
+       struct max77620_fps_config fps_config[MAX77620_PIN_NUM];
+};
+
+static const struct pinctrl_pin_desc max77620_pins_desc[] = {
+       PINCTRL_PIN(MAX77620_GPIO0, "gpio0"),
+       PINCTRL_PIN(MAX77620_GPIO1, "gpio1"),
+       PINCTRL_PIN(MAX77620_GPIO2, "gpio2"),
+       PINCTRL_PIN(MAX77620_GPIO3, "gpio3"),
+       PINCTRL_PIN(MAX77620_GPIO4, "gpio4"),
+       PINCTRL_PIN(MAX77620_GPIO5, "gpio5"),
+       PINCTRL_PIN(MAX77620_GPIO6, "gpio6"),
+       PINCTRL_PIN(MAX77620_GPIO7, "gpio7"),
+};
+
+static const char * const gpio_groups[] = {
+       "gpio0",
+       "gpio1",
+       "gpio2",
+       "gpio3",
+       "gpio4",
+       "gpio5",
+       "gpio6",
+       "gpio7",
+};
+
+#define FUNCTION_GROUP(fname, mux)                     \
+       {                                               \
+               .name = fname,                          \
+               .groups = gpio_groups,                  \
+               .ngroups = ARRAY_SIZE(gpio_groups),     \
+               .mux_option = MAX77620_PINMUX_##mux,    \
+       }
+
+static const struct max77620_pin_function max77620_pin_function[] = {
+       FUNCTION_GROUP("gpio", GPIO),
+       FUNCTION_GROUP("lpm-control-in", LOW_POWER_MODE_CONTROL_IN),
+       FUNCTION_GROUP("fps-out", FLEXIBLE_POWER_SEQUENCER_OUT),
+       FUNCTION_GROUP("32k-out1", 32K_OUT1),
+       FUNCTION_GROUP("sd0-dvs-in", SD0_DYNAMIC_VOLTAGE_SCALING_IN),
+       FUNCTION_GROUP("sd1-dvs-in", SD1_DYNAMIC_VOLTAGE_SCALING_IN),
+       FUNCTION_GROUP("reference-out", REFERENCE_OUT),
+};
+
+#define MAX77620_PINGROUP(pg_name, pin_id, option) \
+       {                                                               \
+               .name = #pg_name,                                       \
+               .pins = {MAX77620_##pin_id},                            \
+               .npins = 1,                                             \
+               .alt_option = MAX77620_PINMUX_##option,                 \
+       }
+
+static const struct max77620_pingroup max77620_pingroups[] = {
+       MAX77620_PINGROUP(gpio0, GPIO0, LOW_POWER_MODE_CONTROL_IN),
+       MAX77620_PINGROUP(gpio1, GPIO1, FLEXIBLE_POWER_SEQUENCER_OUT),
+       MAX77620_PINGROUP(gpio2, GPIO2, FLEXIBLE_POWER_SEQUENCER_OUT),
+       MAX77620_PINGROUP(gpio3, GPIO3, FLEXIBLE_POWER_SEQUENCER_OUT),
+       MAX77620_PINGROUP(gpio4, GPIO4, 32K_OUT1),
+       MAX77620_PINGROUP(gpio5, GPIO5, SD0_DYNAMIC_VOLTAGE_SCALING_IN),
+       MAX77620_PINGROUP(gpio6, GPIO6, SD1_DYNAMIC_VOLTAGE_SCALING_IN),
+       MAX77620_PINGROUP(gpio7, GPIO7, REFERENCE_OUT),
+};
+
+static int max77620_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       return mpci->num_pin_groups;
+}
+
+static const char *max77620_pinctrl_get_group_name(
+               struct pinctrl_dev *pctldev, unsigned int group)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       return mpci->pin_groups[group].name;
+}
+
+static int max77620_pinctrl_get_group_pins(
+               struct pinctrl_dev *pctldev, unsigned int group,
+               const unsigned int **pins, unsigned int *num_pins)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       *pins = mpci->pin_groups[group].pins;
+       *num_pins = mpci->pin_groups[group].npins;
+
+       return 0;
+}
+
+static const struct pinctrl_ops max77620_pinctrl_ops = {
+       .get_groups_count = max77620_pinctrl_get_groups_count,
+       .get_group_name = max77620_pinctrl_get_group_name,
+       .get_group_pins = max77620_pinctrl_get_group_pins,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+       .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int max77620_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       return mpci->num_functions;
+}
+
+static const char *max77620_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+                                                 unsigned int function)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       return mpci->functions[function].name;
+}
+
+static int max77620_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+                                           unsigned int function,
+                                           const char * const **groups,
+                                           unsigned int * const num_groups)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = mpci->functions[function].groups;
+       *num_groups = mpci->functions[function].ngroups;
+
+       return 0;
+}
+
+static int max77620_pinctrl_enable(struct pinctrl_dev *pctldev,
+                                  unsigned int function, unsigned int group)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+       u8 val;
+       int ret;
+
+       if (function == MAX77620_PINMUX_GPIO) {
+               val = 0;
+       } else if (function == mpci->pin_groups[group].alt_option) {
+               val = 1 << group;
+       } else {
+               dev_err(mpci->dev, "GPIO %u doesn't have function %u\n",
+                       group, function);
+               return -EINVAL;
+       }
+       ret = regmap_update_bits(mpci->rmap, MAX77620_REG_AME_GPIO,
+                                BIT(group), val);
+       if (ret < 0)
+               dev_err(mpci->dev, "REG AME GPIO update failed: %d\n", ret);
+
+       return ret;
+}
+
+static const struct pinmux_ops max77620_pinmux_ops = {
+       .get_functions_count    = max77620_pinctrl_get_funcs_count,
+       .get_function_name      = max77620_pinctrl_get_func_name,
+       .get_function_groups    = max77620_pinctrl_get_func_groups,
+       .set_mux                = max77620_pinctrl_enable,
+};
+
+static int max77620_pinconf_get(struct pinctrl_dev *pctldev,
+                               unsigned int pin, unsigned long *config)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+       struct device *dev = mpci->dev;
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       unsigned int val;
+       int arg = 0;
+       int ret;
+
+       switch (param) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               if (mpci->pin_info[pin].drv_type == MAX77620_PIN_OD_DRV)
+                       arg = 1;
+               break;
+
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
+               if (mpci->pin_info[pin].drv_type == MAX77620_PIN_PP_DRV)
+                       arg = 1;
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               ret = regmap_read(mpci->rmap, MAX77620_REG_PUE_GPIO, &val);
+               if (ret < 0) {
+                       dev_err(dev, "Reg PUE_GPIO read failed: %d\n", ret);
+                       return ret;
+               }
+               if (val & BIT(pin))
+                       arg = 1;
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               ret = regmap_read(mpci->rmap, MAX77620_REG_PDE_GPIO, &val);
+               if (ret < 0) {
+                       dev_err(dev, "Reg PDE_GPIO read failed: %d\n", ret);
+                       return ret;
+               }
+               if (val & BIT(pin))
+                       arg = 1;
+               break;
+
+       default:
+               dev_err(dev, "Properties not supported\n");
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, (u16)arg);
+
+       return 0;
+}
+
+static int max77620_get_default_fps(struct max77620_pctrl_info *mpci,
+                                   int addr, int *fps)
+{
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(mpci->rmap, addr, &val);
+       if (ret < 0) {
+               dev_err(mpci->dev, "Reg PUE_GPIO read failed: %d\n", ret);
+               return ret;
+       }
+       *fps = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT;
+
+       return 0;
+}
+
+static int max77620_set_fps_param(struct max77620_pctrl_info *mpci,
+                                 int pin, int param)
+{
+       struct max77620_fps_config *fps_config = &mpci->fps_config[pin];
+       int addr, ret;
+       int param_val;
+       int mask, shift;
+
+       if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+               return 0;
+
+       addr = MAX77620_REG_FPS_GPIO1 + pin - 1;
+       switch (param) {
+       case MAX77620_ACTIVE_FPS_SOURCE:
+       case MAX77620_SUSPEND_FPS_SOURCE:
+               mask = MAX77620_FPS_SRC_MASK;
+               shift = MAX77620_FPS_SRC_SHIFT;
+               param_val = fps_config->active_fps_src;
+               if (param == MAX77620_SUSPEND_FPS_SOURCE)
+                       param_val = fps_config->suspend_fps_src;
+               break;
+
+       case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS:
+       case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS:
+               mask = MAX77620_FPS_PU_PERIOD_MASK;
+               shift = MAX77620_FPS_PU_PERIOD_SHIFT;
+               param_val = fps_config->active_power_up_slots;
+               if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS)
+                       param_val = fps_config->suspend_power_up_slots;
+               break;
+
+       case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS:
+       case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS:
+               mask = MAX77620_FPS_PD_PERIOD_MASK;
+               shift = MAX77620_FPS_PD_PERIOD_SHIFT;
+               param_val = fps_config->active_power_down_slots;
+               if (param == MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS)
+                       param_val = fps_config->suspend_power_down_slots;
+               break;
+
+       default:
+               dev_err(mpci->dev, "Invalid parameter %d for pin %d\n",
+                       param, pin);
+               return -EINVAL;
+       }
+
+       if (param_val < 0)
+               return 0;
+
+       ret = regmap_update_bits(mpci->rmap, addr, mask, param_val << shift);
+       if (ret < 0)
+               dev_err(mpci->dev, "Reg 0x%02x update failed %d\n", addr, ret);
+
+       return ret;
+}
+
+static int max77620_pinconf_set(struct pinctrl_dev *pctldev,
+                               unsigned int pin, unsigned long *configs,
+                               unsigned int num_configs)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+       struct device *dev = mpci->dev;
+       struct max77620_fps_config *fps_config;
+       int param;
+       u16 param_val;
+       unsigned int val;
+       unsigned int pu_val;
+       unsigned int pd_val;
+       int addr, ret;
+       int i;
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(configs[i]);
+               param_val = pinconf_to_config_argument(configs[i]);
+
+               switch (param) {
+               case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+                       val = param_val ? 0 : 1;
+                       ret = regmap_update_bits(mpci->rmap,
+                                                MAX77620_REG_GPIO0 + pin,
+                                                MAX77620_CNFG_GPIO_DRV_MASK,
+                                                val);
+                       if (ret < 0) {
+                               dev_err(dev, "Reg 0x%02x update failed %d\n",
+                                       MAX77620_REG_GPIO0 + pin, ret);
+                               return ret;
+                       }
+                       mpci->pin_info[pin].drv_type = val ?
+                               MAX77620_PIN_PP_DRV : MAX77620_PIN_OD_DRV;
+                       break;
+
+               case PIN_CONFIG_DRIVE_PUSH_PULL:
+                       val = param_val ? 1 : 0;
+                       ret = regmap_update_bits(mpci->rmap,
+                                                MAX77620_REG_GPIO0 + pin,
+                                                MAX77620_CNFG_GPIO_DRV_MASK,
+                                                val);
+                       if (ret < 0) {
+                               dev_err(dev, "Reg 0x%02x update failed %d\n",
+                                       MAX77620_REG_GPIO0 + pin, ret);
+                               return ret;
+                       }
+                       mpci->pin_info[pin].drv_type = val ?
+                               MAX77620_PIN_PP_DRV : MAX77620_PIN_OD_DRV;
+                       break;
+
+               case MAX77620_ACTIVE_FPS_SOURCE:
+               case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS:
+               case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS:
+                       if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+                               return -EINVAL;
+
+                       fps_config = &mpci->fps_config[pin];
+
+                       if ((param == MAX77620_ACTIVE_FPS_SOURCE) &&
+                           (param_val == MAX77620_FPS_SRC_DEF)) {
+                               addr = MAX77620_REG_FPS_GPIO1 + pin - 1;
+                               ret = max77620_get_default_fps(
+                                               mpci, addr,
+                                               &fps_config->active_fps_src);
+                               if (ret < 0)
+                                       return ret;
+                               break;
+                       }
+
+                       if (param == MAX77620_ACTIVE_FPS_SOURCE)
+                               fps_config->active_fps_src = param_val;
+                       else if (param == MAX77620_ACTIVE_FPS_POWER_ON_SLOTS)
+                               fps_config->active_power_up_slots = param_val;
+                       else
+                               fps_config->active_power_down_slots = param_val;
+
+                       ret = max77620_set_fps_param(mpci, pin, param);
+                       if (ret < 0)
+                               return ret;
+                       break;
+
+               case MAX77620_SUSPEND_FPS_SOURCE:
+               case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS:
+               case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS:
+                       if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+                               return -EINVAL;
+
+                       fps_config = &mpci->fps_config[pin];
+
+                       if ((param == MAX77620_SUSPEND_FPS_SOURCE) &&
+                           (param_val == MAX77620_FPS_SRC_DEF)) {
+                               addr = MAX77620_REG_FPS_GPIO1 + pin - 1;
+                               ret = max77620_get_default_fps(
+                                               mpci, addr,
+                                               &fps_config->suspend_fps_src);
+                               if (ret < 0)
+                                       return ret;
+                               break;
+                       }
+
+                       if (param == MAX77620_SUSPEND_FPS_SOURCE)
+                               fps_config->suspend_fps_src = param_val;
+                       else if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS)
+                               fps_config->suspend_power_up_slots = param_val;
+                       else
+                               fps_config->suspend_power_down_slots =
+                                                               param_val;
+                       break;
+
+               case PIN_CONFIG_BIAS_PULL_UP:
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       pu_val = (param == PIN_CONFIG_BIAS_PULL_UP) ?
+                                                       BIT(pin) : 0;
+                       pd_val = (param == PIN_CONFIG_BIAS_PULL_DOWN) ?
+                                                       BIT(pin) : 0;
+
+                       ret = regmap_update_bits(mpci->rmap,
+                                                MAX77620_REG_PUE_GPIO,
+                                                BIT(pin), pu_val);
+                       if (ret < 0) {
+                               dev_err(dev, "PUE_GPIO update failed: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       ret = regmap_update_bits(mpci->rmap,
+                                                MAX77620_REG_PDE_GPIO,
+                                                BIT(pin), pd_val);
+                       if (ret < 0) {
+                               dev_err(dev, "PDE_GPIO update failed: %d\n",
+                                       ret);
+                               return ret;
+                       }
+                       break;
+
+               default:
+                       dev_err(dev, "Properties not supported\n");
+                       return -ENOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops max77620_pinconf_ops = {
+       .pin_config_get = max77620_pinconf_get,
+       .pin_config_set = max77620_pinconf_set,
+};
+
+static struct pinctrl_desc max77620_pinctrl_desc = {
+       .pctlops = &max77620_pinctrl_ops,
+       .pmxops = &max77620_pinmux_ops,
+       .confops = &max77620_pinconf_ops,
+};
+
+static int max77620_pinctrl_probe(struct platform_device *pdev)
+{
+       struct max77620_chip *max77620 = dev_get_drvdata(pdev->dev.parent);
+       struct max77620_pctrl_info *mpci;
+       int i;
+
+       mpci = devm_kzalloc(&pdev->dev, sizeof(*mpci), GFP_KERNEL);
+       if (!mpci)
+               return -ENOMEM;
+
+       mpci->dev = &pdev->dev;
+       mpci->dev->of_node = pdev->dev.parent->of_node;
+       mpci->rmap = max77620->rmap;
+
+       mpci->pins = max77620_pins_desc;
+       mpci->num_pins = ARRAY_SIZE(max77620_pins_desc);
+       mpci->functions = max77620_pin_function;
+       mpci->num_functions = ARRAY_SIZE(max77620_pin_function);
+       mpci->pin_groups = max77620_pingroups;
+       mpci->num_pin_groups = ARRAY_SIZE(max77620_pingroups);
+       platform_set_drvdata(pdev, mpci);
+
+       max77620_pinctrl_desc.name = dev_name(&pdev->dev);
+       max77620_pinctrl_desc.pins = max77620_pins_desc;
+       max77620_pinctrl_desc.npins = ARRAY_SIZE(max77620_pins_desc);
+       max77620_pinctrl_desc.num_custom_params =
+                               ARRAY_SIZE(max77620_cfg_params);
+       max77620_pinctrl_desc.custom_params = max77620_cfg_params;
+
+       for (i = 0; i < MAX77620_PIN_NUM; ++i) {
+               mpci->fps_config[i].active_fps_src = -1;
+               mpci->fps_config[i].active_power_up_slots = -1;
+               mpci->fps_config[i].active_power_down_slots = -1;
+               mpci->fps_config[i].suspend_fps_src = -1;
+               mpci->fps_config[i].suspend_power_up_slots = -1;
+               mpci->fps_config[i].suspend_power_down_slots = -1;
+       }
+
+       mpci->pctl = devm_pinctrl_register(&pdev->dev, &max77620_pinctrl_desc,
+                                          mpci);
+       if (IS_ERR(mpci->pctl)) {
+               dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+               return PTR_ERR(mpci->pctl);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max77620_suspend_fps_param[] = {
+       MAX77620_SUSPEND_FPS_SOURCE,
+       MAX77620_SUSPEND_FPS_POWER_ON_SLOTS,
+       MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS,
+};
+
+static int max77620_active_fps_param[] = {
+       MAX77620_ACTIVE_FPS_SOURCE,
+       MAX77620_ACTIVE_FPS_POWER_ON_SLOTS,
+       MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS,
+};
+
+static int max77620_pinctrl_suspend(struct device *dev)
+{
+       struct max77620_pctrl_info *mpci = dev_get_drvdata(dev);
+       int pin, p;
+
+       for (pin = 0; pin < MAX77620_PIN_NUM; ++pin) {
+               if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+                       continue;
+               for (p = 0; p < 3; ++p)
+                       max77620_set_fps_param(
+                               mpci, pin, max77620_suspend_fps_param[p]);
+       }
+
+       return 0;
+};
+
+static int max77620_pinctrl_resume(struct device *dev)
+{
+       struct max77620_pctrl_info *mpci = dev_get_drvdata(dev);
+       int pin, p;
+
+       for (pin = 0; pin < MAX77620_PIN_NUM; ++pin) {
+               if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+                       continue;
+               for (p = 0; p < 3; ++p)
+                       max77620_set_fps_param(
+                               mpci, pin, max77620_active_fps_param[p]);
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops max77620_pinctrl_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(
+               max77620_pinctrl_suspend, max77620_pinctrl_resume)
+};
+
+static const struct platform_device_id max77620_pinctrl_devtype[] = {
+       { .name = "max77620-pinctrl", },
+       { .name = "max20024-pinctrl", },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, max77620_pinctrl_devtype);
+
+static struct platform_driver max77620_pinctrl_driver = {
+       .driver = {
+               .name = "max77620-pinctrl",
+               .pm = &max77620_pinctrl_pm_ops,
+       },
+       .probe = max77620_pinctrl_probe,
+       .id_table = max77620_pinctrl_devtype,
+};
+
+module_platform_driver(max77620_pinctrl_driver);
+
+MODULE_DESCRIPTION("MAX77620/MAX20024 pin control driver");
+MODULE_AUTHOR("Chaitanya Bandi<bandik@nvidia.com>");
+MODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>");
+MODULE_ALIAS("platform:max77620-pinctrl");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-oxnas.c b/drivers/pinctrl/pinctrl-oxnas.c
new file mode 100644 (file)
index 0000000..917a7d2
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * Oxford Semiconductor OXNAS SoC Family pinctrl driver
+ *
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Based on pinctrl-pic32.c
+ * Joshua Henderson, <joshua.henderson@microchip.com>
+ * Copyright (C) 2015 Microchip Technology Inc.  All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "pinctrl-utils.h"
+
+#define PINS_PER_BANK          32
+
+#define GPIO_BANK_START(bank)          ((bank) * PINS_PER_BANK)
+
+/* Regmap Offsets */
+#define PINMUX_PRIMARY_SEL0    0x0c
+#define PINMUX_SECONDARY_SEL0  0x14
+#define PINMUX_TERTIARY_SEL0   0x8c
+#define PINMUX_PRIMARY_SEL1    0x10
+#define PINMUX_SECONDARY_SEL1  0x18
+#define PINMUX_TERTIARY_SEL1   0x90
+#define PINMUX_PULLUP_CTRL0    0xac
+#define PINMUX_PULLUP_CTRL1    0xb0
+
+/* GPIO Registers */
+#define INPUT_VALUE    0x00
+#define OUTPUT_EN      0x04
+#define IRQ_PENDING    0x0c
+#define OUTPUT_SET     0x14
+#define OUTPUT_CLEAR   0x18
+#define OUTPUT_EN_SET  0x1c
+#define OUTPUT_EN_CLEAR        0x20
+#define RE_IRQ_ENABLE  0x28
+#define FE_IRQ_ENABLE  0x2c
+
+struct oxnas_function {
+       const char *name;
+       const char * const *groups;
+       unsigned int ngroups;
+};
+
+struct oxnas_pin_group {
+       const char *name;
+       unsigned int pin;
+       unsigned int bank;
+       struct oxnas_desc_function *functions;
+};
+
+struct oxnas_desc_function {
+       const char *name;
+       unsigned int fct;
+};
+
+struct oxnas_gpio_bank {
+       void __iomem *reg_base;
+       struct gpio_chip gpio_chip;
+       struct irq_chip irq_chip;
+       unsigned int id;
+};
+
+struct oxnas_pinctrl {
+       struct regmap *regmap;
+       struct device *dev;
+       struct pinctrl_dev *pctldev;
+       const struct pinctrl_pin_desc *pins;
+       unsigned int npins;
+       const struct oxnas_function *functions;
+       unsigned int nfunctions;
+       const struct oxnas_pin_group *groups;
+       unsigned int ngroups;
+       struct oxnas_gpio_bank *gpio_banks;
+       unsigned int nbanks;
+};
+
+static const struct pinctrl_pin_desc oxnas_pins[] = {
+       PINCTRL_PIN(0, "gpio0"),
+       PINCTRL_PIN(1, "gpio1"),
+       PINCTRL_PIN(2, "gpio2"),
+       PINCTRL_PIN(3, "gpio3"),
+       PINCTRL_PIN(4, "gpio4"),
+       PINCTRL_PIN(5, "gpio5"),
+       PINCTRL_PIN(6, "gpio6"),
+       PINCTRL_PIN(7, "gpio7"),
+       PINCTRL_PIN(8, "gpio8"),
+       PINCTRL_PIN(9, "gpio9"),
+       PINCTRL_PIN(10, "gpio10"),
+       PINCTRL_PIN(11, "gpio11"),
+       PINCTRL_PIN(12, "gpio12"),
+       PINCTRL_PIN(13, "gpio13"),
+       PINCTRL_PIN(14, "gpio14"),
+       PINCTRL_PIN(15, "gpio15"),
+       PINCTRL_PIN(16, "gpio16"),
+       PINCTRL_PIN(17, "gpio17"),
+       PINCTRL_PIN(18, "gpio18"),
+       PINCTRL_PIN(19, "gpio19"),
+       PINCTRL_PIN(20, "gpio20"),
+       PINCTRL_PIN(21, "gpio21"),
+       PINCTRL_PIN(22, "gpio22"),
+       PINCTRL_PIN(23, "gpio23"),
+       PINCTRL_PIN(24, "gpio24"),
+       PINCTRL_PIN(25, "gpio25"),
+       PINCTRL_PIN(26, "gpio26"),
+       PINCTRL_PIN(27, "gpio27"),
+       PINCTRL_PIN(28, "gpio28"),
+       PINCTRL_PIN(29, "gpio29"),
+       PINCTRL_PIN(30, "gpio30"),
+       PINCTRL_PIN(31, "gpio31"),
+       PINCTRL_PIN(32, "gpio32"),
+       PINCTRL_PIN(33, "gpio33"),
+       PINCTRL_PIN(34, "gpio34"),
+};
+
+static const char * const oxnas_fct0_group[] = {
+       "gpio0",  "gpio1",  "gpio2",  "gpio3",
+       "gpio4",  "gpio5",  "gpio6",  "gpio7",
+       "gpio8",  "gpio9",  "gpio10", "gpio11",
+       "gpio12", "gpio13", "gpio14", "gpio15",
+       "gpio16", "gpio17", "gpio18", "gpio19",
+       "gpio20", "gpio21", "gpio22", "gpio23",
+       "gpio24", "gpio25", "gpio26", "gpio27",
+       "gpio28", "gpio29", "gpio30", "gpio31",
+       "gpio32", "gpio33", "gpio34"
+};
+
+static const char * const oxnas_fct3_group[] = {
+       "gpio0",  "gpio1",  "gpio2",  "gpio3",
+       "gpio4",  "gpio5",  "gpio6",  "gpio7",
+       "gpio8",  "gpio9",
+       "gpio20",
+       "gpio22", "gpio23", "gpio24", "gpio25",
+       "gpio26", "gpio27", "gpio28", "gpio29",
+       "gpio30", "gpio31", "gpio32", "gpio33",
+       "gpio34"
+};
+
+#define FUNCTION(_name, _gr)                                   \
+       {                                                       \
+               .name = #_name,                                 \
+               .groups = oxnas_##_gr##_group,                  \
+               .ngroups = ARRAY_SIZE(oxnas_##_gr##_group),     \
+       }
+
+static const struct oxnas_function oxnas_functions[] = {
+       FUNCTION(gpio, fct0),
+       FUNCTION(fct3, fct3),
+};
+
+#define OXNAS_PINCTRL_GROUP(_pin, _name, ...)                          \
+       {                                                               \
+               .name = #_name,                                         \
+               .pin = _pin,                                            \
+               .bank = _pin / PINS_PER_BANK,                           \
+               .functions = (struct oxnas_desc_function[]){            \
+                       __VA_ARGS__, { } },                             \
+       }
+
+#define OXNAS_PINCTRL_FUNCTION(_name, _fct)            \
+       {                                               \
+               .name = #_name,                         \
+               .fct = _fct,                            \
+       }
+
+static const struct oxnas_pin_group oxnas_groups[] = {
+       OXNAS_PINCTRL_GROUP(0, gpio0,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(1, gpio1,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(2, gpio2,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(3, gpio3,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(4, gpio4,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(5, gpio5,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(6, gpio6,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(7, gpio7,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(8, gpio8,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(9, gpio9,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(10, gpio10,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(11, gpio11,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(12, gpio12,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(13, gpio13,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(14, gpio14,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(15, gpio15,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(16, gpio16,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(17, gpio17,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(18, gpio18,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(19, gpio19,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(20, gpio20,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(21, gpio21,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(22, gpio22,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(23, gpio23,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(24, gpio24,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(25, gpio25,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(26, gpio26,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(27, gpio27,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(28, gpio28,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(29, gpio29,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(30, gpio30,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(31, gpio31,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(32, gpio32,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(33, gpio33,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(34, gpio34,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+};
+
+static inline struct oxnas_gpio_bank *pctl_to_bank(struct oxnas_pinctrl *pctl,
+                                                  unsigned int pin)
+{
+       return &pctl->gpio_banks[pin / PINS_PER_BANK];
+}
+
+static int oxnas_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->ngroups;
+}
+
+static const char *oxnas_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+                                               unsigned int group)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->groups[group].name;
+}
+
+static int oxnas_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+                                       unsigned int group,
+                                       const unsigned int **pins,
+                                       unsigned int *num_pins)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       *pins = &pctl->groups[group].pin;
+       *num_pins = 1;
+
+       return 0;
+}
+
+static const struct pinctrl_ops oxnas_pinctrl_ops = {
+       .get_groups_count = oxnas_pinctrl_get_groups_count,
+       .get_group_name = oxnas_pinctrl_get_group_name,
+       .get_group_pins = oxnas_pinctrl_get_group_pins,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+       .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int oxnas_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->nfunctions;
+}
+
+static const char *
+oxnas_pinmux_get_function_name(struct pinctrl_dev *pctldev, unsigned int func)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->functions[func].name;
+}
+
+static int oxnas_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+                                           unsigned int func,
+                                           const char * const **groups,
+                                           unsigned int * const num_groups)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = pctl->functions[func].groups;
+       *num_groups = pctl->functions[func].ngroups;
+
+       return 0;
+}
+
+static int oxnas_pinmux_enable(struct pinctrl_dev *pctldev,
+                              unsigned int func, unsigned int group)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct oxnas_pin_group *pg = &pctl->groups[group];
+       const struct oxnas_function *pf = &pctl->functions[func];
+       const char *fname = pf->name;
+       struct oxnas_desc_function *functions = pg->functions;
+       u32 mask = BIT(pg->pin);
+
+       while (functions->name) {
+               if (!strcmp(functions->name, fname)) {
+                       dev_dbg(pctl->dev,
+                               "setting function %s bank %d pin %d fct %d mask %x\n",
+                               fname, pg->bank, pg->pin,
+                               functions->fct, mask);
+
+                       regmap_write_bits(pctl->regmap,
+                                         (pg->bank ?
+                                               PINMUX_PRIMARY_SEL1 :
+                                               PINMUX_PRIMARY_SEL0),
+                                         mask,
+                                         (functions->fct == 1 ?
+                                               mask : 0));
+                       regmap_write_bits(pctl->regmap,
+                                         (pg->bank ?
+                                               PINMUX_SECONDARY_SEL1 :
+                                               PINMUX_SECONDARY_SEL0),
+                                         mask,
+                                         (functions->fct == 2 ?
+                                               mask : 0));
+                       regmap_write_bits(pctl->regmap,
+                                         (pg->bank ?
+                                               PINMUX_TERTIARY_SEL1 :
+                                               PINMUX_TERTIARY_SEL0),
+                                         mask,
+                                         (functions->fct == 3 ?
+                                               mask : 0));
+
+                       return 0;
+               }
+
+               functions++;
+       }
+
+       dev_err(pctl->dev, "cannot mux pin %u to function %u\n", group, func);
+
+       return -EINVAL;
+}
+
+static int oxnas_gpio_request_enable(struct pinctrl_dev *pctldev,
+                                    struct pinctrl_gpio_range *range,
+                                    unsigned int offset)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(range->gc);
+       u32 mask = BIT(offset - bank->gpio_chip.base);
+
+       dev_dbg(pctl->dev, "requesting gpio %d in bank %d (id %d) with mask 0x%x\n",
+               offset, bank->gpio_chip.base, bank->id, mask);
+
+       regmap_write_bits(pctl->regmap,
+                         (bank->id ?
+                               PINMUX_PRIMARY_SEL1 :
+                               PINMUX_PRIMARY_SEL0),
+                         mask, 0);
+       regmap_write_bits(pctl->regmap,
+                         (bank->id ?
+                               PINMUX_SECONDARY_SEL1 :
+                               PINMUX_SECONDARY_SEL0),
+                         mask, 0);
+       regmap_write_bits(pctl->regmap,
+                         (bank->id ?
+                               PINMUX_TERTIARY_SEL1 :
+                               PINMUX_TERTIARY_SEL0),
+                         mask, 0);
+
+       return 0;
+}
+
+static int oxnas_gpio_get_direction(struct gpio_chip *chip,
+                                     unsigned int offset)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       return !(readl_relaxed(bank->reg_base + OUTPUT_EN) & mask);
+}
+
+static int oxnas_gpio_direction_input(struct gpio_chip *chip,
+                                     unsigned int offset)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       writel_relaxed(mask, bank->reg_base + OUTPUT_EN_CLEAR);
+
+       return 0;
+}
+
+static int oxnas_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       return (readl_relaxed(bank->reg_base + INPUT_VALUE) & mask) != 0;
+}
+
+static void oxnas_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                              int value)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       if (value)
+               writel_relaxed(mask, bank->reg_base + OUTPUT_SET);
+       else
+               writel_relaxed(mask, bank->reg_base + OUTPUT_CLEAR);
+}
+
+static int oxnas_gpio_direction_output(struct gpio_chip *chip,
+                                      unsigned int offset, int value)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       oxnas_gpio_set(chip, offset, value);
+       writel_relaxed(mask, bank->reg_base + OUTPUT_EN_SET);
+
+       return 0;
+}
+
+static int oxnas_gpio_set_direction(struct pinctrl_dev *pctldev,
+                                   struct pinctrl_gpio_range *range,
+                                   unsigned int offset, bool input)
+{
+       struct gpio_chip *chip = range->gc;
+
+       if (input)
+               oxnas_gpio_direction_input(chip, offset);
+       else
+               oxnas_gpio_direction_output(chip, offset, 0);
+
+       return 0;
+}
+
+static const struct pinmux_ops oxnas_pinmux_ops = {
+       .get_functions_count = oxnas_pinmux_get_functions_count,
+       .get_function_name = oxnas_pinmux_get_function_name,
+       .get_function_groups = oxnas_pinmux_get_function_groups,
+       .set_mux = oxnas_pinmux_enable,
+       .gpio_request_enable = oxnas_gpio_request_enable,
+       .gpio_set_direction = oxnas_gpio_set_direction,
+};
+
+static int oxnas_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                            unsigned long *config)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct oxnas_gpio_bank *bank = pctl_to_bank(pctl, pin);
+       unsigned int param = pinconf_to_config_param(*config);
+       u32 mask = BIT(pin - bank->gpio_chip.base);
+       int ret;
+       u32 arg;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_PULL_UP:
+               ret = regmap_read(pctl->regmap,
+                                 (bank->id ?
+                                       PINMUX_PULLUP_CTRL1 :
+                                       PINMUX_PULLUP_CTRL0),
+                                 &arg);
+               if (ret)
+                       return ret;
+
+               arg = !!(arg & mask);
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+}
+
+static int oxnas_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                            unsigned long *configs, unsigned int num_configs)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct oxnas_gpio_bank *bank = pctl_to_bank(pctl, pin);
+       unsigned int param;
+       u32 arg;
+       unsigned int i;
+       u32 offset = pin - bank->gpio_chip.base;
+       u32 mask = BIT(offset);
+
+       dev_dbg(pctl->dev, "setting pin %d bank %d mask 0x%x\n",
+               pin, bank->gpio_chip.base, mask);
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(configs[i]);
+               arg = pinconf_to_config_argument(configs[i]);
+
+               switch (param) {
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       dev_dbg(pctl->dev, "   pullup\n");
+                       regmap_write_bits(pctl->regmap,
+                                         (bank->id ?
+                                               PINMUX_PULLUP_CTRL1 :
+                                               PINMUX_PULLUP_CTRL0),
+                                         mask, mask);
+                       break;
+               default:
+                       dev_err(pctl->dev, "Property %u not supported\n",
+                               param);
+                       return -ENOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops oxnas_pinconf_ops = {
+       .pin_config_get = oxnas_pinconf_get,
+       .pin_config_set = oxnas_pinconf_set,
+       .is_generic = true,
+};
+
+static struct pinctrl_desc oxnas_pinctrl_desc = {
+       .name = "oxnas-pinctrl",
+       .pctlops = &oxnas_pinctrl_ops,
+       .pmxops = &oxnas_pinmux_ops,
+       .confops = &oxnas_pinconf_ops,
+       .owner = THIS_MODULE,
+};
+
+static void oxnas_gpio_irq_ack(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(data->hwirq);
+
+       writel(mask, bank->reg_base + IRQ_PENDING);
+}
+
+static void oxnas_gpio_irq_mask(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       unsigned int type = irqd_get_trigger_type(data);
+       u32 mask = BIT(data->hwirq);
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               writel(readl(bank->reg_base + RE_IRQ_ENABLE) & ~mask,
+                      bank->reg_base + RE_IRQ_ENABLE);
+
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               writel(readl(bank->reg_base + FE_IRQ_ENABLE) & ~mask,
+                      bank->reg_base + FE_IRQ_ENABLE);
+}
+
+static void oxnas_gpio_irq_unmask(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       unsigned int type = irqd_get_trigger_type(data);
+       u32 mask = BIT(data->hwirq);
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               writel(readl(bank->reg_base + RE_IRQ_ENABLE) | mask,
+                      bank->reg_base + RE_IRQ_ENABLE);
+
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               writel(readl(bank->reg_base + FE_IRQ_ENABLE) | mask,
+                      bank->reg_base + FE_IRQ_ENABLE);
+}
+
+static unsigned int oxnas_gpio_irq_startup(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+
+       oxnas_gpio_direction_input(chip, data->hwirq);
+       oxnas_gpio_irq_unmask(data);
+
+       return 0;
+}
+
+static int oxnas_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       if ((type & (IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING)) == 0)
+               return -EINVAL;
+
+       irq_set_handler_locked(data, handle_edge_irq);
+
+       return 0;
+}
+
+static void oxnas_gpio_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(gc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       unsigned long stat;
+       unsigned int pin;
+
+       chained_irq_enter(chip, desc);
+
+       stat = readl(bank->reg_base + IRQ_PENDING);
+
+       for_each_set_bit(pin, &stat, BITS_PER_LONG)
+               generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+
+       chained_irq_exit(chip, desc);
+}
+
+#define GPIO_BANK(_bank)                                               \
+       {                                                               \
+               .gpio_chip = {                                          \
+                       .label = "GPIO" #_bank,                         \
+                       .request = gpiochip_generic_request,            \
+                       .free = gpiochip_generic_free,                  \
+                       .get_direction = oxnas_gpio_get_direction,      \
+                       .direction_input = oxnas_gpio_direction_input,  \
+                       .direction_output = oxnas_gpio_direction_output, \
+                       .get = oxnas_gpio_get,                          \
+                       .set = oxnas_gpio_set,                          \
+                       .ngpio = PINS_PER_BANK,                         \
+                       .base = GPIO_BANK_START(_bank),                 \
+                       .owner = THIS_MODULE,                           \
+                       .can_sleep = 0,                                 \
+               },                                                      \
+               .irq_chip = {                                           \
+                       .name = "GPIO" #_bank,                          \
+                       .irq_startup = oxnas_gpio_irq_startup,  \
+                       .irq_ack = oxnas_gpio_irq_ack,          \
+                       .irq_mask = oxnas_gpio_irq_mask,                \
+                       .irq_unmask = oxnas_gpio_irq_unmask,            \
+                       .irq_set_type = oxnas_gpio_irq_set_type,        \
+               },                                                      \
+       }
+
+static struct oxnas_gpio_bank oxnas_gpio_banks[] = {
+       GPIO_BANK(0),
+       GPIO_BANK(1),
+};
+
+static int oxnas_pinctrl_probe(struct platform_device *pdev)
+{
+       struct oxnas_pinctrl *pctl;
+
+       pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+       if (!pctl)
+               return -ENOMEM;
+       pctl->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, pctl);
+
+       pctl->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                      "oxsemi,sys-ctrl");
+       if (IS_ERR(pctl->regmap)) {
+               dev_err(&pdev->dev, "failed to get sys ctrl regmap\n");
+               return -ENODEV;
+       }
+
+       pctl->pins = oxnas_pins;
+       pctl->npins = ARRAY_SIZE(oxnas_pins);
+       pctl->functions = oxnas_functions;
+       pctl->nfunctions = ARRAY_SIZE(oxnas_functions);
+       pctl->groups = oxnas_groups;
+       pctl->ngroups = ARRAY_SIZE(oxnas_groups);
+       pctl->gpio_banks = oxnas_gpio_banks;
+       pctl->nbanks = ARRAY_SIZE(oxnas_gpio_banks);
+
+       oxnas_pinctrl_desc.pins = pctl->pins;
+       oxnas_pinctrl_desc.npins = pctl->npins;
+
+       pctl->pctldev = pinctrl_register(&oxnas_pinctrl_desc,
+                                        &pdev->dev, pctl);
+       if (IS_ERR(pctl->pctldev)) {
+               dev_err(&pdev->dev, "Failed to register pinctrl device\n");
+               return PTR_ERR(pctl->pctldev);
+       }
+
+       return 0;
+}
+
+static int oxnas_gpio_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct of_phandle_args pinspec;
+       struct oxnas_gpio_bank *bank;
+       unsigned int id, ngpios;
+       int irq, ret;
+       struct resource *res;
+
+       if (of_parse_phandle_with_fixed_args(np, "gpio-ranges",
+                                            3, 0, &pinspec)) {
+               dev_err(&pdev->dev, "gpio-ranges property not found\n");
+               return -EINVAL;
+       }
+
+       id = pinspec.args[1] / PINS_PER_BANK;
+       ngpios = pinspec.args[2];
+
+       if (id >= ARRAY_SIZE(oxnas_gpio_banks)) {
+               dev_err(&pdev->dev, "invalid gpio-ranges base arg\n");
+               return -EINVAL;
+       }
+
+       if (ngpios > PINS_PER_BANK) {
+               dev_err(&pdev->dev, "invalid gpio-ranges count arg\n");
+               return -EINVAL;
+       }
+
+       bank = &oxnas_gpio_banks[id];
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       bank->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(bank->reg_base))
+               return PTR_ERR(bank->reg_base);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "irq get failed\n");
+               return irq;
+       }
+
+       bank->id = id;
+       bank->gpio_chip.parent = &pdev->dev;
+       bank->gpio_chip.of_node = np;
+       bank->gpio_chip.ngpio = ngpios;
+       ret = gpiochip_add_data(&bank->gpio_chip, bank);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to add GPIO chip %u: %d\n",
+                       id, ret);
+               return ret;
+       }
+
+       ret = gpiochip_irqchip_add(&bank->gpio_chip, &bank->irq_chip,
+                               0, handle_level_irq, IRQ_TYPE_NONE);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to add IRQ chip %u: %d\n",
+                       id, ret);
+               gpiochip_remove(&bank->gpio_chip);
+               return ret;
+       }
+
+       gpiochip_set_chained_irqchip(&bank->gpio_chip, &bank->irq_chip,
+                                    irq, oxnas_gpio_irq_handler);
+
+       return 0;
+}
+
+static const struct of_device_id oxnas_pinctrl_of_match[] = {
+       { .compatible = "oxsemi,ox810se-pinctrl", },
+       { },
+};
+
+static struct platform_driver oxnas_pinctrl_driver = {
+       .driver = {
+               .name = "oxnas-pinctrl",
+               .of_match_table = oxnas_pinctrl_of_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = oxnas_pinctrl_probe,
+};
+
+static const struct of_device_id oxnas_gpio_of_match[] = {
+       { .compatible = "oxsemi,ox810se-gpio", },
+       { },
+};
+
+static struct platform_driver oxnas_gpio_driver = {
+       .driver = {
+               .name = "oxnas-gpio",
+               .of_match_table = oxnas_gpio_of_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = oxnas_gpio_probe,
+};
+
+static int __init oxnas_gpio_register(void)
+{
+       return platform_driver_register(&oxnas_gpio_driver);
+}
+arch_initcall(oxnas_gpio_register);
+
+static int __init oxnas_pinctrl_register(void)
+{
+       return platform_driver_register(&oxnas_pinctrl_driver);
+}
+arch_initcall(oxnas_pinctrl_register);
index a91026e8cd7c1ab09f6328841f2b6499362d4141..44902c63f507de1a0ad137254b036b46f15be1f1 100644 (file)
@@ -360,7 +360,7 @@ static struct regmap_config rockchip_regmap_config = {
        .reg_stride = 4,
 };
 
-static const inline struct rockchip_pin_group *pinctrl_name_to_group(
+static inline const struct rockchip_pin_group *pinctrl_name_to_group(
                                        const struct rockchip_pinctrl *info,
                                        const char *name)
 {
@@ -2007,7 +2007,7 @@ static void rockchip_irq_gc_mask_clr_bit(struct irq_data *d)
        irq_gc_mask_clr_bit(d);
 }
 
-void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
+static void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct rockchip_pin_bank *bank = gc->private;
index d0ba968af5bb19acb2d5e1b35316898340af852a..0de1c67dfb94cc70e03a56d393140790a0e44cd6 100644 (file)
@@ -844,7 +844,7 @@ static int st_pctl_get_group_pins(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static const inline struct st_pctl_group *st_pctl_find_group_by_name(
+static inline const struct st_pctl_group *st_pctl_find_group_by_name(
        const struct st_pinctrl *info, const char *name)
 {
        int i;
index d1af908a706036de500085f01723632aa1cc804a..9cc80a500880f8285d90b33277b876e950e30460 100644 (file)
@@ -670,7 +670,7 @@ struct u300_pmx {
  * u300_pmx_registers - the array of registers read/written for each pinmux
  * shunt setting
  */
-const u32 u300_pmx_registers[] = {
+static const u32 u300_pmx_registers[] = {
        U300_SYSCON_PMC1LR,
        U300_SYSCON_PMC1HR,
        U300_SYSCON_PMC2R,
index b9375544dff0be4432ff64eea5846780b1c6b05d..dd85ad1807f52f36b5ea0fa4bf1639e7f4b42622 100644 (file)
@@ -1616,50 +1616,74 @@ struct pinctrl_xway_soc {
 
 /* xway xr9 series (DEPRECATED: Use XWAY xRX100/xRX200 Family) */
 static struct pinctrl_xway_soc xr9_pinctrl = {
-       XR9_MAX_PIN, xway_mfp,
-       xway_grps, ARRAY_SIZE(xway_grps),
-       xrx_funcs, ARRAY_SIZE(xrx_funcs),
-       xway_exin_pin_map, 6
+       .pin_count = XR9_MAX_PIN,
+       .mfp = xway_mfp,
+       .grps = xway_grps,
+       .num_grps = ARRAY_SIZE(xway_grps),
+       .funcs = xrx_funcs,
+       .num_funcs = ARRAY_SIZE(xrx_funcs),
+       .exin = xway_exin_pin_map,
+       .num_exin = 6
 };
 
 /* XWAY AMAZON Family */
 static struct pinctrl_xway_soc ase_pinctrl = {
-       ASE_MAX_PIN, ase_mfp,
-       ase_grps, ARRAY_SIZE(ase_grps),
-       ase_funcs, ARRAY_SIZE(ase_funcs),
-       ase_exin_pin_map, 3
+       .pin_count = ASE_MAX_PIN,
+       .mfp = ase_mfp,
+       .grps = ase_grps,
+       .num_grps = ARRAY_SIZE(ase_grps),
+       .funcs = ase_funcs,
+       .num_funcs = ARRAY_SIZE(ase_funcs),
+       .exin = ase_exin_pin_map,
+       .num_exin = 3
 };
 
 /* XWAY DANUBE Family */
 static struct pinctrl_xway_soc danube_pinctrl = {
-       DANUBE_MAX_PIN, danube_mfp,
-       danube_grps, ARRAY_SIZE(danube_grps),
-       danube_funcs, ARRAY_SIZE(danube_funcs),
-       danube_exin_pin_map, 3
+       .pin_count = DANUBE_MAX_PIN,
+       .mfp = danube_mfp,
+       .grps = danube_grps,
+       .num_grps = ARRAY_SIZE(danube_grps),
+       .funcs = danube_funcs,
+       .num_funcs = ARRAY_SIZE(danube_funcs),
+       .exin = danube_exin_pin_map,
+       .num_exin = 3
 };
 
 /* XWAY xRX100 Family */
 static struct pinctrl_xway_soc xrx100_pinctrl = {
-       XRX100_MAX_PIN, xrx100_mfp,
-       xrx100_grps, ARRAY_SIZE(xrx100_grps),
-       xrx100_funcs, ARRAY_SIZE(xrx100_funcs),
-       xrx100_exin_pin_map, 6
+       .pin_count = XRX100_MAX_PIN,
+       .mfp = xrx100_mfp,
+       .grps = xrx100_grps,
+       .num_grps = ARRAY_SIZE(xrx100_grps),
+       .funcs = xrx100_funcs,
+       .num_funcs = ARRAY_SIZE(xrx100_funcs),
+       .exin = xrx100_exin_pin_map,
+       .num_exin = 6
 };
 
 /* XWAY xRX200 Family */
 static struct pinctrl_xway_soc xrx200_pinctrl = {
-       XRX200_MAX_PIN, xrx200_mfp,
-       xrx200_grps, ARRAY_SIZE(xrx200_grps),
-       xrx200_funcs, ARRAY_SIZE(xrx200_funcs),
-       xrx200_exin_pin_map, 6
+       .pin_count = XRX200_MAX_PIN,
+       .mfp = xrx200_mfp,
+       .grps = xrx200_grps,
+       .num_grps = ARRAY_SIZE(xrx200_grps),
+       .funcs = xrx200_funcs,
+       .num_funcs = ARRAY_SIZE(xrx200_funcs),
+       .exin = xrx200_exin_pin_map,
+       .num_exin = 6
 };
 
 /* XWAY xRX300 Family */
 static struct pinctrl_xway_soc xrx300_pinctrl = {
-       XRX300_MAX_PIN, xrx300_mfp,
-       xrx300_grps, ARRAY_SIZE(xrx300_grps),
-       xrx300_funcs, ARRAY_SIZE(xrx300_funcs),
-       xrx300_exin_pin_map, 5
+       .pin_count = XRX300_MAX_PIN,
+       .mfp = xrx300_mfp,
+       .grps = xrx300_grps,
+       .num_grps = ARRAY_SIZE(xrx300_grps),
+       .funcs = xrx300_funcs,
+       .num_funcs = ARRAY_SIZE(xrx300_funcs),
+       .exin = xrx300_exin_pin_map,
+       .num_exin = 5
 };
 
 static struct pinctrl_gpio_range xway_gpio_range = {
index 8fdc60c5aeaf73c375e9258c57157c9fec52a758..7afdbede682314654c3d901374c312641aa0f1b7 100644 (file)
@@ -20,7 +20,7 @@
  */
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -1210,7 +1210,6 @@ static const struct of_device_id zynq_pinctrl_of_match[] = {
        { .compatible = "xlnx,pinctrl-zynq" },
        { }
 };
-MODULE_DEVICE_TABLE(of, zynq_pinctrl_of_match);
 
 static struct platform_driver zynq_pinctrl_driver = {
        .driver = {
@@ -1225,13 +1224,3 @@ static int __init zynq_pinctrl_init(void)
        return platform_driver_register(&zynq_pinctrl_driver);
 }
 arch_initcall(zynq_pinctrl_init);
-
-static void __exit zynq_pinctrl_exit(void)
-{
-       platform_driver_unregister(&zynq_pinctrl_driver);
-}
-module_exit(zynq_pinctrl_exit);
-
-MODULE_AUTHOR("Sören Brinkmann <soren.brinkmann@xilinx.com>");
-MODULE_DESCRIPTION("Xilinx Zynq pinctrl driver");
-MODULE_LICENSE("GPL");
index c223a9ef1fe1fb3def95cddbeabfa367ef94dcfe..ece702881946dd849cae2e7adf2c992697b29fdd 100644 (file)
@@ -256,7 +256,7 @@ int pinmux_request_gpio(struct pinctrl_dev *pctldev,
        /* Conjure some name stating what chip and pin this is taken by */
        owner = kasprintf(GFP_KERNEL, "%s:%d", range->name, gpio);
        if (!owner)
-               return -EINVAL;
+               return -ENOMEM;
 
        ret = pin_request(pctldev, pin, owner, range);
        if (ret < 0)
@@ -606,23 +606,17 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
                if (pmxops->strict) {
                        if (desc->mux_owner)
                                seq_printf(s, "pin %d (%s): device %s%s",
-                                          pin,
-                                          desc->name ? desc->name : "unnamed",
-                                          desc->mux_owner,
+                                          pin, desc->name, desc->mux_owner,
                                           is_hog ? " (HOG)" : "");
                        else if (desc->gpio_owner)
                                seq_printf(s, "pin %d (%s): GPIO %s",
-                                          pin,
-                                          desc->name ? desc->name : "unnamed",
-                                          desc->gpio_owner);
+                                          pin, desc->name, desc->gpio_owner);
                        else
                                seq_printf(s, "pin %d (%s): UNCLAIMED",
-                                          pin,
-                                          desc->name ? desc->name : "unnamed");
+                                          pin, desc->name);
                } else {
                        /* For non-strict controllers */
-                       seq_printf(s, "pin %d (%s): %s %s%s", pin,
-                                  desc->name ? desc->name : "unnamed",
+                       seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name,
                                   desc->mux_owner ? desc->mux_owner
                                   : "(MUX UNCLAIMED)",
                                   desc->gpio_owner ? desc->gpio_owner
index 67bc70dcda64ae5295c9798d23e525aab4f71370..93ef268d5ccdbcab5a78a055dd9c4f87d133da95 100644 (file)
@@ -55,6 +55,14 @@ config PINCTRL_MSM8960
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
          Qualcomm TLMM block found in the Qualcomm 8960 platform.
 
+config PINCTRL_MDM9615
+       tristate "Qualcomm 9615 pin controller driver"
+       depends on GPIOLIB && OF
+       select PINCTRL_MSM
+       help
+         This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+         Qualcomm TLMM block found in the Qualcomm 9615 platform.
+
 config PINCTRL_MSM8X74
        tristate "Qualcomm 8x74 pin controller driver"
        depends on GPIOLIB && OF
index c964a2c4b90ad4bd36d97d319016e51eb8e3753d..8319e11cecb57c75a84d18c7641fb729e9028cb6 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o
 obj-$(CONFIG_PINCTRL_MSM8916)  += pinctrl-msm8916.o
 obj-$(CONFIG_PINCTRL_MSM8996)   += pinctrl-msm8996.o
 obj-$(CONFIG_PINCTRL_QDF2XXX)  += pinctrl-qdf2xxx.o
+obj-$(CONFIG_PINCTRL_MDM9615)  += pinctrl-mdm9615.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
 obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9615.c b/drivers/pinctrl/qcom/pinctrl-mdm9615.c
new file mode 100644 (file)
index 0000000..2b8f452
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2014, Sony Mobile Communications AB.
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author : Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 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.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-msm.h"
+
+static const struct pinctrl_pin_desc mdm9615_pins[] = {
+       PINCTRL_PIN(0, "GPIO_0"),
+       PINCTRL_PIN(1, "GPIO_1"),
+       PINCTRL_PIN(2, "GPIO_2"),
+       PINCTRL_PIN(3, "GPIO_3"),
+       PINCTRL_PIN(4, "GPIO_4"),
+       PINCTRL_PIN(5, "GPIO_5"),
+       PINCTRL_PIN(6, "GPIO_6"),
+       PINCTRL_PIN(7, "GPIO_7"),
+       PINCTRL_PIN(8, "GPIO_8"),
+       PINCTRL_PIN(9, "GPIO_9"),
+       PINCTRL_PIN(10, "GPIO_10"),
+       PINCTRL_PIN(11, "GPIO_11"),
+       PINCTRL_PIN(12, "GPIO_12"),
+       PINCTRL_PIN(13, "GPIO_13"),
+       PINCTRL_PIN(14, "GPIO_14"),
+       PINCTRL_PIN(15, "GPIO_15"),
+       PINCTRL_PIN(16, "GPIO_16"),
+       PINCTRL_PIN(17, "GPIO_17"),
+       PINCTRL_PIN(18, "GPIO_18"),
+       PINCTRL_PIN(19, "GPIO_19"),
+       PINCTRL_PIN(20, "GPIO_20"),
+       PINCTRL_PIN(21, "GPIO_21"),
+       PINCTRL_PIN(22, "GPIO_22"),
+       PINCTRL_PIN(23, "GPIO_23"),
+       PINCTRL_PIN(24, "GPIO_24"),
+       PINCTRL_PIN(25, "GPIO_25"),
+       PINCTRL_PIN(26, "GPIO_26"),
+       PINCTRL_PIN(27, "GPIO_27"),
+       PINCTRL_PIN(28, "GPIO_28"),
+       PINCTRL_PIN(29, "GPIO_29"),
+       PINCTRL_PIN(30, "GPIO_30"),
+       PINCTRL_PIN(31, "GPIO_31"),
+       PINCTRL_PIN(32, "GPIO_32"),
+       PINCTRL_PIN(33, "GPIO_33"),
+       PINCTRL_PIN(34, "GPIO_34"),
+       PINCTRL_PIN(35, "GPIO_35"),
+       PINCTRL_PIN(36, "GPIO_36"),
+       PINCTRL_PIN(37, "GPIO_37"),
+       PINCTRL_PIN(38, "GPIO_38"),
+       PINCTRL_PIN(39, "GPIO_39"),
+       PINCTRL_PIN(40, "GPIO_40"),
+       PINCTRL_PIN(41, "GPIO_41"),
+       PINCTRL_PIN(42, "GPIO_42"),
+       PINCTRL_PIN(43, "GPIO_43"),
+       PINCTRL_PIN(44, "GPIO_44"),
+       PINCTRL_PIN(45, "GPIO_45"),
+       PINCTRL_PIN(46, "GPIO_46"),
+       PINCTRL_PIN(47, "GPIO_47"),
+       PINCTRL_PIN(48, "GPIO_48"),
+       PINCTRL_PIN(49, "GPIO_49"),
+       PINCTRL_PIN(50, "GPIO_50"),
+       PINCTRL_PIN(51, "GPIO_51"),
+       PINCTRL_PIN(52, "GPIO_52"),
+       PINCTRL_PIN(53, "GPIO_53"),
+       PINCTRL_PIN(54, "GPIO_54"),
+       PINCTRL_PIN(55, "GPIO_55"),
+       PINCTRL_PIN(56, "GPIO_56"),
+       PINCTRL_PIN(57, "GPIO_57"),
+       PINCTRL_PIN(58, "GPIO_58"),
+       PINCTRL_PIN(59, "GPIO_59"),
+       PINCTRL_PIN(60, "GPIO_60"),
+       PINCTRL_PIN(61, "GPIO_61"),
+       PINCTRL_PIN(62, "GPIO_62"),
+       PINCTRL_PIN(63, "GPIO_63"),
+       PINCTRL_PIN(64, "GPIO_64"),
+       PINCTRL_PIN(65, "GPIO_65"),
+       PINCTRL_PIN(66, "GPIO_66"),
+       PINCTRL_PIN(67, "GPIO_67"),
+       PINCTRL_PIN(68, "GPIO_68"),
+       PINCTRL_PIN(69, "GPIO_69"),
+       PINCTRL_PIN(70, "GPIO_70"),
+       PINCTRL_PIN(71, "GPIO_71"),
+       PINCTRL_PIN(72, "GPIO_72"),
+       PINCTRL_PIN(73, "GPIO_73"),
+       PINCTRL_PIN(74, "GPIO_74"),
+       PINCTRL_PIN(75, "GPIO_75"),
+       PINCTRL_PIN(76, "GPIO_76"),
+       PINCTRL_PIN(77, "GPIO_77"),
+       PINCTRL_PIN(78, "GPIO_78"),
+       PINCTRL_PIN(79, "GPIO_79"),
+       PINCTRL_PIN(80, "GPIO_80"),
+       PINCTRL_PIN(81, "GPIO_81"),
+       PINCTRL_PIN(82, "GPIO_82"),
+       PINCTRL_PIN(83, "GPIO_83"),
+       PINCTRL_PIN(84, "GPIO_84"),
+       PINCTRL_PIN(85, "GPIO_85"),
+       PINCTRL_PIN(86, "GPIO_86"),
+       PINCTRL_PIN(87, "GPIO_87"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+       static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+
+#define FUNCTION(fname)                                        \
+       [MSM_MUX_##fname] = {                           \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \
+       {                                               \
+               .name = "gpio" #id,                     \
+               .pins = gpio##id##_pins,                \
+               .npins = ARRAY_SIZE(gpio##id##_pins),   \
+               .funcs = (int[]){                       \
+                       MSM_MUX_gpio,                   \
+                       MSM_MUX_##f1,                   \
+                       MSM_MUX_##f2,                   \
+                       MSM_MUX_##f3,                   \
+                       MSM_MUX_##f4,                   \
+                       MSM_MUX_##f5,                   \
+                       MSM_MUX_##f6,                   \
+                       MSM_MUX_##f7,                   \
+                       MSM_MUX_##f8,                   \
+                       MSM_MUX_##f9,                   \
+                       MSM_MUX_##f10,                  \
+                       MSM_MUX_##f11                   \
+               },                                      \
+               .nfuncs = 12,                           \
+               .ctl_reg = 0x1000 + 0x10 * id,          \
+               .io_reg = 0x1004 + 0x10 * id,           \
+               .intr_cfg_reg = 0x1008 + 0x10 * id,     \
+               .intr_status_reg = 0x100c + 0x10 * id,  \
+               .intr_target_reg = 0x400 + 0x4 * id,    \
+               .mux_bit = 2,                           \
+               .pull_bit = 0,                          \
+               .drv_bit = 6,                           \
+               .oe_bit = 9,                            \
+               .in_bit = 0,                            \
+               .out_bit = 1,                           \
+               .intr_enable_bit = 0,                   \
+               .intr_status_bit = 0,                   \
+               .intr_ack_high = 1,                     \
+               .intr_target_bit = 0,                   \
+               .intr_target_kpss_val = 4,              \
+               .intr_raw_status_bit = 3,               \
+               .intr_polarity_bit = 1,                 \
+               .intr_detection_bit = 2,                \
+               .intr_detection_width = 1,              \
+       }
+
+enum mdm9615_functions {
+       MSM_MUX_gpio,
+       MSM_MUX_gsbi2_i2c,
+       MSM_MUX_gsbi3,
+       MSM_MUX_gsbi4,
+       MSM_MUX_gsbi5_i2c,
+       MSM_MUX_gsbi5_uart,
+       MSM_MUX_sdc2,
+       MSM_MUX_ebi2_lcdc,
+       MSM_MUX_ps_hold,
+       MSM_MUX_prim_audio,
+       MSM_MUX_sec_audio,
+       MSM_MUX_cdc_mclk,
+       MSM_MUX_NA,
+};
+
+static const char * const gpio_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+       "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+       "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+       "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+       "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+       "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+       "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+       "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+       "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+       "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+       "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+       "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+       "gpio85", "gpio86", "gpio87"
+};
+
+static const char * const gsbi2_i2c_groups[] = {
+       "gpio4", "gpio5"
+};
+
+static const char * const gsbi3_groups[] = {
+       "gpio8", "gpio9", "gpio10", "gpio11"
+};
+
+static const char * const gsbi4_groups[] = {
+       "gpio12", "gpio13", "gpio14", "gpio15"
+};
+
+static const char * const gsbi5_i2c_groups[] = {
+       "gpio16", "gpio17"
+};
+
+static const char * const gsbi5_uart_groups[] = {
+       "gpio18", "gpio19"
+};
+
+static const char * const sdc2_groups[] = {
+       "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30",
+};
+
+static const char * const ebi2_lcdc_groups[] = {
+       "gpio21", "gpio22", "gpio24",
+};
+
+static const char * const ps_hold_groups[] = {
+       "gpio83",
+};
+
+static const char * const prim_audio_groups[] = {
+       "gpio20", "gpio21", "gpio22", "gpio23",
+};
+
+static const char * const sec_audio_groups[] = {
+       "gpio25", "gpio26", "gpio27", "gpio28",
+};
+
+static const char * const cdc_mclk_groups[] = {
+       "gpio24",
+};
+
+static const struct msm_function mdm9615_functions[] = {
+       FUNCTION(gpio),
+       FUNCTION(gsbi2_i2c),
+       FUNCTION(gsbi3),
+       FUNCTION(gsbi4),
+       FUNCTION(gsbi5_i2c),
+       FUNCTION(gsbi5_uart),
+       FUNCTION(sdc2),
+       FUNCTION(ebi2_lcdc),
+       FUNCTION(ps_hold),
+       FUNCTION(prim_audio),
+       FUNCTION(sec_audio),
+       FUNCTION(cdc_mclk),
+};
+
+static const struct msm_pingroup mdm9615_groups[] = {
+       PINGROUP(0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(4, gsbi2_i2c, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(5, gsbi2_i2c, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(6, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(7, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(8, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(9, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(10, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(11, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(12, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(13, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(14, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(15, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(16, gsbi5_i2c, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(17, gsbi5_i2c, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(18, gsbi5_uart, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(19, gsbi5_uart, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(20, prim_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(21, prim_audio, ebi2_lcdc, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(22, prim_audio, ebi2_lcdc, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(23, prim_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(24, cdc_mclk, NA, ebi2_lcdc, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(25, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(26, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(27, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(28, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(29, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(30, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(31, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(32, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(33, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(34, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(35, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(36, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(37, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(38, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(39, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(40, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(41, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(42, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(43, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(44, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(45, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(46, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(47, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(48, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(49, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(50, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(51, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(52, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(53, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(54, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(55, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(56, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(57, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(58, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(63, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(65, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(67, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(68, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(69, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(79, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(82, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(83, ps_hold, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(84, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(85, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(86, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+};
+
+#define NUM_GPIO_PINGROUPS 88
+
+static const struct msm_pinctrl_soc_data mdm9615_pinctrl = {
+       .pins = mdm9615_pins,
+       .npins = ARRAY_SIZE(mdm9615_pins),
+       .functions = mdm9615_functions,
+       .nfunctions = ARRAY_SIZE(mdm9615_functions),
+       .groups = mdm9615_groups,
+       .ngroups = ARRAY_SIZE(mdm9615_groups),
+       .ngpios = NUM_GPIO_PINGROUPS,
+};
+
+static int mdm9615_pinctrl_probe(struct platform_device *pdev)
+{
+       return msm_pinctrl_probe(pdev, &mdm9615_pinctrl);
+}
+
+static const struct of_device_id mdm9615_pinctrl_of_match[] = {
+       { .compatible = "qcom,mdm9615-pinctrl", },
+       { },
+};
+
+static struct platform_driver mdm9615_pinctrl_driver = {
+       .driver = {
+               .name = "mdm9615-pinctrl",
+               .of_match_table = mdm9615_pinctrl_of_match,
+       },
+       .probe = mdm9615_pinctrl_probe,
+       .remove = msm_pinctrl_remove,
+};
+
+static int __init mdm9615_pinctrl_init(void)
+{
+       return platform_driver_register(&mdm9615_pinctrl_driver);
+}
+arch_initcall(mdm9615_pinctrl_init);
+
+static void __exit mdm9615_pinctrl_exit(void)
+{
+       platform_driver_unregister(&mdm9615_pinctrl_driver);
+}
+module_exit(mdm9615_pinctrl_exit);
+
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Qualcomm MDM9615 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, mdm9615_pinctrl_of_match);
index 1a44e1d033905b8a884f170b710ea219365218c3..51c42d7468837f74344452e8b8ed269646393ef6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/spinlock.h>
 #include <linux/reboot.h>
 #include <linux/pm.h>
+#include <linux/log2.h>
 
 #include "../core.h"
 #include "../pinconf.h"
@@ -138,10 +139,11 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
        struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        const struct msm_pingroup *g;
        unsigned long flags;
-       u32 val;
+       u32 val, mask;
        int i;
 
        g = &pctrl->soc->groups[group];
+       mask = GENMASK(g->mux_bit + order_base_2(g->nfuncs) - 1, g->mux_bit);
 
        for (i = 0; i < g->nfuncs; i++) {
                if (g->funcs[i] == function)
@@ -154,7 +156,7 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
        spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->ctl_reg);
-       val &= ~(0x7 << g->mux_bit);
+       val &= mask;
        val |= i << g->mux_bit;
        writel(val, pctrl->regs + g->ctl_reg);
 
index 3e8f7ac2ac8ab42cc809b95a8d799d5e729098e7..5591d093bf7804560b79631ab716b29fd46ac33e 100644 (file)
@@ -506,6 +506,8 @@ enum msm8660_functions {
        MSM_MUX_usb_fs2_oe_n,
        MSM_MUX_vfe,
        MSM_MUX_vsens_alarm,
+       MSM_MUX_ebi2cs,
+       MSM_MUX_ebi2,
        MSM_MUX__,
 };
 
@@ -696,6 +698,36 @@ static const char * const vfe_groups[] = {
 static const char * const vsens_alarm_groups[] = {
        "gpio127"
 };
+static const char * const ebi2cs_groups[] = {
+       "gpio39", /* CS1A */
+       "gpio40", /* CS2A */
+       "gpio123", /* CS1B */
+       "gpio124", /* CS2B */
+       "gpio131", /* CS5 */
+       "gpio132", /* CS4 */
+       "gpio133", /* CS3 */
+       "gpio134", /* CS0 */
+};
+static const char * const ebi2_groups[] = {
+       /* ADDR9 & ADDR8 */
+       "gpio37", "gpio38",
+       /* ADDR7 - ADDR 0 */
+       "gpio123", "gpio124", "gpio125", "gpio126",
+       "gpio127", "gpio128", "gpio129", "gpio130",
+       /* (muxed address+data) AD15 - AD0 */
+       "gpio135", "gpio136", "gpio137", "gpio138", "gpio139",
+       "gpio140", "gpio141", "gpio142", "gpio143", "gpio144",
+       "gpio145", "gpio146", "gpio147", "gpio148", "gpio149",
+       "gpio150",
+       "gpio151", /* OE output enable */
+       "gpio152", /* clock */
+       "gpio153", /* ADV */
+       "gpio154", /* WAIT (input) */
+       "gpio155", /* UB Upper Byte Enable */
+       "gpio156", /* LB Lower Byte Enable */
+       "gpio157", /* WE Write Enable */
+       "gpio158", /* busy */
+};
 
 static const struct msm_function msm8660_functions[] = {
        FUNCTION(gpio),
@@ -749,6 +781,8 @@ static const struct msm_function msm8660_functions[] = {
        FUNCTION(usb_fs2_oe_n),
        FUNCTION(vfe),
        FUNCTION(vsens_alarm),
+       FUNCTION(ebi2cs), /* for EBI2 chip selects */
+       FUNCTION(ebi2), /* for general EBI2 pins */
 };
 
 static const struct msm_pingroup msm8660_groups[] = {
@@ -789,10 +823,10 @@ static const struct msm_pingroup msm8660_groups[] = {
        PINGROUP(34, gsbi1, _, _, _, _, _, _),
        PINGROUP(35, gsbi1, _, _, _, _, _, _),
        PINGROUP(36, gsbi1, _, _, _, _, _, _),
-       PINGROUP(37, gsbi2, _, _, _, _, _, _),
-       PINGROUP(38, gsbi2, _, _, _, _, _, _),
-       PINGROUP(39, gsbi2, _, mdp_vsync, _, _, _, _),
-       PINGROUP(40, gsbi2, _, _, _, _, _, _),
+       PINGROUP(37, gsbi2, ebi2, _, _, _, _, _),
+       PINGROUP(38, gsbi2, ebi2, _, _, _, _, _),
+       PINGROUP(39, gsbi2, ebi2cs, mdp_vsync, _, _, _, _),
+       PINGROUP(40, gsbi2, ebi2cs, _, _, _, _, _),
        PINGROUP(41, gsbi3, mdp_vsync, _, _, _, _, _),
        PINGROUP(42, gsbi3, vfe, _, _, _, _, _),
        PINGROUP(43, gsbi3, _, _, _, _, _, _),
@@ -875,42 +909,42 @@ static const struct msm_pingroup msm8660_groups[] = {
        PINGROUP(120, i2s, _, _, _, _, _, _),
        PINGROUP(121, i2s, _, _, _, _, _, _),
        PINGROUP(122, i2s, gp_clk_1b, _, _, _, _, _),
-       PINGROUP(123, _, gsbi2_spi_cs1_n, _, _, _, _, _),
-       PINGROUP(124, _, gsbi2_spi_cs2_n, _, _, _, _, _),
-       PINGROUP(125, _, gsbi2_spi_cs3_n, _, _, _, _, _),
-       PINGROUP(126, _, _, _, _, _, _, _),
-       PINGROUP(127, _, vsens_alarm, _, _, _, _, _),
-       PINGROUP(128, _, _, _, _, _, _, _),
-       PINGROUP(129, _, _, _, _, _, _, _),
-       PINGROUP(130, _, _, _, _, _, _, _),
-       PINGROUP(131, _, _, _, _, _, _, _),
-       PINGROUP(132, _, _, _, _, _, _, _),
-       PINGROUP(133, _, _, _, _, _, _, _),
-       PINGROUP(134, _, _, _, _, _, _, _),
-       PINGROUP(135, _, _, _, _, _, _, _),
-       PINGROUP(136, _, _, _, _, _, _, _),
-       PINGROUP(137, _, _, _, _, _, _, _),
-       PINGROUP(138, _, _, _, _, _, _, _),
-       PINGROUP(139, _, _, _, _, _, _, _),
-       PINGROUP(140, _, _, _, _, _, _, _),
-       PINGROUP(141, _, _, _, _, _, _, _),
-       PINGROUP(142, _, _, _, _, _, _, _),
-       PINGROUP(143, _, sdc2, _, _, _, _, _),
-       PINGROUP(144, _, sdc2, _, _, _, _, _),
-       PINGROUP(145, _, sdc2, _, _, _, _, _),
-       PINGROUP(146, _, sdc2, _, _, _, _, _),
-       PINGROUP(147, _, sdc2, _, _, _, _, _),
-       PINGROUP(148, _, sdc2, _, _, _, _, _),
-       PINGROUP(149, _, sdc2, _, _, _, _, _),
-       PINGROUP(150, _, sdc2, _, _, _, _, _),
-       PINGROUP(151, _, sdc2, _, _, _, _, _),
-       PINGROUP(152, _, sdc2, _, _, _, _, _),
-       PINGROUP(153, _, _, _, _, _, _, _),
-       PINGROUP(154, _, _, _, _, _, _, _),
-       PINGROUP(155, _, _, _, _, _, _, _),
-       PINGROUP(156, _, _, _, _, _, _, _),
-       PINGROUP(157, _, _, _, _, _, _, _),
-       PINGROUP(158, _, _, _, _, _, _, _),
+       PINGROUP(123, ebi2, gsbi2_spi_cs1_n, ebi2cs, _, _, _, _),
+       PINGROUP(124, ebi2, gsbi2_spi_cs2_n, ebi2cs, _, _, _, _),
+       PINGROUP(125, ebi2, gsbi2_spi_cs3_n, _, _, _, _, _),
+       PINGROUP(126, ebi2, _, _, _, _, _, _),
+       PINGROUP(127, ebi2, vsens_alarm, _, _, _, _, _),
+       PINGROUP(128, ebi2, _, _, _, _, _, _),
+       PINGROUP(129, ebi2, _, _, _, _, _, _),
+       PINGROUP(130, ebi2, _, _, _, _, _, _),
+       PINGROUP(131, ebi2cs, _, _, _, _, _, _),
+       PINGROUP(132, ebi2cs, _, _, _, _, _, _),
+       PINGROUP(133, ebi2cs, _, _, _, _, _, _),
+       PINGROUP(134, ebi2cs, _, _, _, _, _, _),
+       PINGROUP(135, ebi2, _, _, _, _, _, _),
+       PINGROUP(136, ebi2, _, _, _, _, _, _),
+       PINGROUP(137, ebi2, _, _, _, _, _, _),
+       PINGROUP(138, ebi2, _, _, _, _, _, _),
+       PINGROUP(139, ebi2, _, _, _, _, _, _),
+       PINGROUP(140, ebi2, _, _, _, _, _, _),
+       PINGROUP(141, ebi2, _, _, _, _, _, _),
+       PINGROUP(142, ebi2, _, _, _, _, _, _),
+       PINGROUP(143, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(144, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(145, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(146, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(147, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(148, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(149, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(150, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(151, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(152, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(153, ebi2, _, _, _, _, _, _),
+       PINGROUP(154, ebi2, _, _, _, _, _, _),
+       PINGROUP(155, ebi2, _, _, _, _, _, _),
+       PINGROUP(156, ebi2, _, _, _, _, _, _),
+       PINGROUP(157, ebi2, _, _, _, _, _, _),
+       PINGROUP(158, ebi2, _, _, _, _, _, _),
        PINGROUP(159, sdc1, _, _, _, _, _, _),
        PINGROUP(160, sdc1, _, _, _, _, _, _),
        PINGROUP(161, sdc1, _, _, _, _, _, _),
index 46fe6ad5f97e2ce5f222518afc49e83f9aa4330a..9eb63d3403d45827b01ed7845d2590d1983c871d 100644 (file)
@@ -172,6 +172,8 @@ static const struct pinctrl_pin_desc msm8x74_pins[] = {
        PINCTRL_PIN(149, "SDC2_CLK"),
        PINCTRL_PIN(150, "SDC2_CMD"),
        PINCTRL_PIN(151, "SDC2_DATA"),
+       PINCTRL_PIN(152, "HSIC_STROBE"),
+       PINCTRL_PIN(153, "HSIC_DATA"),
 };
 
 #define DECLARE_MSM_GPIO_PINS(pin) static const unsigned int gpio##pin##_pins[] = { pin }
@@ -328,6 +330,8 @@ static const unsigned int sdc1_data_pins[] = { 148 };
 static const unsigned int sdc2_clk_pins[] = { 149 };
 static const unsigned int sdc2_cmd_pins[] = { 150 };
 static const unsigned int sdc2_data_pins[] = { 151 };
+static const unsigned int hsic_strobe_pins[] = { 152 };
+static const unsigned int hsic_data_pins[] = { 153 };
 
 #define FUNCTION(fname)                                        \
        [MSM_MUX_##fname] = {                           \
@@ -399,6 +403,37 @@ static const unsigned int sdc2_data_pins[] = { 151 };
                .intr_detection_width = -1,             \
        }
 
+#define HSIC_PINGROUP(pg_name, ctl)                    \
+       {                                               \
+               .name = #pg_name,                       \
+               .pins = pg_name##_pins,                 \
+               .npins = ARRAY_SIZE(pg_name##_pins),    \
+               .funcs = (int[]){                       \
+                       MSM_MUX_gpio,                   \
+                       MSM_MUX_hsic_ctl,               \
+               },                                      \
+               .nfuncs = 2,                            \
+               .ctl_reg = ctl,                         \
+               .io_reg = 0,                            \
+               .intr_cfg_reg = 0,                      \
+               .intr_status_reg = 0,                   \
+               .intr_target_reg = 0,                   \
+               .mux_bit = 25,                          \
+               .pull_bit = -1,                         \
+               .drv_bit = -1,                          \
+               .oe_bit = -1,                           \
+               .in_bit = -1,                           \
+               .out_bit = -1,                          \
+               .intr_enable_bit = -1,                  \
+               .intr_status_bit = -1,                  \
+               .intr_target_bit = -1,                  \
+               .intr_target_kpss_val = -1,             \
+               .intr_raw_status_bit = -1,              \
+               .intr_polarity_bit = -1,                \
+               .intr_detection_bit = -1,               \
+               .intr_detection_width = -1,             \
+       }
+
 /*
  * TODO: Add the rest of the possible functions and fill out
  * the pingroup table below.
@@ -509,6 +544,7 @@ enum msm8x74_functions {
        MSM_MUX_fm,
        MSM_MUX_wlan,
        MSM_MUX_slimbus,
+       MSM_MUX_hsic_ctl,
        MSM_MUX_NA,
 };
 
@@ -534,7 +570,8 @@ static const char * const gpio_groups[] = {
        "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
        "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
        "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
-       "gpio141", "gpio142", "gpio143", "gpio144", "gpio145"
+       "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "hsic_data",
+       "hsic_strobe",
 };
 
 static const char * const blsp_uart1_groups[] = {
@@ -754,6 +791,7 @@ static const char * const wlan_groups[] = {
 };
 
 static const char * const slimbus_groups[] = { "gpio70", "gpio71" };
+static const char * const hsic_ctl_groups[] = { "hsic_strobe", "hsic_data" };
 
 static const struct msm_function msm8x74_functions[] = {
        FUNCTION(gpio),
@@ -861,6 +899,7 @@ static const struct msm_function msm8x74_functions[] = {
        FUNCTION(fm),
        FUNCTION(wlan),
        FUNCTION(slimbus),
+       FUNCTION(hsic_ctl),
 };
 
 static const struct msm_pingroup msm8x74_groups[] = {
@@ -1016,6 +1055,8 @@ static const struct msm_pingroup msm8x74_groups[] = {
        SDC_PINGROUP(sdc2_clk, 0x2048, 14, 6),
        SDC_PINGROUP(sdc2_cmd, 0x2048, 11, 3),
        SDC_PINGROUP(sdc2_data, 0x2048, 9, 0),
+       HSIC_PINGROUP(hsic_strobe, 0x2050),
+       HSIC_PINGROUP(hsic_data, 0x2054),
 };
 
 #define NUM_GPIO_PINGROUPS 146
index 9191727aff5e50c36729f9fa703878fdfc45fc47..0d1392fc32dd1b5bf43a594bb825f88acbd6f979 100644 (file)
@@ -744,6 +744,7 @@ static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl,
 static const struct of_device_id pm8xxx_mpp_of_match[] = {
        { .compatible = "qcom,pm8018-mpp" },
        { .compatible = "qcom,pm8038-mpp" },
+       { .compatible = "qcom,pm8058-mpp" },
        { .compatible = "qcom,pm8917-mpp" },
        { .compatible = "qcom,pm8821-mpp" },
        { .compatible = "qcom,pm8921-mpp" },
index fb71fc3e5aa040d1309c782b6f7ba68368566ec5..3000df80709f36f16a13e59b7a86b3f22568c8b1 100644 (file)
@@ -998,6 +998,7 @@ static struct platform_driver exynos5440_pinctrl_driver = {
        .driver = {
                .name   = "exynos5440-pinctrl",
                .of_match_table = exynos5440_pinctrl_dt_match,
+               .suppress_bind_attrs = true,
        },
 };
 
index ed0b70881e19b9ce1476c025a19473dff500af5d..513fe6b23248868c2e60ed273bf9e0303cf10d82 100644 (file)
@@ -1274,6 +1274,7 @@ static struct platform_driver samsung_pinctrl_driver = {
        .driver = {
                .name   = "samsung-pinctrl",
                .of_match_table = samsung_pinctrl_dt_match,
+               .suppress_bind_attrs = true,
        },
 };
 
index 9b9cee06ec59aad30b82dafde1a35537b62878e1..a3b82041b6a22b13989f55001969173e2fe63252 100644 (file)
@@ -598,15 +598,6 @@ static int sh_pfc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int sh_pfc_remove(struct platform_device *pdev)
-{
-#ifdef CONFIG_PINCTRL_SH_PFC_GPIO
-       sh_pfc_unregister_gpiochip(platform_get_drvdata(pdev));
-#endif
-
-       return 0;
-}
-
 static const struct platform_device_id sh_pfc_id_table[] = {
 #ifdef CONFIG_PINCTRL_PFC_SH7203
        { "pfc-sh7203", (kernel_ulong_t)&sh7203_pinmux_info },
@@ -650,7 +641,6 @@ static const struct platform_device_id sh_pfc_id_table[] = {
 
 static struct platform_driver sh_pfc_driver = {
        .probe          = sh_pfc_probe,
-       .remove         = sh_pfc_remove,
        .id_table       = sh_pfc_id_table,
        .driver         = {
                .name   = DRV_NAME,
index dc1b2adb24c5c5882b468d5b5d3e145c2348bafd..0bbdea5849f41713a135b5dd3ae6bc810717e2b3 100644 (file)
 #ifndef __SH_PFC_CORE_H__
 #define __SH_PFC_CORE_H__
 
-#include <linux/compiler.h>
-#include <linux/spinlock.h>
 #include <linux/types.h>
 
 #include "sh_pfc.h"
 
-struct sh_pfc_window {
-       phys_addr_t phys;
-       void __iomem *virt;
-       unsigned long size;
-};
-
-struct sh_pfc_chip;
-struct sh_pfc_pinctrl;
-
 struct sh_pfc_pin_range {
        u16 start;
        u16 end;
 };
 
-struct sh_pfc {
-       struct device *dev;
-       const struct sh_pfc_soc_info *info;
-       spinlock_t lock;
-
-       unsigned int num_windows;
-       struct sh_pfc_window *windows;
-       unsigned int num_irqs;
-       unsigned int *irqs;
-
-       struct sh_pfc_pin_range *ranges;
-       unsigned int nr_ranges;
-
-       unsigned int nr_gpio_pins;
-
-       struct sh_pfc_chip *gpio;
-#ifdef CONFIG_SUPERH
-       struct sh_pfc_chip *func;
-#endif
-
-};
-
 int sh_pfc_register_gpiochip(struct sh_pfc *pfc);
-int sh_pfc_unregister_gpiochip(struct sh_pfc *pfc);
 
 int sh_pfc_register_pinctrl(struct sh_pfc *pfc);
 
@@ -67,28 +33,4 @@ void sh_pfc_write_reg(struct sh_pfc *pfc, u32 reg, unsigned int width,
 int sh_pfc_get_pin_index(struct sh_pfc *pfc, unsigned int pin);
 int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type);
 
-extern const struct sh_pfc_soc_info emev2_pinmux_info;
-extern const struct sh_pfc_soc_info r8a73a4_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7740_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7778_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7779_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7793_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7794_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7795_pinmux_info;
-extern const struct sh_pfc_soc_info sh7203_pinmux_info;
-extern const struct sh_pfc_soc_info sh7264_pinmux_info;
-extern const struct sh_pfc_soc_info sh7269_pinmux_info;
-extern const struct sh_pfc_soc_info sh73a0_pinmux_info;
-extern const struct sh_pfc_soc_info sh7720_pinmux_info;
-extern const struct sh_pfc_soc_info sh7722_pinmux_info;
-extern const struct sh_pfc_soc_info sh7723_pinmux_info;
-extern const struct sh_pfc_soc_info sh7724_pinmux_info;
-extern const struct sh_pfc_soc_info sh7734_pinmux_info;
-extern const struct sh_pfc_soc_info sh7757_pinmux_info;
-extern const struct sh_pfc_soc_info sh7785_pinmux_info;
-extern const struct sh_pfc_soc_info sh7786_pinmux_info;
-extern const struct sh_pfc_soc_info shx3_pinmux_info;
-
 #endif /* __SH_PFC_CORE_H__ */
index 97dff6a09ff08115112748061640260e8440723e..6b5422766f13d7f89ce140b373c5dfbdec7c445c 100644 (file)
@@ -318,7 +318,7 @@ sh_pfc_add_gpiochip(struct sh_pfc *pfc, int(*setup)(struct sh_pfc_chip *),
        if (ret < 0)
                return ERR_PTR(ret);
 
-       ret = gpiochip_add_data(&chip->gpio_chip, chip);
+       ret = devm_gpiochip_add_data(pfc->dev, &chip->gpio_chip, chip);
        if (unlikely(ret < 0))
                return ERR_PTR(ret);
 
@@ -399,18 +399,7 @@ int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
        chip = sh_pfc_add_gpiochip(pfc, gpio_function_setup, NULL);
        if (IS_ERR(chip))
                return PTR_ERR(chip);
-
-       pfc->func = chip;
 #endif /* CONFIG_SUPERH */
 
        return 0;
 }
-
-int sh_pfc_unregister_gpiochip(struct sh_pfc *pfc)
-{
-       gpiochip_remove(&pfc->gpio->gpio_chip);
-#ifdef CONFIG_SUPERH
-       gpiochip_remove(&pfc->func->gpio_chip);
-#endif
-       return 0;
-}
index d9d9228b15faf6f32c8677c1316abfc1d3a0af5b..ff5655dee67e5649806e7fef5427b561aaca6a3a 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
-#include "core.h"
 #include "sh_pfc.h"
 
 #define CPU_ALL_PORT(fn, pfx, sfx)                                     \
index 7f7c8a6e76e88f29904c9f791c0bf47ccf7ad69b..35f436bcb849185a559f4ad4095b6914d5163f4c 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
-#include "core.h"
 #include "sh_pfc.h"
 
 #define CPU_ALL_PORT(fn, pfx, sfx)                                     \
index 411d0887ba19bae6e48ff0eb04cae9bfa5537327..18ef7042b3d1b04761b2e194d11601a1f1d20fe6 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
-#include "core.h"
+
 #include "sh_pfc.h"
 
 #define PORT_GP_PUP_1(bank, pin, fn, sfx)      \
index eed8daa464cc1ebed3366a62e6acd5779f605b6b..b769c05480da681e87c39254f0fe2a0a6ae9aae1 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 
-#include "core.h"
 #include "sh_pfc.h"
 
 /*
@@ -4696,47 +4695,6 @@ static const char * const vin3_groups[] = {
        "vin3_clk",
 };
 
-#define IOCTRL6 0x8c
-
-static int r8a7790_get_io_voltage(struct sh_pfc *pfc, unsigned int pin)
-{
-       u32 data, mask;
-
-       if (WARN(pin < RCAR_GP_PIN(3, 0) || pin > RCAR_GP_PIN(3, 31), "invalid pin %#x", pin))
-               return -EINVAL;
-
-       data = ioread32(pfc->windows->virt + IOCTRL6),
-       /* Bits in IOCTRL6 are numbered in opposite order to pins */
-       mask = 0x80000000 >> (pin & 0x1f);
-
-       return (data & mask) ? 3300 : 1800;
-}
-
-static int r8a7790_set_io_voltage(struct sh_pfc *pfc, unsigned int pin, u16 mV)
-{
-       u32 data, mask;
-
-       if (WARN(pin < RCAR_GP_PIN(3, 0) || pin > RCAR_GP_PIN(3, 31), "invalid pin %#x", pin))
-               return -EINVAL;
-
-       if (mV != 1800 && mV != 3300)
-               return -EINVAL;
-
-       data = ioread32(pfc->windows->virt + IOCTRL6);
-       /* Bits in IOCTRL6 are numbered in opposite order to pins */
-       mask = 0x80000000 >> (pin & 0x1f);
-
-       if (mV == 3300)
-               data |= mask;
-       else
-               data &= ~mask;
-
-       iowrite32(~data, pfc->windows->virt); /* unlock reg */
-       iowrite32(data, pfc->windows->virt + IOCTRL6);
-
-       return 0;
-}
-
 static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(audio_clk),
        SH_PFC_FUNCTION(avb),
@@ -5736,14 +5694,23 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
        { },
 };
 
-static const struct sh_pfc_soc_operations pinmux_ops = {
-       .get_io_voltage = r8a7790_get_io_voltage,
-       .set_io_voltage = r8a7790_set_io_voltage,
+static int r8a7790_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl)
+{
+       if (pin < RCAR_GP_PIN(3, 0) || pin > RCAR_GP_PIN(3, 31))
+               return -EINVAL;
+
+       *pocctrl = 0xe606008c;
+
+       return 31 - (pin & 0x1f);
+}
+
+static const struct sh_pfc_soc_operations r8a7790_pinmux_ops = {
+       .pin_to_pocctrl = r8a7790_pin_to_pocctrl,
 };
 
 const struct sh_pfc_soc_info r8a7790_pinmux_info = {
        .name = "r8a77900_pfc",
-       .ops = &pinmux_ops,
+       .ops = &r8a7790_pinmux_ops,
        .unlock_reg = 0xe6060000, /* PMMR */
 
        .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
index 01abbd5b4e49a783a5181791a4482cc83a2675c9..0c1a60c9a844c7eee8f9f78ea5a2d1face37c69b 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/kernel.h>
 
-#include "core.h"
 #include "sh_pfc.h"
 
 #define CPU_ALL_PORT(fn, sfx)                                          \
index 44632b1a5c978cb39ed9138149ca60c3b4455926..b74cdd310d8304c2e5bd44bc643fce33db1810b7 100644 (file)
        PORT_GP_CFG_16(0, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
        PORT_GP_CFG_28(1, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
        PORT_GP_CFG_15(2, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
-       PORT_GP_CFG_16(3, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
-       PORT_GP_CFG_18(4, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
+       PORT_GP_CFG_12(3, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_IO_VOLTAGE),  \
+       PORT_GP_CFG_1(3, 12, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),   \
+       PORT_GP_CFG_1(3, 13, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),   \
+       PORT_GP_CFG_1(3, 14, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),   \
+       PORT_GP_CFG_1(3, 15, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),   \
+       PORT_GP_CFG_18(4, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_IO_VOLTAGE),  \
        PORT_GP_CFG_26(5, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
        PORT_GP_CFG_32(6, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
        PORT_GP_CFG_4(7, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH)
@@ -552,6 +556,9 @@ static const u16 pinmux_data[] = {
        PINMUX_SINGLE(AVS2),
        PINMUX_SINGLE(HDMI0_CEC),
        PINMUX_SINGLE(HDMI1_CEC),
+       PINMUX_SINGLE(I2C_SEL_0_1),
+       PINMUX_SINGLE(I2C_SEL_3_1),
+       PINMUX_SINGLE(I2C_SEL_5_1),
        PINMUX_SINGLE(MSIOF0_RXD),
        PINMUX_SINGLE(MSIOF0_SCK),
        PINMUX_SINGLE(MSIOF0_TXD),
@@ -1401,11 +1408,6 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_MSEL(IP17_7_4,      STP_ISSYNC_0_E,         SEL_SSP1_0_4),
        PINMUX_IPSR_MSEL(IP17_7_4,      RIF2_D1_B,              SEL_DRIF2_1),
        PINMUX_IPSR_GPSR(IP17_7_4,      TPU0TO3),
-
-       /* I2C */
-       PINMUX_IPSR_NOGP(0,             I2C_SEL_0_1),
-       PINMUX_IPSR_NOGP(0,             I2C_SEL_3_1),
-       PINMUX_IPSR_NOGP(0,             I2C_SEL_5_1),
 };
 
 static const struct sh_pfc_pin pinmux_pins[] = {
@@ -1654,6 +1656,221 @@ static const unsigned int canfd1_data_mux[] = {
        CANFD1_TX_MARK,         CANFD1_RX_MARK,
 };
 
+/* - DRIF0 --------------------------------------------------------------- */
+static const unsigned int drif0_ctrl_a_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9),
+};
+static const unsigned int drif0_ctrl_a_mux[] = {
+       RIF0_CLK_A_MARK, RIF0_SYNC_A_MARK,
+};
+static const unsigned int drif0_data0_a_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 10),
+};
+static const unsigned int drif0_data0_a_mux[] = {
+       RIF0_D0_A_MARK,
+};
+static const unsigned int drif0_data1_a_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 7),
+};
+static const unsigned int drif0_data1_a_mux[] = {
+       RIF0_D1_A_MARK,
+};
+static const unsigned int drif0_ctrl_b_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 4),
+};
+static const unsigned int drif0_ctrl_b_mux[] = {
+       RIF0_CLK_B_MARK, RIF0_SYNC_B_MARK,
+};
+static const unsigned int drif0_data0_b_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(5, 1),
+};
+static const unsigned int drif0_data0_b_mux[] = {
+       RIF0_D0_B_MARK,
+};
+static const unsigned int drif0_data1_b_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(5, 2),
+};
+static const unsigned int drif0_data1_b_mux[] = {
+       RIF0_D1_B_MARK,
+};
+static const unsigned int drif0_ctrl_c_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 15),
+};
+static const unsigned int drif0_ctrl_c_mux[] = {
+       RIF0_CLK_C_MARK, RIF0_SYNC_C_MARK,
+};
+static const unsigned int drif0_data0_c_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(5, 13),
+};
+static const unsigned int drif0_data0_c_mux[] = {
+       RIF0_D0_C_MARK,
+};
+static const unsigned int drif0_data1_c_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(5, 14),
+};
+static const unsigned int drif0_data1_c_mux[] = {
+       RIF0_D1_C_MARK,
+};
+/* - DRIF1 --------------------------------------------------------------- */
+static const unsigned int drif1_ctrl_a_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18),
+};
+static const unsigned int drif1_ctrl_a_mux[] = {
+       RIF1_CLK_A_MARK, RIF1_SYNC_A_MARK,
+};
+static const unsigned int drif1_data0_a_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 19),
+};
+static const unsigned int drif1_data0_a_mux[] = {
+       RIF1_D0_A_MARK,
+};
+static const unsigned int drif1_data1_a_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 20),
+};
+static const unsigned int drif1_data1_a_mux[] = {
+       RIF1_D1_A_MARK,
+};
+static const unsigned int drif1_ctrl_b_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(5, 9), RCAR_GP_PIN(5, 3),
+};
+static const unsigned int drif1_ctrl_b_mux[] = {
+       RIF1_CLK_B_MARK, RIF1_SYNC_B_MARK,
+};
+static const unsigned int drif1_data0_b_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(5, 7),
+};
+static const unsigned int drif1_data0_b_mux[] = {
+       RIF1_D0_B_MARK,
+};
+static const unsigned int drif1_data1_b_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(5, 8),
+};
+static const unsigned int drif1_data1_b_mux[] = {
+       RIF1_D1_B_MARK,
+};
+static const unsigned int drif1_ctrl_c_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 11),
+};
+static const unsigned int drif1_ctrl_c_mux[] = {
+       RIF1_CLK_C_MARK, RIF1_SYNC_C_MARK,
+};
+static const unsigned int drif1_data0_c_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(5, 6),
+};
+static const unsigned int drif1_data0_c_mux[] = {
+       RIF1_D0_C_MARK,
+};
+static const unsigned int drif1_data1_c_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(5, 10),
+};
+static const unsigned int drif1_data1_c_mux[] = {
+       RIF1_D1_C_MARK,
+};
+/* - DRIF2 --------------------------------------------------------------- */
+static const unsigned int drif2_ctrl_a_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9),
+};
+static const unsigned int drif2_ctrl_a_mux[] = {
+       RIF2_CLK_A_MARK, RIF2_SYNC_A_MARK,
+};
+static const unsigned int drif2_data0_a_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 7),
+};
+static const unsigned int drif2_data0_a_mux[] = {
+       RIF2_D0_A_MARK,
+};
+static const unsigned int drif2_data1_a_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 10),
+};
+static const unsigned int drif2_data1_a_mux[] = {
+       RIF2_D1_A_MARK,
+};
+static const unsigned int drif2_ctrl_b_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 26), RCAR_GP_PIN(6, 27),
+};
+static const unsigned int drif2_ctrl_b_mux[] = {
+       RIF2_CLK_B_MARK, RIF2_SYNC_B_MARK,
+};
+static const unsigned int drif2_data0_b_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 30),
+};
+static const unsigned int drif2_data0_b_mux[] = {
+       RIF2_D0_B_MARK,
+};
+static const unsigned int drif2_data1_b_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 31),
+};
+static const unsigned int drif2_data1_b_mux[] = {
+       RIF2_D1_B_MARK,
+};
+/* - DRIF3 --------------------------------------------------------------- */
+static const unsigned int drif3_ctrl_a_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18),
+};
+static const unsigned int drif3_ctrl_a_mux[] = {
+       RIF3_CLK_A_MARK, RIF3_SYNC_A_MARK,
+};
+static const unsigned int drif3_data0_a_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 19),
+};
+static const unsigned int drif3_data0_a_mux[] = {
+       RIF3_D0_A_MARK,
+};
+static const unsigned int drif3_data1_a_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 20),
+};
+static const unsigned int drif3_data1_a_mux[] = {
+       RIF3_D1_A_MARK,
+};
+static const unsigned int drif3_ctrl_b_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25),
+};
+static const unsigned int drif3_ctrl_b_mux[] = {
+       RIF3_CLK_B_MARK, RIF3_SYNC_B_MARK,
+};
+static const unsigned int drif3_data0_b_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 28),
+};
+static const unsigned int drif3_data0_b_mux[] = {
+       RIF3_D0_B_MARK,
+};
+static const unsigned int drif3_data1_b_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 29),
+};
+static const unsigned int drif3_data1_b_mux[] = {
+       RIF3_D1_B_MARK,
+};
+
 /* - HSCIF0 ----------------------------------------------------------------- */
 static const unsigned int hscif0_data_pins[] = {
        /* RX, TX */
@@ -3346,6 +3563,36 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(canfd0_data_a),
        SH_PFC_PIN_GROUP(canfd0_data_b),
        SH_PFC_PIN_GROUP(canfd1_data),
+       SH_PFC_PIN_GROUP(drif0_ctrl_a),
+       SH_PFC_PIN_GROUP(drif0_data0_a),
+       SH_PFC_PIN_GROUP(drif0_data1_a),
+       SH_PFC_PIN_GROUP(drif0_ctrl_b),
+       SH_PFC_PIN_GROUP(drif0_data0_b),
+       SH_PFC_PIN_GROUP(drif0_data1_b),
+       SH_PFC_PIN_GROUP(drif0_ctrl_c),
+       SH_PFC_PIN_GROUP(drif0_data0_c),
+       SH_PFC_PIN_GROUP(drif0_data1_c),
+       SH_PFC_PIN_GROUP(drif1_ctrl_a),
+       SH_PFC_PIN_GROUP(drif1_data0_a),
+       SH_PFC_PIN_GROUP(drif1_data1_a),
+       SH_PFC_PIN_GROUP(drif1_ctrl_b),
+       SH_PFC_PIN_GROUP(drif1_data0_b),
+       SH_PFC_PIN_GROUP(drif1_data1_b),
+       SH_PFC_PIN_GROUP(drif1_ctrl_c),
+       SH_PFC_PIN_GROUP(drif1_data0_c),
+       SH_PFC_PIN_GROUP(drif1_data1_c),
+       SH_PFC_PIN_GROUP(drif2_ctrl_a),
+       SH_PFC_PIN_GROUP(drif2_data0_a),
+       SH_PFC_PIN_GROUP(drif2_data1_a),
+       SH_PFC_PIN_GROUP(drif2_ctrl_b),
+       SH_PFC_PIN_GROUP(drif2_data0_b),
+       SH_PFC_PIN_GROUP(drif2_data1_b),
+       SH_PFC_PIN_GROUP(drif3_ctrl_a),
+       SH_PFC_PIN_GROUP(drif3_data0_a),
+       SH_PFC_PIN_GROUP(drif3_data1_a),
+       SH_PFC_PIN_GROUP(drif3_ctrl_b),
+       SH_PFC_PIN_GROUP(drif3_data0_b),
+       SH_PFC_PIN_GROUP(drif3_data1_b),
        SH_PFC_PIN_GROUP(hscif0_data),
        SH_PFC_PIN_GROUP(hscif0_clk),
        SH_PFC_PIN_GROUP(hscif0_ctrl),
@@ -3629,6 +3876,48 @@ static const char * const canfd1_groups[] = {
        "canfd1_data",
 };
 
+static const char * const drif0_groups[] = {
+       "drif0_ctrl_a",
+       "drif0_data0_a",
+       "drif0_data1_a",
+       "drif0_ctrl_b",
+       "drif0_data0_b",
+       "drif0_data1_b",
+       "drif0_ctrl_c",
+       "drif0_data0_c",
+       "drif0_data1_c",
+};
+
+static const char * const drif1_groups[] = {
+       "drif1_ctrl_a",
+       "drif1_data0_a",
+       "drif1_data1_a",
+       "drif1_ctrl_b",
+       "drif1_data0_b",
+       "drif1_data1_b",
+       "drif1_ctrl_c",
+       "drif1_data0_c",
+       "drif1_data1_c",
+};
+
+static const char * const drif2_groups[] = {
+       "drif2_ctrl_a",
+       "drif2_data0_a",
+       "drif2_data1_a",
+       "drif2_ctrl_b",
+       "drif2_data0_b",
+       "drif2_data1_b",
+};
+
+static const char * const drif3_groups[] = {
+       "drif3_ctrl_a",
+       "drif3_data0_a",
+       "drif3_data1_a",
+       "drif3_ctrl_b",
+       "drif3_data0_b",
+       "drif3_data1_b",
+};
+
 static const char * const hscif0_groups[] = {
        "hscif0_data",
        "hscif0_clk",
@@ -3972,6 +4261,10 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(can_clk),
        SH_PFC_FUNCTION(canfd0),
        SH_PFC_FUNCTION(canfd1),
+       SH_PFC_FUNCTION(drif0),
+       SH_PFC_FUNCTION(drif1),
+       SH_PFC_FUNCTION(drif2),
+       SH_PFC_FUNCTION(drif3),
        SH_PFC_FUNCTION(hscif0),
        SH_PFC_FUNCTION(hscif1),
        SH_PFC_FUNCTION(hscif2),
@@ -4765,8 +5058,28 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        { },
 };
 
+static int r8a7795_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl)
+{
+       int bit = -EINVAL;
+
+       *pocctrl = 0xe6060380;
+
+       if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 11))
+               bit = pin & 0x1f;
+
+       if (pin >= RCAR_GP_PIN(4, 0) && pin <= RCAR_GP_PIN(4, 17))
+               bit = (pin & 0x1f) + 12;
+
+       return bit;
+}
+
+static const struct sh_pfc_soc_operations r8a7795_pinmux_ops = {
+       .pin_to_pocctrl = r8a7795_pin_to_pocctrl,
+};
+
 const struct sh_pfc_soc_info r8a7795_pinmux_info = {
        .name = "r8a77950_pfc",
+       .ops = &r8a7795_pinmux_ops,
        .unlock_reg = 0xe6060000, /* PMMR */
 
        .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
index 0555a1fe076ed353c4627239534a702e1b810c5c..6d8c31caefc105e0a543d1508f8eb31d997783b4 100644 (file)
@@ -1625,7 +1625,6 @@ static const struct pinmux_func pinmux_func_gpios[] = {
        GPIO_FN(VBIOS_CS),
 
        /* PTW (mobule: LBSC, EVC, SCIF) */
-       GPIO_FN(A16),
        GPIO_FN(A15),
        GPIO_FN(A14),
        GPIO_FN(A13),
index fdb445d68b9a08a67992c07f46750bfb33875fc6..e208ee04a9f45482044606bc509c70ec5170c4cb 100644 (file)
@@ -632,19 +632,21 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin,
        }
 
        case PIN_CONFIG_POWER_SOURCE: {
-               int ret;
+               u32 pocctrl, val;
+               int bit;
 
-               if (!pfc->info->ops || !pfc->info->ops->get_io_voltage)
+               if (!pfc->info->ops || !pfc->info->ops->pin_to_pocctrl)
                        return -ENOTSUPP;
 
+               bit = pfc->info->ops->pin_to_pocctrl(pfc, _pin, &pocctrl);
+               if (WARN(bit < 0, "invalid pin %#x", _pin))
+                       return bit;
+
                spin_lock_irqsave(&pfc->lock, flags);
-               ret = pfc->info->ops->get_io_voltage(pfc, _pin);
+               val = sh_pfc_read_reg(pfc, pocctrl, 32);
                spin_unlock_irqrestore(&pfc->lock, flags);
 
-               if (ret < 0)
-                       return ret;
-
-               *config = ret;
+               *config = (val & BIT(bit)) ? 3300 : 1800;
                break;
        }
 
@@ -696,20 +698,29 @@ static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin,
                }
 
                case PIN_CONFIG_POWER_SOURCE: {
-                       unsigned int arg =
-                               pinconf_to_config_argument(configs[i]);
-                       int ret;
+                       unsigned int mV = pinconf_to_config_argument(configs[i]);
+                       u32 pocctrl, val;
+                       int bit;
 
-                       if (!pfc->info->ops || !pfc->info->ops->set_io_voltage)
+                       if (!pfc->info->ops || !pfc->info->ops->pin_to_pocctrl)
                                return -ENOTSUPP;
 
+                       bit = pfc->info->ops->pin_to_pocctrl(pfc, _pin, &pocctrl);
+                       if (WARN(bit < 0, "invalid pin %#x", _pin))
+                               return bit;
+
+                       if (mV != 1800 && mV != 3300)
+                               return -EINVAL;
+
                        spin_lock_irqsave(&pfc->lock, flags);
-                       ret = pfc->info->ops->set_io_voltage(pfc, _pin, arg);
+                       val = sh_pfc_read_reg(pfc, pocctrl, 32);
+                       if (mV == 3300)
+                               val |= BIT(bit);
+                       else
+                               val &= ~BIT(bit);
+                       sh_pfc_write_reg(pfc, pocctrl, 32, val);
                        spin_unlock_irqrestore(&pfc->lock, flags);
 
-                       if (ret)
-                               return ret;
-
                        break;
                }
 
@@ -803,8 +814,5 @@ int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
        pmx->pctl_desc.npins = pfc->info->nr_pins;
 
        pmx->pctl = devm_pinctrl_register(pfc->dev, &pmx->pctl_desc, pmx);
-       if (IS_ERR(pmx->pctl))
-               return PTR_ERR(pmx->pctl);
-
-       return 0;
+       return PTR_ERR_OR_ZERO(pmx->pctl);
 }
index 656ea32f776c92ed93683ab93603c2dde0b1b189..5e966c09434d969cd62201ed84b5d751bb902ad8 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/bug.h>
 #include <linux/pinctrl/pinconf-generic.h>
+#include <linux/spinlock.h>
 #include <linux/stringify.h>
 
 enum {
@@ -182,16 +183,38 @@ struct pinmux_range {
        u16 force;
 };
 
-struct sh_pfc;
+struct sh_pfc_window {
+       phys_addr_t phys;
+       void __iomem *virt;
+       unsigned long size;
+};
+
+struct sh_pfc_pin_range;
+
+struct sh_pfc {
+       struct device *dev;
+       const struct sh_pfc_soc_info *info;
+       spinlock_t lock;
+
+       unsigned int num_windows;
+       struct sh_pfc_window *windows;
+       unsigned int num_irqs;
+       unsigned int *irqs;
+
+       struct sh_pfc_pin_range *ranges;
+       unsigned int nr_ranges;
+
+       unsigned int nr_gpio_pins;
+
+       struct sh_pfc_chip *gpio;
+};
 
 struct sh_pfc_soc_operations {
        int (*init)(struct sh_pfc *pfc);
        unsigned int (*get_bias)(struct sh_pfc *pfc, unsigned int pin);
        void (*set_bias)(struct sh_pfc *pfc, unsigned int pin,
                         unsigned int bias);
-       int (*get_io_voltage)(struct sh_pfc *pfc, unsigned int pin);
-       int (*set_io_voltage)(struct sh_pfc *pfc, unsigned int pin,
-                             u16 voltage_mV);
+       int (*pin_to_pocctrl)(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl);
 };
 
 struct sh_pfc_soc_info {
@@ -227,6 +250,30 @@ struct sh_pfc_soc_info {
        u32 unlock_reg;
 };
 
+extern const struct sh_pfc_soc_info emev2_pinmux_info;
+extern const struct sh_pfc_soc_info r8a73a4_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7740_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7778_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7779_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7793_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7794_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7795_pinmux_info;
+extern const struct sh_pfc_soc_info sh7203_pinmux_info;
+extern const struct sh_pfc_soc_info sh7264_pinmux_info;
+extern const struct sh_pfc_soc_info sh7269_pinmux_info;
+extern const struct sh_pfc_soc_info sh73a0_pinmux_info;
+extern const struct sh_pfc_soc_info sh7720_pinmux_info;
+extern const struct sh_pfc_soc_info sh7722_pinmux_info;
+extern const struct sh_pfc_soc_info sh7723_pinmux_info;
+extern const struct sh_pfc_soc_info sh7724_pinmux_info;
+extern const struct sh_pfc_soc_info sh7734_pinmux_info;
+extern const struct sh_pfc_soc_info sh7757_pinmux_info;
+extern const struct sh_pfc_soc_info sh7785_pinmux_info;
+extern const struct sh_pfc_soc_info sh7786_pinmux_info;
+extern const struct sh_pfc_soc_info shx3_pinmux_info;
+
 /* -----------------------------------------------------------------------------
  * Helper macros to create pin and port lists
  */
index 168c0f5d40793bceb2612b98ab62e72acc517f5e..19952f73fa8ca05fb95b5f3588194b594e99bc7c 100644 (file)
@@ -5424,8 +5424,10 @@ static int atlas7_pinmux_probe(struct platform_device *pdev)
        if (ret)
                return ret;
        pmx->sys2pci_base = devm_ioremap_resource(&pdev->dev, &res);
-       if (IS_ERR(pmx->sys2pci_base))
+       if (IS_ERR(pmx->sys2pci_base)) {
+               of_node_put(sys2pci_np);
                return -ENOMEM;
+       }
 
        pmx->dev = &pdev->dev;
 
index 0f28841b2332c5559e249651f60fca0fa3a9bc99..4c40dae384d13233df118f4b3142cbc91dfcd117 100644 (file)
@@ -13,4 +13,10 @@ config PINCTRL_STM32F429
        default MACH_STM32F429
        select PINCTRL_STM32
 
+config PINCTRL_STM32F746
+       bool "STMicroelectronics STM32F746 pin control" if COMPILE_TEST && !MACH_STM32F746
+       depends on OF
+       default MACH_STM32F746
+       select PINCTRL_STM32
+
 endif
index fc17d42388456f1553a741936eac1a158571e296..4a1ee748441f1718ee5ba9d17363b499918dcd18 100644 (file)
@@ -3,3 +3,4 @@ obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o
 
 # SoC Drivers
 obj-$(CONFIG_PINCTRL_STM32F429)        += pinctrl-stm32f429.o
+obj-$(CONFIG_PINCTRL_STM32F746)        += pinctrl-stm32f746.o
index ae9fab82a1b9ac1fe274ae7e01681ed7850e2851..4ae596bf19b5b594a0f8fd1807a8d7d8599b5679 100644 (file)
@@ -638,8 +638,8 @@ static u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank,
        return (val >> (offset * 2));
 }
 
-static bool stm32_pconf_input_get(struct stm32_gpio_bank *bank,
-       unsigned int offset)
+static bool stm32_pconf_get(struct stm32_gpio_bank *bank,
+       unsigned int offset, bool dir)
 {
        unsigned long flags;
        u32 val;
@@ -647,23 +647,12 @@ static bool stm32_pconf_input_get(struct stm32_gpio_bank *bank,
        clk_enable(bank->clk);
        spin_lock_irqsave(&bank->lock, flags);
 
-       val = !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & BIT(offset));
-
-       spin_unlock_irqrestore(&bank->lock, flags);
-       clk_disable(bank->clk);
-
-       return val;
-}
-
-static bool stm32_pconf_output_get(struct stm32_gpio_bank *bank,
-       unsigned int offset)
-{
-       unsigned long flags;
-       u32 val;
-
-       clk_enable(bank->clk);
-       spin_lock_irqsave(&bank->lock, flags);
-       val = !!(readl_relaxed(bank->base + STM32_GPIO_ODR) & BIT(offset));
+       if (dir)
+               val = !!(readl_relaxed(bank->base + STM32_GPIO_IDR) &
+                        BIT(offset));
+       else
+               val = !!(readl_relaxed(bank->base + STM32_GPIO_ODR) &
+                        BIT(offset));
 
        spin_unlock_irqrestore(&bank->lock, flags);
        clk_disable(bank->clk);
@@ -772,7 +761,7 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev,
        switch (mode) {
        /* input */
        case 0:
-               val = stm32_pconf_input_get(bank, offset);
+               val = stm32_pconf_get(bank, offset, true);
                seq_printf(s, "- %s - %s",
                           val ? "high" : "low",
                           biasing[bias]);
@@ -782,7 +771,7 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev,
        case 1:
                drive = stm32_pconf_get_driving(bank, offset);
                speed = stm32_pconf_get_speed(bank, offset);
-               val = stm32_pconf_output_get(bank, offset);
+               val = stm32_pconf_get(bank, offset, false);
                seq_printf(s, "- %s - %s - %s - %s %s",
                           val ? "high" : "low",
                           drive ? "open drain" : "push pull",
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32f746.c b/drivers/pinctrl/stm32/pinctrl-stm32f746.c
new file mode 100644 (file)
index 0000000..c0b4462
--- /dev/null
@@ -0,0 +1,1681 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-stm32.h"
+
+static const struct stm32_desc_pin stm32f746_pins[] = {
+       STM32_PIN(
+               PINCTRL_PIN(0, "PA0"),
+               STM32_FUNCTION(0, "GPIOA0"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(3, "TIM5_CH1"),
+               STM32_FUNCTION(4, "TIM8_ETR"),
+               STM32_FUNCTION(8, "USART2_CTS"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(12, "ETH_MII_CRS"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(1, "PA1"),
+               STM32_FUNCTION(0, "GPIOA1"),
+               STM32_FUNCTION(2, "TIM2_CH2"),
+               STM32_FUNCTION(3, "TIM5_CH2"),
+               STM32_FUNCTION(8, "USART2_RTS"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(11, "SAI2_MCLK_B"),
+               STM32_FUNCTION(12, "ETH_MII_RX_CLK ETH_RMII_REF_CLK"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(2, "PA2"),
+               STM32_FUNCTION(0, "GPIOA2"),
+               STM32_FUNCTION(2, "TIM2_CH3"),
+               STM32_FUNCTION(3, "TIM5_CH3"),
+               STM32_FUNCTION(4, "TIM9_CH1"),
+               STM32_FUNCTION(8, "USART2_TX"),
+               STM32_FUNCTION(9, "SAI2_SCK_B"),
+               STM32_FUNCTION(12, "ETH_MDIO"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(3, "PA3"),
+               STM32_FUNCTION(0, "GPIOA3"),
+               STM32_FUNCTION(2, "TIM2_CH4"),
+               STM32_FUNCTION(3, "TIM5_CH4"),
+               STM32_FUNCTION(4, "TIM9_CH2"),
+               STM32_FUNCTION(8, "USART2_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D0"),
+               STM32_FUNCTION(12, "ETH_MII_COL"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(4, "PA4"),
+               STM32_FUNCTION(0, "GPIOA4"),
+               STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"),
+               STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"),
+               STM32_FUNCTION(8, "USART2_CK"),
+               STM32_FUNCTION(13, "OTG_HS_SOF"),
+               STM32_FUNCTION(14, "DCMI_HSYNC"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(5, "PA5"),
+               STM32_FUNCTION(0, "GPIOA5"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_CK"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(6, "PA6"),
+               STM32_FUNCTION(0, "GPIOA6"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(4, "TIM8_BKIN"),
+               STM32_FUNCTION(6, "SPI1_MISO"),
+               STM32_FUNCTION(10, "TIM13_CH1"),
+               STM32_FUNCTION(14, "DCMI_PIXCLK"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(7, "PA7"),
+               STM32_FUNCTION(0, "GPIOA7"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(6, "SPI1_MOSI I2S1_SD"),
+               STM32_FUNCTION(10, "TIM14_CH1"),
+               STM32_FUNCTION(12, "ETH_MII_RX_DV ETH_RMII_CRS_DV"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(8, "PA8"),
+               STM32_FUNCTION(0, "GPIOA8"),
+               STM32_FUNCTION(1, "MCO1"),
+               STM32_FUNCTION(2, "TIM1_CH1"),
+               STM32_FUNCTION(4, "TIM8_BKIN2"),
+               STM32_FUNCTION(5, "I2C3_SCL"),
+               STM32_FUNCTION(8, "USART1_CK"),
+               STM32_FUNCTION(11, "OTG_FS_SOF"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(9, "PA9"),
+               STM32_FUNCTION(0, "GPIOA9"),
+               STM32_FUNCTION(2, "TIM1_CH2"),
+               STM32_FUNCTION(5, "I2C3_SMBA"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART1_TX"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(10, "PA10"),
+               STM32_FUNCTION(0, "GPIOA10"),
+               STM32_FUNCTION(2, "TIM1_CH3"),
+               STM32_FUNCTION(8, "USART1_RX"),
+               STM32_FUNCTION(11, "OTG_FS_ID"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(11, "PA11"),
+               STM32_FUNCTION(0, "GPIOA11"),
+               STM32_FUNCTION(2, "TIM1_CH4"),
+               STM32_FUNCTION(8, "USART1_CTS"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(11, "OTG_FS_DM"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(12, "PA12"),
+               STM32_FUNCTION(0, "GPIOA12"),
+               STM32_FUNCTION(2, "TIM1_ETR"),
+               STM32_FUNCTION(8, "USART1_RTS"),
+               STM32_FUNCTION(9, "SAI2_FS_B"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(11, "OTG_FS_DP"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(13, "PA13"),
+               STM32_FUNCTION(0, "GPIOA13"),
+               STM32_FUNCTION(1, "JTMS SWDIO"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(14, "PA14"),
+               STM32_FUNCTION(0, "GPIOA14"),
+               STM32_FUNCTION(1, "JTCK SWCLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(15, "PA15"),
+               STM32_FUNCTION(0, "GPIOA15"),
+               STM32_FUNCTION(1, "JTDI"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(5, "HDMI_CEC"),
+               STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"),
+               STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"),
+               STM32_FUNCTION(9, "UART4_RTS"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(16, "PB0"),
+               STM32_FUNCTION(0, "GPIOB0"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(3, "TIM3_CH3"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(9, "UART4_CTS"),
+               STM32_FUNCTION(10, "LCD_R3"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D1"),
+               STM32_FUNCTION(12, "ETH_MII_RXD2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(17, "PB1"),
+               STM32_FUNCTION(0, "GPIOB1"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(3, "TIM3_CH4"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(10, "LCD_R6"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D2"),
+               STM32_FUNCTION(12, "ETH_MII_RXD3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(18, "PB2"),
+               STM32_FUNCTION(0, "GPIOB2"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(8, "SPI3_MOSI I2S3_SD"),
+               STM32_FUNCTION(10, "QUADSPI_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(19, "PB3"),
+               STM32_FUNCTION(0, "GPIOB3"),
+               STM32_FUNCTION(1, "JTDO TRACESWO"),
+               STM32_FUNCTION(2, "TIM2_CH2"),
+               STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"),
+               STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(20, "PB4"),
+               STM32_FUNCTION(0, "GPIOB4"),
+               STM32_FUNCTION(1, "NJTRST"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(6, "SPI1_MISO"),
+               STM32_FUNCTION(7, "SPI3_MISO"),
+               STM32_FUNCTION(8, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(21, "PB5"),
+               STM32_FUNCTION(0, "GPIOB5"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(5, "I2C1_SMBA"),
+               STM32_FUNCTION(6, "SPI1_MOSI I2S1_SD"),
+               STM32_FUNCTION(7, "SPI3_MOSI I2S3_SD"),
+               STM32_FUNCTION(10, "CAN2_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D7"),
+               STM32_FUNCTION(12, "ETH_PPS_OUT"),
+               STM32_FUNCTION(13, "FMC_SDCKE1"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(22, "PB6"),
+               STM32_FUNCTION(0, "GPIOB6"),
+               STM32_FUNCTION(3, "TIM4_CH1"),
+               STM32_FUNCTION(4, "HDMI_CEC"),
+               STM32_FUNCTION(5, "I2C1_SCL"),
+               STM32_FUNCTION(8, "USART1_TX"),
+               STM32_FUNCTION(10, "CAN2_TX"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_NCS"),
+               STM32_FUNCTION(13, "FMC_SDNE1"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(23, "PB7"),
+               STM32_FUNCTION(0, "GPIOB7"),
+               STM32_FUNCTION(3, "TIM4_CH2"),
+               STM32_FUNCTION(5, "I2C1_SDA"),
+               STM32_FUNCTION(8, "USART1_RX"),
+               STM32_FUNCTION(13, "FMC_NL"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(24, "PB8"),
+               STM32_FUNCTION(0, "GPIOB8"),
+               STM32_FUNCTION(3, "TIM4_CH3"),
+               STM32_FUNCTION(4, "TIM10_CH1"),
+               STM32_FUNCTION(5, "I2C1_SCL"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(12, "ETH_MII_TXD3"),
+               STM32_FUNCTION(13, "SDMMC1_D4"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(25, "PB9"),
+               STM32_FUNCTION(0, "GPIOB9"),
+               STM32_FUNCTION(3, "TIM4_CH4"),
+               STM32_FUNCTION(4, "TIM11_CH1"),
+               STM32_FUNCTION(5, "I2C1_SDA"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(13, "SDMMC1_D5"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(26, "PB10"),
+               STM32_FUNCTION(0, "GPIOB10"),
+               STM32_FUNCTION(2, "TIM2_CH3"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D3"),
+               STM32_FUNCTION(12, "ETH_MII_RX_ER"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(27, "PB11"),
+               STM32_FUNCTION(0, "GPIOB11"),
+               STM32_FUNCTION(2, "TIM2_CH4"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D4"),
+               STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(28, "PB12"),
+               STM32_FUNCTION(0, "GPIOB12"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(10, "CAN2_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D5"),
+               STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"),
+               STM32_FUNCTION(13, "OTG_HS_ID"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(29, "PB13"),
+               STM32_FUNCTION(0, "GPIOB13"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART3_CTS"),
+               STM32_FUNCTION(10, "CAN2_TX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D6"),
+               STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(30, "PB14"),
+               STM32_FUNCTION(0, "GPIOB14"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(6, "SPI2_MISO"),
+               STM32_FUNCTION(8, "USART3_RTS"),
+               STM32_FUNCTION(10, "TIM12_CH1"),
+               STM32_FUNCTION(13, "OTG_HS_DM"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(31, "PB15"),
+               STM32_FUNCTION(0, "GPIOB15"),
+               STM32_FUNCTION(1, "RTC_REFIN"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+               STM32_FUNCTION(10, "TIM12_CH2"),
+               STM32_FUNCTION(13, "OTG_HS_DP"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(32, "PC0"),
+               STM32_FUNCTION(0, "GPIOC0"),
+               STM32_FUNCTION(9, "SAI2_FS_B"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_STP"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(33, "PC1"),
+               STM32_FUNCTION(0, "GPIOC1"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(12, "ETH_MDC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(34, "PC2"),
+               STM32_FUNCTION(0, "GPIOC2"),
+               STM32_FUNCTION(6, "SPI2_MISO"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"),
+               STM32_FUNCTION(12, "ETH_MII_TXD2"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(35, "PC3"),
+               STM32_FUNCTION(0, "GPIOC3"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"),
+               STM32_FUNCTION(12, "ETH_MII_TX_CLK"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(36, "PC4"),
+               STM32_FUNCTION(0, "GPIOC4"),
+               STM32_FUNCTION(6, "I2S1_MCK"),
+               STM32_FUNCTION(9, "SPDIFRX_IN2"),
+               STM32_FUNCTION(12, "ETH_MII_RXD0 ETH_RMII_RXD0"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(37, "PC5"),
+               STM32_FUNCTION(0, "GPIOC5"),
+               STM32_FUNCTION(9, "SPDIFRX_IN3"),
+               STM32_FUNCTION(12, "ETH_MII_RXD1 ETH_RMII_RXD1"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(38, "PC6"),
+               STM32_FUNCTION(0, "GPIOC6"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(4, "TIM8_CH1"),
+               STM32_FUNCTION(6, "I2S2_MCK"),
+               STM32_FUNCTION(9, "USART6_TX"),
+               STM32_FUNCTION(13, "SDMMC1_D6"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(39, "PC7"),
+               STM32_FUNCTION(0, "GPIOC7"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(4, "TIM8_CH2"),
+               STM32_FUNCTION(7, "I2S3_MCK"),
+               STM32_FUNCTION(9, "USART6_RX"),
+               STM32_FUNCTION(13, "SDMMC1_D7"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(40, "PC8"),
+               STM32_FUNCTION(0, "GPIOC8"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(3, "TIM3_CH3"),
+               STM32_FUNCTION(4, "TIM8_CH3"),
+               STM32_FUNCTION(8, "UART5_RTS"),
+               STM32_FUNCTION(9, "USART6_CK"),
+               STM32_FUNCTION(13, "SDMMC1_D0"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(41, "PC9"),
+               STM32_FUNCTION(0, "GPIOC9"),
+               STM32_FUNCTION(1, "MCO2"),
+               STM32_FUNCTION(3, "TIM3_CH4"),
+               STM32_FUNCTION(4, "TIM8_CH4"),
+               STM32_FUNCTION(5, "I2C3_SDA"),
+               STM32_FUNCTION(6, "I2S_CKIN"),
+               STM32_FUNCTION(8, "UART5_CTS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(13, "SDMMC1_D1"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(42, "PC10"),
+               STM32_FUNCTION(0, "GPIOC10"),
+               STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(13, "SDMMC1_D2"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(43, "PC11"),
+               STM32_FUNCTION(0, "GPIOC11"),
+               STM32_FUNCTION(7, "SPI3_MISO"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_NCS"),
+               STM32_FUNCTION(13, "SDMMC1_D3"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(44, "PC12"),
+               STM32_FUNCTION(0, "GPIOC12"),
+               STM32_FUNCTION(1, "TRACED3"),
+               STM32_FUNCTION(7, "SPI3_MOSI I2S3_SD"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(9, "UART5_TX"),
+               STM32_FUNCTION(13, "SDMMC1_CK"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(45, "PC13"),
+               STM32_FUNCTION(0, "GPIOC13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(46, "PC14"),
+               STM32_FUNCTION(0, "GPIOC14"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(47, "PC15"),
+               STM32_FUNCTION(0, "GPIOC15"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(48, "PD0"),
+               STM32_FUNCTION(0, "GPIOD0"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(13, "FMC_D2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(49, "PD1"),
+               STM32_FUNCTION(0, "GPIOD1"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(13, "FMC_D3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(50, "PD2"),
+               STM32_FUNCTION(0, "GPIOD2"),
+               STM32_FUNCTION(1, "TRACED2"),
+               STM32_FUNCTION(3, "TIM3_ETR"),
+               STM32_FUNCTION(9, "UART5_RX"),
+               STM32_FUNCTION(13, "SDMMC1_CMD"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(51, "PD3"),
+               STM32_FUNCTION(0, "GPIOD3"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART2_CTS"),
+               STM32_FUNCTION(13, "FMC_CLK"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(52, "PD4"),
+               STM32_FUNCTION(0, "GPIOD4"),
+               STM32_FUNCTION(8, "USART2_RTS"),
+               STM32_FUNCTION(13, "FMC_NOE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(53, "PD5"),
+               STM32_FUNCTION(0, "GPIOD5"),
+               STM32_FUNCTION(8, "USART2_TX"),
+               STM32_FUNCTION(13, "FMC_NWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(54, "PD6"),
+               STM32_FUNCTION(0, "GPIOD6"),
+               STM32_FUNCTION(6, "SPI3_MOSI I2S3_SD"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(8, "USART2_RX"),
+               STM32_FUNCTION(13, "FMC_NWAIT"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(55, "PD7"),
+               STM32_FUNCTION(0, "GPIOD7"),
+               STM32_FUNCTION(8, "USART2_CK"),
+               STM32_FUNCTION(9, "SPDIFRX_IN0"),
+               STM32_FUNCTION(13, "FMC_NE1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(56, "PD8"),
+               STM32_FUNCTION(0, "GPIOD8"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(9, "SPDIFRX_IN1"),
+               STM32_FUNCTION(13, "FMC_D13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(57, "PD9"),
+               STM32_FUNCTION(0, "GPIOD9"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(13, "FMC_D14"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(58, "PD10"),
+               STM32_FUNCTION(0, "GPIOD10"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(13, "FMC_D15"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(59, "PD11"),
+               STM32_FUNCTION(0, "GPIOD11"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(8, "USART3_CTS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(11, "SAI2_SD_A"),
+               STM32_FUNCTION(13, "FMC_A16 FMC_CLE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(60, "PD12"),
+               STM32_FUNCTION(0, "GPIOD12"),
+               STM32_FUNCTION(3, "TIM4_CH1"),
+               STM32_FUNCTION(4, "LPTIM1_IN1"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(8, "USART3_RTS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(11, "SAI2_FS_A"),
+               STM32_FUNCTION(13, "FMC_A17 FMC_ALE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(61, "PD13"),
+               STM32_FUNCTION(0, "GPIOD13"),
+               STM32_FUNCTION(3, "TIM4_CH2"),
+               STM32_FUNCTION(4, "LPTIM1_OUT"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(11, "SAI2_SCK_A"),
+               STM32_FUNCTION(13, "FMC_A18"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(62, "PD14"),
+               STM32_FUNCTION(0, "GPIOD14"),
+               STM32_FUNCTION(3, "TIM4_CH3"),
+               STM32_FUNCTION(9, "UART8_CTS"),
+               STM32_FUNCTION(13, "FMC_D0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(63, "PD15"),
+               STM32_FUNCTION(0, "GPIOD15"),
+               STM32_FUNCTION(3, "TIM4_CH4"),
+               STM32_FUNCTION(9, "UART8_RTS"),
+               STM32_FUNCTION(13, "FMC_D1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(64, "PE0"),
+               STM32_FUNCTION(0, "GPIOE0"),
+               STM32_FUNCTION(3, "TIM4_ETR"),
+               STM32_FUNCTION(4, "LPTIM1_ETR"),
+               STM32_FUNCTION(9, "UART8_RX"),
+               STM32_FUNCTION(11, "SAI2_MCLK_A"),
+               STM32_FUNCTION(13, "FMC_NBL0"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(65, "PE1"),
+               STM32_FUNCTION(0, "GPIOE1"),
+               STM32_FUNCTION(4, "LPTIM1_IN2"),
+               STM32_FUNCTION(9, "UART8_TX"),
+               STM32_FUNCTION(13, "FMC_NBL1"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(66, "PE2"),
+               STM32_FUNCTION(0, "GPIOE2"),
+               STM32_FUNCTION(1, "TRACECLK"),
+               STM32_FUNCTION(6, "SPI4_SCK"),
+               STM32_FUNCTION(7, "SAI1_MCLK_A"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO2"),
+               STM32_FUNCTION(12, "ETH_MII_TXD3"),
+               STM32_FUNCTION(13, "FMC_A23"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(67, "PE3"),
+               STM32_FUNCTION(0, "GPIOE3"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(7, "SAI1_SD_B"),
+               STM32_FUNCTION(13, "FMC_A19"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(68, "PE4"),
+               STM32_FUNCTION(0, "GPIOE4"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(6, "SPI4_NSS"),
+               STM32_FUNCTION(7, "SAI1_FS_A"),
+               STM32_FUNCTION(13, "FMC_A20"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(69, "PE5"),
+               STM32_FUNCTION(0, "GPIOE5"),
+               STM32_FUNCTION(1, "TRACED2"),
+               STM32_FUNCTION(4, "TIM9_CH1"),
+               STM32_FUNCTION(6, "SPI4_MISO"),
+               STM32_FUNCTION(7, "SAI1_SCK_A"),
+               STM32_FUNCTION(13, "FMC_A21"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_G0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(70, "PE6"),
+               STM32_FUNCTION(0, "GPIOE6"),
+               STM32_FUNCTION(1, "TRACED3"),
+               STM32_FUNCTION(2, "TIM1_BKIN2"),
+               STM32_FUNCTION(4, "TIM9_CH2"),
+               STM32_FUNCTION(6, "SPI4_MOSI"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(11, "SAI2_MCLK_B"),
+               STM32_FUNCTION(13, "FMC_A22"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_G1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(71, "PE7"),
+               STM32_FUNCTION(0, "GPIOE7"),
+               STM32_FUNCTION(2, "TIM1_ETR"),
+               STM32_FUNCTION(9, "UART7_RX"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO0"),
+               STM32_FUNCTION(13, "FMC_D4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(72, "PE8"),
+               STM32_FUNCTION(0, "GPIOE8"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(9, "UART7_TX"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO1"),
+               STM32_FUNCTION(13, "FMC_D5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(73, "PE9"),
+               STM32_FUNCTION(0, "GPIOE9"),
+               STM32_FUNCTION(2, "TIM1_CH1"),
+               STM32_FUNCTION(9, "UART7_RTS"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO2"),
+               STM32_FUNCTION(13, "FMC_D6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(74, "PE10"),
+               STM32_FUNCTION(0, "GPIOE10"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(9, "UART7_CTS"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO3"),
+               STM32_FUNCTION(13, "FMC_D7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(75, "PE11"),
+               STM32_FUNCTION(0, "GPIOE11"),
+               STM32_FUNCTION(2, "TIM1_CH2"),
+               STM32_FUNCTION(6, "SPI4_NSS"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_D8"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(76, "PE12"),
+               STM32_FUNCTION(0, "GPIOE12"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(6, "SPI4_SCK"),
+               STM32_FUNCTION(11, "SAI2_SCK_B"),
+               STM32_FUNCTION(13, "FMC_D9"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(77, "PE13"),
+               STM32_FUNCTION(0, "GPIOE13"),
+               STM32_FUNCTION(2, "TIM1_CH3"),
+               STM32_FUNCTION(6, "SPI4_MISO"),
+               STM32_FUNCTION(11, "SAI2_FS_B"),
+               STM32_FUNCTION(13, "FMC_D10"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(78, "PE14"),
+               STM32_FUNCTION(0, "GPIOE14"),
+               STM32_FUNCTION(2, "TIM1_CH4"),
+               STM32_FUNCTION(6, "SPI4_MOSI"),
+               STM32_FUNCTION(11, "SAI2_MCLK_B"),
+               STM32_FUNCTION(13, "FMC_D11"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(79, "PE15"),
+               STM32_FUNCTION(0, "GPIOE15"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(13, "FMC_D12"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(80, "PF0"),
+               STM32_FUNCTION(0, "GPIOF0"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(13, "FMC_A0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(81, "PF1"),
+               STM32_FUNCTION(0, "GPIOF1"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(13, "FMC_A1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(82, "PF2"),
+               STM32_FUNCTION(0, "GPIOF2"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(13, "FMC_A2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(83, "PF3"),
+               STM32_FUNCTION(0, "GPIOF3"),
+               STM32_FUNCTION(13, "FMC_A3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(84, "PF4"),
+               STM32_FUNCTION(0, "GPIOF4"),
+               STM32_FUNCTION(13, "FMC_A4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(85, "PF5"),
+               STM32_FUNCTION(0, "GPIOF5"),
+               STM32_FUNCTION(13, "FMC_A5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(86, "PF6"),
+               STM32_FUNCTION(0, "GPIOF6"),
+               STM32_FUNCTION(4, "TIM10_CH1"),
+               STM32_FUNCTION(6, "SPI5_NSS"),
+               STM32_FUNCTION(7, "SAI1_SD_B"),
+               STM32_FUNCTION(9, "UART7_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(87, "PF7"),
+               STM32_FUNCTION(0, "GPIOF7"),
+               STM32_FUNCTION(4, "TIM11_CH1"),
+               STM32_FUNCTION(6, "SPI5_SCK"),
+               STM32_FUNCTION(7, "SAI1_MCLK_B"),
+               STM32_FUNCTION(9, "UART7_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(88, "PF8"),
+               STM32_FUNCTION(0, "GPIOF8"),
+               STM32_FUNCTION(6, "SPI5_MISO"),
+               STM32_FUNCTION(7, "SAI1_SCK_B"),
+               STM32_FUNCTION(9, "UART7_RTS"),
+               STM32_FUNCTION(10, "TIM13_CH1"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(89, "PF9"),
+               STM32_FUNCTION(0, "GPIOF9"),
+               STM32_FUNCTION(6, "SPI5_MOSI"),
+               STM32_FUNCTION(7, "SAI1_FS_B"),
+               STM32_FUNCTION(9, "UART7_CTS"),
+               STM32_FUNCTION(10, "TIM14_CH1"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(90, "PF10"),
+               STM32_FUNCTION(0, "GPIOF10"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(91, "PF11"),
+               STM32_FUNCTION(0, "GPIOF11"),
+               STM32_FUNCTION(6, "SPI5_MOSI"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_SDNRAS"),
+               STM32_FUNCTION(14, "DCMI_D12"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(92, "PF12"),
+               STM32_FUNCTION(0, "GPIOF12"),
+               STM32_FUNCTION(13, "FMC_A6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(93, "PF13"),
+               STM32_FUNCTION(0, "GPIOF13"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(13, "FMC_A7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(94, "PF14"),
+               STM32_FUNCTION(0, "GPIOF14"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(13, "FMC_A8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(95, "PF15"),
+               STM32_FUNCTION(0, "GPIOF15"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(13, "FMC_A9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(96, "PG0"),
+               STM32_FUNCTION(0, "GPIOG0"),
+               STM32_FUNCTION(13, "FMC_A10"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(97, "PG1"),
+               STM32_FUNCTION(0, "GPIOG1"),
+               STM32_FUNCTION(13, "FMC_A11"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(98, "PG2"),
+               STM32_FUNCTION(0, "GPIOG2"),
+               STM32_FUNCTION(13, "FMC_A12"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(99, "PG3"),
+               STM32_FUNCTION(0, "GPIOG3"),
+               STM32_FUNCTION(13, "FMC_A13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(100, "PG4"),
+               STM32_FUNCTION(0, "GPIOG4"),
+               STM32_FUNCTION(13, "FMC_A14 FMC_BA0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(101, "PG5"),
+               STM32_FUNCTION(0, "GPIOG5"),
+               STM32_FUNCTION(13, "FMC_A15 FMC_BA1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(102, "PG6"),
+               STM32_FUNCTION(0, "GPIOG6"),
+               STM32_FUNCTION(14, "DCMI_D12"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(103, "PG7"),
+               STM32_FUNCTION(0, "GPIOG7"),
+               STM32_FUNCTION(9, "USART6_CK"),
+               STM32_FUNCTION(13, "FMC_INT"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(104, "PG8"),
+               STM32_FUNCTION(0, "GPIOG8"),
+               STM32_FUNCTION(6, "SPI6_NSS"),
+               STM32_FUNCTION(8, "SPDIFRX_IN2"),
+               STM32_FUNCTION(9, "USART6_RTS"),
+               STM32_FUNCTION(12, "ETH_PPS_OUT"),
+               STM32_FUNCTION(13, "FMC_SDCLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(105, "PG9"),
+               STM32_FUNCTION(0, "GPIOG9"),
+               STM32_FUNCTION(8, "SPDIFRX_IN3"),
+               STM32_FUNCTION(9, "USART6_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO2"),
+               STM32_FUNCTION(11, "SAI2_FS_B"),
+               STM32_FUNCTION(13, "FMC_NE2 FMC_NCE"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(106, "PG10"),
+               STM32_FUNCTION(0, "GPIOG10"),
+               STM32_FUNCTION(10, "LCD_G3"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_NE3"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(107, "PG11"),
+               STM32_FUNCTION(0, "GPIOG11"),
+               STM32_FUNCTION(8, "SPDIFRX_IN0"),
+               STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(108, "PG12"),
+               STM32_FUNCTION(0, "GPIOG12"),
+               STM32_FUNCTION(4, "LPTIM1_IN1"),
+               STM32_FUNCTION(6, "SPI6_MISO"),
+               STM32_FUNCTION(8, "SPDIFRX_IN1"),
+               STM32_FUNCTION(9, "USART6_RTS"),
+               STM32_FUNCTION(10, "LCD_B4"),
+               STM32_FUNCTION(13, "FMC_NE4"),
+               STM32_FUNCTION(15, "LCD_B1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(109, "PG13"),
+               STM32_FUNCTION(0, "GPIOG13"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(4, "LPTIM1_OUT"),
+               STM32_FUNCTION(6, "SPI6_SCK"),
+               STM32_FUNCTION(9, "USART6_CTS"),
+               STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"),
+               STM32_FUNCTION(13, "FMC_A24"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(110, "PG14"),
+               STM32_FUNCTION(0, "GPIOG14"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(4, "LPTIM1_ETR"),
+               STM32_FUNCTION(6, "SPI6_MOSI"),
+               STM32_FUNCTION(9, "USART6_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO3"),
+               STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+               STM32_FUNCTION(13, "FMC_A25"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(111, "PG15"),
+               STM32_FUNCTION(0, "GPIOG15"),
+               STM32_FUNCTION(9, "USART6_CTS"),
+               STM32_FUNCTION(13, "FMC_SDNCAS"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(112, "PH0"),
+               STM32_FUNCTION(0, "GPIOH0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(113, "PH1"),
+               STM32_FUNCTION(0, "GPIOH1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(114, "PH2"),
+               STM32_FUNCTION(0, "GPIOH2"),
+               STM32_FUNCTION(4, "LPTIM1_IN2"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO0"),
+               STM32_FUNCTION(11, "SAI2_SCK_B"),
+               STM32_FUNCTION(12, "ETH_MII_CRS"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(115, "PH3"),
+               STM32_FUNCTION(0, "GPIOH3"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO1"),
+               STM32_FUNCTION(11, "SAI2_MCLK_B"),
+               STM32_FUNCTION(12, "ETH_MII_COL"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(116, "PH4"),
+               STM32_FUNCTION(0, "GPIOH4"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(117, "PH5"),
+               STM32_FUNCTION(0, "GPIOH5"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(6, "SPI5_NSS"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(118, "PH6"),
+               STM32_FUNCTION(0, "GPIOH6"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(6, "SPI5_SCK"),
+               STM32_FUNCTION(10, "TIM12_CH1"),
+               STM32_FUNCTION(12, "ETH_MII_RXD2"),
+               STM32_FUNCTION(13, "FMC_SDNE1"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(119, "PH7"),
+               STM32_FUNCTION(0, "GPIOH7"),
+               STM32_FUNCTION(5, "I2C3_SCL"),
+               STM32_FUNCTION(6, "SPI5_MISO"),
+               STM32_FUNCTION(12, "ETH_MII_RXD3"),
+               STM32_FUNCTION(13, "FMC_SDCKE1"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(120, "PH8"),
+               STM32_FUNCTION(0, "GPIOH8"),
+               STM32_FUNCTION(5, "I2C3_SDA"),
+               STM32_FUNCTION(13, "FMC_D16"),
+               STM32_FUNCTION(14, "DCMI_HSYNC"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(121, "PH9"),
+               STM32_FUNCTION(0, "GPIOH9"),
+               STM32_FUNCTION(5, "I2C3_SMBA"),
+               STM32_FUNCTION(10, "TIM12_CH2"),
+               STM32_FUNCTION(13, "FMC_D17"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(15, "LCD_R3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(122, "PH10"),
+               STM32_FUNCTION(0, "GPIOH10"),
+               STM32_FUNCTION(3, "TIM5_CH1"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(13, "FMC_D18"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(123, "PH11"),
+               STM32_FUNCTION(0, "GPIOH11"),
+               STM32_FUNCTION(3, "TIM5_CH2"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(13, "FMC_D19"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(124, "PH12"),
+               STM32_FUNCTION(0, "GPIOH12"),
+               STM32_FUNCTION(3, "TIM5_CH3"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(13, "FMC_D20"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(125, "PH13"),
+               STM32_FUNCTION(0, "GPIOH13"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(13, "FMC_D21"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(126, "PH14"),
+               STM32_FUNCTION(0, "GPIOH14"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(13, "FMC_D22"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(127, "PH15"),
+               STM32_FUNCTION(0, "GPIOH15"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(13, "FMC_D23"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(128, "PI0"),
+               STM32_FUNCTION(0, "GPIOI0"),
+               STM32_FUNCTION(3, "TIM5_CH4"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(13, "FMC_D24"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(129, "PI1"),
+               STM32_FUNCTION(0, "GPIOI1"),
+               STM32_FUNCTION(4, "TIM8_BKIN2"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(13, "FMC_D25"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(130, "PI2"),
+               STM32_FUNCTION(0, "GPIOI2"),
+               STM32_FUNCTION(4, "TIM8_CH4"),
+               STM32_FUNCTION(6, "SPI2_MISO"),
+               STM32_FUNCTION(13, "FMC_D26"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(131, "PI3"),
+               STM32_FUNCTION(0, "GPIOI3"),
+               STM32_FUNCTION(4, "TIM8_ETR"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+               STM32_FUNCTION(13, "FMC_D27"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(132, "PI4"),
+               STM32_FUNCTION(0, "GPIOI4"),
+               STM32_FUNCTION(4, "TIM8_BKIN"),
+               STM32_FUNCTION(11, "SAI2_MCLK_A"),
+               STM32_FUNCTION(13, "FMC_NBL2"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(133, "PI5"),
+               STM32_FUNCTION(0, "GPIOI5"),
+               STM32_FUNCTION(4, "TIM8_CH1"),
+               STM32_FUNCTION(11, "SAI2_SCK_A"),
+               STM32_FUNCTION(13, "FMC_NBL3"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(134, "PI6"),
+               STM32_FUNCTION(0, "GPIOI6"),
+               STM32_FUNCTION(4, "TIM8_CH2"),
+               STM32_FUNCTION(11, "SAI2_SD_A"),
+               STM32_FUNCTION(13, "FMC_D28"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(135, "PI7"),
+               STM32_FUNCTION(0, "GPIOI7"),
+               STM32_FUNCTION(4, "TIM8_CH3"),
+               STM32_FUNCTION(11, "SAI2_FS_A"),
+               STM32_FUNCTION(13, "FMC_D29"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(136, "PI8"),
+               STM32_FUNCTION(0, "GPIOI8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(137, "PI9"),
+               STM32_FUNCTION(0, "GPIOI9"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(13, "FMC_D30"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(138, "PI10"),
+               STM32_FUNCTION(0, "GPIOI10"),
+               STM32_FUNCTION(12, "ETH_MII_RX_ER"),
+               STM32_FUNCTION(13, "FMC_D31"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(139, "PI11"),
+               STM32_FUNCTION(0, "GPIOI11"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(140, "PI12"),
+               STM32_FUNCTION(0, "GPIOI12"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(141, "PI13"),
+               STM32_FUNCTION(0, "GPIOI13"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(142, "PI14"),
+               STM32_FUNCTION(0, "GPIOI14"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(143, "PI15"),
+               STM32_FUNCTION(0, "GPIOI15"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(144, "PJ0"),
+               STM32_FUNCTION(0, "GPIOJ0"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(145, "PJ1"),
+               STM32_FUNCTION(0, "GPIOJ1"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(146, "PJ2"),
+               STM32_FUNCTION(0, "GPIOJ2"),
+               STM32_FUNCTION(15, "LCD_R3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(147, "PJ3"),
+               STM32_FUNCTION(0, "GPIOJ3"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(148, "PJ4"),
+               STM32_FUNCTION(0, "GPIOJ4"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(149, "PJ5"),
+               STM32_FUNCTION(0, "GPIOJ5"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(150, "PJ6"),
+               STM32_FUNCTION(0, "GPIOJ6"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(151, "PJ7"),
+               STM32_FUNCTION(0, "GPIOJ7"),
+               STM32_FUNCTION(15, "LCD_G0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(152, "PJ8"),
+               STM32_FUNCTION(0, "GPIOJ8"),
+               STM32_FUNCTION(15, "LCD_G1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(153, "PJ9"),
+               STM32_FUNCTION(0, "GPIOJ9"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(154, "PJ10"),
+               STM32_FUNCTION(0, "GPIOJ10"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(155, "PJ11"),
+               STM32_FUNCTION(0, "GPIOJ11"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(156, "PJ12"),
+               STM32_FUNCTION(0, "GPIOJ12"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(157, "PJ13"),
+               STM32_FUNCTION(0, "GPIOJ13"),
+               STM32_FUNCTION(15, "LCD_B1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(158, "PJ14"),
+               STM32_FUNCTION(0, "GPIOJ14"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(159, "PJ15"),
+               STM32_FUNCTION(0, "GPIOJ15"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(160, "PK0"),
+               STM32_FUNCTION(0, "GPIOK0"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(161, "PK1"),
+               STM32_FUNCTION(0, "GPIOK1"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(162, "PK2"),
+               STM32_FUNCTION(0, "GPIOK2"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(163, "PK3"),
+               STM32_FUNCTION(0, "GPIOK3"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(164, "PK4"),
+               STM32_FUNCTION(0, "GPIOK4"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(165, "PK5"),
+               STM32_FUNCTION(0, "GPIOK5"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(166, "PK6"),
+               STM32_FUNCTION(0, "GPIOK6"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(167, "PK7"),
+               STM32_FUNCTION(0, "GPIOK7"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+};
+
+static struct stm32_pinctrl_match_data stm32f746_match_data = {
+       .pins = stm32f746_pins,
+       .npins = ARRAY_SIZE(stm32f746_pins),
+};
+
+static const struct of_device_id stm32f746_pctrl_match[] = {
+       {
+               .compatible = "st,stm32f746-pinctrl",
+               .data = &stm32f746_match_data,
+       },
+       { }
+};
+
+static struct platform_driver stm32f746_pinctrl_driver = {
+       .probe = stm32_pctl_probe,
+       .driver = {
+               .name = "stm32f746-pinctrl",
+               .of_match_table = stm32f746_pctrl_match,
+       },
+};
+builtin_platform_driver(stm32f746_pinctrl_driver);
index 55083d278bb1eb36e38772fc36206f41a1460138..ce483b03a2631f18b25569cde3b60352f9eda53f 100644 (file)
@@ -180,17 +180,17 @@ static const struct sunxi_desc_pin sun8i_a23_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index 8b381d69df8632c806f45bde5a5d1e6645b35d40..3040abe6f73a1ad1b40991821f26de1c1db711d5 100644 (file)
@@ -140,17 +140,17 @@ static const struct sunxi_desc_pin sun8i_a33_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
index 11760bbe9d51acd4ebb4d44b82af2c525f68e1dd..26a2ad3b651f3f8231d140da016e46828b09b9fe 100644 (file)
@@ -219,17 +219,17 @@ static const struct sunxi_desc_pin sun8i_h3_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
index 6e82b290cb4f70da806939dda9d39d42bff2896e..277622b4b6fb9bb90b4c045e984ca106eb2f4b2f 100644 (file)
@@ -632,11 +632,11 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
        u32 val;
 
        for (i = 0; i < pmx->soc->ngroups; ++i) {
-               if (pmx->soc->groups[i].parked_reg >= 0) {
-                       g = &pmx->soc->groups[i];
-                       val = pmx_readl(pmx, g->parked_bank, g->parked_reg);
+               g = &pmx->soc->groups[i];
+               if (g->parked_bit >= 0) {
+                       val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
                        val &= ~(1 << g->parked_bit);
-                       pmx_writel(pmx, val, g->parked_bank, g->parked_reg);
+                       pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
                }
        }
 }
index d2ced17382b56ac4dada88fefcbd8cef738bd381..33b17cb1471e56a2f4cb173fe21c196d9a19c7db 100644 (file)
@@ -93,9 +93,7 @@ struct tegra_function {
  * @tri_reg:           Tri-state register offset.
  * @tri_bank:          Tri-state register bank.
  * @tri_bit:           Tri-state register bit.
- * @parked_reg:                Parked register offset. -1 if unsupported.
- * @parked_bank:       Parked register bank. 0 if unsupported.
- * @parked_bit:                Parked register bit. 0 if unsupported.
+ * @parked_bit:                Parked register bit. -1 if unsupported.
  * @einput_bit:                Enable-input register bit.
  * @odrain_bit:                Open-drain register bit.
  * @lock_bit:          Lock register bit.
@@ -138,12 +136,10 @@ struct tegra_pingroup {
        s16 pupd_reg;
        s16 tri_reg;
        s16 drv_reg;
-       s16 parked_reg;
        u32 mux_bank:2;
        u32 pupd_bank:2;
        u32 tri_bank:2;
        u32 drv_bank:2;
-       u32 parked_bank:2;
        s32 mux_bit:6;
        s32 pupd_bit:6;
        s32 tri_bit:6;
index 4851d169f4c7a33c37a6e69bb766b4e8fe84422b..952132ce5ea0ca75e0b270db47811affe4f64e0b 100644 (file)
@@ -1578,7 +1578,7 @@ static struct tegra_function tegra114_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9),               \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
        }
 
@@ -1599,7 +1599,7 @@ static struct tegra_function tegra114_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
index a0ce723a9482d4efd6937c4cd76f98ca4968a196..bca239e3ae500c389fef9d211e22725800d0216c 100644 (file)
@@ -1747,7 +1747,7 @@ static struct tegra_function tegra124_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9),               \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
        }
 
@@ -1768,7 +1768,7 @@ static struct tegra_function tegra124_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
index 09bad6980ad1e81292a6b180866511ecab903585..ad62451a5a9be86571db61b0049f019900582e90 100644 (file)
@@ -1994,7 +1994,7 @@ static struct tegra_function tegra20_functions[] = {
                .tri_reg = ((tri_r) - TRISTATE_REG_A),          \
                .tri_bank = 0,                                  \
                .tri_bit = tri_b,                               \
-               .parked_reg = -1,                               \
+               .parked_bit = -1,                               \
                .einput_bit = -1,                               \
                .odrain_bit = -1,                               \
                .lock_bit = -1,                                 \
@@ -2014,7 +2014,7 @@ static struct tegra_function tegra20_functions[] = {
                .pupd_bank = 2,                                 \
                .pupd_bit = pupd_b,                             \
                .drv_reg = -1,                                  \
-               .parked_reg = -1,                               \
+               .parked_bit = -1,                               \
        }
 
 /* Pin groups for drive strength registers (configurable version) */
@@ -2030,7 +2030,7 @@ static struct tegra_function tegra20_functions[] = {
                .tri_reg = -1,                                  \
                .drv_reg = ((r) - PINGROUP_REG_A),              \
                .drv_bank = 3,                                  \
-               .parked_reg = -1,                               \
+               .parked_bit = -1,                               \
                .hsm_bit = hsm_b,                               \
                .schmitt_bit = schmitt_b,                       \
                .lpmd_bit = lpmd_b,                             \
index 2d856af389ef8a2a6997e0f41baa2a88410097d3..2b70e93da9dbc381fae5addc7842794b487bc988 100644 (file)
@@ -1310,8 +1310,6 @@ static struct tegra_function tegra210_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = -1,                                      \
                .rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10),              \
-               .parked_reg = PINGROUP_REG(r),                          \
-               .parked_bank = 1,                                       \
                .parked_bit = 5,                                        \
                .hsm_bit = PINGROUP_BIT_##hsm(9),                       \
                .schmitt_bit = 12,                                      \
@@ -1345,7 +1343,7 @@ static struct tegra_function tegra210_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .hsm_bit = -1,                                          \
                .schmitt_bit = -1,                                      \
                .lpmd_bit = -1,                                         \
index fb7817fea2d942d1a3a2cb98b1d3e3b7a8cddddf..474ac6daf5131605ba477f730ad6ae5ce6e0e3a1 100644 (file)
@@ -2139,7 +2139,7 @@ static struct tegra_function tegra30_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = -1,                                      \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
        }
 
@@ -2160,7 +2160,7 @@ static struct tegra_function tegra30_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
index 0b40ded5738f57689097f06e53bb3c8ba8af66ad..e077a9ec23d9b00cb01e111549fbc4ecf9c42394 100644 (file)
@@ -10,26 +10,34 @@ if PINCTRL_UNIPHIER
 
 config PINCTRL_UNIPHIER_LD4
        tristate "UniPhier PH1-LD4 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_PRO4
        tristate "UniPhier PH1-Pro4 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_SLD8
        tristate "UniPhier PH1-sLD8 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_PRO5
        tristate "UniPhier PH1-Pro5 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_PXS2
        tristate "UniPhier ProXstream2 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_LD6B
        tristate "UniPhier PH1-LD6b SoC pinctrl driver"
-       default y
+       default ARM
+
+config PINCTRL_UNIPHIER_LD11
+       tristate "UniPhier PH1-LD11 SoC pinctrl driver"
+       default ARM64
+
+config PINCTRL_UNIPHIER_LD20
+       tristate "UniPhier PH1-LD20 SoC pinctrl driver"
+       default ARM64
 
 endif
index 3b8f9ee0bb6fd22ac30ddd482ebd5c45d252d744..9f4bc8aa6f681ae8681dbfe93608b5548e3b2864 100644 (file)
@@ -6,3 +6,5 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_SLD8)     += pinctrl-uniphier-sld8.o
 obj-$(CONFIG_PINCTRL_UNIPHIER_PRO5)    += pinctrl-uniphier-pro5.o
 obj-$(CONFIG_PINCTRL_UNIPHIER_PXS2)    += pinctrl-uniphier-pxs2.o
 obj-$(CONFIG_PINCTRL_UNIPHIER_LD6B)    += pinctrl-uniphier-ld6b.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_LD11)    += pinctrl-uniphier-ld11.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_LD20)    += pinctrl-uniphier-ld20.o
index 967400971d4554a05adf82a8e2a0b65168a2b22c..9b2ee717bcccb99fb1ca773806b09afa75f62077 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/export.h>
 #include <linux/mfd/syscon.h>
+#include <linux/of.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinctrl.h>
 #include "pinctrl-uniphier.h"
 
 struct uniphier_pinctrl_priv {
+       struct pinctrl_desc pctldesc;
        struct pinctrl_dev *pctldev;
        struct regmap *regmap;
+       unsigned int regbase;
        struct uniphier_pinctrl_socdata *socdata;
 };
 
@@ -63,16 +66,22 @@ static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev,
 static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
                                       struct seq_file *s, unsigned offset)
 {
-       const struct pinctrl_pin_desc *pin = &pctldev->desc->pins[offset];
-       const char *pull_dir, *drv_str;
+       const struct pin_desc *desc = pin_desc_get(pctldev, offset);
+       const char *pull_dir, *drv_type;
 
-       switch (uniphier_pin_get_pull_dir(pin->drv_data)) {
+       switch (uniphier_pin_get_pull_dir(desc->drv_data)) {
        case UNIPHIER_PIN_PULL_UP:
                pull_dir = "UP";
                break;
        case UNIPHIER_PIN_PULL_DOWN:
                pull_dir = "DOWN";
                break;
+       case UNIPHIER_PIN_PULL_UP_FIXED:
+               pull_dir = "UP(FIXED)";
+               break;
+       case UNIPHIER_PIN_PULL_DOWN_FIXED:
+               pull_dir = "DOWN(FIXED)";
+               break;
        case UNIPHIER_PIN_PULL_NONE:
                pull_dir = "NONE";
                break;
@@ -80,30 +89,33 @@ static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
                BUG();
        }
 
-       switch (uniphier_pin_get_drv_str(pin->drv_data)) {
-       case UNIPHIER_PIN_DRV_4_8:
-               drv_str = "4/8(mA)";
+       switch (uniphier_pin_get_drv_type(desc->drv_data)) {
+       case UNIPHIER_PIN_DRV_1BIT:
+               drv_type = "4/8(mA)";
+               break;
+       case UNIPHIER_PIN_DRV_2BIT:
+               drv_type = "8/12/16/20(mA)";
                break;
-       case UNIPHIER_PIN_DRV_8_12_16_20:
-               drv_str = "8/12/16/20(mA)";
+       case UNIPHIER_PIN_DRV_3BIT:
+               drv_type = "4/5/7/9/11/12/14/16(mA)";
                break;
-       case UNIPHIER_PIN_DRV_FIXED_4:
-               drv_str = "4(mA)";
+       case UNIPHIER_PIN_DRV_FIXED4:
+               drv_type = "4(mA)";
                break;
-       case UNIPHIER_PIN_DRV_FIXED_5:
-               drv_str = "5(mA)";
+       case UNIPHIER_PIN_DRV_FIXED5:
+               drv_type = "5(mA)";
                break;
-       case UNIPHIER_PIN_DRV_FIXED_8:
-               drv_str = "8(mA)";
+       case UNIPHIER_PIN_DRV_FIXED8:
+               drv_type = "8(mA)";
                break;
        case UNIPHIER_PIN_DRV_NONE:
-               drv_str = "NONE";
+               drv_type = "NONE";
                break;
        default:
                BUG();
        }
 
-       seq_printf(s, " PULL_DIR=%s  DRV_STR=%s", pull_dir, drv_str);
+       seq_printf(s, " PULL_DIR=%s  DRV_TYPE=%s", pull_dir, drv_type);
 }
 #endif
 
@@ -119,12 +131,12 @@ static const struct pinctrl_ops uniphier_pctlops = {
 };
 
 static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev,
-                                     const struct pinctrl_pin_desc *pin,
+                                     const struct pin_desc *desc,
                                      enum pin_config_param param)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
        enum uniphier_pin_pull_dir pull_dir =
-                               uniphier_pin_get_pull_dir(pin->drv_data);
+                               uniphier_pin_get_pull_dir(desc->drv_data);
        unsigned int pupdctrl, reg, shift, val;
        unsigned int expected = 1;
        int ret;
@@ -154,12 +166,12 @@ static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev,
                BUG();
        }
 
-       pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data);
+       pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data);
 
        reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4;
        shift = pupdctrl % 32;
 
-       ret = regmap_read(priv->regmap, reg, &val);
+       ret = regmap_read(priv->regmap, priv->regbase + reg, &val);
        if (ret)
                return ret;
 
@@ -169,34 +181,42 @@ static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev,
 }
 
 static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev,
-                                      const struct pinctrl_pin_desc *pin,
+                                      const struct pin_desc *desc,
                                       u16 *strength)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       enum uniphier_pin_drv_str drv_str =
-                               uniphier_pin_get_drv_str(pin->drv_data);
-       const unsigned int strength_4_8[] = {4, 8};
-       const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20};
+       enum uniphier_pin_drv_type type =
+                               uniphier_pin_get_drv_type(desc->drv_data);
+       const unsigned int strength_1bit[] = {4, 8};
+       const unsigned int strength_2bit[] = {8, 12, 16, 20};
+       const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, 16};
        const unsigned int *supported_strength;
        unsigned int drvctrl, reg, shift, mask, width, val;
        int ret;
 
-       switch (drv_str) {
-       case UNIPHIER_PIN_DRV_4_8:
-               supported_strength = strength_4_8;
+       switch (type) {
+       case UNIPHIER_PIN_DRV_1BIT:
+               supported_strength = strength_1bit;
+               reg = UNIPHIER_PINCTRL_DRVCTRL_BASE;
                width = 1;
                break;
-       case UNIPHIER_PIN_DRV_8_12_16_20:
-               supported_strength = strength_8_12_16_20;
+       case UNIPHIER_PIN_DRV_2BIT:
+               supported_strength = strength_2bit;
+               reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE;
                width = 2;
                break;
-       case UNIPHIER_PIN_DRV_FIXED_4:
+       case UNIPHIER_PIN_DRV_3BIT:
+               supported_strength = strength_3bit;
+               reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE;
+               width = 4;
+               break;
+       case UNIPHIER_PIN_DRV_FIXED4:
                *strength = 4;
                return 0;
-       case UNIPHIER_PIN_DRV_FIXED_5:
+       case UNIPHIER_PIN_DRV_FIXED5:
                *strength = 5;
                return 0;
-       case UNIPHIER_PIN_DRV_FIXED_8:
+       case UNIPHIER_PIN_DRV_FIXED8:
                *strength = 8;
                return 0;
        default:
@@ -204,17 +224,14 @@ static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev,
                return -EINVAL;
        }
 
-       drvctrl = uniphier_pin_get_drvctrl(pin->drv_data);
+       drvctrl = uniphier_pin_get_drvctrl(desc->drv_data);
        drvctrl *= width;
 
-       reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE :
-                            UNIPHIER_PINCTRL_DRVCTRL_BASE;
-
        reg += drvctrl / 32 * 4;
        shift = drvctrl % 32;
        mask = (1U << width) - 1;
 
-       ret = regmap_read(priv->regmap, reg, &val);
+       ret = regmap_read(priv->regmap, priv->regbase + reg, &val);
        if (ret)
                return ret;
 
@@ -224,10 +241,10 @@ static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev,
 }
 
 static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev,
-                                       const struct pinctrl_pin_desc *pin)
+                                             const struct pin_desc *desc)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data);
+       unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data);
        unsigned int val;
        int ret;
 
@@ -235,7 +252,8 @@ static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev,
                /* This pin is always input-enabled. */
                return 0;
 
-       ret = regmap_read(priv->regmap, UNIPHIER_PINCTRL_IECTRL, &val);
+       ret = regmap_read(priv->regmap,
+                         priv->regbase + UNIPHIER_PINCTRL_IECTRL, &val);
        if (ret)
                return ret;
 
@@ -246,7 +264,7 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
                                        unsigned pin,
                                        unsigned long *configs)
 {
-       const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin];
+       const struct pin_desc *desc = pin_desc_get(pctldev, pin);
        enum pin_config_param param = pinconf_to_config_param(*configs);
        bool has_arg = false;
        u16 arg;
@@ -256,14 +274,14 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
        case PIN_CONFIG_BIAS_DISABLE:
        case PIN_CONFIG_BIAS_PULL_UP:
        case PIN_CONFIG_BIAS_PULL_DOWN:
-               ret = uniphier_conf_pin_bias_get(pctldev, pin_desc, param);
+               ret = uniphier_conf_pin_bias_get(pctldev, desc, param);
                break;
        case PIN_CONFIG_DRIVE_STRENGTH:
-               ret = uniphier_conf_pin_drive_get(pctldev, pin_desc, &arg);
+               ret = uniphier_conf_pin_drive_get(pctldev, desc, &arg);
                has_arg = true;
                break;
        case PIN_CONFIG_INPUT_ENABLE:
-               ret = uniphier_conf_pin_input_enable_get(pctldev, pin_desc);
+               ret = uniphier_conf_pin_input_enable_get(pctldev, desc);
                break;
        default:
                /* unsupported parameter */
@@ -278,13 +296,12 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
 }
 
 static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
-                                     const struct pinctrl_pin_desc *pin,
-                                     enum pin_config_param param,
-                                     u16 arg)
+                                     const struct pin_desc *desc,
+                                     enum pin_config_param param, u16 arg)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
        enum uniphier_pin_pull_dir pull_dir =
-                               uniphier_pin_get_pull_dir(pin->drv_data);
+                               uniphier_pin_get_pull_dir(desc->drv_data);
        unsigned int pupdctrl, reg, shift;
        unsigned int val = 1;
 
@@ -295,8 +312,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED ||
                    pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) {
                        dev_err(pctldev->dev,
-                               "can not disable pull register for pin %u (%s)\n",
-                               pin->number, pin->name);
+                               "can not disable pull register for pin %s\n",
+                               desc->name);
                        return -EINVAL;
                }
                val = 0;
@@ -306,8 +323,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                        return 0;
                if (pull_dir != UNIPHIER_PIN_PULL_UP) {
                        dev_err(pctldev->dev,
-                               "pull-up is unsupported for pin %u (%s)\n",
-                               pin->number, pin->name);
+                               "pull-up is unsupported for pin %s\n",
+                               desc->name);
                        return -EINVAL;
                }
                if (arg == 0) {
@@ -320,8 +337,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                        return 0;
                if (pull_dir != UNIPHIER_PIN_PULL_DOWN) {
                        dev_err(pctldev->dev,
-                               "pull-down is unsupported for pin %u (%s)\n",
-                               pin->number, pin->name);
+                               "pull-down is unsupported for pin %s\n",
+                               desc->name);
                        return -EINVAL;
                }
                if (arg == 0) {
@@ -332,8 +349,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
        case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
                if (pull_dir == UNIPHIER_PIN_PULL_NONE) {
                        dev_err(pctldev->dev,
-                               "pull-up/down is unsupported for pin %u (%s)\n",
-                               pin->number, pin->name);
+                               "pull-up/down is unsupported for pin %s\n",
+                               desc->name);
                        return -EINVAL;
                }
 
@@ -344,39 +361,48 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                BUG();
        }
 
-       pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data);
+       pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data);
 
        reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4;
        shift = pupdctrl % 32;
 
-       return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift);
+       return regmap_update_bits(priv->regmap, priv->regbase + reg,
+                                 1 << shift, val << shift);
 }
 
 static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev,
-                                      const struct pinctrl_pin_desc *pin,
+                                      const struct pin_desc *desc,
                                       u16 strength)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       enum uniphier_pin_drv_str drv_str =
-                               uniphier_pin_get_drv_str(pin->drv_data);
-       const unsigned int strength_4_8[] = {4, 8, -1};
-       const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20, -1};
+       enum uniphier_pin_drv_type type =
+                               uniphier_pin_get_drv_type(desc->drv_data);
+       const unsigned int strength_1bit[] = {4, 8, -1};
+       const unsigned int strength_2bit[] = {8, 12, 16, 20, -1};
+       const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, 16, -1};
        const unsigned int *supported_strength;
        unsigned int drvctrl, reg, shift, mask, width, val;
 
-       switch (drv_str) {
-       case UNIPHIER_PIN_DRV_4_8:
-               supported_strength = strength_4_8;
+       switch (type) {
+       case UNIPHIER_PIN_DRV_1BIT:
+               supported_strength = strength_1bit;
+               reg = UNIPHIER_PINCTRL_DRVCTRL_BASE;
                width = 1;
                break;
-       case UNIPHIER_PIN_DRV_8_12_16_20:
-               supported_strength = strength_8_12_16_20;
+       case UNIPHIER_PIN_DRV_2BIT:
+               supported_strength = strength_2bit;
+               reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE;
                width = 2;
                break;
+       case UNIPHIER_PIN_DRV_3BIT:
+               supported_strength = strength_3bit;
+               reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE;
+               width = 4;
+               break;
        default:
                dev_err(pctldev->dev,
-                       "cannot change drive strength for pin %u (%s)\n",
-                       pin->number, pin->name);
+                       "cannot change drive strength for pin %s\n",
+                       desc->name);
                return -EINVAL;
        }
 
@@ -387,49 +413,48 @@ static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev,
 
        if (val == 0) {
                dev_err(pctldev->dev,
-                       "unsupported drive strength %u mA for pin %u (%s)\n",
-                       strength, pin->number, pin->name);
+                       "unsupported drive strength %u mA for pin %s\n",
+                       strength, desc->name);
                return -EINVAL;
        }
 
        val--;
 
-       drvctrl = uniphier_pin_get_drvctrl(pin->drv_data);
+       drvctrl = uniphier_pin_get_drvctrl(desc->drv_data);
        drvctrl *= width;
 
-       reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE :
-                            UNIPHIER_PINCTRL_DRVCTRL_BASE;
-
        reg += drvctrl / 32 * 4;
        shift = drvctrl % 32;
        mask = (1U << width) - 1;
 
-       return regmap_update_bits(priv->regmap, reg,
+       return regmap_update_bits(priv->regmap, priv->regbase + reg,
                                  mask << shift, val << shift);
 }
 
 static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev,
-                                         const struct pinctrl_pin_desc *pin,
+                                         const struct pin_desc *desc,
                                          u16 enable)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data);
+       unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data);
+       unsigned int reg, mask;
 
-       if (enable == 0) {
-               /*
-                * Multiple pins share one input enable, so per-pin disabling
-                * is impossible.
-                */
-               dev_err(pctldev->dev, "unable to disable input\n");
+       /*
+        * Multiple pins share one input enable, per-pin disabling is
+        * impossible.
+        */
+       if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) &&
+           !enable)
                return -EINVAL;
-       }
 
+       /* UNIPHIER_PIN_IECTRL_NONE means the pin is always input-enabled */
        if (iectrl == UNIPHIER_PIN_IECTRL_NONE)
-               /* This pin is always input-enabled. nothing to do. */
-               return 0;
+               return enable ? 0 : -EINVAL;
+
+       reg = priv->regbase + UNIPHIER_PINCTRL_IECTRL + iectrl / 32 * 4;
+       mask = BIT(iectrl % 32);
 
-       return regmap_update_bits(priv->regmap, UNIPHIER_PINCTRL_IECTRL,
-                                 BIT(iectrl), BIT(iectrl));
+       return regmap_update_bits(priv->regmap, reg, mask, enable ? mask : 0);
 }
 
 static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
@@ -437,7 +462,7 @@ static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
                                        unsigned long *configs,
                                        unsigned num_configs)
 {
-       const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin];
+       const struct pin_desc *desc = pin_desc_get(pctldev, pin);
        int i, ret;
 
        for (i = 0; i < num_configs; i++) {
@@ -450,16 +475,15 @@ static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
                case PIN_CONFIG_BIAS_PULL_UP:
                case PIN_CONFIG_BIAS_PULL_DOWN:
                case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
-                       ret = uniphier_conf_pin_bias_set(pctldev, pin_desc,
+                       ret = uniphier_conf_pin_bias_set(pctldev, desc,
                                                         param, arg);
                        break;
                case PIN_CONFIG_DRIVE_STRENGTH:
-                       ret = uniphier_conf_pin_drive_set(pctldev, pin_desc,
-                                                         arg);
+                       ret = uniphier_conf_pin_drive_set(pctldev, desc, arg);
                        break;
                case PIN_CONFIG_INPUT_ENABLE:
-                       ret = uniphier_conf_pin_input_enable(pctldev,
-                                                            pin_desc, arg);
+                       ret = uniphier_conf_pin_input_enable(pctldev, desc,
+                                                            arg);
                        break;
                default:
                        dev_err(pctldev->dev,
@@ -531,20 +555,42 @@ static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev,
 }
 
 static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin,
-                                   unsigned muxval)
+                                   int muxval)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       unsigned mux_bits = priv->socdata->mux_bits;
-       unsigned reg_stride = priv->socdata->reg_stride;
-       unsigned reg, reg_end, shift, mask;
+       unsigned int mux_bits, reg_stride, reg, reg_end, shift, mask;
+       bool load_pinctrl;
        int ret;
 
        /* some pins need input-enabling */
        ret = uniphier_conf_pin_input_enable(pctldev,
-                                            &pctldev->desc->pins[pin], 1);
+                                            pin_desc_get(pctldev, pin), 1);
        if (ret)
                return ret;
 
+       if (muxval < 0)
+               return 0;       /* dedicated pin; nothing to do for pin-mux */
+
+       if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) {
+               /*
+                *  Mode     reg_offset     bit_position
+                *  Normal    4 * n        shift+3:shift
+                *  Debug     4 * n        shift+7:shift+4
+                */
+               mux_bits = 4;
+               reg_stride = 8;
+               load_pinctrl = true;
+       } else {
+               /*
+                *  Mode     reg_offset     bit_position
+                *  Normal    8 * n        shift+3:shift
+                *  Debug     8 * n + 4    shift+3:shift
+                */
+               mux_bits = 8;
+               reg_stride = 4;
+               load_pinctrl = false;
+       }
+
        reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride;
        reg_end = reg + reg_stride;
        shift = pin * mux_bits % 32;
@@ -555,16 +601,17 @@ static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin,
         * stored in the offset+4.
         */
        for (; reg < reg_end; reg += 4) {
-               ret = regmap_update_bits(priv->regmap, reg,
+               ret = regmap_update_bits(priv->regmap, priv->regbase + reg,
                                         mask << shift, muxval << shift);
                if (ret)
                        return ret;
                muxval >>= mux_bits;
        }
 
-       if (priv->socdata->load_pinctrl) {
+       if (load_pinctrl) {
                ret = regmap_write(priv->regmap,
-                                  UNIPHIER_PINCTRL_LOAD_PINMUX, 1);
+                                  priv->regbase + UNIPHIER_PINCTRL_LOAD_PINMUX,
+                                  1);
                if (ret)
                        return ret;
        }
@@ -633,19 +680,16 @@ static const struct pinmux_ops uniphier_pmxops = {
 };
 
 int uniphier_pinctrl_probe(struct platform_device *pdev,
-                          struct pinctrl_desc *desc,
                           struct uniphier_pinctrl_socdata *socdata)
 {
        struct device *dev = &pdev->dev;
        struct uniphier_pinctrl_priv *priv;
+       struct device_node *parent;
 
        if (!socdata ||
-           !socdata->groups ||
-           !socdata->groups_count ||
-           !socdata->functions ||
-           !socdata->functions_count ||
-           !socdata->mux_bits ||
-           !socdata->reg_stride) {
+           !socdata->pins || !socdata->npins ||
+           !socdata->groups || !socdata->groups_count ||
+           !socdata->functions || !socdata->functions_count) {
                dev_err(dev, "pinctrl socdata lacks necessary members\n");
                return -EINVAL;
        }
@@ -654,18 +698,36 @@ int uniphier_pinctrl_probe(struct platform_device *pdev,
        if (!priv)
                return -ENOMEM;
 
-       priv->regmap = syscon_node_to_regmap(dev->of_node);
+       if (of_device_is_compatible(dev->of_node, "socionext,ph1-ld4-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,ph1-pro4-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,ph1-sld8-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,ph1-pro5-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,proxstream2-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,ph1-ld6b-pinctrl")) {
+               /* old binding */
+               priv->regmap = syscon_node_to_regmap(dev->of_node);
+       } else {
+               priv->regbase = 0x1000;
+               parent = of_get_parent(dev->of_node);
+               priv->regmap = syscon_node_to_regmap(parent);
+               of_node_put(parent);
+       }
+
        if (IS_ERR(priv->regmap)) {
                dev_err(dev, "failed to get regmap\n");
                return PTR_ERR(priv->regmap);
        }
 
        priv->socdata = socdata;
-       desc->pctlops = &uniphier_pctlops;
-       desc->pmxops = &uniphier_pmxops;
-       desc->confops = &uniphier_confops;
-
-       priv->pctldev = devm_pinctrl_register(dev, desc, priv);
+       priv->pctldesc.name = dev->driver->name;
+       priv->pctldesc.pins = socdata->pins;
+       priv->pctldesc.npins = socdata->npins;
+       priv->pctldesc.pctlops = &uniphier_pctlops;
+       priv->pctldesc.pmxops = &uniphier_pmxops;
+       priv->pctldesc.confops = &uniphier_confops;
+       priv->pctldesc.owner = dev->driver->owner;
+
+       priv->pctldev = devm_pinctrl_register(dev, &priv->pctldesc, priv);
        if (IS_ERR(priv->pctldev)) {
                dev_err(dev, "failed to register UniPhier pinctrl driver\n");
                return PTR_ERR(priv->pctldev);
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
new file mode 100644 (file)
index 0000000..77a0236
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-uniphier.h"
+
+static const struct pinctrl_pin_desc uniphier_ld11_pins[] = {
+       UNIPHIER_PINCTRL_PIN(0, "XECS1", 0,
+                            0, UNIPHIER_PIN_DRV_1BIT,
+                            0, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(1, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
+                            1, UNIPHIER_PIN_DRV_1BIT,
+                            1, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(2, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
+                            2, UNIPHIER_PIN_DRV_1BIT,
+                            2, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(3, "XNFWP", 3,
+                            3, UNIPHIER_PIN_DRV_1BIT,
+                            3, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(4, "XNFCE0", 4,
+                            4, UNIPHIER_PIN_DRV_1BIT,
+                            4, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(5, "NFRYBY0", 5,
+                            5, UNIPHIER_PIN_DRV_1BIT,
+                            5, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(6, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
+                            6, UNIPHIER_PIN_DRV_1BIT,
+                            6, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(7, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
+                            7, UNIPHIER_PIN_DRV_1BIT,
+                            7, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(8, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
+                            8, UNIPHIER_PIN_DRV_1BIT,
+                            8, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(9, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
+                            9, UNIPHIER_PIN_DRV_1BIT,
+                            9, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(10, "NFD0", 10,
+                            10, UNIPHIER_PIN_DRV_1BIT,
+                            10, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(11, "NFD1", 11,
+                            11, UNIPHIER_PIN_DRV_1BIT,
+                            11, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(12, "NFD2", 12,
+                            12, UNIPHIER_PIN_DRV_1BIT,
+                            12, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(13, "NFD3", 13,
+                            13, UNIPHIER_PIN_DRV_1BIT,
+                            13, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(14, "NFD4", 14,
+                            14, UNIPHIER_PIN_DRV_1BIT,
+                            14, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(15, "NFD5", 15,
+                            15, UNIPHIER_PIN_DRV_1BIT,
+                            15, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(16, "NFD6", 16,
+                            16, UNIPHIER_PIN_DRV_1BIT,
+                            16, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(17, "NFD7", 17,
+                            17, UNIPHIER_PIN_DRV_1BIT,
+                            17, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(18, "XERST", 18,
+                            0, UNIPHIER_PIN_DRV_2BIT,
+                            18, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(19, "MMCCLK", 19,
+                            1, UNIPHIER_PIN_DRV_2BIT,
+                            19, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(20, "MMCCMD", 20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
+                            20, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(21, "MMCDS", 21,
+                            3, UNIPHIER_PIN_DRV_2BIT,
+                            21, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(22, "MMCDAT0", 22,
+                            4, UNIPHIER_PIN_DRV_2BIT,
+                            22, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(23, "MMCDAT1", 23,
+                            5, UNIPHIER_PIN_DRV_2BIT,
+                            23, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(24, "MMCDAT2", 24,
+                            6, UNIPHIER_PIN_DRV_2BIT,
+                            24, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(25, "MMCDAT3", 25,
+                            7, UNIPHIER_PIN_DRV_2BIT,
+                            25, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(26, "MMCDAT4", 26,
+                            8, UNIPHIER_PIN_DRV_2BIT,
+                            26, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(27, "MMCDAT5", 27,
+                            9, UNIPHIER_PIN_DRV_2BIT,
+                            27, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(28, "MMCDAT6", 28,
+                            10, UNIPHIER_PIN_DRV_2BIT,
+                            28, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(29, "MMCDAT7", 29,
+                            11, UNIPHIER_PIN_DRV_2BIT,
+                            29, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(46, "USB0VBUS", 46,
+                            46, UNIPHIER_PIN_DRV_1BIT,
+                            46, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(47, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
+                            47, UNIPHIER_PIN_DRV_1BIT,
+                            47, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(48, "USB1VBUS", 48,
+                            48, UNIPHIER_PIN_DRV_1BIT,
+                            48, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(49, "USB1OD", 49,
+                            49, UNIPHIER_PIN_DRV_1BIT,
+                            49, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(50, "USB2VBUS", 50,
+                            50, UNIPHIER_PIN_DRV_1BIT,
+                            50, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(51, "USB2OD", 51,
+                            51, UNIPHIER_PIN_DRV_1BIT,
+                            51, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(54, "TXD0", 54,
+                            54, UNIPHIER_PIN_DRV_1BIT,
+                            54, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(55, "RXD0", 55,
+                            55, UNIPHIER_PIN_DRV_1BIT,
+                            55, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(56, "SPISYNC0", 56,
+                            56, UNIPHIER_PIN_DRV_1BIT,
+                            56, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(57, "SPISCLK0", 57,
+                            57, UNIPHIER_PIN_DRV_1BIT,
+                            57, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(58, "SPITXD0", 58,
+                            58, UNIPHIER_PIN_DRV_1BIT,
+                            58, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(59, "SPIRXD0", 59,
+                            59, UNIPHIER_PIN_DRV_1BIT,
+                            59, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(60, "AGCI", 60,
+                            60, UNIPHIER_PIN_DRV_1BIT,
+                            60, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(61, "DMDSDA0", 61,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(62, "DMDSCL0", 62,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(63, "SDA0", 63,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(64, "SCL0", 64,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(65, "SDA1", 65,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(66, "SCL1", 66,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(67, "HIN", 67,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(68, "VIN", 68,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(69, "PCA00", 69,
+                            69, UNIPHIER_PIN_DRV_1BIT,
+                            69, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(70, "PCA01", 70,
+                            70, UNIPHIER_PIN_DRV_1BIT,
+                            70, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(71, "PCA02", 71,
+                            71, UNIPHIER_PIN_DRV_1BIT,
+                            71, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(72, "PCA03", 72,
+                            72, UNIPHIER_PIN_DRV_1BIT,
+                            72, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(73, "PCA04", 73,
+                            73, UNIPHIER_PIN_DRV_1BIT,
+                            73, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(74, "PCA05", 74,
+                            74, UNIPHIER_PIN_DRV_1BIT,
+                            74, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(75, "PCA06", 75,
+                            75, UNIPHIER_PIN_DRV_1BIT,
+                            75, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(76, "PCA07", 76,
+                            76, UNIPHIER_PIN_DRV_1BIT,
+                            76, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(77, "PCA08", 77,
+                            77, UNIPHIER_PIN_DRV_1BIT,
+                            77, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(78, "PCA09", 78,
+                            78, UNIPHIER_PIN_DRV_1BIT,
+                            78, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(79, "PCA10", 79,
+                            79, UNIPHIER_PIN_DRV_1BIT,
+                            79, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(80, "PCA11", 80,
+                            80, UNIPHIER_PIN_DRV_1BIT,
+                            80, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(81, "PCA12", 81,
+                            81, UNIPHIER_PIN_DRV_1BIT,
+                            81, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(82, "PCA13", 82,
+                            82, UNIPHIER_PIN_DRV_1BIT,
+                            82, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(83, "PCA14", 83,
+                            83, UNIPHIER_PIN_DRV_1BIT,
+                            83, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(84, "PC0READY", 84,
+                            84, UNIPHIER_PIN_DRV_1BIT,
+                            84, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(85, "PC0CD1", 85,
+                            85, UNIPHIER_PIN_DRV_1BIT,
+                            85, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(86, "PC0CD2", 86,
+                            86, UNIPHIER_PIN_DRV_1BIT,
+                            86, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(87, "PC0WAIT", 87,
+                            87, UNIPHIER_PIN_DRV_1BIT,
+                            87, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(88, "PC0RESET", 88,
+                            88, UNIPHIER_PIN_DRV_1BIT,
+                            88, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(89, "PC0CE1", 89,
+                            89, UNIPHIER_PIN_DRV_1BIT,
+                            89, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(90, "PC0WE", 90,
+                            90, UNIPHIER_PIN_DRV_1BIT,
+                            90, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(91, "PC0OE", 91,
+                            91, UNIPHIER_PIN_DRV_1BIT,
+                            91, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(92, "PC0IOWR", 92,
+                            92, UNIPHIER_PIN_DRV_1BIT,
+                            92, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(93, "PC0IORD", 93,
+                            93, UNIPHIER_PIN_DRV_1BIT,
+                            93, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(94, "PCD00", 94,
+                            94, UNIPHIER_PIN_DRV_1BIT,
+                            94, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(95, "PCD01", 95,
+                            95, UNIPHIER_PIN_DRV_1BIT,
+                            95, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(96, "PCD02", 96,
+                            96, UNIPHIER_PIN_DRV_1BIT,
+                            96, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(97, "PCD03", 97,
+                            97, UNIPHIER_PIN_DRV_1BIT,
+                            97, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(98, "PCD04", 98,
+                            98, UNIPHIER_PIN_DRV_1BIT,
+                            98, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(99, "PCD05", 99,
+                            99, UNIPHIER_PIN_DRV_1BIT,
+                            99, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(100, "PCD06", 100,
+                            100, UNIPHIER_PIN_DRV_1BIT,
+                            100, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(101, "PCD07", 101,
+                            101, UNIPHIER_PIN_DRV_1BIT,
+                            101, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(102, "HS0BCLKIN", 102,
+                            102, UNIPHIER_PIN_DRV_1BIT,
+                            102, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(103, "HS0SYNCIN", 103,
+                            103, UNIPHIER_PIN_DRV_1BIT,
+                            103, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(104, "HS0VALIN", 104,
+                            104, UNIPHIER_PIN_DRV_1BIT,
+                            104, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(105, "HS0DIN0", 105,
+                            105, UNIPHIER_PIN_DRV_1BIT,
+                            105, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(106, "HS0DIN1", 106,
+                            106, UNIPHIER_PIN_DRV_1BIT,
+                            106, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(107, "HS0DIN2", 107,
+                            107, UNIPHIER_PIN_DRV_1BIT,
+                            107, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(108, "HS0DIN3", 108,
+                            108, UNIPHIER_PIN_DRV_1BIT,
+                            108, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(109, "HS0DIN4", 109,
+                            109, UNIPHIER_PIN_DRV_1BIT,
+                            109, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(110, "HS0DIN5", 110,
+                            110, UNIPHIER_PIN_DRV_1BIT,
+                            110, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(111, "HS0DIN6", 111,
+                            111, UNIPHIER_PIN_DRV_1BIT,
+                            111, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(112, "HS0DIN7", 112,
+                            112, UNIPHIER_PIN_DRV_1BIT,
+                            112, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(113, "HS0BCLKOUT", 113,
+                            113, UNIPHIER_PIN_DRV_1BIT,
+                            113, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(114, "HS0SYNCOUT", 114,
+                            114, UNIPHIER_PIN_DRV_1BIT,
+                            114, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(115, "HS0VALOUT", 115,
+                            115, UNIPHIER_PIN_DRV_1BIT,
+                            115, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(116, "HS0DOUT0", 116,
+                            116, UNIPHIER_PIN_DRV_1BIT,
+                            116, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(117, "HS0DOUT1", 117,
+                            117, UNIPHIER_PIN_DRV_1BIT,
+                            117, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(118, "HS0DOUT2", 118,
+                            118, UNIPHIER_PIN_DRV_1BIT,
+                            118, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(119, "HS0DOUT3", 119,
+                            119, UNIPHIER_PIN_DRV_1BIT,
+                            119, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(120, "HS0DOUT4", 120,
+                            120, UNIPHIER_PIN_DRV_1BIT,
+                            120, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(121, "HS0DOUT5", 121,
+                            121, UNIPHIER_PIN_DRV_1BIT,
+                            121, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(122, "HS0DOUT6", 122,
+                            122, UNIPHIER_PIN_DRV_1BIT,
+                            122, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(123, "HS0DOUT7", 123,
+                            123, UNIPHIER_PIN_DRV_1BIT,
+                            123, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(124, "HS1BCLKIN", 124,
+                            124, UNIPHIER_PIN_DRV_1BIT,
+                            124, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(125, "HS1SYNCIN", 125,
+                            125, UNIPHIER_PIN_DRV_1BIT,
+                            125, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(126, "HS1VALIN", 126,
+                            126, UNIPHIER_PIN_DRV_1BIT,
+                            126, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(127, "HS1DIN0", 127,
+                            127, UNIPHIER_PIN_DRV_1BIT,
+                            127, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(128, "HS1DIN1", 128,
+                            128, UNIPHIER_PIN_DRV_1BIT,
+                            128, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(129, "HS1DIN2", 129,
+                            129, UNIPHIER_PIN_DRV_1BIT,
+                            129, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(130, "HS1DIN3", 130,
+                            130, UNIPHIER_PIN_DRV_1BIT,
+                            130, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(131, "HS1DIN4", 131,
+                            131, UNIPHIER_PIN_DRV_1BIT,
+                            131, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(132, "HS1DIN5", 132,
+                            132, UNIPHIER_PIN_DRV_1BIT,
+                            132, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(133, "HS1DIN6", 133,
+                            133, UNIPHIER_PIN_DRV_1BIT,
+                            133, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(134, "HS1DIN7", 134,
+                            134, UNIPHIER_PIN_DRV_1BIT,
+                            134, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(135, "AO1IEC", 135,
+                            135, UNIPHIER_PIN_DRV_1BIT,
+                            135, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(136, "AO1ARC", 136,
+                            136, UNIPHIER_PIN_DRV_1BIT,
+                            136, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(137, "AO1DACCK", 137,
+                            137, UNIPHIER_PIN_DRV_1BIT,
+                            137, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(138, "AO1BCK", 138,
+                            138, UNIPHIER_PIN_DRV_1BIT,
+                            138, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(139, "AO1LRCK", 139,
+                            139, UNIPHIER_PIN_DRV_1BIT,
+                            139, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(140, "AO1D0", 140,
+                            140, UNIPHIER_PIN_DRV_1BIT,
+                            140, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(141, "TCON0", 141,
+                            141, UNIPHIER_PIN_DRV_1BIT,
+                            141, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(142, "TCON1", 142,
+                            142, UNIPHIER_PIN_DRV_1BIT,
+                            142, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(143, "TCON2", 143,
+                            143, UNIPHIER_PIN_DRV_1BIT,
+                            143, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(144, "TCON3", 144,
+                            144, UNIPHIER_PIN_DRV_1BIT,
+                            144, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(145, "TCON4", 145,
+                            145, UNIPHIER_PIN_DRV_1BIT,
+                            145, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(146, "TCON5", 146,
+                            146, UNIPHIER_PIN_DRV_1BIT,
+                            146, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(147, "PWMA", 147,
+                            147, UNIPHIER_PIN_DRV_1BIT,
+                            147, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(148, "LR_GOUT", 148,
+                            148, UNIPHIER_PIN_DRV_1BIT,
+                            148, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(149, "XIRQ0", 149,
+                            149, UNIPHIER_PIN_DRV_1BIT,
+                            149, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(150, "XIRQ1", 150,
+                            150, UNIPHIER_PIN_DRV_1BIT,
+                            150, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(151, "XIRQ2", 151,
+                            151, UNIPHIER_PIN_DRV_1BIT,
+                            151, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(152, "XIRQ3", 152,
+                            152, UNIPHIER_PIN_DRV_1BIT,
+                            152, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(153, "XIRQ4", 153,
+                            153, UNIPHIER_PIN_DRV_1BIT,
+                            153, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(154, "XIRQ5", 154,
+                            154, UNIPHIER_PIN_DRV_1BIT,
+                            154, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(155, "XIRQ6", 155,
+                            155, UNIPHIER_PIN_DRV_1BIT,
+                            155, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(156, "XIRQ7", 156,
+                            156, UNIPHIER_PIN_DRV_1BIT,
+                            156, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(157, "XIRQ8", 157,
+                            157, UNIPHIER_PIN_DRV_1BIT,
+                            157, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(158, "AGCBS", 158,
+                            158, UNIPHIER_PIN_DRV_1BIT,
+                            158, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(159, "XIRQ21", 159,
+                            159, UNIPHIER_PIN_DRV_1BIT,
+                            159, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(160, "XIRQ22", 160,
+                            160, UNIPHIER_PIN_DRV_1BIT,
+                            160, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(161, "XIRQ23", 161,
+                            161, UNIPHIER_PIN_DRV_1BIT,
+                            161, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(162, "CH2CLK", 162,
+                            162, UNIPHIER_PIN_DRV_1BIT,
+                            162, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(163, "CH2PSYNC", 163,
+                            163, UNIPHIER_PIN_DRV_1BIT,
+                            163, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(164, "CH2VAL", 164,
+                            164, UNIPHIER_PIN_DRV_1BIT,
+                            164, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(165, "CH2DATA", 165,
+                            165, UNIPHIER_PIN_DRV_1BIT,
+                            165, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(166, "CK25O", 166,
+                            166, UNIPHIER_PIN_DRV_1BIT,
+                            166, UNIPHIER_PIN_PULL_DOWN),
+};
+
+static const unsigned emmc_pins[] = {18, 19, 20, 21, 22, 23, 24, 25};
+static const int emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned emmc_dat8_pins[] = {26, 27, 28, 29};
+static const int emmc_dat8_muxvals[] = {0, 0, 0, 0};
+static const unsigned ether_rmii_pins[] = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+                                          16, 17};
+static const int ether_rmii_muxvals[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
+static const unsigned i2c0_pins[] = {63, 64};
+static const int i2c0_muxvals[] = {0, 0};
+static const unsigned i2c1_pins[] = {65, 66};
+static const int i2c1_muxvals[] = {0, 0};
+static const unsigned i2c3_pins[] = {67, 68};
+static const int i2c3_muxvals[] = {1, 1};
+static const unsigned i2c4_pins[] = {61, 62};
+static const int i2c4_muxvals[] = {1, 1};
+static const unsigned nand_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+                                    15, 16, 17};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {1, 2, 6, 7, 8, 9, 10, 11, 12, 13,
+                                          14, 15, 16, 17};
+static const int system_bus_muxvals[] = {0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+                                        2};
+static const unsigned system_bus_cs1_pins[] = {0};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned uart0_pins[] = {54, 55};
+static const int uart0_muxvals[] = {0, 0};
+static const unsigned uart1_pins[] = {58, 59};
+static const int uart1_muxvals[] = {1, 1};
+static const unsigned uart2_pins[] = {90, 91};
+static const int uart2_muxvals[] = {1, 1};
+static const unsigned uart3_pins[] = {94, 95};
+static const int uart3_muxvals[] = {1, 1};
+static const unsigned usb0_pins[] = {46, 47};
+static const int usb0_muxvals[] = {0, 0};
+static const unsigned usb1_pins[] = {48, 49};
+static const int usb1_muxvals[] = {0, 0};
+static const unsigned usb2_pins[] = {50, 51};
+static const int usb2_muxvals[] = {0, 0};
+static const unsigned port_range_pins[] = {
+       159, 160, 161, 162, 163, 164, 165, 166,         /* PORT0x */
+       0, 1, 2, 3, 4, 5, 6, 7,                         /* PORT1x */
+       8, 9, 10, 11, 12, 13, 14, 15,                   /* PORT2x */
+       16, 17, 18, -1, -1, -1, -1, -1,                 /* PORT3x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT4x */
+       -1, -1, -1, 46, 47, 48, 49, 50,                 /* PORT5x */
+       51, -1, -1, 54, 55, 56, 57, 58,                 /* PORT6x */
+       59, 60, 69, 70, 71, 72, 73, 74,                 /* PORT7x */
+       75, 76, 77, 78, 79, 80, 81, 82,                 /* PORT8x */
+       83, 84, 85, 86, 87, 88, 89, 90,                 /* PORT9x */
+       91, 92, 93, 94, 95, 96, 97, 98,                 /* PORT10x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT11x */
+       99, 100, 101, 102, 103, 104, 105, 106,          /* PORT12x */
+       107, 108, 109, 110, 111, 112, 113, 114,         /* PORT13x */
+       115, 116, 117, 118, 119, 120, 121, 122,         /* PORT14x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT15x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT16x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT17x */
+       61, 62, 63, 64, 65, 66, 67, 68,                 /* PORT18x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT19x */
+       123, 124, 125, 126, 127, 128, 129, 130,         /* PORT20x */
+       131, 132, 133, 134, 135, 136, 137, 138,         /* PORT21x */
+       139, 140, 141, 142, -1, -1, -1, -1,             /* PORT22x */
+       147, 148, 149, 150, 151, 152, 153, 154,         /* PORT23x */
+       155, 156, 157, 143, 144, 145, 146, 158,         /* PORT24x */
+};
+static const int port_range_muxvals[] = {
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
+       15, 15, 15, -1, -1, -1, -1, -1,                 /* PORT3x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT4x */
+       -1, -1, -1, 15, 15, 15, 15, 15,                 /* PORT5x */
+       15, -1, -1, 15, 15, 15, 15, 15,                 /* PORT6x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT7x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT8x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT9x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT10x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT11x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT12x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT13x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT15x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT16x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT17x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT18x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT19x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT20x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT21x */
+       15, 15, 15, 15, -1, -1, -1, -1,                 /* PORT22x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT23x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT24x */
+};
+static const unsigned xirq_pins[] = {
+       149, 150, 151, 152, 153, 154, 155, 156,         /* XIRQ0-7 */
+       157, 143, 144, 145, 85, 146, 158, 84,           /* XIRQ8-15 */
+       141, 142, 148, 50, 51, 159, 160, 161,           /* XIRQ16-23 */
+};
+static const int xirq_muxvals[] = {
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
+       14, 14, 14, 14, 13, 14, 14, 13,                 /* XIRQ8-15 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
+};
+static const unsigned xirq_alternatives_pins[] = {
+       94, 95, 96, 97, 98, 99, 100, 101,               /* XIRQ0-7 */
+       102, 103, 104, 105, 106, 107,                   /* XIRQ8-11,13,14 */
+       108, 109, 110, 111, 112, 113, 114, 115,         /* XIRQ16-23 */
+       9, 10, 11, 12, 13, 14, 15, 16,                  /* XIRQ4-11 */
+       17, 0, 1, 2, 3, 4, 5, 6, 7, 8,                  /* XIRQ13,14,16-23 */
+       139, 140, 135, 147,                             /* XIRQ17,18,21,22 */
+};
+static const int xirq_alternatives_muxvals[] = {
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
+       14, 14, 14, 14, 14, 14,                         /* XIRQ8-11,13,14 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ4-11 */
+       14, 14, 14, 14, 14, 14, 14, 14, 14, 14,         /* XIRQ13,14,16-23 */
+       14, 14, 14, 14,                                 /* XIRQ17,18,21,22 */
+};
+
+static const struct uniphier_pinctrl_group uniphier_ld11_groups[] = {
+       UNIPHIER_PINCTRL_GROUP(emmc),
+       UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
+       UNIPHIER_PINCTRL_GROUP(i2c0),
+       UNIPHIER_PINCTRL_GROUP(i2c1),
+       UNIPHIER_PINCTRL_GROUP(i2c3),
+       UNIPHIER_PINCTRL_GROUP(i2c4),
+       UNIPHIER_PINCTRL_GROUP(nand),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(uart0),
+       UNIPHIER_PINCTRL_GROUP(uart1),
+       UNIPHIER_PINCTRL_GROUP(uart2),
+       UNIPHIER_PINCTRL_GROUP(uart3),
+       UNIPHIER_PINCTRL_GROUP(usb0),
+       UNIPHIER_PINCTRL_GROUP(usb1),
+       UNIPHIER_PINCTRL_GROUP(usb2),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range, 24),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range, 25),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range, 26),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range, 43),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range, 44),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range, 45),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range, 46),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range, 47),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range, 48),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range, 51),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range, 52),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range, 53),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range, 54),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range, 55),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range, 56),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range, 57),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range, 58),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range, 59),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range, 60),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range, 61),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range, 62),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range, 63),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range, 64),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range, 65),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range, 66),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range, 67),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range, 68),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range, 69),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range, 70),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range, 71),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range, 72),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range, 73),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range, 74),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range, 75),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range, 76),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range, 77),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range, 78),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range, 79),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range, 80),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range, 81),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range, 82),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range, 83),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range, 84),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range, 85),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range, 86),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range, 87),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range, 96),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range, 97),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range, 98),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range, 99),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range, 100),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range, 101),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range, 102),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range, 103),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range, 104),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range, 105),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range, 106),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range, 107),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range, 108),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range, 109),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range, 110),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range, 111),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range, 112),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range, 113),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range, 114),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range, 115),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range, 116),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range, 117),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range, 118),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range, 119),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range, 144),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range, 145),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range, 146),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range, 147),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range, 148),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range, 149),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range, 150),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range, 151),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range, 160),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range, 161),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range, 162),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range, 163),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range, 164),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range, 165),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range, 166),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range, 167),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range, 168),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range, 169),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range, 170),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range, 171),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range, 172),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range, 173),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range, 174),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range, 175),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range, 176),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range, 177),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range, 178),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range, 179),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range, 184),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range, 185),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range, 186),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range, 187),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range, 188),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range, 189),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range, 190),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range, 191),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range, 192),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range, 193),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range, 194),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range, 195),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range, 196),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range, 197),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range, 198),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range, 199),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21, xirq, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22, xirq, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23, xirq, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0b, xirq_alternatives, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1b, xirq_alternatives, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2b, xirq_alternatives, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3b, xirq_alternatives, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4b, xirq_alternatives, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5b, xirq_alternatives, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6b, xirq_alternatives, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7b, xirq_alternatives, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8b, xirq_alternatives, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9b, xirq_alternatives, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10b, xirq_alternatives, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11b, xirq_alternatives, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13b, xirq_alternatives, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14b, xirq_alternatives, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16b, xirq_alternatives, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17b, xirq_alternatives, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18b, xirq_alternatives, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19b, xirq_alternatives, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20b, xirq_alternatives, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21b, xirq_alternatives, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22b, xirq_alternatives, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23b, xirq_alternatives, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4c, xirq_alternatives, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5c, xirq_alternatives, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6c, xirq_alternatives, 24),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7c, xirq_alternatives, 25),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8c, xirq_alternatives, 26),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9c, xirq_alternatives, 27),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10c, xirq_alternatives, 28),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11c, xirq_alternatives, 29),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13c, xirq_alternatives, 30),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14c, xirq_alternatives, 31),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16c, xirq_alternatives, 32),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17c, xirq_alternatives, 33),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18c, xirq_alternatives, 34),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19c, xirq_alternatives, 35),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20c, xirq_alternatives, 36),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21c, xirq_alternatives, 37),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22c, xirq_alternatives, 38),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23c, xirq_alternatives, 39),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17d, xirq_alternatives, 40),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18d, xirq_alternatives, 41),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21d, xirq_alternatives, 42),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22d, xirq_alternatives, 43),
+};
+
+static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
+static const char * const i2c0_groups[] = {"i2c0"};
+static const char * const i2c1_groups[] = {"i2c1"};
+static const char * const i2c3_groups[] = {"i2c3"};
+static const char * const i2c4_groups[] = {"i2c4"};
+static const char * const nand_groups[] = {"nand"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1"};
+static const char * const uart0_groups[] = {"uart0"};
+static const char * const uart1_groups[] = {"uart1"};
+static const char * const uart2_groups[] = {"uart2"};
+static const char * const uart3_groups[] = {"uart3"};
+static const char * const usb0_groups[] = {"usb0"};
+static const char * const usb1_groups[] = {"usb1"};
+static const char * const usb2_groups[] = {"usb2"};
+static const char * const port_groups[] = {
+       "port00",  "port01",  "port02",  "port03",
+       "port04",  "port05",  "port06",  "port07",
+       "port10",  "port11",  "port12",  "port13",
+       "port14",  "port15",  "port16",  "port17",
+       "port20",  "port21",  "port22",  "port23",
+       "port24",  "port25",  "port26",  "port27",
+       "port30",  "port31",  "port32",
+       /* port33-52 missing */          "port53",
+       "port54",  "port55",  "port56",  "port57",
+       "port60", /* port61-62 missing*/ "port63",
+       "port64",  "port65",  "port66",  "port67",
+       "port70",  "port71",  "port72",  "port73",
+       "port74",  "port75",  "port76",  "port77",
+       "port80",  "port81",  "port82",  "port83",
+       "port84",  "port85",  "port86",  "port87",
+       "port90",  "port91",  "port92",  "port93",
+       "port94",  "port95",  "port96",  "port97",
+       "port100", "port101", "port102", "port103",
+       "port104", "port105", "port106", "port107",
+       /* port110-117 missing */
+       "port120", "port121", "port122", "port123",
+       "port124", "port125", "port126", "port127",
+       "port130", "port131", "port132", "port133",
+       "port134", "port135", "port136", "port137",
+       "port140", "port141", "port142", "port143",
+       "port144", "port145", "port146", "port147",
+       /* port150-177 missing */
+       "port180", "port181", "port182", "port183",
+       "port184", "port185", "port186", "port187",
+       /* port190-197 missing */
+       "port200", "port201", "port202", "port203",
+       "port204", "port205", "port206", "port207",
+       "port210", "port211", "port212", "port213",
+       "port214", "port215", "port216", "port217",
+       "port220", "port221", "port222", "port223",
+       /* port224-227 missing */
+       "port230", "port231", "port232", "port233",
+       "port234", "port235", "port236", "port237",
+       "port240", "port241", "port242", "port243",
+       "port244", "port245", "port246", "port247",
+};
+static const char * const xirq_groups[] = {
+       "xirq0",  "xirq1",  "xirq2",  "xirq3",
+       "xirq4",  "xirq5",  "xirq6",  "xirq7",
+       "xirq8",  "xirq9",  "xirq10", "xirq11",
+       "xirq12", "xirq13", "xirq14", "xirq15",
+       "xirq16", "xirq17", "xirq18", "xirq19",
+       "xirq20", "xirq21", "xirq22", "xirq23",
+       "xirq0b",  "xirq1b",  "xirq2b",  "xirq3b",
+       "xirq4b",  "xirq5b",  "xirq6b",  "xirq7b",
+       "xirq8b",  "xirq9b",  "xirq10b", "xirq11b",
+       /* none */ "xirq13b", "xirq14b", /* none */
+       "xirq16b", "xirq17b", "xirq18b", "xirq19b",
+       "xirq20b", "xirq21b", "xirq22b", "xirq23b",
+       "xirq4c",  "xirq5c",  "xirq6c",  "xirq7c",
+       "xirq8c",  "xirq9c",  "xirq10c", "xirq11c",
+       /* none */ "xirq13c", "xirq14c", /* none */
+       "xirq16c", "xirq17c", "xirq18c", "xirq19c",
+       "xirq20c", "xirq21c", "xirq22c", "xirq23c",
+       "xirq17d", "xirq18d", "xirq21d", "xirq22d",
+};
+
+static const struct uniphier_pinmux_function uniphier_ld11_functions[] = {
+       UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
+       UNIPHIER_PINMUX_FUNCTION(i2c0),
+       UNIPHIER_PINMUX_FUNCTION(i2c1),
+       UNIPHIER_PINMUX_FUNCTION(i2c3),
+       UNIPHIER_PINMUX_FUNCTION(i2c4),
+       UNIPHIER_PINMUX_FUNCTION(nand),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
+       UNIPHIER_PINMUX_FUNCTION(uart0),
+       UNIPHIER_PINMUX_FUNCTION(uart1),
+       UNIPHIER_PINMUX_FUNCTION(uart2),
+       UNIPHIER_PINMUX_FUNCTION(uart3),
+       UNIPHIER_PINMUX_FUNCTION(usb0),
+       UNIPHIER_PINMUX_FUNCTION(usb1),
+       UNIPHIER_PINMUX_FUNCTION(usb2),
+       UNIPHIER_PINMUX_FUNCTION(port),
+       UNIPHIER_PINMUX_FUNCTION(xirq),
+};
+
+static struct uniphier_pinctrl_socdata uniphier_ld11_pindata = {
+       .pins = uniphier_ld11_pins,
+       .npins = ARRAY_SIZE(uniphier_ld11_pins),
+       .groups = uniphier_ld11_groups,
+       .groups_count = ARRAY_SIZE(uniphier_ld11_groups),
+       .functions = uniphier_ld11_functions,
+       .functions_count = ARRAY_SIZE(uniphier_ld11_functions),
+       .caps = UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL,
+};
+
+static int uniphier_ld11_pinctrl_probe(struct platform_device *pdev)
+{
+       return uniphier_pinctrl_probe(pdev, &uniphier_ld11_pindata);
+}
+
+static const struct of_device_id uniphier_ld11_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-ld11-pinctrl" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_ld11_pinctrl_match);
+
+static struct platform_driver uniphier_ld11_pinctrl_driver = {
+       .probe = uniphier_ld11_pinctrl_probe,
+       .driver = {
+               .name = "uniphier-ld11-pinctrl",
+               .of_match_table = uniphier_ld11_pinctrl_match,
+       },
+};
+module_platform_driver(uniphier_ld11_pinctrl_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier PH1-LD11 pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
new file mode 100644 (file)
index 0000000..aa8bd97
--- /dev/null
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-uniphier.h"
+
+static const struct pinctrl_pin_desc uniphier_ld20_pins[] = {
+       UNIPHIER_PINCTRL_PIN(0, "XECS1", 0,
+                            0, UNIPHIER_PIN_DRV_3BIT,
+                            0, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(1, "ERXW", 1,
+                            1, UNIPHIER_PIN_DRV_3BIT,
+                            1, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(2, "XERWE1", 2,
+                            2, UNIPHIER_PIN_DRV_3BIT,
+                            2, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(3, "XNFWP", 3,
+                            3, UNIPHIER_PIN_DRV_3BIT,
+                            3, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(4, "XNFCE0", 4,
+                            4, UNIPHIER_PIN_DRV_3BIT,
+                            4, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(5, "NFRYBY0", 5,
+                            5, UNIPHIER_PIN_DRV_3BIT,
+                            5, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(6, "XNFRE", 6,
+                            6, UNIPHIER_PIN_DRV_3BIT,
+                            6, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(7, "XNFWE", 7,
+                            7, UNIPHIER_PIN_DRV_3BIT,
+                            7, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(8, "NFALE", 8,
+                            8, UNIPHIER_PIN_DRV_3BIT,
+                            8, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(9, "NFCLE", 9,
+                            9, UNIPHIER_PIN_DRV_3BIT,
+                            9, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(10, "NFD0", 10,
+                            10, UNIPHIER_PIN_DRV_3BIT,
+                            10, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(11, "NFD1", 11,
+                            11, UNIPHIER_PIN_DRV_3BIT,
+                            11, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(12, "NFD2", 12,
+                            12, UNIPHIER_PIN_DRV_3BIT,
+                            12, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(13, "NFD3", 13,
+                            13, UNIPHIER_PIN_DRV_3BIT,
+                            13, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(14, "NFD4", 14,
+                            14, UNIPHIER_PIN_DRV_3BIT,
+                            14, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(15, "NFD5", 15,
+                            15, UNIPHIER_PIN_DRV_3BIT,
+                            15, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(16, "NFD6", 16,
+                            16, UNIPHIER_PIN_DRV_3BIT,
+                            16, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(17, "NFD7", 17,
+                            17, UNIPHIER_PIN_DRV_3BIT,
+                            17, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(18, "XERST", 18,
+                            0, UNIPHIER_PIN_DRV_2BIT,
+                            18, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(19, "MMCCLK", 19,
+                            1, UNIPHIER_PIN_DRV_2BIT,
+                            19, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(20, "MMCCMD", 20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
+                            20, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(21, "MMCDS", 21,
+                            3, UNIPHIER_PIN_DRV_2BIT,
+                            21, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(22, "MMCDAT0", 22,
+                            4, UNIPHIER_PIN_DRV_2BIT,
+                            22, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(23, "MMCDAT1", 23,
+                            5, UNIPHIER_PIN_DRV_2BIT,
+                            23, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(24, "MMCDAT2", 24,
+                            6, UNIPHIER_PIN_DRV_2BIT,
+                            24, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(25, "MMCDAT3", 25,
+                            7, UNIPHIER_PIN_DRV_2BIT,
+                            25, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(26, "MMCDAT4", 26,
+                            8, UNIPHIER_PIN_DRV_2BIT,
+                            26, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(27, "MMCDAT5", 27,
+                            9, UNIPHIER_PIN_DRV_2BIT,
+                            27, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(28, "MMCDAT6", 28,
+                            10, UNIPHIER_PIN_DRV_2BIT,
+                            28, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(29, "MMCDAT7", 29,
+                            11, UNIPHIER_PIN_DRV_2BIT,
+                            29, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(30, "MDC", 30,
+                            18, UNIPHIER_PIN_DRV_3BIT,
+                            30, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(31, "MDIO", 31,
+                            19, UNIPHIER_PIN_DRV_3BIT,
+                            31, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(32, "MDIO_INTL", 32,
+                            20, UNIPHIER_PIN_DRV_3BIT,
+                            32, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(33, "PHYRSTL", 33,
+                            21, UNIPHIER_PIN_DRV_3BIT,
+                            33, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(34, "RGMII_RXCLK", 34,
+                            22, UNIPHIER_PIN_DRV_3BIT,
+                            34, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(35, "RGMII_RXD0", 35,
+                            23, UNIPHIER_PIN_DRV_3BIT,
+                            35, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(36, "RGMII_RXD1", 36,
+                            24, UNIPHIER_PIN_DRV_3BIT,
+                            36, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(37, "RGMII_RXD2", 37,
+                            25, UNIPHIER_PIN_DRV_3BIT,
+                            37, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(38, "RGMII_RXD3", 38,
+                            26, UNIPHIER_PIN_DRV_3BIT,
+                            38, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(39, "RGMII_RXCTL", 39,
+                            27, UNIPHIER_PIN_DRV_3BIT,
+                            39, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(40, "RGMII_TXCLK", 40,
+                            28, UNIPHIER_PIN_DRV_3BIT,
+                            40, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(41, "RGMII_TXD0", 41,
+                            29, UNIPHIER_PIN_DRV_3BIT,
+                            41, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(42, "RGMII_TXD1", 42,
+                            30, UNIPHIER_PIN_DRV_3BIT,
+                            42, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(43, "RGMII_TXD2", 43,
+                            31, UNIPHIER_PIN_DRV_3BIT,
+                            43, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(44, "RGMII_TXD3", 44,
+                            32, UNIPHIER_PIN_DRV_3BIT,
+                            44, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(45, "RGMII_TXCTL", 45,
+                            33, UNIPHIER_PIN_DRV_3BIT,
+                            45, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(46, "USB0VBUS", 46,
+                            34, UNIPHIER_PIN_DRV_3BIT,
+                            46, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(47, "USB0OD", 47,
+                            35, UNIPHIER_PIN_DRV_3BIT,
+                            47, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(48, "USB1VBUS", 48,
+                            36, UNIPHIER_PIN_DRV_3BIT,
+                            48, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(49, "USB1OD", 49,
+                            37, UNIPHIER_PIN_DRV_3BIT,
+                            49, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(50, "USB2VBUS", 50,
+                            38, UNIPHIER_PIN_DRV_3BIT,
+                            50, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(51, "USB2OD", 51,
+                            39, UNIPHIER_PIN_DRV_3BIT,
+                            51, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(52, "USB3VBUS", 52,
+                            40, UNIPHIER_PIN_DRV_3BIT,
+                            52, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(53, "USB3OD", 53,
+                            41, UNIPHIER_PIN_DRV_3BIT,
+                            53, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(54, "TXD0", 54,
+                            42, UNIPHIER_PIN_DRV_3BIT,
+                            54, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(55, "RXD0", 55,
+                            43, UNIPHIER_PIN_DRV_3BIT,
+                            55, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(56, "SPISYNC0", 56,
+                            44, UNIPHIER_PIN_DRV_3BIT,
+                            56, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(57, "SPISCLK0", 57,
+                            45, UNIPHIER_PIN_DRV_3BIT,
+                            57, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(58, "SPITXD0", 58,
+                            46, UNIPHIER_PIN_DRV_3BIT,
+                            58, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(59, "SPIRXD0", 59,
+                            47, UNIPHIER_PIN_DRV_3BIT,
+                            59, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(60, "AGCI", 60,
+                            48, UNIPHIER_PIN_DRV_3BIT,
+                            60, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(61, "DMDSDA0", 61,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(62, "DMDSCL0", 62,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(63, "SDA0", 63,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(64, "SCL0", 64,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(65, "SDA1", 65,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(66, "SCL1", 66,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(67, "HIN", 67,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(68, "VIN", 68,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(69, "PCA00", 69,
+                            49, UNIPHIER_PIN_DRV_3BIT,
+                            69, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(70, "PCA01", 70,
+                            50, UNIPHIER_PIN_DRV_3BIT,
+                            70, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(71, "PCA02", 71,
+                            51, UNIPHIER_PIN_DRV_3BIT,
+                            71, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(72, "PCA03", 72,
+                            52, UNIPHIER_PIN_DRV_3BIT,
+                            72, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(73, "PCA04", 73,
+                            53, UNIPHIER_PIN_DRV_3BIT,
+                            73, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(74, "PCA05", 74,
+                            54, UNIPHIER_PIN_DRV_3BIT,
+                            74, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(75, "PCA06", 75,
+                            55, UNIPHIER_PIN_DRV_3BIT,
+                            75, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(76, "PCA07", 76,
+                            56, UNIPHIER_PIN_DRV_3BIT,
+                            76, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(77, "PCA08", 77,
+                            57, UNIPHIER_PIN_DRV_3BIT,
+                            77, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(78, "PCA09", 78,
+                            58, UNIPHIER_PIN_DRV_3BIT,
+                            78, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(79, "PCA10", 79,
+                            59, UNIPHIER_PIN_DRV_3BIT,
+                            79, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(80, "PCA11", 80,
+                            60, UNIPHIER_PIN_DRV_3BIT,
+                            80, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(81, "PCA12", 81,
+                            61, UNIPHIER_PIN_DRV_3BIT,
+                            81, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(82, "PCA13", 82,
+                            62, UNIPHIER_PIN_DRV_3BIT,
+                            82, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(83, "PCA14", 83,
+                            63, UNIPHIER_PIN_DRV_3BIT,
+                            83, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(84, "PC0READY", 84,
+                            0, UNIPHIER_PIN_DRV_1BIT,
+                            84, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(85, "PC0CD1", 85,
+                            1, UNIPHIER_PIN_DRV_1BIT,
+                            85, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(86, "PC0CD2", 86,
+                            2, UNIPHIER_PIN_DRV_1BIT,
+                            86, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(87, "PC0WAIT", 87,
+                            3, UNIPHIER_PIN_DRV_1BIT,
+                            87, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(88, "PC0RESET", 88,
+                            4, UNIPHIER_PIN_DRV_1BIT,
+                            88, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(89, "PC0CE1", 89,
+                            5, UNIPHIER_PIN_DRV_1BIT,
+                            89, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(90, "PC0WE", 90,
+                            6, UNIPHIER_PIN_DRV_1BIT,
+                            90, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(91, "PC0OE", 91,
+                            7, UNIPHIER_PIN_DRV_1BIT,
+                            91, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(92, "PC0IOWR", 92,
+                            8, UNIPHIER_PIN_DRV_1BIT,
+                            92, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(93, "PC0IORD", 93,
+                            9, UNIPHIER_PIN_DRV_1BIT,
+                            93, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(94, "PCD00", 94,
+                            10, UNIPHIER_PIN_DRV_1BIT,
+                            94, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(95, "PCD01", 95,
+                            11, UNIPHIER_PIN_DRV_1BIT,
+                            95, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(96, "PCD02", 96,
+                            12, UNIPHIER_PIN_DRV_1BIT,
+                            96, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(97, "PCD03", 97,
+                            13, UNIPHIER_PIN_DRV_1BIT,
+                            97, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(98, "PCD04", 98,
+                            14, UNIPHIER_PIN_DRV_1BIT,
+                            98, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(99, "PCD05", 99,
+                            15, UNIPHIER_PIN_DRV_1BIT,
+                            99, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(100, "PCD06", 100,
+                            16, UNIPHIER_PIN_DRV_1BIT,
+                            100, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(101, "PCD07", 101,
+                            17, UNIPHIER_PIN_DRV_1BIT,
+                            101, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(102, "HS0BCLKIN", 102,
+                            18, UNIPHIER_PIN_DRV_1BIT,
+                            102, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(103, "HS0SYNCIN", 103,
+                            19, UNIPHIER_PIN_DRV_1BIT,
+                            103, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(104, "HS0VALIN", 104,
+                            20, UNIPHIER_PIN_DRV_1BIT,
+                            104, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(105, "HS0DIN0", 105,
+                            21, UNIPHIER_PIN_DRV_1BIT,
+                            105, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(106, "HS0DIN1", 106,
+                            22, UNIPHIER_PIN_DRV_1BIT,
+                            106, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(107, "HS0DIN2", 107,
+                            23, UNIPHIER_PIN_DRV_1BIT,
+                            107, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(108, "HS0DIN3", 108,
+                            24, UNIPHIER_PIN_DRV_1BIT,
+                            108, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(109, "HS0DIN4", 109,
+                            25, UNIPHIER_PIN_DRV_1BIT,
+                            109, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(110, "HS0DIN5", 110,
+                            26, UNIPHIER_PIN_DRV_1BIT,
+                            110, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(111, "HS0DIN6", 111,
+                            27, UNIPHIER_PIN_DRV_1BIT,
+                            111, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(112, "HS0DIN7", 112,
+                            28, UNIPHIER_PIN_DRV_1BIT,
+                            112, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(113, "HS0BCLKOUT", 113,
+                            64, UNIPHIER_PIN_DRV_3BIT,
+                            113, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(114, "HS0SYNCOUT", 114,
+                            65, UNIPHIER_PIN_DRV_3BIT,
+                            114, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(115, "HS0VALOUT", 115,
+                            66, UNIPHIER_PIN_DRV_3BIT,
+                            115, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(116, "HS0DOUT0", 116,
+                            67, UNIPHIER_PIN_DRV_3BIT,
+                            116, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(117, "HS0DOUT1", 117,
+                            68, UNIPHIER_PIN_DRV_3BIT,
+                            117, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(118, "HS0DOUT2", 118,
+                            69, UNIPHIER_PIN_DRV_3BIT,
+                            118, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(119, "HS0DOUT3", 119,
+                            70, UNIPHIER_PIN_DRV_3BIT,
+                            119, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(120, "HS0DOUT4", 120,
+                            71, UNIPHIER_PIN_DRV_3BIT,
+                            120, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(121, "HS0DOUT5", 121,
+                            72, UNIPHIER_PIN_DRV_3BIT,
+                            121, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(122, "HS0DOUT6", 122,
+                            73, UNIPHIER_PIN_DRV_3BIT,
+                            122, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(123, "HS0DOUT7", 123,
+                            74, UNIPHIER_PIN_DRV_3BIT,
+                            123, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(124, "HS1BCLKIN", 124,
+                            75, UNIPHIER_PIN_DRV_3BIT,
+                            124, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(125, "HS1SYNCIN", 125,
+                            76, UNIPHIER_PIN_DRV_3BIT,
+                            125, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(126, "HS1VALIN", 126,
+                            77, UNIPHIER_PIN_DRV_3BIT,
+                            126, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(127, "HS1DIN0", 127,
+                            78, UNIPHIER_PIN_DRV_3BIT,
+                            127, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(128, "HS1DIN1", 128,
+                            79, UNIPHIER_PIN_DRV_3BIT,
+                            128, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(129, "HS1DIN2", 129,
+                            80, UNIPHIER_PIN_DRV_3BIT,
+                            129, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(130, "HS1DIN3", 130,
+                            81, UNIPHIER_PIN_DRV_3BIT,
+                            130, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(131, "HS1DIN4", 131,
+                            82, UNIPHIER_PIN_DRV_3BIT,
+                            131, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(132, "HS1DIN5", 132,
+                            83, UNIPHIER_PIN_DRV_3BIT,
+                            132, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(133, "HS1DIN6", 133,
+                            84, UNIPHIER_PIN_DRV_3BIT,
+                            133, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(134, "HS1DIN7", 134,
+                            85, UNIPHIER_PIN_DRV_3BIT,
+                            134, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(135, "AO1IEC", 135,
+                            86, UNIPHIER_PIN_DRV_3BIT,
+                            135, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(136, "AO1ARC", 136,
+                            87, UNIPHIER_PIN_DRV_3BIT,
+                            136, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(137, "AO1DACCK", 137,
+                            88, UNIPHIER_PIN_DRV_3BIT,
+                            137, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(138, "AO1BCK", 138,
+                            89, UNIPHIER_PIN_DRV_3BIT,
+                            138, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(139, "AO1LRCK", 139,
+                            90, UNIPHIER_PIN_DRV_3BIT,
+                            139, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(140, "AO1D0", 140,
+                            91, UNIPHIER_PIN_DRV_3BIT,
+                            140, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(141, "AO1D1", 141,
+                            92, UNIPHIER_PIN_DRV_3BIT,
+                            141, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(142, "AO1D2", 142,
+                            93, UNIPHIER_PIN_DRV_3BIT,
+                            142, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(143, "HTPDN0", 143,
+                            94, UNIPHIER_PIN_DRV_3BIT,
+                            143, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(144, "LOCKN0", 144,
+                            95, UNIPHIER_PIN_DRV_3BIT,
+                            144, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(145, "HTPDN1", 145,
+                            96, UNIPHIER_PIN_DRV_3BIT,
+                            145, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(146, "LOCKN1", 146,
+                            97, UNIPHIER_PIN_DRV_3BIT,
+                            146, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(147, "PWMA", 147,
+                            98, UNIPHIER_PIN_DRV_3BIT,
+                            147, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(148, "LR_GOUT", 148,
+                            99, UNIPHIER_PIN_DRV_3BIT,
+                            148, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(149, "XIRQ0", 149,
+                            100, UNIPHIER_PIN_DRV_3BIT,
+                            149, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(150, "XIRQ1", 150,
+                            101, UNIPHIER_PIN_DRV_3BIT,
+                            150, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(151, "XIRQ2", 151,
+                            102, UNIPHIER_PIN_DRV_3BIT,
+                            151, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(152, "XIRQ3", 152,
+                            103, UNIPHIER_PIN_DRV_3BIT,
+                            152, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(153, "XIRQ4", 153,
+                            104, UNIPHIER_PIN_DRV_3BIT,
+                            153, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(154, "XIRQ5", 154,
+                            105, UNIPHIER_PIN_DRV_3BIT,
+                            154, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(155, "XIRQ6", 155,
+                            106, UNIPHIER_PIN_DRV_3BIT,
+                            155, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(156, "XIRQ7", 156,
+                            107, UNIPHIER_PIN_DRV_3BIT,
+                            156, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(157, "XIRQ8", 157,
+                            108, UNIPHIER_PIN_DRV_3BIT,
+                            157, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(158, "XIRQ9", 158,
+                            109, UNIPHIER_PIN_DRV_3BIT,
+                            158, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(159, "XIRQ10", 159,
+                            110, UNIPHIER_PIN_DRV_3BIT,
+                            159, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(160, "XIRQ11", 160,
+                            111, UNIPHIER_PIN_DRV_3BIT,
+                            160, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(161, "XIRQ13", 161,
+                            112, UNIPHIER_PIN_DRV_3BIT,
+                            161, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(162, "XIRQ14", 162,
+                            113, UNIPHIER_PIN_DRV_3BIT,
+                            162, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(163, "XIRQ16", 163,
+                            114, UNIPHIER_PIN_DRV_3BIT,
+                            163, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(164, "XIRQ17", 164,
+                            115, UNIPHIER_PIN_DRV_3BIT,
+                            164, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(165, "XIRQ18", 165,
+                            116, UNIPHIER_PIN_DRV_3BIT,
+                            165, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(166, "XIRQ19", 166,
+                            117, UNIPHIER_PIN_DRV_3BIT,
+                            166, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(167, "XIRQ20", 167,
+                            118, UNIPHIER_PIN_DRV_3BIT,
+                            167, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(168, "PORT00", 168,
+                            119, UNIPHIER_PIN_DRV_3BIT,
+                            168, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(169, "PORT01", 169,
+                            120, UNIPHIER_PIN_DRV_3BIT,
+                            169, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(170, "PORT02", 170,
+                            121, UNIPHIER_PIN_DRV_3BIT,
+                            170, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(171, "PORT03", 171,
+                            122, UNIPHIER_PIN_DRV_3BIT,
+                            171, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(172, "PORT04", 172,
+                            123, UNIPHIER_PIN_DRV_3BIT,
+                            172, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(173, "CK27FO", 173,
+                            124, UNIPHIER_PIN_DRV_3BIT,
+                            173, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(174, "PHSYNCO", 174,
+                            125, UNIPHIER_PIN_DRV_3BIT,
+                            174, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(175, "PVSYNCO", 175,
+                            126, UNIPHIER_PIN_DRV_3BIT,
+                            175, UNIPHIER_PIN_PULL_DOWN),
+};
+
+static const unsigned emmc_pins[] = {18, 19, 20, 21, 22, 23, 24, 25};
+static const int emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned emmc_dat8_pins[] = {26, 27, 28, 29};
+static const int emmc_dat8_muxvals[] = {0, 0, 0, 0};
+static const unsigned ether_rgmii_pins[] = {30, 31, 32, 33, 34, 35, 36, 37, 38,
+                                           39, 40, 41, 42, 43, 44, 45};
+static const int ether_rgmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                         0, 0, 0, 0};
+static const unsigned ether_rmii_pins[] = {30, 31, 32, 33, 34, 35, 36, 37, 39,
+                                          41, 42, 45};
+static const int ether_rmii_muxvals[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+static const unsigned i2c0_pins[] = {63, 64};
+static const int i2c0_muxvals[] = {0, 0};
+static const unsigned i2c1_pins[] = {65, 66};
+static const int i2c1_muxvals[] = {0, 0};
+static const unsigned i2c3_pins[] = {67, 68};
+static const int i2c3_muxvals[] = {1, 1};
+static const unsigned i2c4_pins[] = {61, 62};
+static const int i2c4_muxvals[] = {1, 1};
+static const unsigned nand_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+                                    15, 16, 17};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned sd_pins[] = {10, 11, 12, 13, 14, 15, 16, 17};
+static const int sd_muxvals[] = {3, 3, 3, 3, 3, 3, 3, 3};  /* No SDVOLC */
+static const unsigned system_bus_pins[] = {1, 2, 6, 7, 8, 9, 10, 11, 12, 13,
+                                          14, 15, 16, 17};
+static const int system_bus_muxvals[] = {0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+                                        2};
+static const unsigned system_bus_cs1_pins[] = {0};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned uart0_pins[] = {54, 55};
+static const int uart0_muxvals[] = {0, 0};
+static const unsigned uart1_pins[] = {58, 59};
+static const int uart1_muxvals[] = {1, 1};
+static const unsigned uart2_pins[] = {90, 91};
+static const int uart2_muxvals[] = {1, 1};
+static const unsigned uart3_pins[] = {94, 95};
+static const int uart3_muxvals[] = {1, 1};
+static const unsigned usb0_pins[] = {46, 47};
+static const int usb0_muxvals[] = {0, 0};
+static const unsigned usb1_pins[] = {48, 49};
+static const int usb1_muxvals[] = {0, 0};
+static const unsigned usb2_pins[] = {50, 51};
+static const int usb2_muxvals[] = {0, 0};
+static const unsigned usb3_pins[] = {52, 53};
+static const int usb3_muxvals[] = {0, 0};
+static const unsigned port_range_pins[] = {
+       168, 169, 170, 171, 172, 173, 174, 175,         /* PORT0x */
+       0, 1, 2, 3, 4, 5, 6, 7,                         /* PORT1x */
+       8, 9, 10, 11, 12, 13, 14, 15,                   /* PORT2x */
+       16, 17, 18, 30, 31, 32, 33, 34,                 /* PORT3x */
+       35, 36, 37, 38, 39, 40, 41, 42,                 /* PORT4x */
+       43, 44, 45, 46, 47, 48, 49, 50,                 /* PORT5x */
+       51, 52, 53, 54, 55, 56, 57, 58,                 /* PORT6x */
+       59, 60, 69, 70, 71, 72, 73, 74,                 /* PORT7x */
+       75, 76, 77, 78, 79, 80, 81, 82,                 /* PORT8x */
+       83, 84, 85, 86, 87, 88, 89, 90,                 /* PORT9x */
+       91, 92, 93, 94, 95, 96, 97, 98,                 /* PORT10x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT11x */
+       99, 100, 101, 102, 103, 104, 105, 106,          /* PORT12x */
+       107, 108, 109, 110, 111, 112, 113, 114,         /* PORT13x */
+       115, 116, 117, 118, 119, 120, 121, 122,         /* PORT14x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT15x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT16x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT17x */
+       61, 62, 63, 64, 65, 66, 67, 68,                 /* PORT18x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT19x */
+       123, 124, 125, 126, 127, 128, 129, 130,         /* PORT20x */
+       131, 132, 133, 134, 135, 136, 137, 138,         /* PORT21x */
+       139, 140, 141, 142, 143, 144, 145, 146,         /* PORT22x */
+       147, 148, 149, 150, 151, 152, 153, 154,         /* PORT23x */
+       155, 156, 157, 158, 159, 160, 161, 162,         /* PORT24x */
+       163, 164, 165, 166, 167,                        /* PORT25x */
+};
+static const int port_range_muxvals[] = {
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT3x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT4x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT5x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT6x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT7x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT8x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT9x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT10x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT11x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT12x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT13x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT15x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT16x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT17x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT18x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT19x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT20x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT21x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT22x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT23x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT24x */
+       15, 15, 15, 15, 15,                             /* PORT25x */
+};
+static const unsigned xirq_pins[] = {
+       149, 150, 151, 152, 153, 154, 155, 156,         /* XIRQ0-7 */
+       157, 158, 159, 160, 85, 161, 162, 84,           /* XIRQ8-15 */
+       163, 164, 165, 166, 167, 146, 52, 53,           /* XIRQ16-23 */
+};
+static const int xirq_muxvals[] = {
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
+       14, 14, 14, 14, 13, 14, 14, 13,                 /* XIRQ8-15 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
+};
+static const unsigned xirq_alternatives_pins[] = {
+       94, 95, 96, 97, 98, 99, 100, 101,               /* XIRQ0-7 */
+       102, 103, 104, 105, 106, 107,                   /* XIRQ8-11,13,14 */
+       108, 109, 110, 111, 112, 147, 141, 142,         /* XIRQ16-23 */
+};
+static const int xirq_alternatives_muxvals[] = {
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
+       14, 14, 14, 14, 14, 14,                         /* XIRQ8-11,13,14 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
+};
+
+static const struct uniphier_pinctrl_group uniphier_ld20_groups[] = {
+       UNIPHIER_PINCTRL_GROUP(emmc),
+       UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_rgmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
+       UNIPHIER_PINCTRL_GROUP(i2c0),
+       UNIPHIER_PINCTRL_GROUP(i2c1),
+       UNIPHIER_PINCTRL_GROUP(i2c3),
+       UNIPHIER_PINCTRL_GROUP(i2c4),
+       UNIPHIER_PINCTRL_GROUP(nand),
+       UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(uart0),
+       UNIPHIER_PINCTRL_GROUP(uart1),
+       UNIPHIER_PINCTRL_GROUP(uart2),
+       UNIPHIER_PINCTRL_GROUP(uart3),
+       UNIPHIER_PINCTRL_GROUP(usb0),
+       UNIPHIER_PINCTRL_GROUP(usb1),
+       UNIPHIER_PINCTRL_GROUP(usb2),
+       UNIPHIER_PINCTRL_GROUP(usb3),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range, 24),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range, 25),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range, 26),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range, 27),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range, 28),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range, 29),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range, 30),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range, 31),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range, 32),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range, 33),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range, 34),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range, 35),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range, 36),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range, 37),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range, 38),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range, 39),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range, 40),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range, 41),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range, 42),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range, 43),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range, 44),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range, 45),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range, 46),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range, 47),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range, 48),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range, 49),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range, 50),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range, 51),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range, 52),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range, 53),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range, 54),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range, 55),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range, 56),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range, 57),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range, 58),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range, 59),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range, 60),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range, 61),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range, 62),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range, 63),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range, 64),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range, 65),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range, 66),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range, 67),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range, 68),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range, 69),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range, 70),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range, 71),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range, 72),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range, 73),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range, 74),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range, 75),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range, 76),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range, 77),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range, 78),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range, 79),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range, 80),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range, 81),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range, 82),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range, 83),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range, 84),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range, 85),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range, 86),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range, 87),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range, 96),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range, 97),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range, 98),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range, 99),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range, 100),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range, 101),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range, 102),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range, 103),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range, 104),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range, 105),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range, 106),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range, 107),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range, 108),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range, 109),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range, 110),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range, 111),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range, 112),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range, 113),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range, 114),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range, 115),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range, 116),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range, 117),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range, 118),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range, 119),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range, 144),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range, 145),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range, 146),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range, 147),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range, 148),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range, 149),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range, 150),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range, 151),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range, 160),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range, 161),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range, 162),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range, 163),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range, 164),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range, 165),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range, 166),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range, 167),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range, 168),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range, 169),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range, 170),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range, 171),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range, 172),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range, 173),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range, 174),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range, 175),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range, 176),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range, 177),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range, 178),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range, 179),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range, 180),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range, 181),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range, 182),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range, 183),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range, 184),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range, 185),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range, 186),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range, 187),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range, 188),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range, 189),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range, 190),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range, 191),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range, 192),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range, 193),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range, 194),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range, 195),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range, 196),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range, 197),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range, 198),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range, 199),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range, 200),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range, 201),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range, 202),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range, 203),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range, 204),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21, xirq, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22, xirq, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23, xirq, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0b, xirq_alternatives, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1b, xirq_alternatives, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2b, xirq_alternatives, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3b, xirq_alternatives, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4b, xirq_alternatives, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5b, xirq_alternatives, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6b, xirq_alternatives, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7b, xirq_alternatives, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8b, xirq_alternatives, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9b, xirq_alternatives, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10b, xirq_alternatives, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11b, xirq_alternatives, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13b, xirq_alternatives, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14b, xirq_alternatives, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16b, xirq_alternatives, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17b, xirq_alternatives, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18b, xirq_alternatives, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19b, xirq_alternatives, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20b, xirq_alternatives, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21b, xirq_alternatives, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22b, xirq_alternatives, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23b, xirq_alternatives, 21),
+};
+
+static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_rgmii_groups[] = {"ether_rgmii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
+static const char * const i2c0_groups[] = {"i2c0"};
+static const char * const i2c1_groups[] = {"i2c1"};
+static const char * const i2c3_groups[] = {"i2c3"};
+static const char * const i2c4_groups[] = {"i2c4"};
+static const char * const nand_groups[] = {"nand"};
+static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1"};
+static const char * const uart0_groups[] = {"uart0"};
+static const char * const uart1_groups[] = {"uart1"};
+static const char * const uart2_groups[] = {"uart2"};
+static const char * const uart3_groups[] = {"uart3"};
+static const char * const usb0_groups[] = {"usb0"};
+static const char * const usb1_groups[] = {"usb1"};
+static const char * const usb2_groups[] = {"usb2"};
+static const char * const usb3_groups[] = {"usb3"};
+static const char * const port_groups[] = {
+       "port00", "port01", "port02", "port03",
+       "port04", "port05", "port06", "port07",
+       "port10", "port11", "port12", "port13",
+       "port14", "port15", "port16", "port17",
+       "port20", "port21", "port22", "port23",
+       "port24", "port25", "port26", "port27",
+       "port30", "port31", "port32", "port33",
+       "port34", "port35", "port36", "port37",
+       "port40", "port41", "port42", "port43",
+       "port44", "port45", "port46", "port47",
+       "port50", "port51", "port52", "port53",
+       "port54", "port55", "port56", "port57",
+       "port60", "port61", "port62", "port63",
+       "port64", "port65", "port66", "port67",
+       "port70", "port71", "port72", "port73",
+       "port74", "port75", "port76", "port77",
+       "port80", "port81", "port82", "port83",
+       "port84", "port85", "port86", "port87",
+       "port90", "port91", "port92", "port93",
+       "port94", "port95", "port96", "port97",
+       "port100", "port101", "port102", "port103",
+       "port104", "port105", "port106", "port107",
+       /* port110-117 missing */
+       "port120", "port121", "port122", "port123",
+       "port124", "port125", "port126", "port127",
+       "port130", "port131", "port132", "port133",
+       "port134", "port135", "port136", "port137",
+       "port140", "port141", "port142", "port143",
+       "port144", "port145", "port146", "port147",
+       /* port150-177 missing */
+       "port180", "port181", "port182", "port183",
+       "port184", "port185", "port186", "port187",
+       /* port190-197 missing */
+       "port200", "port201", "port202", "port203",
+       "port204", "port205", "port206", "port207",
+       "port210", "port211", "port212", "port213",
+       "port214", "port215", "port216", "port217",
+       "port220", "port221", "port222", "port223",
+       "port224", "port225", "port226", "port227",
+       "port230", "port231", "port232", "port233",
+       "port234", "port235", "port236", "port237",
+       "port240", "port241", "port242", "port243",
+       "port244", "port245", "port246", "port247",
+       "port250", "port251", "port252", "port253",
+       "port254",
+};
+static const char * const xirq_groups[] = {
+       "xirq0",  "xirq1",  "xirq2",  "xirq3",
+       "xirq4",  "xirq5",  "xirq6",  "xirq7",
+       "xirq8",  "xirq9",  "xirq10", "xirq11",
+       "xirq12", "xirq13", "xirq14", "xirq15",
+       "xirq16", "xirq17", "xirq18", "xirq19",
+       "xirq20", "xirq21", "xirq22", "xirq23",
+       "xirq0b",  "xirq1b",  "xirq2b",  "xirq3b",
+       "xirq4b",  "xirq5b",  "xirq6b",  "xirq7b",
+       "xirq8b",  "xirq9b",  "xirq10b", "xirq11b",
+       /* none */ "xirq13b", "xirq14b", /* none */
+       "xirq16b", "xirq17b", "xirq18b", "xirq19b",
+       "xirq20b", "xirq21b", "xirq22b", "xirq23b",
+};
+
+static const struct uniphier_pinmux_function uniphier_ld20_functions[] = {
+       UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_rgmii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
+       UNIPHIER_PINMUX_FUNCTION(i2c0),
+       UNIPHIER_PINMUX_FUNCTION(i2c1),
+       UNIPHIER_PINMUX_FUNCTION(i2c3),
+       UNIPHIER_PINMUX_FUNCTION(i2c4),
+       UNIPHIER_PINMUX_FUNCTION(nand),
+       UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
+       UNIPHIER_PINMUX_FUNCTION(uart0),
+       UNIPHIER_PINMUX_FUNCTION(uart1),
+       UNIPHIER_PINMUX_FUNCTION(uart2),
+       UNIPHIER_PINMUX_FUNCTION(uart3),
+       UNIPHIER_PINMUX_FUNCTION(usb0),
+       UNIPHIER_PINMUX_FUNCTION(usb1),
+       UNIPHIER_PINMUX_FUNCTION(usb2),
+       UNIPHIER_PINMUX_FUNCTION(usb3),
+       UNIPHIER_PINMUX_FUNCTION(port),
+       UNIPHIER_PINMUX_FUNCTION(xirq),
+};
+
+static struct uniphier_pinctrl_socdata uniphier_ld20_pindata = {
+       .pins = uniphier_ld20_pins,
+       .npins = ARRAY_SIZE(uniphier_ld20_pins),
+       .groups = uniphier_ld20_groups,
+       .groups_count = ARRAY_SIZE(uniphier_ld20_groups),
+       .functions = uniphier_ld20_functions,
+       .functions_count = ARRAY_SIZE(uniphier_ld20_functions),
+       .caps = UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL,
+};
+
+static int uniphier_ld20_pinctrl_probe(struct platform_device *pdev)
+{
+       return uniphier_pinctrl_probe(pdev, &uniphier_ld20_pindata);
+}
+
+static const struct of_device_id uniphier_ld20_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-ld20-pinctrl" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_ld20_pinctrl_match);
+
+static struct platform_driver uniphier_ld20_pinctrl_driver = {
+       .probe = uniphier_ld20_pinctrl_probe,
+       .driver = {
+               .name = "uniphier-ld20-pinctrl",
+               .of_match_table = uniphier_ld20_pinctrl_match,
+       },
+};
+module_platform_driver(uniphier_ld20_pinctrl_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier PH1-LD20 pinctrl driver");
+MODULE_LICENSE("GPL");
index 4a0439c80aa0b6891ab0c710efa6c11651b808bc..3edfb6f9d6df997253f0c472f9d50ae1812ec13a 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-ld4-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_ld4_pins[] = {
+static const struct pinctrl_pin_desc uniphier_ld4_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "EA1", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "EA2", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "EA3", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "EA4", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "EA5", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "EA6", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "EA7", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "EA8", 0,
-                            15, UNIPHIER_PIN_DRV_4_8,
+                            15, UNIPHIER_PIN_DRV_1BIT,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "EA9", 0,
-                            16, UNIPHIER_PIN_DRV_4_8,
+                            16, UNIPHIER_PIN_DRV_1BIT,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "EA10", 0,
-                            17, UNIPHIER_PIN_DRV_4_8,
+                            17, UNIPHIER_PIN_DRV_1BIT,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "EA11", 0,
-                            18, UNIPHIER_PIN_DRV_4_8,
+                            18, UNIPHIER_PIN_DRV_1BIT,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "EA12", 0,
-                            19, UNIPHIER_PIN_DRV_4_8,
+                            19, UNIPHIER_PIN_DRV_1BIT,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "EA13", 0,
-                            20, UNIPHIER_PIN_DRV_4_8,
+                            20, UNIPHIER_PIN_DRV_1BIT,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(13, "EA14", 0,
-                            21, UNIPHIER_PIN_DRV_4_8,
+                            21, UNIPHIER_PIN_DRV_1BIT,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "EA15", 0,
-                            22, UNIPHIER_PIN_DRV_4_8,
+                            22, UNIPHIER_PIN_DRV_1BIT,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "ECLK", UNIPHIER_PIN_IECTRL_NONE,
-                            23, UNIPHIER_PIN_DRV_4_8,
+                            23, UNIPHIER_PIN_DRV_1BIT,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(16, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_4_8,
+                            24, UNIPHIER_PIN_DRV_1BIT,
                             24, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(17, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            25, UNIPHIER_PIN_DRV_4_8,
+                            25, UNIPHIER_PIN_DRV_1BIT,
                             25, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(18, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            27, UNIPHIER_PIN_DRV_4_8,
+                            27, UNIPHIER_PIN_DRV_1BIT,
                             27, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(19, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_4_8,
+                            28, UNIPHIER_PIN_DRV_1BIT,
                             28, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(20, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            29, UNIPHIER_PIN_DRV_4_8,
+                            29, UNIPHIER_PIN_DRV_1BIT,
                             29, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(21, "XERST", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(22, "MMCCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             146, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(23, "MMCCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             147, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(24, "MMCDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             148, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(25, "MMCDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             149, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(26, "MMCDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             150, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(27, "MMCDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             151, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(28, "MMCDAT4", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_8_12_16_20,
+                            6, UNIPHIER_PIN_DRV_2BIT,
                             152, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(29, "MMCDAT5", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_8_12_16_20,
+                            7, UNIPHIER_PIN_DRV_2BIT,
                             153, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(30, "MMCDAT6", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_8_12_16_20,
+                            8, UNIPHIER_PIN_DRV_2BIT,
                             154, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "MMCDAT7", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_8_12_16_20,
+                            9, UNIPHIER_PIN_DRV_2BIT,
                             155, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "RMII_RXD0", 6,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(33, "RMII_RXD1", 6,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(34, "RMII_CRS_DV", 6,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(35, "RMII_RXER", 6,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(36, "RMII_REFCLK", 6,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(37, "RMII_TXD0", 6,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(38, "RMII_TXD1", 6,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(39, "RMII_TXEN", 6,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(40, "MDC", 6,
-                            47, UNIPHIER_PIN_DRV_4_8,
+                            47, UNIPHIER_PIN_DRV_1BIT,
                             47, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(41, "MDIO", 6,
-                            48, UNIPHIER_PIN_DRV_4_8,
+                            48, UNIPHIER_PIN_DRV_1BIT,
                             48, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(42, "MDIO_INTL", 6,
-                            49, UNIPHIER_PIN_DRV_4_8,
+                            49, UNIPHIER_PIN_DRV_1BIT,
                             49, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(43, "PHYRSTL", 6,
-                            50, UNIPHIER_PIN_DRV_4_8,
+                            50, UNIPHIER_PIN_DRV_1BIT,
                             50, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(44, "SDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_8_12_16_20,
+                            10, UNIPHIER_PIN_DRV_2BIT,
                             156, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(45, "SDCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_8_12_16_20,
+                            11, UNIPHIER_PIN_DRV_2BIT,
                             157, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(46, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            48, UNIPHIER_PIN_DRV_8_12_16_20,
+                            12, UNIPHIER_PIN_DRV_2BIT,
                             158, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(47, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_8_12_16_20,
+                            13, UNIPHIER_PIN_DRV_2BIT,
                             159, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(48, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            56, UNIPHIER_PIN_DRV_8_12_16_20,
+                            14, UNIPHIER_PIN_DRV_2BIT,
                             160, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(49, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            60, UNIPHIER_PIN_DRV_8_12_16_20,
+                            15, UNIPHIER_PIN_DRV_2BIT,
                             161, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(50, "SDCD", UNIPHIER_PIN_IECTRL_NONE,
-                            51, UNIPHIER_PIN_DRV_4_8,
+                            51, UNIPHIER_PIN_DRV_1BIT,
                             51, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(51, "SDWP", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_4_8,
+                            52, UNIPHIER_PIN_DRV_1BIT,
                             52, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(52, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE,
-                            53, UNIPHIER_PIN_DRV_4_8,
+                            53, UNIPHIER_PIN_DRV_1BIT,
                             53, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(53, "USB0VBUS", 0,
-                            54, UNIPHIER_PIN_DRV_4_8,
+                            54, UNIPHIER_PIN_DRV_1BIT,
                             54, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(54, "USB0OD", 0,
-                            55, UNIPHIER_PIN_DRV_4_8,
+                            55, UNIPHIER_PIN_DRV_1BIT,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(55, "USB1VBUS", 0,
-                            56, UNIPHIER_PIN_DRV_4_8,
+                            56, UNIPHIER_PIN_DRV_1BIT,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "USB1OD", 0,
-                            57, UNIPHIER_PIN_DRV_4_8,
+                            57, UNIPHIER_PIN_DRV_1BIT,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "PCRESET", 0,
-                            58, UNIPHIER_PIN_DRV_4_8,
+                            58, UNIPHIER_PIN_DRV_1BIT,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "PCREG", 0,
-                            59, UNIPHIER_PIN_DRV_4_8,
+                            59, UNIPHIER_PIN_DRV_1BIT,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "PCCE2", 0,
-                            60, UNIPHIER_PIN_DRV_4_8,
+                            60, UNIPHIER_PIN_DRV_1BIT,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "PCVS1", 0,
-                            61, UNIPHIER_PIN_DRV_4_8,
+                            61, UNIPHIER_PIN_DRV_1BIT,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "PCCD2", 0,
-                            62, UNIPHIER_PIN_DRV_4_8,
+                            62, UNIPHIER_PIN_DRV_1BIT,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "PCCD1", 0,
-                            63, UNIPHIER_PIN_DRV_4_8,
+                            63, UNIPHIER_PIN_DRV_1BIT,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "PCREADY", 0,
-                            64, UNIPHIER_PIN_DRV_4_8,
+                            64, UNIPHIER_PIN_DRV_1BIT,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "PCDOE", 0,
-                            65, UNIPHIER_PIN_DRV_4_8,
+                            65, UNIPHIER_PIN_DRV_1BIT,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "PCCE1", 0,
-                            66, UNIPHIER_PIN_DRV_4_8,
+                            66, UNIPHIER_PIN_DRV_1BIT,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "PCWE", 0,
-                            67, UNIPHIER_PIN_DRV_4_8,
+                            67, UNIPHIER_PIN_DRV_1BIT,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "PCOE", 0,
-                            68, UNIPHIER_PIN_DRV_4_8,
+                            68, UNIPHIER_PIN_DRV_1BIT,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "PCWAIT", 0,
-                            69, UNIPHIER_PIN_DRV_4_8,
+                            69, UNIPHIER_PIN_DRV_1BIT,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "PCIOWR", 0,
-                            70, UNIPHIER_PIN_DRV_4_8,
+                            70, UNIPHIER_PIN_DRV_1BIT,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "PCIORD", 0,
-                            71, UNIPHIER_PIN_DRV_4_8,
+                            71, UNIPHIER_PIN_DRV_1BIT,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "HS0DIN0", 0,
-                            72, UNIPHIER_PIN_DRV_4_8,
+                            72, UNIPHIER_PIN_DRV_1BIT,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "HS0DIN1", 0,
-                            73, UNIPHIER_PIN_DRV_4_8,
+                            73, UNIPHIER_PIN_DRV_1BIT,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "HS0DIN2", 0,
-                            74, UNIPHIER_PIN_DRV_4_8,
+                            74, UNIPHIER_PIN_DRV_1BIT,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "HS0DIN3", 0,
-                            75, UNIPHIER_PIN_DRV_4_8,
+                            75, UNIPHIER_PIN_DRV_1BIT,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "HS0DIN4", 0,
-                            76, UNIPHIER_PIN_DRV_4_8,
+                            76, UNIPHIER_PIN_DRV_1BIT,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "HS0DIN5", 0,
-                            77, UNIPHIER_PIN_DRV_4_8,
+                            77, UNIPHIER_PIN_DRV_1BIT,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "HS0DIN6", 0,
-                            78, UNIPHIER_PIN_DRV_4_8,
+                            78, UNIPHIER_PIN_DRV_1BIT,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "HS0DIN7", 0,
-                            79, UNIPHIER_PIN_DRV_4_8,
+                            79, UNIPHIER_PIN_DRV_1BIT,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "HS0BCLKIN", 0,
-                            80, UNIPHIER_PIN_DRV_4_8,
+                            80, UNIPHIER_PIN_DRV_1BIT,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "HS0VALIN", 0,
-                            81, UNIPHIER_PIN_DRV_4_8,
+                            81, UNIPHIER_PIN_DRV_1BIT,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "HS0SYNCIN", 0,
-                            82, UNIPHIER_PIN_DRV_4_8,
+                            82, UNIPHIER_PIN_DRV_1BIT,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "HSDOUT0", 0,
-                            83, UNIPHIER_PIN_DRV_4_8,
+                            83, UNIPHIER_PIN_DRV_1BIT,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "HSDOUT1", 0,
-                            84, UNIPHIER_PIN_DRV_4_8,
+                            84, UNIPHIER_PIN_DRV_1BIT,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "HSDOUT2", 0,
-                            85, UNIPHIER_PIN_DRV_4_8,
+                            85, UNIPHIER_PIN_DRV_1BIT,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "HSDOUT3", 0,
-                            86, UNIPHIER_PIN_DRV_4_8,
+                            86, UNIPHIER_PIN_DRV_1BIT,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "HSDOUT4", 0,
-                            87, UNIPHIER_PIN_DRV_4_8,
+                            87, UNIPHIER_PIN_DRV_1BIT,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "HSDOUT5", 0,
-                            88, UNIPHIER_PIN_DRV_4_8,
+                            88, UNIPHIER_PIN_DRV_1BIT,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "HSDOUT6", 0,
-                            89, UNIPHIER_PIN_DRV_4_8,
+                            89, UNIPHIER_PIN_DRV_1BIT,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "HSDOUT7", 0,
-                            90, UNIPHIER_PIN_DRV_4_8,
+                            90, UNIPHIER_PIN_DRV_1BIT,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "HSBCLKOUT", 0,
-                            91, UNIPHIER_PIN_DRV_4_8,
+                            91, UNIPHIER_PIN_DRV_1BIT,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "HSVALOUT", 0,
-                            92, UNIPHIER_PIN_DRV_4_8,
+                            92, UNIPHIER_PIN_DRV_1BIT,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "HSSYNCOUT", 0,
-                            93, UNIPHIER_PIN_DRV_4_8,
+                            93, UNIPHIER_PIN_DRV_1BIT,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "AGCI", 3,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             162, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "AGCR", 4,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             163, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "AGCBS", 5,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             164, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "IECOUT", 0,
-                            94, UNIPHIER_PIN_DRV_4_8,
+                            94, UNIPHIER_PIN_DRV_1BIT,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "ASMCK", 0,
-                            95, UNIPHIER_PIN_DRV_4_8,
+                            95, UNIPHIER_PIN_DRV_1BIT,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "ABCKO", UNIPHIER_PIN_IECTRL_NONE,
-                            96, UNIPHIER_PIN_DRV_4_8,
+                            96, UNIPHIER_PIN_DRV_1BIT,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "ALRCKO", UNIPHIER_PIN_IECTRL_NONE,
-                            97, UNIPHIER_PIN_DRV_4_8,
+                            97, UNIPHIER_PIN_DRV_1BIT,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "ASDOUT0", UNIPHIER_PIN_IECTRL_NONE,
-                            98, UNIPHIER_PIN_DRV_4_8,
+                            98, UNIPHIER_PIN_DRV_1BIT,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "ARCOUT", 0,
-                            99, UNIPHIER_PIN_DRV_4_8,
+                            99, UNIPHIER_PIN_DRV_1BIT,
                             99, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(103, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(104, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(105, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(106, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(107, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(108, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(109, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(110, "SBO0", UNIPHIER_PIN_IECTRL_NONE,
-                            100, UNIPHIER_PIN_DRV_4_8,
+                            100, UNIPHIER_PIN_DRV_1BIT,
                             100, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(111, "SBI0", UNIPHIER_PIN_IECTRL_NONE,
-                            101, UNIPHIER_PIN_DRV_4_8,
+                            101, UNIPHIER_PIN_DRV_1BIT,
                             101, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(112, "HIN", 1,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(113, "VIN", 2,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(114, "TCON0", UNIPHIER_PIN_IECTRL_NONE,
-                            102, UNIPHIER_PIN_DRV_4_8,
+                            102, UNIPHIER_PIN_DRV_1BIT,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(115, "TCON1", UNIPHIER_PIN_IECTRL_NONE,
-                            103, UNIPHIER_PIN_DRV_4_8,
+                            103, UNIPHIER_PIN_DRV_1BIT,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(116, "TCON2", UNIPHIER_PIN_IECTRL_NONE,
-                            104, UNIPHIER_PIN_DRV_4_8,
+                            104, UNIPHIER_PIN_DRV_1BIT,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(117, "TCON3", UNIPHIER_PIN_IECTRL_NONE,
-                            105, UNIPHIER_PIN_DRV_4_8,
+                            105, UNIPHIER_PIN_DRV_1BIT,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(118, "TCON4", UNIPHIER_PIN_IECTRL_NONE,
-                            106, UNIPHIER_PIN_DRV_4_8,
+                            106, UNIPHIER_PIN_DRV_1BIT,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(119, "TCON5", UNIPHIER_PIN_IECTRL_NONE,
-                            107, UNIPHIER_PIN_DRV_4_8,
+                            107, UNIPHIER_PIN_DRV_1BIT,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(120, "TCON6", 0,
-                            108, UNIPHIER_PIN_DRV_4_8,
+                            108, UNIPHIER_PIN_DRV_1BIT,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "TCON7", 0,
-                            109, UNIPHIER_PIN_DRV_4_8,
+                            109, UNIPHIER_PIN_DRV_1BIT,
                             109, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "PWMA", 0,
-                            110, UNIPHIER_PIN_DRV_4_8,
+                            110, UNIPHIER_PIN_DRV_1BIT,
                             110, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "XIRQ1", 0,
-                            111, UNIPHIER_PIN_DRV_4_8,
+                            111, UNIPHIER_PIN_DRV_1BIT,
                             111, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "XIRQ2", 0,
-                            112, UNIPHIER_PIN_DRV_4_8,
+                            112, UNIPHIER_PIN_DRV_1BIT,
                             112, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "XIRQ3", 0,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(126, "XIRQ4", 0,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "XIRQ5", 0,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(128, "XIRQ6", 0,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "XIRQ7", 0,
-                            117, UNIPHIER_PIN_DRV_4_8,
+                            117, UNIPHIER_PIN_DRV_1BIT,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(130, "XIRQ8", 0,
-                            118, UNIPHIER_PIN_DRV_4_8,
+                            118, UNIPHIER_PIN_DRV_1BIT,
                             118, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "XIRQ9", 0,
-                            119, UNIPHIER_PIN_DRV_4_8,
+                            119, UNIPHIER_PIN_DRV_1BIT,
                             119, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "XIRQ10", 0,
-                            120, UNIPHIER_PIN_DRV_4_8,
+                            120, UNIPHIER_PIN_DRV_1BIT,
                             120, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "XIRQ11", 0,
-                            121, UNIPHIER_PIN_DRV_4_8,
+                            121, UNIPHIER_PIN_DRV_1BIT,
                             121, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "XIRQ14", 0,
-                            122, UNIPHIER_PIN_DRV_4_8,
+                            122, UNIPHIER_PIN_DRV_1BIT,
                             122, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "PORT00", 0,
-                            123, UNIPHIER_PIN_DRV_4_8,
+                            123, UNIPHIER_PIN_DRV_1BIT,
                             123, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(136, "PORT01", 0,
-                            124, UNIPHIER_PIN_DRV_4_8,
+                            124, UNIPHIER_PIN_DRV_1BIT,
                             124, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(137, "PORT02", 0,
-                            125, UNIPHIER_PIN_DRV_4_8,
+                            125, UNIPHIER_PIN_DRV_1BIT,
                             125, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(138, "PORT03", 0,
-                            126, UNIPHIER_PIN_DRV_4_8,
+                            126, UNIPHIER_PIN_DRV_1BIT,
                             126, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(139, "PORT04", 0,
-                            127, UNIPHIER_PIN_DRV_4_8,
+                            127, UNIPHIER_PIN_DRV_1BIT,
                             127, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(140, "PORT05", 0,
-                            128, UNIPHIER_PIN_DRV_4_8,
+                            128, UNIPHIER_PIN_DRV_1BIT,
                             128, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(141, "PORT06", 0,
-                            129, UNIPHIER_PIN_DRV_4_8,
+                            129, UNIPHIER_PIN_DRV_1BIT,
                             129, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "PORT07", 0,
-                            130, UNIPHIER_PIN_DRV_4_8,
+                            130, UNIPHIER_PIN_DRV_1BIT,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(143, "PORT10", 0,
-                            131, UNIPHIER_PIN_DRV_4_8,
+                            131, UNIPHIER_PIN_DRV_1BIT,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(144, "PORT11", 0,
-                            132, UNIPHIER_PIN_DRV_4_8,
+                            132, UNIPHIER_PIN_DRV_1BIT,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(145, "PORT12", 0,
-                            133, UNIPHIER_PIN_DRV_4_8,
+                            133, UNIPHIER_PIN_DRV_1BIT,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(146, "PORT13", 0,
-                            134, UNIPHIER_PIN_DRV_4_8,
+                            134, UNIPHIER_PIN_DRV_1BIT,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(147, "PORT14", 0,
-                            135, UNIPHIER_PIN_DRV_4_8,
+                            135, UNIPHIER_PIN_DRV_1BIT,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(148, "PORT15", 0,
-                            136, UNIPHIER_PIN_DRV_4_8,
+                            136, UNIPHIER_PIN_DRV_1BIT,
                             136, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(149, "PORT16", 0,
-                            137, UNIPHIER_PIN_DRV_4_8,
+                            137, UNIPHIER_PIN_DRV_1BIT,
                             137, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(150, "PORT17", UNIPHIER_PIN_IECTRL_NONE,
-                            138, UNIPHIER_PIN_DRV_4_8,
+                            138, UNIPHIER_PIN_DRV_1BIT,
                             138, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(151, "PORT20", 0,
-                            139, UNIPHIER_PIN_DRV_4_8,
+                            139, UNIPHIER_PIN_DRV_1BIT,
                             139, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(152, "PORT21", 0,
-                            140, UNIPHIER_PIN_DRV_4_8,
+                            140, UNIPHIER_PIN_DRV_1BIT,
                             140, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(153, "PORT22", 0,
-                            141, UNIPHIER_PIN_DRV_4_8,
+                            141, UNIPHIER_PIN_DRV_1BIT,
                             141, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(154, "PORT23", 0,
-                            142, UNIPHIER_PIN_DRV_4_8,
+                            142, UNIPHIER_PIN_DRV_1BIT,
                             142, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(155, "PORT24", UNIPHIER_PIN_IECTRL_NONE,
-                            143, UNIPHIER_PIN_DRV_4_8,
+                            143, UNIPHIER_PIN_DRV_1BIT,
                             143, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(156, "PORT25", 0,
-                            144, UNIPHIER_PIN_DRV_4_8,
+                            144, UNIPHIER_PIN_DRV_1BIT,
                             144, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(157, "PORT26", 0,
-                            145, UNIPHIER_PIN_DRV_4_8,
+                            145, UNIPHIER_PIN_DRV_1BIT,
                             145, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(158, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(159, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(160, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(164, "NANDRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_UP),
+       /* dedicated pins */
+       UNIPHIER_PINCTRL_PIN(165, "ED0", -1,
+                            0, UNIPHIER_PIN_DRV_1BIT,
+                            0, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(166, "ED1", -1,
+                            1, UNIPHIER_PIN_DRV_1BIT,
+                            1, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(167, "ED2", -1,
+                            2, UNIPHIER_PIN_DRV_1BIT,
+                            2, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(168, "ED3", -1,
+                            3, UNIPHIER_PIN_DRV_1BIT,
+                            3, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(169, "ED4", -1,
+                            4, UNIPHIER_PIN_DRV_1BIT,
+                            4, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(170, "ED5", -1,
+                            5, UNIPHIER_PIN_DRV_1BIT,
+                            5, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(171, "ED6", -1,
+                            6, UNIPHIER_PIN_DRV_1BIT,
+                            6, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(172, "ED7", -1,
+                            7, UNIPHIER_PIN_DRV_1BIT,
+                            7, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(173, "ERXW", -1,
+                            26, UNIPHIER_PIN_DRV_1BIT,
+                            26, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(174, "XECS1", -1,
+                            30, UNIPHIER_PIN_DRV_1BIT,
+                            30, UNIPHIER_PIN_PULL_UP),
 };
 
 static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27};
-static const unsigned emmc_muxvals[] = {0, 1, 1, 1, 1, 1, 1};
+static const int emmc_muxvals[] = {0, 1, 1, 1, 1, 1, 1};
 static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31};
-static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const int emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const unsigned ether_mii_pins[] = {32, 33, 34, 35, 36, 37, 38, 39, 40,
+                                         41, 42, 43, 136, 137, 138, 139, 140,
+                                         141, 142};
+static const int ether_mii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                       4, 4, 4, 4, 4, 4, 4};
+static const unsigned ether_rmii_pins[] = {32, 33, 34, 35, 36, 37, 38, 39, 40,
+                                          41, 42, 43};
+static const int ether_rmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned i2c0_pins[] = {102, 103};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {104, 105};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {108, 109};
-static const unsigned i2c2_muxvals[] = {2, 2};
+static const int i2c2_muxvals[] = {2, 2};
 static const unsigned i2c3_pins[] = {108, 109};
-static const unsigned i2c3_muxvals[] = {3, 3};
+static const int i2c3_muxvals[] = {3, 3};
 static const unsigned nand_pins[] = {24, 25, 26, 27, 28, 29, 30, 31, 158, 159,
                                     160, 161, 162, 163, 164};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {22, 23};
-static const unsigned nand_cs1_muxvals[] = {0, 0};
+static const int nand_cs1_muxvals[] = {0, 0};
 static const unsigned sd_pins[] = {44, 45, 46, 47, 48, 49, 50, 51, 52};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {16, 17, 18, 19, 20, 165, 166, 167,
+                                          168, 169, 170, 171, 172, 173};
+static const int system_bus_muxvals[] = {0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1,
+                                        -1, -1, -1};
+static const unsigned system_bus_cs0_pins[] = {155};
+static const int system_bus_cs0_muxvals[] = {1};
+static const unsigned system_bus_cs1_pins[] = {174};
+static const int system_bus_cs1_muxvals[] = {-1};
+static const unsigned system_bus_cs2_pins[] = {64};
+static const int system_bus_cs2_muxvals[] = {1};
+static const unsigned system_bus_cs3_pins[] = {156};
+static const int system_bus_cs3_muxvals[] = {1};
 static const unsigned uart0_pins[] = {85, 88};
-static const unsigned uart0_muxvals[] = {1, 1};
+static const int uart0_muxvals[] = {1, 1};
 static const unsigned uart1_pins[] = {155, 156};
-static const unsigned uart1_muxvals[] = {13, 13};
+static const int uart1_muxvals[] = {13, 13};
 static const unsigned uart1b_pins[] = {69, 70};
-static const unsigned uart1b_muxvals[] = {23, 23};
+static const int uart1b_muxvals[] = {23, 23};
 static const unsigned uart2_pins[] = {128, 129};
-static const unsigned uart2_muxvals[] = {13, 13};
+static const int uart2_muxvals[] = {13, 13};
 static const unsigned uart3_pins[] = {110, 111};
-static const unsigned uart3_muxvals[] = {1, 1};
+static const int uart3_muxvals[] = {1, 1};
 static const unsigned usb0_pins[] = {53, 54};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {55, 56};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {155, 156};
-static const unsigned usb2_muxvals[] = {4, 4};
+static const int usb2_muxvals[] = {4, 4};
 static const unsigned usb2b_pins[] = {67, 68};
-static const unsigned usb2b_muxvals[] = {23, 23};
+static const int usb2b_muxvals[] = {23, 23};
 static const unsigned port_range0_pins[] = {
        135, 136, 137, 138, 139, 140, 141, 142,         /* PORT0x */
        143, 144, 145, 146, 147, 148, 149, 150,         /* PORT1x */
@@ -574,7 +622,7 @@ static const unsigned port_range0_pins[] = {
        98, 99, 100, 6, 101, 114, 115, 116,             /* PORT13x */
        103, 108, 21, 22, 23, 117, 118, 119,            /* PORT14x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        0, 0, 0, 0, 0, 0, 0, 0,                         /* PORT0x */
        0, 0, 0, 0, 0, 0, 0, 0,                         /* PORT1x */
        0, 0, 0, 0, 0, 0, 0, 15,                        /* PORT2x */
@@ -594,27 +642,29 @@ static const unsigned port_range0_muxvals[] = {
 static const unsigned port_range1_pins[] = {
        7,                                              /* PORT166 */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15,                                             /* PORT166 */
 };
 static const unsigned xirq_range0_pins[] = {
        151, 123, 124, 125, 126, 127, 128, 129,         /* XIRQ0-7 */
        130, 131, 132, 133, 62,                         /* XIRQ8-12 */
 };
-static const unsigned xirq_range0_muxvals[] = {
+static const int xirq_range0_muxvals[] = {
        14, 0, 0, 0, 0, 0, 0, 0,                        /* XIRQ0-7 */
        0, 0, 0, 0, 14,                                 /* XIRQ8-12 */
 };
 static const unsigned xirq_range1_pins[] = {
        134, 63,                                        /* XIRQ14-15 */
 };
-static const unsigned xirq_range1_muxvals[] = {
+static const int xirq_range1_muxvals[] = {
        0, 14,                                          /* XIRQ14-15 */
 };
 
-static const struct uniphier_pinctrl_group ph1_ld4_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_ld4_groups[] = {
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_mii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -622,6 +672,11 @@ static const struct uniphier_pinctrl_group ph1_ld4_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs0),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart1),
        UNIPHIER_PINCTRL_GROUP(uart1b),
@@ -774,12 +829,19 @@ static const struct uniphier_pinctrl_group ph1_ld4_groups[] = {
 };
 
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_mii_groups[] = {"ether_mii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
 static const char * const i2c3_groups[] = {"i2c3"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs0",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3"};
 static const char * const uart0_groups[] = {"uart0"};
 static const char * const uart1_groups[] = {"uart1", "uart1b"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -828,14 +890,17 @@ static const char * const xirq_groups[] = {
        "xirq12", /* none*/ "xirq14", "xirq15",
 };
 
-static const struct uniphier_pinmux_function ph1_ld4_functions[] = {
+static const struct uniphier_pinmux_function uniphier_ld4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_mii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
        UNIPHIER_PINMUX_FUNCTION(i2c3),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -847,43 +912,36 @@ static const struct uniphier_pinmux_function ph1_ld4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_ld4_pindata = {
-       .groups = ph1_ld4_groups,
-       .groups_count = ARRAY_SIZE(ph1_ld4_groups),
-       .functions = ph1_ld4_functions,
-       .functions_count = ARRAY_SIZE(ph1_ld4_functions),
-       .mux_bits = 8,
-       .reg_stride = 4,
-       .load_pinctrl = false,
-};
-
-static struct pinctrl_desc ph1_ld4_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_ld4_pins,
-       .npins = ARRAY_SIZE(ph1_ld4_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_ld4_pindata = {
+       .pins = uniphier_ld4_pins,
+       .npins = ARRAY_SIZE(uniphier_ld4_pins),
+       .groups = uniphier_ld4_groups,
+       .groups_count = ARRAY_SIZE(uniphier_ld4_groups),
+       .functions = uniphier_ld4_functions,
+       .functions_count = ARRAY_SIZE(uniphier_ld4_functions),
+       .caps = 0,
 };
 
-static int ph1_ld4_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_ld4_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_ld4_pinctrl_desc,
-                                     &ph1_ld4_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_ld4_pindata);
 }
 
-static const struct of_device_id ph1_ld4_pinctrl_match[] = {
+static const struct of_device_id uniphier_ld4_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-ld4-pinctrl" },
        { .compatible = "socionext,ph1-ld4-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_ld4_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_ld4_pinctrl_match);
 
-static struct platform_driver ph1_ld4_pinctrl_driver = {
-       .probe = ph1_ld4_pinctrl_probe,
+static struct platform_driver uniphier_ld4_pinctrl_driver = {
+       .probe = uniphier_ld4_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_ld4_pinctrl_match,
+               .name = "uniphier-ld4-pinctrl",
+               .of_match_table = uniphier_ld4_pinctrl_match,
        },
 };
-module_platform_driver(ph1_ld4_pinctrl_driver);
+module_platform_driver(uniphier_ld4_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-LD4 pinctrl driver");
index 150d33928df2796e977dc97fd2730bb4778ff3d3..708e5100cf34ba892b91c528a1c35489dca741d8 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-ld6b-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_ld6b_pins[] = {
+static const struct pinctrl_pin_desc uniphier_ld6b_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "ED0", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_4_8,
+                            0, UNIPHIER_PIN_DRV_1BIT,
                             0, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "ED1", UNIPHIER_PIN_IECTRL_NONE,
-                            1, UNIPHIER_PIN_DRV_4_8,
+                            1, UNIPHIER_PIN_DRV_1BIT,
                             1, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "ED2", UNIPHIER_PIN_IECTRL_NONE,
-                            2, UNIPHIER_PIN_DRV_4_8,
+                            2, UNIPHIER_PIN_DRV_1BIT,
                             2, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "ED3", UNIPHIER_PIN_IECTRL_NONE,
-                            3, UNIPHIER_PIN_DRV_4_8,
+                            3, UNIPHIER_PIN_DRV_1BIT,
                             3, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "ED4", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_4_8,
+                            4, UNIPHIER_PIN_DRV_1BIT,
                             4, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "ED5", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_4_8,
+                            5, UNIPHIER_PIN_DRV_1BIT,
                             5, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "ED6", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_4_8,
+                            6, UNIPHIER_PIN_DRV_1BIT,
                             6, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "ED7", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_4_8,
+                            7, UNIPHIER_PIN_DRV_1BIT,
                             7, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(13, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "XECS1", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "PCA00", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(16, "PCA01", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(17, "PCA02", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(18, "PCA03", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(19, "PCA04", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(20, "PCA05", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(21, "PCA06", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(22, "PCA07", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(23, "PCA08", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(24, "PCA09", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             24, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(25, "PCA10", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             25, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(26, "PCA11", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             26, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(27, "PCA12", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             27, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(28, "PCA13", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             28, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(29, "PCA14", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             29, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(30, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(33, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(34, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(35, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(36, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(37, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(38, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(39, "NFD0", UNIPHIER_PIN_IECTRL_NONE,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(40, "NFD1", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(41, "NFD2", UNIPHIER_PIN_IECTRL_NONE,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(42, "NFD3", UNIPHIER_PIN_IECTRL_NONE,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(43, "NFD4", UNIPHIER_PIN_IECTRL_NONE,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(44, "NFD5", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(45, "NFD6", UNIPHIER_PIN_IECTRL_NONE,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(46, "NFD7", UNIPHIER_PIN_IECTRL_NONE,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(47, "SDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(48, "SDCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(49, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(50, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(51, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(52, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(53, "SDCD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             53, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(54, "SDWP", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             54, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(55, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "USB1OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "USB2OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "USB3OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "HS0BCLKOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "HS0SYNCOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "HS0VALOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "HS0DOUT0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "HS0DOUT1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "HS0DOUT2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "HS0DOUT3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "HS0DOUT4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "HS0DOUT5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "HS0DOUT6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "HS0DOUT7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "HS1BCLKIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "HS1SYNCIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "HS1VALIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "HS1DIN0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "HS1DIN1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "HS1DIN2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "HS1DIN3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "HS1DIN4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "HS1DIN5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "HS1DIN6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "HS1DIN7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "HS2BCLKIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "HS2SYNCIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "HS2VALIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "HS2DIN0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "HS2DIN1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "HS2DIN2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "HS2DIN3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "HS2DIN4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "HS2DIN5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "HS2DIN6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "HS2DIN7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             99, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             100, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "AO1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "AO1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(103, "AO1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(104, "AO1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(105, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(106, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(107, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(108, "AO2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(109, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             109, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(110, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             110, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(111, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             111, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(112, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             112, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(113, "SBO0", 0,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(114, "SBI0", 0,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "TXD1", 0,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "RXD1", 0,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(117, "PWSRA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(118, "XIRQ0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             118, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(119, "XIRQ1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             119, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(120, "XIRQ2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             120, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             121, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             122, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "XIRQ5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             123, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "XIRQ6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             124, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "XIRQ7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             125, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(126, "XIRQ8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             126, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "PORT00", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             127, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(128, "PORT01", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             128, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "PORT02", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             129, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(130, "PORT03", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "PORT04", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "PORT05", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "PORT06", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "PORT07", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "PORT10", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(136, "PORT11", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             136, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(137, "PORT12", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             137, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(138, "PORT13", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             138, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(139, "PORT14", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             139, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(140, "PORT15", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             140, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(141, "PORT16", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             141, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "LPST", UNIPHIER_PIN_IECTRL_NONE,
-                            142, UNIPHIER_PIN_DRV_4_8,
+                            142, UNIPHIER_PIN_DRV_1BIT,
                             142, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(143, "MDC", 0,
-                            143, UNIPHIER_PIN_DRV_4_8,
+                            143, UNIPHIER_PIN_DRV_1BIT,
                             143, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(144, "MDIO", 0,
-                            144, UNIPHIER_PIN_DRV_4_8,
+                            144, UNIPHIER_PIN_DRV_1BIT,
                             144, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(145, "MDIO_INTL", 0,
-                            145, UNIPHIER_PIN_DRV_4_8,
+                            145, UNIPHIER_PIN_DRV_1BIT,
                             145, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(146, "PHYRSTL", 0,
-                            146, UNIPHIER_PIN_DRV_4_8,
+                            146, UNIPHIER_PIN_DRV_1BIT,
                             146, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(147, "RGMII_RXCLK", 0,
-                            147, UNIPHIER_PIN_DRV_4_8,
+                            147, UNIPHIER_PIN_DRV_1BIT,
                             147, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(148, "RGMII_RXD0", 0,
-                            148, UNIPHIER_PIN_DRV_4_8,
+                            148, UNIPHIER_PIN_DRV_1BIT,
                             148, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(149, "RGMII_RXD1", 0,
-                            149, UNIPHIER_PIN_DRV_4_8,
+                            149, UNIPHIER_PIN_DRV_1BIT,
                             149, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(150, "RGMII_RXD2", 0,
-                            150, UNIPHIER_PIN_DRV_4_8,
+                            150, UNIPHIER_PIN_DRV_1BIT,
                             150, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(151, "RGMII_RXD3", 0,
-                            151, UNIPHIER_PIN_DRV_4_8,
+                            151, UNIPHIER_PIN_DRV_1BIT,
                             151, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(152, "RGMII_RXCTL", 0,
-                            152, UNIPHIER_PIN_DRV_4_8,
+                            152, UNIPHIER_PIN_DRV_1BIT,
                             152, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(153, "RGMII_TXCLK", 0,
-                            153, UNIPHIER_PIN_DRV_4_8,
+                            153, UNIPHIER_PIN_DRV_1BIT,
                             153, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(154, "RGMII_TXD0", 0,
-                            154, UNIPHIER_PIN_DRV_4_8,
+                            154, UNIPHIER_PIN_DRV_1BIT,
                             154, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(155, "RGMII_TXD1", 0,
-                            155, UNIPHIER_PIN_DRV_4_8,
+                            155, UNIPHIER_PIN_DRV_1BIT,
                             155, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(156, "RGMII_TXD2", 0,
-                            156, UNIPHIER_PIN_DRV_4_8,
+                            156, UNIPHIER_PIN_DRV_1BIT,
                             156, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(157, "RGMII_TXD3", 0,
-                            157, UNIPHIER_PIN_DRV_4_8,
+                            157, UNIPHIER_PIN_DRV_1BIT,
                             157, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(158, "RGMII_TXCTL", 0,
-                            158, UNIPHIER_PIN_DRV_4_8,
+                            158, UNIPHIER_PIN_DRV_1BIT,
                             158, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(159, "A_D_PCD00OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             159, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(160, "A_D_PCD01OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             160, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "A_D_PCD02OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             161, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "A_D_PCD03OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             162, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "A_D_PCD04OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             163, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(164, "A_D_PCD05OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             164, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(165, "A_D_PCD06OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             165, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(166, "A_D_PCD07OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             166, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(167, "A_D_PCD00IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             167, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(168, "A_D_PCD01IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             168, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(169, "A_D_PCD02IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             169, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(170, "A_D_PCD03IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             170, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(171, "A_D_PCD04IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             171, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(172, "A_D_PCD05IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             172, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(173, "A_D_PCD06IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             173, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(174, "A_D_PCD07IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             174, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(175, "A_D_PCDNOE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             175, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(176, "A_D_PC0READY", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             176, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(177, "A_D_PC0CD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             177, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(178, "A_D_PC0CD2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             178, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(179, "A_D_PC0WAIT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             179, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(180, "A_D_PC0RESET", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             180, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(181, "A_D_PC0CE1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             181, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(182, "A_D_PC0WE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             182, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(183, "A_D_PC0OE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             183, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(184, "A_D_PC0IOWR", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             184, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(185, "A_D_PC0IORD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             185, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(186, "A_D_PC0NOE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             186, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(187, "A_D_HS0BCLKIN", 0,
-                            187, UNIPHIER_PIN_DRV_4_8,
+                            187, UNIPHIER_PIN_DRV_1BIT,
                             187, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(188, "A_D_HS0SYNCIN", 0,
-                            188, UNIPHIER_PIN_DRV_4_8,
+                            188, UNIPHIER_PIN_DRV_1BIT,
                             188, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(189, "A_D_HS0VALIN", 0,
-                            189, UNIPHIER_PIN_DRV_4_8,
+                            189, UNIPHIER_PIN_DRV_1BIT,
                             189, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(190, "A_D_HS0DIN0", 0,
-                            190, UNIPHIER_PIN_DRV_4_8,
+                            190, UNIPHIER_PIN_DRV_1BIT,
                             190, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(191, "A_D_HS0DIN1", 0,
-                            191, UNIPHIER_PIN_DRV_4_8,
+                            191, UNIPHIER_PIN_DRV_1BIT,
                             191, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(192, "A_D_HS0DIN2", 0,
-                            192, UNIPHIER_PIN_DRV_4_8,
+                            192, UNIPHIER_PIN_DRV_1BIT,
                             192, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(193, "A_D_HS0DIN3", 0,
-                            193, UNIPHIER_PIN_DRV_4_8,
+                            193, UNIPHIER_PIN_DRV_1BIT,
                             193, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(194, "A_D_HS0DIN4", 0,
-                            194, UNIPHIER_PIN_DRV_4_8,
+                            194, UNIPHIER_PIN_DRV_1BIT,
                             194, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(195, "A_D_HS0DIN5", 0,
-                            195, UNIPHIER_PIN_DRV_4_8,
+                            195, UNIPHIER_PIN_DRV_1BIT,
                             195, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(196, "A_D_HS0DIN6", 0,
-                            196, UNIPHIER_PIN_DRV_4_8,
+                            196, UNIPHIER_PIN_DRV_1BIT,
                             196, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(197, "A_D_HS0DIN7", 0,
-                            197, UNIPHIER_PIN_DRV_4_8,
+                            197, UNIPHIER_PIN_DRV_1BIT,
                             197, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(198, "A_D_AO1ARC", 0,
-                            198, UNIPHIER_PIN_DRV_4_8,
+                            198, UNIPHIER_PIN_DRV_1BIT,
                             198, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(199, "A_D_SPIXRST", UNIPHIER_PIN_IECTRL_NONE,
-                            199, UNIPHIER_PIN_DRV_4_8,
+                            199, UNIPHIER_PIN_DRV_1BIT,
                             199, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(200, "A_D_SPISCLK0", UNIPHIER_PIN_IECTRL_NONE,
-                            200, UNIPHIER_PIN_DRV_4_8,
+                            200, UNIPHIER_PIN_DRV_1BIT,
                             200, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(201, "A_D_SPITXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            201, UNIPHIER_PIN_DRV_4_8,
+                            201, UNIPHIER_PIN_DRV_1BIT,
                             201, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(202, "A_D_SPIRXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            202, UNIPHIER_PIN_DRV_4_8,
+                            202, UNIPHIER_PIN_DRV_1BIT,
                             202, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(203, "A_D_DMDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             203, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(204, "A_D_DMDPSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             204, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(205, "A_D_DMDVAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             205, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(206, "A_D_DMDDATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             206, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(207, "A_D_HDMIRXXIRQ", 0,
-                            207, UNIPHIER_PIN_DRV_4_8,
+                            207, UNIPHIER_PIN_DRV_1BIT,
                             207, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(208, "A_D_VBIXIRQ", 0,
-                            208, UNIPHIER_PIN_DRV_4_8,
+                            208, UNIPHIER_PIN_DRV_1BIT,
                             208, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(209, "A_D_HDMITXXIRQ", 0,
-                            209, UNIPHIER_PIN_DRV_4_8,
+                            209, UNIPHIER_PIN_DRV_1BIT,
                             209, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(210, "A_D_DMDIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            210, UNIPHIER_PIN_DRV_4_8,
+                            210, UNIPHIER_PIN_DRV_1BIT,
                             210, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(211, "A_D_SPICIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            211, UNIPHIER_PIN_DRV_4_8,
+                            211, UNIPHIER_PIN_DRV_1BIT,
                             211, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(212, "A_D_SPIBIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            212, UNIPHIER_PIN_DRV_4_8,
+                            212, UNIPHIER_PIN_DRV_1BIT,
                             212, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(213, "A_D_BESDAOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             213, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(214, "A_D_BESDAIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             214, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(215, "A_D_BESCLOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            215, UNIPHIER_PIN_DRV_4_8,
+                            215, UNIPHIER_PIN_DRV_1BIT,
                             215, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(216, "A_D_VDACCLKOUT", 0,
-                            216, UNIPHIER_PIN_DRV_4_8,
+                            216, UNIPHIER_PIN_DRV_1BIT,
                             216, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(217, "A_D_VDACDOUT5", 0,
-                            217, UNIPHIER_PIN_DRV_4_8,
+                            217, UNIPHIER_PIN_DRV_1BIT,
                             217, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(218, "A_D_VDACDOUT6", 0,
-                            218, UNIPHIER_PIN_DRV_4_8,
+                            218, UNIPHIER_PIN_DRV_1BIT,
                             218, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(219, "A_D_VDACDOUT7", 0,
-                            219, UNIPHIER_PIN_DRV_4_8,
+                            219, UNIPHIER_PIN_DRV_1BIT,
                             219, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(220, "A_D_VDACDOUT8", 0,
-                            220, UNIPHIER_PIN_DRV_4_8,
+                            220, UNIPHIER_PIN_DRV_1BIT,
                             220, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(221, "A_D_VDACDOUT9", 0,
-                            221, UNIPHIER_PIN_DRV_4_8,
+                            221, UNIPHIER_PIN_DRV_1BIT,
                             221, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(222, "A_D_SIFBCKIN", 0,
-                            222, UNIPHIER_PIN_DRV_4_8,
+                            222, UNIPHIER_PIN_DRV_1BIT,
                             222, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(223, "A_D_SIFLRCKIN", 0,
-                            223, UNIPHIER_PIN_DRV_4_8,
+                            223, UNIPHIER_PIN_DRV_1BIT,
                             223, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(224, "A_D_SIFDIN", 0,
-                            224, UNIPHIER_PIN_DRV_4_8,
+                            224, UNIPHIER_PIN_DRV_1BIT,
                             224, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(225, "A_D_LIBCKOUT", 0,
-                            225, UNIPHIER_PIN_DRV_4_8,
+                            225, UNIPHIER_PIN_DRV_1BIT,
                             225, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(226, "A_D_LILRCKOUT", 0,
-                            226, UNIPHIER_PIN_DRV_4_8,
+                            226, UNIPHIER_PIN_DRV_1BIT,
                             226, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(227, "A_D_LIDIN", 0,
-                            227, UNIPHIER_PIN_DRV_4_8,
+                            227, UNIPHIER_PIN_DRV_1BIT,
                             227, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(228, "A_D_LODOUT", 0,
-                            228, UNIPHIER_PIN_DRV_4_8,
+                            228, UNIPHIER_PIN_DRV_1BIT,
                             228, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(229, "A_D_HPDOUT", 0,
-                            229, UNIPHIER_PIN_DRV_4_8,
+                            229, UNIPHIER_PIN_DRV_1BIT,
                             229, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(230, "A_D_MCLK", 0,
-                            230, UNIPHIER_PIN_DRV_4_8,
+                            230, UNIPHIER_PIN_DRV_1BIT,
                             230, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(231, "A_D_A2PLLREFOUT", 0,
-                            231, UNIPHIER_PIN_DRV_4_8,
+                            231, UNIPHIER_PIN_DRV_1BIT,
                             231, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(232, "A_D_HDMI3DSDAOUT", 0,
-                            232, UNIPHIER_PIN_DRV_4_8,
+                            232, UNIPHIER_PIN_DRV_1BIT,
                             232, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(233, "A_D_HDMI3DSDAIN", 0,
-                            233, UNIPHIER_PIN_DRV_4_8,
+                            233, UNIPHIER_PIN_DRV_1BIT,
                             233, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(234, "A_D_HDMI3DSCLIN", 0,
-                            234, UNIPHIER_PIN_DRV_4_8,
+                            234, UNIPHIER_PIN_DRV_1BIT,
                             234, UNIPHIER_PIN_PULL_DOWN),
 };
 
@@ -737,52 +735,73 @@ static const unsigned adinter_pins[] = {
        215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228,
        229, 230, 231, 232, 233, 234,
 };
-static const unsigned adinter_muxvals[] = {
+static const int adinter_muxvals[] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0,
 };
 static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42};
-static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
+static const int emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
 static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46};
-static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const int emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const unsigned ether_rgmii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                           150, 151, 152, 153, 154, 155, 156,
+                                           157, 158};
+static const int ether_rgmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                         0, 0, 0, 0};
+static const unsigned ether_rmii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                          150, 152, 154, 155, 158};
+static const int ether_rmii_muxvals[] = {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1};
 static const unsigned i2c0_pins[] = {109, 110};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {111, 112};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {115, 116};
-static const unsigned i2c2_muxvals[] = {1, 1};
+static const int i2c2_muxvals[] = {1, 1};
 static const unsigned i2c3_pins[] = {118, 119};
-static const unsigned i2c3_muxvals[] = {1, 1};
+static const int i2c3_muxvals[] = {1, 1};
 static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41,
                                     42, 43, 44, 45, 46};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {37, 38};
-static const unsigned nand_cs1_muxvals[] = {0, 0};
+static const int nand_cs1_muxvals[] = {0, 0};
 static const unsigned sd_pins[] = {47, 48, 49, 50, 51, 52, 53, 54, 55};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+                                          11, 12, 13};
+static const int system_bus_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                        0};
+static const unsigned system_bus_cs1_pins[] = {14};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned system_bus_cs2_pins[] = {37};
+static const int system_bus_cs2_muxvals[] = {6};
+static const unsigned system_bus_cs3_pins[] = {38};
+static const int system_bus_cs3_muxvals[] = {6};
+static const unsigned system_bus_cs4_pins[] = {115};
+static const int system_bus_cs4_muxvals[] = {6};
+static const unsigned system_bus_cs5_pins[] = {55};
+static const int system_bus_cs5_muxvals[] = {6};
 static const unsigned uart0_pins[] = {135, 136};
-static const unsigned uart0_muxvals[] = {3, 3};
+static const int uart0_muxvals[] = {3, 3};
 static const unsigned uart0b_pins[] = {11, 12};
-static const unsigned uart0b_muxvals[] = {2, 2};
+static const int uart0b_muxvals[] = {2, 2};
 static const unsigned uart1_pins[] = {115, 116};
-static const unsigned uart1_muxvals[] = {0, 0};
+static const int uart1_muxvals[] = {0, 0};
 static const unsigned uart1b_pins[] = {113, 114};
-static const unsigned uart1b_muxvals[] = {1, 1};
+static const int uart1b_muxvals[] = {1, 1};
 static const unsigned uart2_pins[] = {113, 114};
-static const unsigned uart2_muxvals[] = {2, 2};
+static const int uart2_muxvals[] = {2, 2};
 static const unsigned uart2b_pins[] = {86, 87};
-static const unsigned uart2b_muxvals[] = {1, 1};
+static const int uart2b_muxvals[] = {1, 1};
 static const unsigned usb0_pins[] = {56, 57};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {58, 59};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {60, 61};
-static const unsigned usb2_muxvals[] = {0, 0};
+static const int usb2_muxvals[] = {0, 0};
 static const unsigned usb3_pins[] = {62, 63};
-static const unsigned usb3_muxvals[] = {0, 0};
+static const int usb3_muxvals[] = {0, 0};
 static const unsigned port_range0_pins[] = {
        127, 128, 129, 130, 131, 132, 133, 134,         /* PORT0x */
        135, 136, 137, 138, 139, 140, 141, 142,         /* PORT1x */
@@ -796,7 +815,7 @@ static const unsigned port_range0_pins[] = {
        61, 62, 63, 64, 65, 66, 67, 68,                 /* PORT9x */
        69, 70, 71, 76, 77, 78, 79, 80,                 /* PORT10x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
@@ -828,7 +847,7 @@ static const unsigned port_range1_pins[] = {
        218, 219, 220, 221, 223, 224, 225, 226,         /* PORT27x */
        227, 228, 229, 230, 231, 232, 233, 234,         /* PORT28x */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT12x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT13x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
@@ -852,16 +871,18 @@ static const unsigned xirq_pins[] = {
        126, 72, 73, 92, 177, 93, 94, 176,              /* XIRQ8-15 */
        74, 91, 27, 28, 29, 75, 20, 26,                 /* XIRQ16-23 */
 };
-static const unsigned xirq_muxvals[] = {
+static const int xirq_muxvals[] = {
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ8-15 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
 };
 
-static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_ld6b_groups[] = {
        UNIPHIER_PINCTRL_GROUP(adinter),
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_rgmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -869,6 +890,12 @@ static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs4),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs5),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart0b),
        UNIPHIER_PINCTRL_GROUP(uart1),
@@ -1134,12 +1161,20 @@ static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = {
 
 static const char * const adinter_groups[] = {"adinter"};
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_rgmii_groups[] = {"ether_rgmii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
 static const char * const i2c3_groups[] = {"i2c3"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3",
+                                                "system_bus_cs4",
+                                                "system_bus_cs5"};
 static const char * const uart0_groups[] = {"uart0", "uart0b"};
 static const char * const uart1_groups[] = {"uart1", "uart1b"};
 static const char * const uart2_groups[] = {"uart2", "uart2b"};
@@ -1215,15 +1250,18 @@ static const char * const xirq_groups[] = {
        "xirq20", "xirq21", "xirq22", "xirq23",
 };
 
-static const struct uniphier_pinmux_function ph1_ld6b_functions[] = {
+static const struct uniphier_pinmux_function uniphier_ld6b_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(adinter), /* Achip-Dchip interconnect */
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_rgmii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
        UNIPHIER_PINMUX_FUNCTION(i2c3),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -1235,43 +1273,36 @@ static const struct uniphier_pinmux_function ph1_ld6b_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_ld6b_pindata = {
-       .groups = ph1_ld6b_groups,
-       .groups_count = ARRAY_SIZE(ph1_ld6b_groups),
-       .functions = ph1_ld6b_functions,
-       .functions_count = ARRAY_SIZE(ph1_ld6b_functions),
-       .mux_bits = 8,
-       .reg_stride = 4,
-       .load_pinctrl = false,
-};
-
-static struct pinctrl_desc ph1_ld6b_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_ld6b_pins,
-       .npins = ARRAY_SIZE(ph1_ld6b_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_ld6b_pindata = {
+       .pins = uniphier_ld6b_pins,
+       .npins = ARRAY_SIZE(uniphier_ld6b_pins),
+       .groups = uniphier_ld6b_groups,
+       .groups_count = ARRAY_SIZE(uniphier_ld6b_groups),
+       .functions = uniphier_ld6b_functions,
+       .functions_count = ARRAY_SIZE(uniphier_ld6b_functions),
+       .caps = 0,
 };
 
-static int ph1_ld6b_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_ld6b_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_ld6b_pinctrl_desc,
-                                     &ph1_ld6b_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_ld6b_pindata);
 }
 
-static const struct of_device_id ph1_ld6b_pinctrl_match[] = {
+static const struct of_device_id uniphier_ld6b_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-ld6b-pinctrl" },
        { .compatible = "socionext,ph1-ld6b-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_ld6b_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_ld6b_pinctrl_match);
 
-static struct platform_driver ph1_ld6b_pinctrl_driver = {
-       .probe = ph1_ld6b_pinctrl_probe,
+static struct platform_driver uniphier_ld6b_pinctrl_driver = {
+       .probe = uniphier_ld6b_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_ld6b_pinctrl_match,
+               .name = "uniphier-ld6b-pinctrl",
+               .of_match_table = uniphier_ld6b_pinctrl_match,
        },
 };
-module_platform_driver(ph1_ld6b_pinctrl_driver);
+module_platform_driver(uniphier_ld6b_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-LD6b pinctrl driver");
index b1f09e68f90e6aa234e244cecd3d227ad7ca8361..c306e844f58461982379ce8309317c3f97b2bd07 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-pro4-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_pro4_pins[] = {
+static const struct pinctrl_pin_desc uniphier_pro4_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "CK24O", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_4_8,
+                            0, UNIPHIER_PIN_DRV_1BIT,
                             0, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "VC27A", UNIPHIER_PIN_IECTRL_NONE,
-                            1, UNIPHIER_PIN_DRV_4_8,
+                            1, UNIPHIER_PIN_DRV_1BIT,
                             1, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "CK27AI", UNIPHIER_PIN_IECTRL_NONE,
-                            2, UNIPHIER_PIN_DRV_4_8,
+                            2, UNIPHIER_PIN_DRV_1BIT,
                             2, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "CK27AO", UNIPHIER_PIN_IECTRL_NONE,
-                            3, UNIPHIER_PIN_DRV_4_8,
+                            3, UNIPHIER_PIN_DRV_1BIT,
                             3, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "CKSEL", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_4_8,
+                            4, UNIPHIER_PIN_DRV_1BIT,
                             4, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(5, "CK27AV", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_4_8,
+                            5, UNIPHIER_PIN_DRV_1BIT,
                             5, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "AEXCKA", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_4_8,
+                            6, UNIPHIER_PIN_DRV_1BIT,
                             6, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "ASEL", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_4_8,
+                            7, UNIPHIER_PIN_DRV_1BIT,
                             7, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "ARCRESET", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "ARCUNLOCK", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "XSRST", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "XNMIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(12, "XSCIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(13, "EXTRG", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "TRCCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "TRCCTL", UNIPHIER_PIN_IECTRL_NONE,
-                            15, UNIPHIER_PIN_DRV_4_8,
+                            15, UNIPHIER_PIN_DRV_1BIT,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(16, "TRCD0", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_4_8,
+                            16, UNIPHIER_PIN_DRV_1BIT,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(17, "TRCD1", UNIPHIER_PIN_IECTRL_NONE,
-                            17, UNIPHIER_PIN_DRV_4_8,
+                            17, UNIPHIER_PIN_DRV_1BIT,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(18, "TRCD2", UNIPHIER_PIN_IECTRL_NONE,
-                            18, UNIPHIER_PIN_DRV_4_8,
+                            18, UNIPHIER_PIN_DRV_1BIT,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(19, "TRCD3", UNIPHIER_PIN_IECTRL_NONE,
-                            19, UNIPHIER_PIN_DRV_4_8,
+                            19, UNIPHIER_PIN_DRV_1BIT,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(20, "TRCD4", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_4_8,
+                            20, UNIPHIER_PIN_DRV_1BIT,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(21, "TRCD5", UNIPHIER_PIN_IECTRL_NONE,
-                            21, UNIPHIER_PIN_DRV_4_8,
+                            21, UNIPHIER_PIN_DRV_1BIT,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(22, "TRCD6", UNIPHIER_PIN_IECTRL_NONE,
-                            22, UNIPHIER_PIN_DRV_4_8,
+                            22, UNIPHIER_PIN_DRV_1BIT,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(23, "TRCD7", UNIPHIER_PIN_IECTRL_NONE,
-                            23, UNIPHIER_PIN_DRV_4_8,
+                            23, UNIPHIER_PIN_DRV_1BIT,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(24, "XECS1", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_4_8,
+                            24, UNIPHIER_PIN_DRV_1BIT,
                             24, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(25, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
-                            25, UNIPHIER_PIN_DRV_4_8,
+                            25, UNIPHIER_PIN_DRV_1BIT,
                             25, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(26, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            26, UNIPHIER_PIN_DRV_4_8,
+                            26, UNIPHIER_PIN_DRV_1BIT,
                             26, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(27, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            27, UNIPHIER_PIN_DRV_4_8,
+                            27, UNIPHIER_PIN_DRV_1BIT,
                             27, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(28, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_4_8,
+                            28, UNIPHIER_PIN_DRV_1BIT,
                             28, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(29, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            29, UNIPHIER_PIN_DRV_4_8,
+                            29, UNIPHIER_PIN_DRV_1BIT,
                             29, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(30, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(31, "ED0", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(32, "ED1", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(33, "ED2", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(34, "ED3", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(35, "ED4", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(36, "ED5", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(37, "ED6", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(38, "ED7", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(39, "BOOTSWAP", UNIPHIER_PIN_IECTRL_NONE,
-                            39, UNIPHIER_PIN_DRV_NONE,
+                            -1, UNIPHIER_PIN_DRV_NONE,
                             39, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(40, "NFD0", UNIPHIER_PIN_IECTRL_NONE,
-                            2, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             40, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(41, "NFD1", UNIPHIER_PIN_IECTRL_NONE,
-                            3, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             41, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(42, "NFD2", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             42, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(43, "NFD3", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             43, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(44, "NFD4", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_8_12_16_20,
+                            6, UNIPHIER_PIN_DRV_2BIT,
                             44, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(45, "NFD5", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_8_12_16_20,
+                            7, UNIPHIER_PIN_DRV_2BIT,
                             45, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(46, "NFD6", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            8, UNIPHIER_PIN_DRV_2BIT,
                             46, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(47, "NFD7", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_8_12_16_20,
+                            9, UNIPHIER_PIN_DRV_2BIT,
                             47, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(48, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            48, UNIPHIER_PIN_DRV_4_8,
+                            48, UNIPHIER_PIN_DRV_1BIT,
                             48, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(49, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            49, UNIPHIER_PIN_DRV_4_8,
+                            49, UNIPHIER_PIN_DRV_1BIT,
                             49, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(50, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            50, UNIPHIER_PIN_DRV_4_8,
+                            50, UNIPHIER_PIN_DRV_1BIT,
                             50, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(51, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             51, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(52, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_4_8,
+                            52, UNIPHIER_PIN_DRV_1BIT,
                             52, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(53, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            1, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             53, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(54, "NRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            54, UNIPHIER_PIN_DRV_4_8,
+                            54, UNIPHIER_PIN_DRV_1BIT,
                             54, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(55, "DMDSCLTST", UNIPHIER_PIN_IECTRL_NONE,
                             -1, UNIPHIER_PIN_DRV_NONE,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(56, "DMDSDATST", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(57, "AGCI0", 3,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(59, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(60, "AGCBS0", 5,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(62, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(63, "ANTSHORT", UNIPHIER_PIN_IECTRL_NONE,
-                            57, UNIPHIER_PIN_DRV_4_8,
+                            57, UNIPHIER_PIN_DRV_1BIT,
                             57, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(64, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            58, UNIPHIER_PIN_DRV_4_8,
+                            58, UNIPHIER_PIN_DRV_1BIT,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            59, UNIPHIER_PIN_DRV_4_8,
+                            59, UNIPHIER_PIN_DRV_1BIT,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            60, UNIPHIER_PIN_DRV_4_8,
+                            60, UNIPHIER_PIN_DRV_1BIT,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            61, UNIPHIER_PIN_DRV_4_8,
+                            61, UNIPHIER_PIN_DRV_1BIT,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            62, UNIPHIER_PIN_DRV_4_8,
+                            62, UNIPHIER_PIN_DRV_1BIT,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            63, UNIPHIER_PIN_DRV_4_8,
+                            63, UNIPHIER_PIN_DRV_1BIT,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            64, UNIPHIER_PIN_DRV_4_8,
+                            64, UNIPHIER_PIN_DRV_1BIT,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            65, UNIPHIER_PIN_DRV_4_8,
+                            65, UNIPHIER_PIN_DRV_1BIT,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            66, UNIPHIER_PIN_DRV_4_8,
+                            66, UNIPHIER_PIN_DRV_1BIT,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            67, UNIPHIER_PIN_DRV_4_8,
+                            67, UNIPHIER_PIN_DRV_1BIT,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            68, UNIPHIER_PIN_DRV_4_8,
+                            68, UNIPHIER_PIN_DRV_1BIT,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            69, UNIPHIER_PIN_DRV_4_8,
+                            69, UNIPHIER_PIN_DRV_1BIT,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            70, UNIPHIER_PIN_DRV_4_8,
+                            70, UNIPHIER_PIN_DRV_1BIT,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            71, UNIPHIER_PIN_DRV_4_8,
+                            71, UNIPHIER_PIN_DRV_1BIT,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            72, UNIPHIER_PIN_DRV_4_8,
+                            72, UNIPHIER_PIN_DRV_1BIT,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            73, UNIPHIER_PIN_DRV_4_8,
+                            73, UNIPHIER_PIN_DRV_1BIT,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            74, UNIPHIER_PIN_DRV_4_8,
+                            74, UNIPHIER_PIN_DRV_1BIT,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            75, UNIPHIER_PIN_DRV_4_8,
+                            75, UNIPHIER_PIN_DRV_1BIT,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            76, UNIPHIER_PIN_DRV_4_8,
+                            76, UNIPHIER_PIN_DRV_1BIT,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            77, UNIPHIER_PIN_DRV_4_8,
+                            77, UNIPHIER_PIN_DRV_1BIT,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            78, UNIPHIER_PIN_DRV_4_8,
+                            78, UNIPHIER_PIN_DRV_1BIT,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            79, UNIPHIER_PIN_DRV_4_8,
+                            79, UNIPHIER_PIN_DRV_1BIT,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            80, UNIPHIER_PIN_DRV_4_8,
+                            80, UNIPHIER_PIN_DRV_1BIT,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            81, UNIPHIER_PIN_DRV_4_8,
+                            81, UNIPHIER_PIN_DRV_1BIT,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            82, UNIPHIER_PIN_DRV_4_8,
+                            82, UNIPHIER_PIN_DRV_1BIT,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            83, UNIPHIER_PIN_DRV_4_8,
+                            83, UNIPHIER_PIN_DRV_1BIT,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            84, UNIPHIER_PIN_DRV_4_8,
+                            84, UNIPHIER_PIN_DRV_1BIT,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            85, UNIPHIER_PIN_DRV_4_8,
+                            85, UNIPHIER_PIN_DRV_1BIT,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "CKFEO", UNIPHIER_PIN_IECTRL_NONE,
-                            86, UNIPHIER_PIN_DRV_4_8,
+                            86, UNIPHIER_PIN_DRV_1BIT,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "XFERST", UNIPHIER_PIN_IECTRL_NONE,
-                            87, UNIPHIER_PIN_DRV_4_8,
+                            87, UNIPHIER_PIN_DRV_1BIT,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "P_FE_ON", UNIPHIER_PIN_IECTRL_NONE,
-                            88, UNIPHIER_PIN_DRV_4_8,
+                            88, UNIPHIER_PIN_DRV_1BIT,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "P_TU0_ON", UNIPHIER_PIN_IECTRL_NONE,
-                            89, UNIPHIER_PIN_DRV_4_8,
+                            89, UNIPHIER_PIN_DRV_1BIT,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "XFEIRQ0", UNIPHIER_PIN_IECTRL_NONE,
-                            90, UNIPHIER_PIN_DRV_4_8,
+                            90, UNIPHIER_PIN_DRV_1BIT,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "XFEIRQ1", UNIPHIER_PIN_IECTRL_NONE,
-                            91, UNIPHIER_PIN_DRV_4_8,
+                            91, UNIPHIER_PIN_DRV_1BIT,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "XFEIRQ2", UNIPHIER_PIN_IECTRL_NONE,
-                            92, UNIPHIER_PIN_DRV_4_8,
+                            92, UNIPHIER_PIN_DRV_1BIT,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "XFEIRQ3", UNIPHIER_PIN_IECTRL_NONE,
-                            93, UNIPHIER_PIN_DRV_4_8,
+                            93, UNIPHIER_PIN_DRV_1BIT,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "XFEIRQ4", UNIPHIER_PIN_IECTRL_NONE,
-                            94, UNIPHIER_PIN_DRV_4_8,
+                            94, UNIPHIER_PIN_DRV_1BIT,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "XFEIRQ5", UNIPHIER_PIN_IECTRL_NONE,
-                            95, UNIPHIER_PIN_DRV_4_8,
+                            95, UNIPHIER_PIN_DRV_1BIT,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "XFEIRQ6", UNIPHIER_PIN_IECTRL_NONE,
-                            96, UNIPHIER_PIN_DRV_4_8,
+                            96, UNIPHIER_PIN_DRV_1BIT,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(103, "SMTCLK0", UNIPHIER_PIN_IECTRL_NONE,
-                            97, UNIPHIER_PIN_DRV_4_8,
+                            97, UNIPHIER_PIN_DRV_1BIT,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(104, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE,
-                            98, UNIPHIER_PIN_DRV_4_8,
+                            98, UNIPHIER_PIN_DRV_1BIT,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(105, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE,
-                            99, UNIPHIER_PIN_DRV_4_8,
+                            99, UNIPHIER_PIN_DRV_1BIT,
                             99, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(106, "SMTD0", UNIPHIER_PIN_IECTRL_NONE,
-                            100, UNIPHIER_PIN_DRV_4_8,
+                            100, UNIPHIER_PIN_DRV_1BIT,
                             100, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(107, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE,
-                            101, UNIPHIER_PIN_DRV_4_8,
+                            101, UNIPHIER_PIN_DRV_1BIT,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(108, "SMTDET0", UNIPHIER_PIN_IECTRL_NONE,
-                            102, UNIPHIER_PIN_DRV_4_8,
+                            102, UNIPHIER_PIN_DRV_1BIT,
                             102, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(109, "SMTCLK1", UNIPHIER_PIN_IECTRL_NONE,
-                            103, UNIPHIER_PIN_DRV_4_8,
+                            103, UNIPHIER_PIN_DRV_1BIT,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(110, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE,
-                            104, UNIPHIER_PIN_DRV_4_8,
+                            104, UNIPHIER_PIN_DRV_1BIT,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(111, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE,
-                            105, UNIPHIER_PIN_DRV_4_8,
+                            105, UNIPHIER_PIN_DRV_1BIT,
                             105, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(112, "SMTD1", UNIPHIER_PIN_IECTRL_NONE,
-                            106, UNIPHIER_PIN_DRV_4_8,
+                            106, UNIPHIER_PIN_DRV_1BIT,
                             106, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(113, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE,
-                            107, UNIPHIER_PIN_DRV_4_8,
+                            107, UNIPHIER_PIN_DRV_1BIT,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(114, "SMTDET1", UNIPHIER_PIN_IECTRL_NONE,
-                            108, UNIPHIER_PIN_DRV_4_8,
+                            108, UNIPHIER_PIN_DRV_1BIT,
                             108, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "XINTM", UNIPHIER_PIN_IECTRL_NONE,
-                            109, UNIPHIER_PIN_DRV_4_8,
+                            109, UNIPHIER_PIN_DRV_1BIT,
                             109, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "SCLKM", UNIPHIER_PIN_IECTRL_NONE,
-                            110, UNIPHIER_PIN_DRV_4_8,
+                            110, UNIPHIER_PIN_DRV_1BIT,
                             110, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(117, "SBMTP", UNIPHIER_PIN_IECTRL_NONE,
-                            111, UNIPHIER_PIN_DRV_4_8,
+                            111, UNIPHIER_PIN_DRV_1BIT,
                             111, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(118, "SBPTM", UNIPHIER_PIN_IECTRL_NONE,
-                            112, UNIPHIER_PIN_DRV_4_8,
+                            112, UNIPHIER_PIN_DRV_1BIT,
                             112, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(119, "XMPREQ", UNIPHIER_PIN_IECTRL_NONE,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(120, "XINTP", UNIPHIER_PIN_IECTRL_NONE,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(121, "LPST", UNIPHIER_PIN_IECTRL_NONE,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "SDBOOT", UNIPHIER_PIN_IECTRL_NONE,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(123, "BFAIL", UNIPHIER_PIN_IECTRL_NONE,
-                            117, UNIPHIER_PIN_DRV_4_8,
+                            117, UNIPHIER_PIN_DRV_1BIT,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "XFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            118, UNIPHIER_PIN_DRV_4_8,
+                            118, UNIPHIER_PIN_DRV_1BIT,
                             118, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(125, "RF_COM_RDY", UNIPHIER_PIN_IECTRL_NONE,
-                            119, UNIPHIER_PIN_DRV_4_8,
+                            119, UNIPHIER_PIN_DRV_1BIT,
                             119, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(126, "XDIAG0", UNIPHIER_PIN_IECTRL_NONE,
-                            120, UNIPHIER_PIN_DRV_4_8,
+                            120, UNIPHIER_PIN_DRV_1BIT,
                             120, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(127, "RXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            121, UNIPHIER_PIN_DRV_4_8,
+                            121, UNIPHIER_PIN_DRV_1BIT,
                             121, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(128, "TXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            122, UNIPHIER_PIN_DRV_4_8,
+                            122, UNIPHIER_PIN_DRV_1BIT,
                             122, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(129, "RXD1", UNIPHIER_PIN_IECTRL_NONE,
-                            123, UNIPHIER_PIN_DRV_4_8,
+                            123, UNIPHIER_PIN_DRV_1BIT,
                             123, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(130, "TXD1", UNIPHIER_PIN_IECTRL_NONE,
-                            124, UNIPHIER_PIN_DRV_4_8,
+                            124, UNIPHIER_PIN_DRV_1BIT,
                             124, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(131, "RXD2", UNIPHIER_PIN_IECTRL_NONE,
-                            125, UNIPHIER_PIN_DRV_4_8,
+                            125, UNIPHIER_PIN_DRV_1BIT,
                             125, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(132, "TXD2", UNIPHIER_PIN_IECTRL_NONE,
-                            126, UNIPHIER_PIN_DRV_4_8,
+                            126, UNIPHIER_PIN_DRV_1BIT,
                             126, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(133, "SS0CS", UNIPHIER_PIN_IECTRL_NONE,
-                            127, UNIPHIER_PIN_DRV_4_8,
+                            127, UNIPHIER_PIN_DRV_1BIT,
                             127, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(134, "SS0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            128, UNIPHIER_PIN_DRV_4_8,
+                            128, UNIPHIER_PIN_DRV_1BIT,
                             128, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(135, "SS0DO", UNIPHIER_PIN_IECTRL_NONE,
-                            129, UNIPHIER_PIN_DRV_4_8,
+                            129, UNIPHIER_PIN_DRV_1BIT,
                             129, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(136, "SS0DI", UNIPHIER_PIN_IECTRL_NONE,
-                            130, UNIPHIER_PIN_DRV_4_8,
+                            130, UNIPHIER_PIN_DRV_1BIT,
                             130, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(137, "MS0CS0", UNIPHIER_PIN_IECTRL_NONE,
-                            131, UNIPHIER_PIN_DRV_4_8,
+                            131, UNIPHIER_PIN_DRV_1BIT,
                             131, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(138, "MS0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            132, UNIPHIER_PIN_DRV_4_8,
+                            132, UNIPHIER_PIN_DRV_1BIT,
                             132, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(139, "MS0DI", UNIPHIER_PIN_IECTRL_NONE,
-                            133, UNIPHIER_PIN_DRV_4_8,
+                            133, UNIPHIER_PIN_DRV_1BIT,
                             133, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(140, "MS0DO", UNIPHIER_PIN_IECTRL_NONE,
-                            134, UNIPHIER_PIN_DRV_4_8,
+                            134, UNIPHIER_PIN_DRV_1BIT,
                             134, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(141, "XMDMRST", UNIPHIER_PIN_IECTRL_NONE,
-                            135, UNIPHIER_PIN_DRV_4_8,
+                            135, UNIPHIER_PIN_DRV_1BIT,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(143, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(144, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(145, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(146, "SCL2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(147, "SDA2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(148, "SCL3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(149, "SDA3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(150, "SD0DAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            12, UNIPHIER_PIN_DRV_2BIT,
                             136, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(151, "SD0DAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_8_12_16_20,
+                            13, UNIPHIER_PIN_DRV_2BIT,
                             137, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(152, "SD0DAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_8_12_16_20,
+                            14, UNIPHIER_PIN_DRV_2BIT,
                             138, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(153, "SD0DAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            15, UNIPHIER_PIN_DRV_8_12_16_20,
+                            15, UNIPHIER_PIN_DRV_2BIT,
                             139, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(154, "SD0CMD", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_8_12_16_20,
+                            11, UNIPHIER_PIN_DRV_2BIT,
                             141, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(155, "SD0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_8_12_16_20,
+                            10, UNIPHIER_PIN_DRV_2BIT,
                             140, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(156, "SD0CD", UNIPHIER_PIN_IECTRL_NONE,
-                            142, UNIPHIER_PIN_DRV_4_8,
+                            142, UNIPHIER_PIN_DRV_1BIT,
                             142, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(157, "SD0WP", UNIPHIER_PIN_IECTRL_NONE,
-                            143, UNIPHIER_PIN_DRV_4_8,
+                            143, UNIPHIER_PIN_DRV_1BIT,
                             143, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(158, "SD0VTCG", UNIPHIER_PIN_IECTRL_NONE,
-                            144, UNIPHIER_PIN_DRV_4_8,
+                            144, UNIPHIER_PIN_DRV_1BIT,
                             144, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(159, "CK25O", UNIPHIER_PIN_IECTRL_NONE,
-                            145, UNIPHIER_PIN_DRV_4_8,
+                            145, UNIPHIER_PIN_DRV_1BIT,
                             145, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(160, "RGMII_TXCLK", 6,
-                            146, UNIPHIER_PIN_DRV_4_8,
+                            146, UNIPHIER_PIN_DRV_1BIT,
                             146, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "RGMII_TXD0", 6,
-                            147, UNIPHIER_PIN_DRV_4_8,
+                            147, UNIPHIER_PIN_DRV_1BIT,
                             147, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "RGMII_TXD1", 6,
-                            148, UNIPHIER_PIN_DRV_4_8,
+                            148, UNIPHIER_PIN_DRV_1BIT,
                             148, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "RGMII_TXD2", 6,
-                            149, UNIPHIER_PIN_DRV_4_8,
+                            149, UNIPHIER_PIN_DRV_1BIT,
                             149, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(164, "RGMII_TXD3", 6,
-                            150, UNIPHIER_PIN_DRV_4_8,
+                            150, UNIPHIER_PIN_DRV_1BIT,
                             150, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(165, "RGMII_TXCTL", 6,
-                            151, UNIPHIER_PIN_DRV_4_8,
+                            151, UNIPHIER_PIN_DRV_1BIT,
                             151, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(166, "MII_TXER", UNIPHIER_PIN_IECTRL_NONE,
-                            152, UNIPHIER_PIN_DRV_4_8,
+                            152, UNIPHIER_PIN_DRV_1BIT,
                             152, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(167, "RGMII_RXCLK", 6,
-                            153, UNIPHIER_PIN_DRV_4_8,
+                            153, UNIPHIER_PIN_DRV_1BIT,
                             153, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(168, "RGMII_RXD0", 6,
-                            154, UNIPHIER_PIN_DRV_4_8,
+                            154, UNIPHIER_PIN_DRV_1BIT,
                             154, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(169, "RGMII_RXD1", 6,
-                            155, UNIPHIER_PIN_DRV_4_8,
+                            155, UNIPHIER_PIN_DRV_1BIT,
                             155, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(170, "RGMII_RXD2", 6,
-                            156, UNIPHIER_PIN_DRV_4_8,
+                            156, UNIPHIER_PIN_DRV_1BIT,
                             156, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(171, "RGMII_RXD3", 6,
-                            157, UNIPHIER_PIN_DRV_4_8,
+                            157, UNIPHIER_PIN_DRV_1BIT,
                             157, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(172, "RGMII_RXCTL", 6,
-                            158, UNIPHIER_PIN_DRV_4_8,
+                            158, UNIPHIER_PIN_DRV_1BIT,
                             158, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(173, "MII_RXER", 6,
-                            159, UNIPHIER_PIN_DRV_4_8,
+                            159, UNIPHIER_PIN_DRV_1BIT,
                             159, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(174, "MII_CRS", 6,
-                            160, UNIPHIER_PIN_DRV_4_8,
+                            160, UNIPHIER_PIN_DRV_1BIT,
                             160, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(175, "MII_COL", 6,
-                            161, UNIPHIER_PIN_DRV_4_8,
+                            161, UNIPHIER_PIN_DRV_1BIT,
                             161, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(176, "MDC", 6,
-                            162, UNIPHIER_PIN_DRV_4_8,
+                            162, UNIPHIER_PIN_DRV_1BIT,
                             162, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(177, "MDIO", 6,
-                            163, UNIPHIER_PIN_DRV_4_8,
+                            163, UNIPHIER_PIN_DRV_1BIT,
                             163, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(178, "MDIO_INTL", 6,
-                            164, UNIPHIER_PIN_DRV_4_8,
+                            164, UNIPHIER_PIN_DRV_1BIT,
                             164, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(179, "XETH_RST", 6,
-                            165, UNIPHIER_PIN_DRV_4_8,
+                            165, UNIPHIER_PIN_DRV_1BIT,
                             165, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(180, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            166, UNIPHIER_PIN_DRV_4_8,
+                            166, UNIPHIER_PIN_DRV_1BIT,
                             166, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(181, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
-                            167, UNIPHIER_PIN_DRV_4_8,
+                            167, UNIPHIER_PIN_DRV_1BIT,
                             167, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(182, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            168, UNIPHIER_PIN_DRV_4_8,
+                            168, UNIPHIER_PIN_DRV_1BIT,
                             168, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(183, "USB1OD", UNIPHIER_PIN_IECTRL_NONE,
-                            169, UNIPHIER_PIN_DRV_4_8,
+                            169, UNIPHIER_PIN_DRV_1BIT,
                             169, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(184, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            170, UNIPHIER_PIN_DRV_4_8,
+                            170, UNIPHIER_PIN_DRV_1BIT,
                             170, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(185, "USB2OD", UNIPHIER_PIN_IECTRL_NONE,
-                            171, UNIPHIER_PIN_DRV_4_8,
+                            171, UNIPHIER_PIN_DRV_1BIT,
                             171, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(186, "USB2ID", UNIPHIER_PIN_IECTRL_NONE,
-                            172, UNIPHIER_PIN_DRV_4_8,
+                            172, UNIPHIER_PIN_DRV_1BIT,
                             172, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(187, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            173, UNIPHIER_PIN_DRV_4_8,
+                            173, UNIPHIER_PIN_DRV_1BIT,
                             173, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(188, "USB3OD", UNIPHIER_PIN_IECTRL_NONE,
-                            174, UNIPHIER_PIN_DRV_4_8,
+                            174, UNIPHIER_PIN_DRV_1BIT,
                             174, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(189, "LINKCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            175, UNIPHIER_PIN_DRV_4_8,
+                            175, UNIPHIER_PIN_DRV_1BIT,
                             175, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(190, "LINKREQ", UNIPHIER_PIN_IECTRL_NONE,
-                            176, UNIPHIER_PIN_DRV_4_8,
+                            176, UNIPHIER_PIN_DRV_1BIT,
                             176, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(191, "LINKCTL0", UNIPHIER_PIN_IECTRL_NONE,
-                            177, UNIPHIER_PIN_DRV_4_8,
+                            177, UNIPHIER_PIN_DRV_1BIT,
                             177, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(192, "LINKCTL1", UNIPHIER_PIN_IECTRL_NONE,
-                            178, UNIPHIER_PIN_DRV_4_8,
+                            178, UNIPHIER_PIN_DRV_1BIT,
                             178, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(193, "LINKDT0", UNIPHIER_PIN_IECTRL_NONE,
-                            179, UNIPHIER_PIN_DRV_4_8,
+                            179, UNIPHIER_PIN_DRV_1BIT,
                             179, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(194, "LINKDT1", UNIPHIER_PIN_IECTRL_NONE,
-                            180, UNIPHIER_PIN_DRV_4_8,
+                            180, UNIPHIER_PIN_DRV_1BIT,
                             180, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(195, "LINKDT2", UNIPHIER_PIN_IECTRL_NONE,
-                            181, UNIPHIER_PIN_DRV_4_8,
+                            181, UNIPHIER_PIN_DRV_1BIT,
                             181, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(196, "LINKDT3", UNIPHIER_PIN_IECTRL_NONE,
-                            182, UNIPHIER_PIN_DRV_4_8,
+                            182, UNIPHIER_PIN_DRV_1BIT,
                             182, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(197, "LINKDT4", UNIPHIER_PIN_IECTRL_NONE,
-                            183, UNIPHIER_PIN_DRV_4_8,
+                            183, UNIPHIER_PIN_DRV_1BIT,
                             183, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(198, "LINKDT5", UNIPHIER_PIN_IECTRL_NONE,
-                            184, UNIPHIER_PIN_DRV_4_8,
+                            184, UNIPHIER_PIN_DRV_1BIT,
                             184, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(199, "LINKDT6", UNIPHIER_PIN_IECTRL_NONE,
-                            185, UNIPHIER_PIN_DRV_4_8,
+                            185, UNIPHIER_PIN_DRV_1BIT,
                             185, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(200, "LINKDT7", UNIPHIER_PIN_IECTRL_NONE,
-                            186, UNIPHIER_PIN_DRV_4_8,
+                            186, UNIPHIER_PIN_DRV_1BIT,
                             186, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(201, "CKDVO", UNIPHIER_PIN_IECTRL_NONE,
-                            187, UNIPHIER_PIN_DRV_4_8,
+                            187, UNIPHIER_PIN_DRV_1BIT,
                             187, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(202, "PHY_PD", UNIPHIER_PIN_IECTRL_NONE,
-                            188, UNIPHIER_PIN_DRV_4_8,
+                            188, UNIPHIER_PIN_DRV_1BIT,
                             188, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(203, "X1394_RST", UNIPHIER_PIN_IECTRL_NONE,
-                            189, UNIPHIER_PIN_DRV_4_8,
+                            189, UNIPHIER_PIN_DRV_1BIT,
                             189, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(204, "VOUT_MUTE_L", UNIPHIER_PIN_IECTRL_NONE,
-                            190, UNIPHIER_PIN_DRV_4_8,
+                            190, UNIPHIER_PIN_DRV_1BIT,
                             190, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(205, "CLK54O", UNIPHIER_PIN_IECTRL_NONE,
-                            191, UNIPHIER_PIN_DRV_4_8,
+                            191, UNIPHIER_PIN_DRV_1BIT,
                             191, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(206, "CLK54I", UNIPHIER_PIN_IECTRL_NONE,
-                            192, UNIPHIER_PIN_DRV_NONE,
+                            -1, UNIPHIER_PIN_DRV_NONE,
                             192, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(207, "YIN0", UNIPHIER_PIN_IECTRL_NONE,
-                            193, UNIPHIER_PIN_DRV_4_8,
+                            193, UNIPHIER_PIN_DRV_1BIT,
                             193, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(208, "YIN1", UNIPHIER_PIN_IECTRL_NONE,
-                            194, UNIPHIER_PIN_DRV_4_8,
+                            194, UNIPHIER_PIN_DRV_1BIT,
                             194, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(209, "YIN2", UNIPHIER_PIN_IECTRL_NONE,
-                            195, UNIPHIER_PIN_DRV_4_8,
+                            195, UNIPHIER_PIN_DRV_1BIT,
                             195, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(210, "YIN3", UNIPHIER_PIN_IECTRL_NONE,
-                            196, UNIPHIER_PIN_DRV_4_8,
+                            196, UNIPHIER_PIN_DRV_1BIT,
                             196, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(211, "YIN4", UNIPHIER_PIN_IECTRL_NONE,
-                            197, UNIPHIER_PIN_DRV_4_8,
+                            197, UNIPHIER_PIN_DRV_1BIT,
                             197, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(212, "YIN5", UNIPHIER_PIN_IECTRL_NONE,
-                            198, UNIPHIER_PIN_DRV_4_8,
+                            198, UNIPHIER_PIN_DRV_1BIT,
                             198, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(213, "CIN0", UNIPHIER_PIN_IECTRL_NONE,
-                            199, UNIPHIER_PIN_DRV_4_8,
+                            199, UNIPHIER_PIN_DRV_1BIT,
                             199, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(214, "CIN1", UNIPHIER_PIN_IECTRL_NONE,
-                            200, UNIPHIER_PIN_DRV_4_8,
+                            200, UNIPHIER_PIN_DRV_1BIT,
                             200, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(215, "CIN2", UNIPHIER_PIN_IECTRL_NONE,
-                            201, UNIPHIER_PIN_DRV_4_8,
+                            201, UNIPHIER_PIN_DRV_1BIT,
                             201, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(216, "CIN3", UNIPHIER_PIN_IECTRL_NONE,
-                            202, UNIPHIER_PIN_DRV_4_8,
+                            202, UNIPHIER_PIN_DRV_1BIT,
                             202, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(217, "CIN4", UNIPHIER_PIN_IECTRL_NONE,
-                            203, UNIPHIER_PIN_DRV_4_8,
+                            203, UNIPHIER_PIN_DRV_1BIT,
                             203, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(218, "CIN5", UNIPHIER_PIN_IECTRL_NONE,
-                            204, UNIPHIER_PIN_DRV_4_8,
+                            204, UNIPHIER_PIN_DRV_1BIT,
                             204, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(219, "GCP", UNIPHIER_PIN_IECTRL_NONE,
-                            205, UNIPHIER_PIN_DRV_4_8,
+                            205, UNIPHIER_PIN_DRV_1BIT,
                             205, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(220, "ADFLG", UNIPHIER_PIN_IECTRL_NONE,
-                            206, UNIPHIER_PIN_DRV_4_8,
+                            206, UNIPHIER_PIN_DRV_1BIT,
                             206, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(221, "CK27AIOF", UNIPHIER_PIN_IECTRL_NONE,
-                            207, UNIPHIER_PIN_DRV_4_8,
+                            207, UNIPHIER_PIN_DRV_1BIT,
                             207, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(222, "DACOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            208, UNIPHIER_PIN_DRV_4_8,
+                            208, UNIPHIER_PIN_DRV_1BIT,
                             208, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(223, "DAFLG", UNIPHIER_PIN_IECTRL_NONE,
-                            209, UNIPHIER_PIN_DRV_4_8,
+                            209, UNIPHIER_PIN_DRV_1BIT,
                             209, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(224, "VBIH", UNIPHIER_PIN_IECTRL_NONE,
-                            210, UNIPHIER_PIN_DRV_4_8,
+                            210, UNIPHIER_PIN_DRV_1BIT,
                             210, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(225, "VBIL", UNIPHIER_PIN_IECTRL_NONE,
-                            211, UNIPHIER_PIN_DRV_4_8,
+                            211, UNIPHIER_PIN_DRV_1BIT,
                             211, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(226, "XSUB_RST", UNIPHIER_PIN_IECTRL_NONE,
-                            212, UNIPHIER_PIN_DRV_4_8,
+                            212, UNIPHIER_PIN_DRV_1BIT,
                             212, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(227, "XADC_PD", UNIPHIER_PIN_IECTRL_NONE,
-                            213, UNIPHIER_PIN_DRV_4_8,
+                            213, UNIPHIER_PIN_DRV_1BIT,
                             213, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(228, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            214, UNIPHIER_PIN_DRV_4_8,
+                            214, UNIPHIER_PIN_DRV_1BIT,
                             214, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(229, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            215, UNIPHIER_PIN_DRV_4_8,
+                            215, UNIPHIER_PIN_DRV_1BIT,
                             215, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(230, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            216, UNIPHIER_PIN_DRV_4_8,
+                            216, UNIPHIER_PIN_DRV_1BIT,
                             216, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(231, "AI1DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            217, UNIPHIER_PIN_DRV_4_8,
+                            217, UNIPHIER_PIN_DRV_1BIT,
                             217, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(232, "CK27HD", UNIPHIER_PIN_IECTRL_NONE,
-                            218, UNIPHIER_PIN_DRV_4_8,
+                            218, UNIPHIER_PIN_DRV_1BIT,
                             218, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(233, "XHD_RST", UNIPHIER_PIN_IECTRL_NONE,
-                            219, UNIPHIER_PIN_DRV_4_8,
+                            219, UNIPHIER_PIN_DRV_1BIT,
                             219, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(234, "INTHD", UNIPHIER_PIN_IECTRL_NONE,
-                            220, UNIPHIER_PIN_DRV_4_8,
+                            220, UNIPHIER_PIN_DRV_1BIT,
                             220, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(235, "VO1HDCK", UNIPHIER_PIN_IECTRL_NONE,
-                            221, UNIPHIER_PIN_DRV_4_8,
+                            221, UNIPHIER_PIN_DRV_1BIT,
                             221, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(236, "VO1HSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            222, UNIPHIER_PIN_DRV_4_8,
+                            222, UNIPHIER_PIN_DRV_1BIT,
                             222, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(237, "VO1VSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            223, UNIPHIER_PIN_DRV_4_8,
+                            223, UNIPHIER_PIN_DRV_1BIT,
                             223, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(238, "VO1DE", UNIPHIER_PIN_IECTRL_NONE,
-                            224, UNIPHIER_PIN_DRV_4_8,
+                            224, UNIPHIER_PIN_DRV_1BIT,
                             224, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(239, "VO1Y0", UNIPHIER_PIN_IECTRL_NONE,
-                            225, UNIPHIER_PIN_DRV_4_8,
+                            225, UNIPHIER_PIN_DRV_1BIT,
                             225, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(240, "VO1Y1", UNIPHIER_PIN_IECTRL_NONE,
-                            226, UNIPHIER_PIN_DRV_4_8,
+                            226, UNIPHIER_PIN_DRV_1BIT,
                             226, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(241, "VO1Y2", UNIPHIER_PIN_IECTRL_NONE,
-                            227, UNIPHIER_PIN_DRV_4_8,
+                            227, UNIPHIER_PIN_DRV_1BIT,
                             227, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(242, "VO1Y3", UNIPHIER_PIN_IECTRL_NONE,
-                            228, UNIPHIER_PIN_DRV_4_8,
+                            228, UNIPHIER_PIN_DRV_1BIT,
                             228, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(243, "VO1Y4", UNIPHIER_PIN_IECTRL_NONE,
-                            229, UNIPHIER_PIN_DRV_4_8,
+                            229, UNIPHIER_PIN_DRV_1BIT,
                             229, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(244, "VO1Y5", UNIPHIER_PIN_IECTRL_NONE,
-                            230, UNIPHIER_PIN_DRV_4_8,
+                            230, UNIPHIER_PIN_DRV_1BIT,
                             230, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(245, "VO1Y6", UNIPHIER_PIN_IECTRL_NONE,
-                            231, UNIPHIER_PIN_DRV_4_8,
+                            231, UNIPHIER_PIN_DRV_1BIT,
                             231, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(246, "VO1Y7", UNIPHIER_PIN_IECTRL_NONE,
-                            232, UNIPHIER_PIN_DRV_4_8,
+                            232, UNIPHIER_PIN_DRV_1BIT,
                             232, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(247, "VO1Y8", UNIPHIER_PIN_IECTRL_NONE,
-                            233, UNIPHIER_PIN_DRV_4_8,
+                            233, UNIPHIER_PIN_DRV_1BIT,
                             233, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(248, "VO1Y9", UNIPHIER_PIN_IECTRL_NONE,
-                            234, UNIPHIER_PIN_DRV_4_8,
+                            234, UNIPHIER_PIN_DRV_1BIT,
                             234, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(249, "VO1Y10", UNIPHIER_PIN_IECTRL_NONE,
-                            235, UNIPHIER_PIN_DRV_4_8,
+                            235, UNIPHIER_PIN_DRV_1BIT,
                             235, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(250, "VO1Y11", UNIPHIER_PIN_IECTRL_NONE,
-                            236, UNIPHIER_PIN_DRV_4_8,
+                            236, UNIPHIER_PIN_DRV_1BIT,
                             236, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(251, "VO1CB0", UNIPHIER_PIN_IECTRL_NONE,
-                            237, UNIPHIER_PIN_DRV_4_8,
+                            237, UNIPHIER_PIN_DRV_1BIT,
                             237, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(252, "VO1CB1", UNIPHIER_PIN_IECTRL_NONE,
-                            238, UNIPHIER_PIN_DRV_4_8,
+                            238, UNIPHIER_PIN_DRV_1BIT,
                             238, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(253, "VO1CB2", UNIPHIER_PIN_IECTRL_NONE,
-                            239, UNIPHIER_PIN_DRV_4_8,
+                            239, UNIPHIER_PIN_DRV_1BIT,
                             239, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(254, "VO1CB3", UNIPHIER_PIN_IECTRL_NONE,
-                            240, UNIPHIER_PIN_DRV_4_8,
+                            240, UNIPHIER_PIN_DRV_1BIT,
                             240, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(255, "VO1CB4", UNIPHIER_PIN_IECTRL_NONE,
-                            241, UNIPHIER_PIN_DRV_4_8,
+                            241, UNIPHIER_PIN_DRV_1BIT,
                             241, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(256, "VO1CB5", UNIPHIER_PIN_IECTRL_NONE,
-                            242, UNIPHIER_PIN_DRV_4_8,
+                            242, UNIPHIER_PIN_DRV_1BIT,
                             242, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(257, "VO1CB6", UNIPHIER_PIN_IECTRL_NONE,
-                            243, UNIPHIER_PIN_DRV_4_8,
+                            243, UNIPHIER_PIN_DRV_1BIT,
                             243, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(258, "VO1CB7", UNIPHIER_PIN_IECTRL_NONE,
-                            244, UNIPHIER_PIN_DRV_4_8,
+                            244, UNIPHIER_PIN_DRV_1BIT,
                             244, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(259, "VO1CB8", UNIPHIER_PIN_IECTRL_NONE,
-                            245, UNIPHIER_PIN_DRV_4_8,
+                            245, UNIPHIER_PIN_DRV_1BIT,
                             245, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(260, "VO1CB9", UNIPHIER_PIN_IECTRL_NONE,
-                            246, UNIPHIER_PIN_DRV_4_8,
+                            246, UNIPHIER_PIN_DRV_1BIT,
                             246, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(261, "VO1CB10", UNIPHIER_PIN_IECTRL_NONE,
-                            247, UNIPHIER_PIN_DRV_4_8,
+                            247, UNIPHIER_PIN_DRV_1BIT,
                             247, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(262, "VO1CB11", UNIPHIER_PIN_IECTRL_NONE,
-                            248, UNIPHIER_PIN_DRV_4_8,
+                            248, UNIPHIER_PIN_DRV_1BIT,
                             248, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(263, "VO1CR0", UNIPHIER_PIN_IECTRL_NONE,
-                            249, UNIPHIER_PIN_DRV_4_8,
+                            249, UNIPHIER_PIN_DRV_1BIT,
                             249, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(264, "VO1CR1", UNIPHIER_PIN_IECTRL_NONE,
-                            250, UNIPHIER_PIN_DRV_4_8,
+                            250, UNIPHIER_PIN_DRV_1BIT,
                             250, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(265, "VO1CR2", UNIPHIER_PIN_IECTRL_NONE,
-                            251, UNIPHIER_PIN_DRV_4_8,
+                            251, UNIPHIER_PIN_DRV_1BIT,
                             251, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(266, "VO1CR3", UNIPHIER_PIN_IECTRL_NONE,
-                            252, UNIPHIER_PIN_DRV_4_8,
+                            252, UNIPHIER_PIN_DRV_1BIT,
                             252, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(267, "VO1CR4", UNIPHIER_PIN_IECTRL_NONE,
-                            253, UNIPHIER_PIN_DRV_4_8,
+                            253, UNIPHIER_PIN_DRV_1BIT,
                             253, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(268, "VO1CR5", UNIPHIER_PIN_IECTRL_NONE,
-                            254, UNIPHIER_PIN_DRV_4_8,
+                            254, UNIPHIER_PIN_DRV_1BIT,
                             254, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(269, "VO1CR6", UNIPHIER_PIN_IECTRL_NONE,
-                            255, UNIPHIER_PIN_DRV_4_8,
+                            255, UNIPHIER_PIN_DRV_1BIT,
                             255, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(270, "VO1CR7", UNIPHIER_PIN_IECTRL_NONE,
-                            256, UNIPHIER_PIN_DRV_4_8,
+                            256, UNIPHIER_PIN_DRV_1BIT,
                             256, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(271, "VO1CR8", UNIPHIER_PIN_IECTRL_NONE,
-                            257, UNIPHIER_PIN_DRV_4_8,
+                            257, UNIPHIER_PIN_DRV_1BIT,
                             257, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(272, "VO1CR9", UNIPHIER_PIN_IECTRL_NONE,
-                            258, UNIPHIER_PIN_DRV_4_8,
+                            258, UNIPHIER_PIN_DRV_1BIT,
                             258, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(273, "VO1CR10", UNIPHIER_PIN_IECTRL_NONE,
-                            259, UNIPHIER_PIN_DRV_4_8,
+                            259, UNIPHIER_PIN_DRV_1BIT,
                             259, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(274, "VO1CR11", UNIPHIER_PIN_IECTRL_NONE,
-                            260, UNIPHIER_PIN_DRV_4_8,
+                            260, UNIPHIER_PIN_DRV_1BIT,
                             260, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(275, "VO1EX0", UNIPHIER_PIN_IECTRL_NONE,
-                            261, UNIPHIER_PIN_DRV_4_8,
+                            261, UNIPHIER_PIN_DRV_1BIT,
                             261, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(276, "VO1EX1", UNIPHIER_PIN_IECTRL_NONE,
-                            262, UNIPHIER_PIN_DRV_4_8,
+                            262, UNIPHIER_PIN_DRV_1BIT,
                             262, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(277, "VO1EX2", UNIPHIER_PIN_IECTRL_NONE,
-                            263, UNIPHIER_PIN_DRV_4_8,
+                            263, UNIPHIER_PIN_DRV_1BIT,
                             263, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(278, "VO1EX3", UNIPHIER_PIN_IECTRL_NONE,
-                            264, UNIPHIER_PIN_DRV_4_8,
+                            264, UNIPHIER_PIN_DRV_1BIT,
                             264, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(279, "VEXCKA", UNIPHIER_PIN_IECTRL_NONE,
-                            265, UNIPHIER_PIN_DRV_4_8,
+                            265, UNIPHIER_PIN_DRV_1BIT,
                             265, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(280, "VSEL0", UNIPHIER_PIN_IECTRL_NONE,
-                            266, UNIPHIER_PIN_DRV_4_8,
+                            266, UNIPHIER_PIN_DRV_1BIT,
                             266, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(281, "VSEL1", UNIPHIER_PIN_IECTRL_NONE,
-                            267, UNIPHIER_PIN_DRV_4_8,
+                            267, UNIPHIER_PIN_DRV_1BIT,
                             267, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(282, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            268, UNIPHIER_PIN_DRV_4_8,
+                            268, UNIPHIER_PIN_DRV_1BIT,
                             268, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(283, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            269, UNIPHIER_PIN_DRV_4_8,
+                            269, UNIPHIER_PIN_DRV_1BIT,
                             269, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(284, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            270, UNIPHIER_PIN_DRV_4_8,
+                            270, UNIPHIER_PIN_DRV_1BIT,
                             270, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(285, "AO1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            271, UNIPHIER_PIN_DRV_4_8,
+                            271, UNIPHIER_PIN_DRV_1BIT,
                             271, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(286, "AO1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            272, UNIPHIER_PIN_DRV_4_8,
+                            272, UNIPHIER_PIN_DRV_1BIT,
                             272, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(287, "AO1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            273, UNIPHIER_PIN_DRV_4_8,
+                            273, UNIPHIER_PIN_DRV_1BIT,
                             273, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(288, "AO1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            274, UNIPHIER_PIN_DRV_4_8,
+                            274, UNIPHIER_PIN_DRV_1BIT,
                             274, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(289, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            275, UNIPHIER_PIN_DRV_4_8,
+                            275, UNIPHIER_PIN_DRV_1BIT,
                             275, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(290, "XDAC_PD", UNIPHIER_PIN_IECTRL_NONE,
-                            276, UNIPHIER_PIN_DRV_4_8,
+                            276, UNIPHIER_PIN_DRV_1BIT,
                             276, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(291, "EX_A_MUTE", UNIPHIER_PIN_IECTRL_NONE,
-                            277, UNIPHIER_PIN_DRV_4_8,
+                            277, UNIPHIER_PIN_DRV_1BIT,
                             277, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(292, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            278, UNIPHIER_PIN_DRV_4_8,
+                            278, UNIPHIER_PIN_DRV_1BIT,
                             278, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(293, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            279, UNIPHIER_PIN_DRV_4_8,
+                            279, UNIPHIER_PIN_DRV_1BIT,
                             279, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(294, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            280, UNIPHIER_PIN_DRV_4_8,
+                            280, UNIPHIER_PIN_DRV_1BIT,
                             280, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(295, "AO2DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            281, UNIPHIER_PIN_DRV_4_8,
+                            281, UNIPHIER_PIN_DRV_1BIT,
                             281, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(296, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            282, UNIPHIER_PIN_DRV_4_8,
+                            282, UNIPHIER_PIN_DRV_1BIT,
                             282, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(297, "HTHPD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(298, "HTSCL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(299, "HTSDA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(300, "PORT00", UNIPHIER_PIN_IECTRL_NONE,
-                            284, UNIPHIER_PIN_DRV_4_8,
+                            284, UNIPHIER_PIN_DRV_1BIT,
                             284, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(301, "PORT01", UNIPHIER_PIN_IECTRL_NONE,
-                            285, UNIPHIER_PIN_DRV_4_8,
+                            285, UNIPHIER_PIN_DRV_1BIT,
                             285, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(302, "PORT02", UNIPHIER_PIN_IECTRL_NONE,
-                            286, UNIPHIER_PIN_DRV_4_8,
+                            286, UNIPHIER_PIN_DRV_1BIT,
                             286, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(303, "PORT03", UNIPHIER_PIN_IECTRL_NONE,
-                            287, UNIPHIER_PIN_DRV_4_8,
+                            287, UNIPHIER_PIN_DRV_1BIT,
                             287, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(304, "PORT04", UNIPHIER_PIN_IECTRL_NONE,
-                            288, UNIPHIER_PIN_DRV_4_8,
+                            288, UNIPHIER_PIN_DRV_1BIT,
                             288, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(305, "PORT05", UNIPHIER_PIN_IECTRL_NONE,
-                            289, UNIPHIER_PIN_DRV_4_8,
+                            289, UNIPHIER_PIN_DRV_1BIT,
                             289, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(306, "PORT06", UNIPHIER_PIN_IECTRL_NONE,
-                            290, UNIPHIER_PIN_DRV_4_8,
+                            290, UNIPHIER_PIN_DRV_1BIT,
                             290, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(307, "PORT07", UNIPHIER_PIN_IECTRL_NONE,
-                            291, UNIPHIER_PIN_DRV_4_8,
+                            291, UNIPHIER_PIN_DRV_1BIT,
                             291, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(308, "PORT10", UNIPHIER_PIN_IECTRL_NONE,
-                            292, UNIPHIER_PIN_DRV_4_8,
+                            292, UNIPHIER_PIN_DRV_1BIT,
                             292, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(309, "PORT11", UNIPHIER_PIN_IECTRL_NONE,
-                            293, UNIPHIER_PIN_DRV_4_8,
+                            293, UNIPHIER_PIN_DRV_1BIT,
                             293, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(310, "PORT12", UNIPHIER_PIN_IECTRL_NONE,
-                            294, UNIPHIER_PIN_DRV_4_8,
+                            294, UNIPHIER_PIN_DRV_1BIT,
                             294, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(311, "PORT13", UNIPHIER_PIN_IECTRL_NONE,
-                            295, UNIPHIER_PIN_DRV_4_8,
+                            295, UNIPHIER_PIN_DRV_1BIT,
                             295, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(312, "PORT14", UNIPHIER_PIN_IECTRL_NONE,
-                            296, UNIPHIER_PIN_DRV_4_8,
+                            296, UNIPHIER_PIN_DRV_1BIT,
                             296, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(313, "PORT15", UNIPHIER_PIN_IECTRL_NONE,
-                            297, UNIPHIER_PIN_DRV_4_8,
+                            297, UNIPHIER_PIN_DRV_1BIT,
                             297, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(314, "PORT16", UNIPHIER_PIN_IECTRL_NONE,
-                            298, UNIPHIER_PIN_DRV_4_8,
+                            298, UNIPHIER_PIN_DRV_1BIT,
                             298, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(315, "PORT17", UNIPHIER_PIN_IECTRL_NONE,
-                            299, UNIPHIER_PIN_DRV_4_8,
+                            299, UNIPHIER_PIN_DRV_1BIT,
                             299, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(316, "PORT20", UNIPHIER_PIN_IECTRL_NONE,
-                            300, UNIPHIER_PIN_DRV_4_8,
+                            300, UNIPHIER_PIN_DRV_1BIT,
                             300, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(317, "PORT21", UNIPHIER_PIN_IECTRL_NONE,
-                            301, UNIPHIER_PIN_DRV_4_8,
+                            301, UNIPHIER_PIN_DRV_1BIT,
                             301, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(318, "PORT22", UNIPHIER_PIN_IECTRL_NONE,
-                            302, UNIPHIER_PIN_DRV_4_8,
+                            302, UNIPHIER_PIN_DRV_1BIT,
                             302, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(319, "SD1DAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            303, UNIPHIER_PIN_DRV_4_8,
+                            303, UNIPHIER_PIN_DRV_1BIT,
                             303, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(320, "SD1DAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            304, UNIPHIER_PIN_DRV_4_8,
+                            304, UNIPHIER_PIN_DRV_1BIT,
                             304, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(321, "SD1DAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            305, UNIPHIER_PIN_DRV_4_8,
+                            305, UNIPHIER_PIN_DRV_1BIT,
                             305, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(322, "SD1DAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            306, UNIPHIER_PIN_DRV_4_8,
+                            306, UNIPHIER_PIN_DRV_1BIT,
                             306, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(323, "SD1CMD", UNIPHIER_PIN_IECTRL_NONE,
-                            307, UNIPHIER_PIN_DRV_4_8,
+                            307, UNIPHIER_PIN_DRV_1BIT,
                             307, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(324, "SD1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            308, UNIPHIER_PIN_DRV_4_8,
+                            308, UNIPHIER_PIN_DRV_1BIT,
                             308, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(325, "SD1CD", UNIPHIER_PIN_IECTRL_NONE,
-                            309, UNIPHIER_PIN_DRV_4_8,
+                            309, UNIPHIER_PIN_DRV_1BIT,
                             309, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(326, "SD1WP", UNIPHIER_PIN_IECTRL_NONE,
-                            310, UNIPHIER_PIN_DRV_4_8,
+                            310, UNIPHIER_PIN_DRV_1BIT,
                             310, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(327, "SD1VTCG", UNIPHIER_PIN_IECTRL_NONE,
-                            311, UNIPHIER_PIN_DRV_4_8,
+                            311, UNIPHIER_PIN_DRV_1BIT,
                             311, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(328, "DMDISO", UNIPHIER_PIN_IECTRL_NONE,
-                            312, UNIPHIER_PIN_DRV_NONE,
+                            -1, UNIPHIER_PIN_DRV_NONE,
                             312, UNIPHIER_PIN_PULL_DOWN),
 };
 
 static const unsigned emmc_pins[] = {40, 41, 42, 43, 51, 52, 53};
-static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
+static const int emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
 static const unsigned emmc_dat8_pins[] = {44, 45, 46, 47};
-static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const int emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const unsigned ether_mii_pins[] = {160, 161, 162, 163, 164, 165, 166,
+                                         167, 168, 169, 170, 171, 172, 173,
+                                         174, 175, 176, 177, 178, 179};
+static const int ether_mii_muxvals[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0};
+static const unsigned ether_rgmii_pins[] = {160, 161, 162, 163, 164, 165, 167,
+                                           168, 169, 170, 171, 172, 176, 177,
+                                           178, 179};
+static const int ether_rgmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                         0, 0, 0, 0};
+static const unsigned ether_rmii_pins[] = {160, 161, 162, 165, 168, 169, 172,
+                                          173, 176, 177, 178, 179};
+static const int ether_rmii_muxvals[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned ether_rmiib_pins[] = {161, 162, 165, 167, 168, 169, 172,
+                                           173, 176, 177, 178, 179};
+static const int ether_rmiib_muxvals[] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned i2c0_pins[] = {142, 143};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {144, 145};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {146, 147};
-static const unsigned i2c2_muxvals[] = {0, 0};
+static const int i2c2_muxvals[] = {0, 0};
 static const unsigned i2c3_pins[] = {148, 149};
-static const unsigned i2c3_muxvals[] = {0, 0};
+static const int i2c3_muxvals[] = {0, 0};
 static const unsigned i2c6_pins[] = {308, 309};
-static const unsigned i2c6_muxvals[] = {6, 6};
+static const int i2c6_muxvals[] = {6, 6};
 static const unsigned nand_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
                                     50, 51, 52, 53, 54};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {131, 132};
-static const unsigned nand_cs1_muxvals[] = {1, 1};
+static const int nand_cs1_muxvals[] = {1, 1};
 static const unsigned sd_pins[] = {150, 151, 152, 153, 154, 155, 156, 157, 158};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned sd1_pins[] = {319, 320, 321, 322, 323, 324, 325, 326,
                                    327};
-static const unsigned sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {25, 26, 27, 28, 29, 30, 31, 32, 33,
+                                          34, 35, 36, 37, 38};
+static const int system_bus_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                        0};
+static const unsigned system_bus_cs0_pins[] = {318};
+static const int system_bus_cs0_muxvals[] = {5};
+static const unsigned system_bus_cs1_pins[] = {24};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned system_bus_cs2_pins[] = {315};
+static const int system_bus_cs2_muxvals[] = {5};
+static const unsigned system_bus_cs3_pins[] = {313};
+static const int system_bus_cs3_muxvals[] = {5};
+static const unsigned system_bus_cs4_pins[] = {305};
+static const int system_bus_cs4_muxvals[] = {5};
+static const unsigned system_bus_cs5_pins[] = {303};
+static const int system_bus_cs5_muxvals[] = {6};
+static const unsigned system_bus_cs6_pins[] = {307};
+static const int system_bus_cs6_muxvals[] = {6};
+static const unsigned system_bus_cs7_pins[] = {312};
+static const int system_bus_cs7_muxvals[] = {6};
 static const unsigned uart0_pins[] = {127, 128};
-static const unsigned uart0_muxvals[] = {0, 0};
+static const int uart0_muxvals[] = {0, 0};
 static const unsigned uart1_pins[] = {129, 130};
-static const unsigned uart1_muxvals[] = {0, 0};
+static const int uart1_muxvals[] = {0, 0};
 static const unsigned uart2_pins[] = {131, 132};
-static const unsigned uart2_muxvals[] = {0, 0};
+static const int uart2_muxvals[] = {0, 0};
 static const unsigned uart3_pins[] = {88, 89};
-static const unsigned uart3_muxvals[] = {2, 2};
+static const int uart3_muxvals[] = {2, 2};
 static const unsigned usb0_pins[] = {180, 181};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {182, 183};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {184, 185};
-static const unsigned usb2_muxvals[] = {0, 0};
+static const int usb2_muxvals[] = {0, 0};
 static const unsigned usb3_pins[] = {186, 187};
-static const unsigned usb3_muxvals[] = {0, 0};
+static const int usb3_muxvals[] = {0, 0};
 static const unsigned port_range0_pins[] = {
        300, 301, 302, 303, 304, 305, 306, 307,         /* PORT0x */
        308, 309, 310, 311, 312, 313, 314, 315,         /* PORT1x */
@@ -1069,7 +1102,7 @@ static const unsigned port_range0_pins[] = {
        76, 77, 78, 79, 80, 81, 82, 83,                 /* PORT13x */
        84, 85, 86, 87, 88, 89, 90, 91,                 /* PORT14x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT0x */
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT1x */
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT2x */
@@ -1102,7 +1135,7 @@ static const unsigned port_range1_pins[] = {
        251, 252, 261, 262, 263, 264, 273, 274,         /* PORT29x */
        31, 32, 33, 34, 35, 36, 37, 38,                 /* PORT30x */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        7, 7, 7,                                        /* PORT175-177 */
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT18x */
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT19x */
@@ -1123,7 +1156,7 @@ static const unsigned xirq_pins[] = {
        234, 186, 99, 100, 101, 102, 184, 301,          /* XIRQ8-15 */
        302, 303, 304, 305, 306,                        /* XIRQ16-20 */
 };
-static const unsigned xirq_muxvals[] = {
+static const int xirq_muxvals[] = {
        7, 7, 7, 7, 7, 7, 7, 7,                         /* XIRQ0-7 */
        7, 7, 7, 7, 7, 7, 2, 2,                         /* XIRQ8-15 */
        2, 2, 2, 2, 2,                                  /* XIRQ16-20 */
@@ -1131,13 +1164,17 @@ static const unsigned xirq_muxvals[] = {
 static const unsigned xirq_alternatives_pins[] = {
        184, 310, 316,
 };
-static const unsigned xirq_alternatives_muxvals[] = {
+static const int xirq_alternatives_muxvals[] = {
        2, 2, 2,
 };
 
-static const struct uniphier_pinctrl_group ph1_pro4_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_pro4_groups[] = {
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_mii),
+       UNIPHIER_PINCTRL_GROUP(ether_rgmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmiib),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -1147,6 +1184,15 @@ static const struct uniphier_pinctrl_group ph1_pro4_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
        UNIPHIER_PINCTRL_GROUP(sd1),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs0),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs4),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs5),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs6),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs7),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart1),
        UNIPHIER_PINCTRL_GROUP(uart2),
@@ -1413,6 +1459,9 @@ static const struct uniphier_pinctrl_group ph1_pro4_groups[] = {
 };
 
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_mii_groups[] = {"ether_mii"};
+static const char * const ether_rgmii_groups[] = {"ether_rgmii"};
+static const char * const ether_rmii_groups[] = {"ether_rgmii", "ether_rgmiib"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
@@ -1421,6 +1470,15 @@ static const char * const i2c6_groups[] = {"i2c6"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
 static const char * const sd1_groups[] = {"sd1"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs0",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3",
+                                                "system_bus_cs4",
+                                                "system_bus_cs5",
+                                                "system_bus_cs6",
+                                                "system_bus_cs7"};
 static const char * const uart0_groups[] = {"uart0"};
 static const char * const uart1_groups[] = {"uart1"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -1499,8 +1557,11 @@ static const char * const xirq_groups[] = {
        "xirq14b", "xirq17b", "xirq18b",
 };
 
-static const struct uniphier_pinmux_function ph1_pro4_functions[] = {
+static const struct uniphier_pinmux_function uniphier_pro4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_mii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rgmii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
@@ -1509,6 +1570,7 @@ static const struct uniphier_pinmux_function ph1_pro4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
        UNIPHIER_PINMUX_FUNCTION(sd1),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -1521,43 +1583,36 @@ static const struct uniphier_pinmux_function ph1_pro4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_pro4_pindata = {
-       .groups = ph1_pro4_groups,
-       .groups_count = ARRAY_SIZE(ph1_pro4_groups),
-       .functions = ph1_pro4_functions,
-       .functions_count = ARRAY_SIZE(ph1_pro4_functions),
-       .mux_bits = 4,
-       .reg_stride = 8,
-       .load_pinctrl = true,
-};
-
-static struct pinctrl_desc ph1_pro4_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_pro4_pins,
-       .npins = ARRAY_SIZE(ph1_pro4_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_pro4_pindata = {
+       .pins = uniphier_pro4_pins,
+       .npins = ARRAY_SIZE(uniphier_pro4_pins),
+       .groups = uniphier_pro4_groups,
+       .groups_count = ARRAY_SIZE(uniphier_pro4_groups),
+       .functions = uniphier_pro4_functions,
+       .functions_count = ARRAY_SIZE(uniphier_pro4_functions),
+       .caps = UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE,
 };
 
-static int ph1_pro4_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_pro4_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_pro4_pinctrl_desc,
-                                     &ph1_pro4_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_pro4_pindata);
 }
 
-static const struct of_device_id ph1_pro4_pinctrl_match[] = {
+static const struct of_device_id uniphier_pro4_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-pro4-pinctrl" },
        { .compatible = "socionext,ph1-pro4-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_pro4_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_pro4_pinctrl_match);
 
-static struct platform_driver ph1_pro4_pinctrl_driver = {
-       .probe = ph1_pro4_pinctrl_probe,
+static struct platform_driver uniphier_pro4_pinctrl_driver = {
+       .probe = uniphier_pro4_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_pro4_pinctrl_match,
+               .name = "uniphier-pro4-pinctrl",
+               .of_match_table = uniphier_pro4_pinctrl_match,
        },
 };
-module_platform_driver(ph1_pro4_pinctrl_driver);
+module_platform_driver(uniphier_pro4_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-Pro4 pinctrl driver");
index 3087f76752a6c969de496c9ac1daf9daa366c9d4..55d4a12282a0da47a0912f490544e85afeb96eaf 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-pro5-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_pro5_pins[] = {
+static const struct pinctrl_pin_desc uniphier_pro5_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "AEXCKA1", 0,
-                            0, UNIPHIER_PIN_DRV_4_8,
+                            0, UNIPHIER_PIN_DRV_1BIT,
                             0, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "AEXCKA2", 0,
-                            1, UNIPHIER_PIN_DRV_4_8,
+                            1, UNIPHIER_PIN_DRV_1BIT,
                             1, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "CK27EXI", 0,
-                            2, UNIPHIER_PIN_DRV_4_8,
+                            2, UNIPHIER_PIN_DRV_1BIT,
                             2, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "CK54EXI", 0,
-                            3, UNIPHIER_PIN_DRV_4_8,
+                            3, UNIPHIER_PIN_DRV_1BIT,
                             3, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "ED0", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_4_8,
+                            4, UNIPHIER_PIN_DRV_1BIT,
                             4, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "ED1", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_4_8,
+                            5, UNIPHIER_PIN_DRV_1BIT,
                             5, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "ED2", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_4_8,
+                            6, UNIPHIER_PIN_DRV_1BIT,
                             6, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "ED3", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_4_8,
+                            7, UNIPHIER_PIN_DRV_1BIT,
                             7, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "ED4", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "ED5", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "ED6", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "ED7", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(13, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(14, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(15, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            15, UNIPHIER_PIN_DRV_4_8,
+                            15, UNIPHIER_PIN_DRV_1BIT,
                             15, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(16, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_4_8,
+                            16, UNIPHIER_PIN_DRV_1BIT,
                             16, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(17, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            17, UNIPHIER_PIN_DRV_4_8,
+                            17, UNIPHIER_PIN_DRV_1BIT,
                             17, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(18, "XECS1", UNIPHIER_PIN_IECTRL_NONE,
-                            18, UNIPHIER_PIN_DRV_4_8,
+                            18, UNIPHIER_PIN_DRV_1BIT,
                             18, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(19, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            19, UNIPHIER_PIN_DRV_4_8,
+                            19, UNIPHIER_PIN_DRV_1BIT,
                             19, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(20, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_4_8,
+                            20, UNIPHIER_PIN_DRV_1BIT,
                             20, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(21, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            21, UNIPHIER_PIN_DRV_4_8,
+                            21, UNIPHIER_PIN_DRV_1BIT,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(22, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            22, UNIPHIER_PIN_DRV_4_8,
+                            22, UNIPHIER_PIN_DRV_1BIT,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(23, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            23, UNIPHIER_PIN_DRV_4_8,
+                            23, UNIPHIER_PIN_DRV_1BIT,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(24, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_4_8,
+                            24, UNIPHIER_PIN_DRV_1BIT,
                             24, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(25, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            25, UNIPHIER_PIN_DRV_4_8,
+                            25, UNIPHIER_PIN_DRV_1BIT,
                             25, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(26, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE,
-                            26, UNIPHIER_PIN_DRV_4_8,
+                            26, UNIPHIER_PIN_DRV_1BIT,
                             26, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(27, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE,
-                            27, UNIPHIER_PIN_DRV_4_8,
+                            27, UNIPHIER_PIN_DRV_1BIT,
                             27, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(28, "NFD0", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_4_8,
+                            28, UNIPHIER_PIN_DRV_1BIT,
                             28, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(29, "NFD1", UNIPHIER_PIN_IECTRL_NONE,
-                            29, UNIPHIER_PIN_DRV_4_8,
+                            29, UNIPHIER_PIN_DRV_1BIT,
                             29, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(30, "NFD2", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "NFD3", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "NFD4", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(33, "NFD5", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(34, "NFD6", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(35, "NFD7", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(36, "XERST", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(37, "MMCCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(38, "MMCCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(39, "MMCDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(40, "MMCDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(41, "MMCDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(42, "MMCDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(43, "MMCDAT4", UNIPHIER_PIN_IECTRL_NONE,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(44, "MMCDAT5", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(45, "MMCDAT6", UNIPHIER_PIN_IECTRL_NONE,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(46, "MMCDAT7", UNIPHIER_PIN_IECTRL_NONE,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(47, "TXD0", 0,
-                            47, UNIPHIER_PIN_DRV_4_8,
+                            47, UNIPHIER_PIN_DRV_1BIT,
                             47, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(48, "RXD0", 0,
-                            48, UNIPHIER_PIN_DRV_4_8,
+                            48, UNIPHIER_PIN_DRV_1BIT,
                             48, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(49, "TXD1", 0,
-                            49, UNIPHIER_PIN_DRV_4_8,
+                            49, UNIPHIER_PIN_DRV_1BIT,
                             49, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(50, "RXD1", 0,
-                            50, UNIPHIER_PIN_DRV_4_8,
+                            50, UNIPHIER_PIN_DRV_1BIT,
                             50, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(51, "TXD2", UNIPHIER_PIN_IECTRL_NONE,
-                            51, UNIPHIER_PIN_DRV_4_8,
+                            51, UNIPHIER_PIN_DRV_1BIT,
                             51, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(52, "RXD2", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_4_8,
+                            52, UNIPHIER_PIN_DRV_1BIT,
                             52, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(53, "TXD3", 0,
-                            53, UNIPHIER_PIN_DRV_4_8,
+                            53, UNIPHIER_PIN_DRV_1BIT,
                             53, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(54, "RXD3", 0,
-                            54, UNIPHIER_PIN_DRV_4_8,
+                            54, UNIPHIER_PIN_DRV_1BIT,
                             54, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(55, "MS0CS0", 0,
-                            55, UNIPHIER_PIN_DRV_4_8,
+                            55, UNIPHIER_PIN_DRV_1BIT,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "MS0DO", 0,
-                            56, UNIPHIER_PIN_DRV_4_8,
+                            56, UNIPHIER_PIN_DRV_1BIT,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "MS0DI", 0,
-                            57, UNIPHIER_PIN_DRV_4_8,
+                            57, UNIPHIER_PIN_DRV_1BIT,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "MS0CLK", 0,
-                            58, UNIPHIER_PIN_DRV_4_8,
+                            58, UNIPHIER_PIN_DRV_1BIT,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "CSCLK", 0,
-                            59, UNIPHIER_PIN_DRV_4_8,
+                            59, UNIPHIER_PIN_DRV_1BIT,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "CSBPTM", 0,
-                            60, UNIPHIER_PIN_DRV_4_8,
+                            60, UNIPHIER_PIN_DRV_1BIT,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "CSBMTP", 0,
-                            61, UNIPHIER_PIN_DRV_4_8,
+                            61, UNIPHIER_PIN_DRV_1BIT,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "XCINTP", 0,
-                            62, UNIPHIER_PIN_DRV_4_8,
+                            62, UNIPHIER_PIN_DRV_1BIT,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "XCINTM", 0,
-                            63, UNIPHIER_PIN_DRV_4_8,
+                            63, UNIPHIER_PIN_DRV_1BIT,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "XCMPREQ", 0,
-                            64, UNIPHIER_PIN_DRV_4_8,
+                            64, UNIPHIER_PIN_DRV_1BIT,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "XSRST", 0,
-                            65, UNIPHIER_PIN_DRV_4_8,
+                            65, UNIPHIER_PIN_DRV_1BIT,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "LPST", UNIPHIER_PIN_IECTRL_NONE,
-                            66, UNIPHIER_PIN_DRV_4_8,
+                            66, UNIPHIER_PIN_DRV_1BIT,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "PWMA", 0,
-                            67, UNIPHIER_PIN_DRV_4_8,
+                            67, UNIPHIER_PIN_DRV_1BIT,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "XIRQ0", 0,
-                            68, UNIPHIER_PIN_DRV_4_8,
+                            68, UNIPHIER_PIN_DRV_1BIT,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "XIRQ1", 0,
-                            69, UNIPHIER_PIN_DRV_4_8,
+                            69, UNIPHIER_PIN_DRV_1BIT,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "XIRQ2", 0,
-                            70, UNIPHIER_PIN_DRV_4_8,
+                            70, UNIPHIER_PIN_DRV_1BIT,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "XIRQ3", 0,
-                            71, UNIPHIER_PIN_DRV_4_8,
+                            71, UNIPHIER_PIN_DRV_1BIT,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "XIRQ4", 0,
-                            72, UNIPHIER_PIN_DRV_4_8,
+                            72, UNIPHIER_PIN_DRV_1BIT,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "XIRQ5", 0,
-                            73, UNIPHIER_PIN_DRV_4_8,
+                            73, UNIPHIER_PIN_DRV_1BIT,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "XIRQ6", 0,
-                            74, UNIPHIER_PIN_DRV_4_8,
+                            74, UNIPHIER_PIN_DRV_1BIT,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "XIRQ7", 0,
-                            75, UNIPHIER_PIN_DRV_4_8,
+                            75, UNIPHIER_PIN_DRV_1BIT,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "XIRQ8", 0,
-                            76, UNIPHIER_PIN_DRV_4_8,
+                            76, UNIPHIER_PIN_DRV_1BIT,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "XIRQ9", 0,
-                            77, UNIPHIER_PIN_DRV_4_8,
+                            77, UNIPHIER_PIN_DRV_1BIT,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "XIRQ10", 0,
-                            78, UNIPHIER_PIN_DRV_4_8,
+                            78, UNIPHIER_PIN_DRV_1BIT,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "XIRQ11", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "XIRQ12", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "XIRQ13", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "XIRQ14", 0,
-                            82, UNIPHIER_PIN_DRV_4_8,
+                            82, UNIPHIER_PIN_DRV_1BIT,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "XIRQ15", 0,
-                            83, UNIPHIER_PIN_DRV_4_8,
+                            83, UNIPHIER_PIN_DRV_1BIT,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "XIRQ16", 0,
-                            84, UNIPHIER_PIN_DRV_4_8,
+                            84, UNIPHIER_PIN_DRV_1BIT,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "XIRQ17", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "XIRQ18", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "XIRQ19", 0,
-                            87, UNIPHIER_PIN_DRV_4_8,
+                            87, UNIPHIER_PIN_DRV_1BIT,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "XIRQ20", 0,
-                            88, UNIPHIER_PIN_DRV_4_8,
+                            88, UNIPHIER_PIN_DRV_1BIT,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "PORT00", 0,
-                            89, UNIPHIER_PIN_DRV_4_8,
+                            89, UNIPHIER_PIN_DRV_1BIT,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "PORT01", 0,
-                            90, UNIPHIER_PIN_DRV_4_8,
+                            90, UNIPHIER_PIN_DRV_1BIT,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "PORT02", 0,
-                            91, UNIPHIER_PIN_DRV_4_8,
+                            91, UNIPHIER_PIN_DRV_1BIT,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "PORT03", 0,
-                            92, UNIPHIER_PIN_DRV_4_8,
+                            92, UNIPHIER_PIN_DRV_1BIT,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "PORT04", 0,
-                            93, UNIPHIER_PIN_DRV_4_8,
+                            93, UNIPHIER_PIN_DRV_1BIT,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "PORT05", 0,
-                            94, UNIPHIER_PIN_DRV_4_8,
+                            94, UNIPHIER_PIN_DRV_1BIT,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "PORT06", 0,
-                            95, UNIPHIER_PIN_DRV_4_8,
+                            95, UNIPHIER_PIN_DRV_1BIT,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "PORT07", 0,
-                            96, UNIPHIER_PIN_DRV_4_8,
+                            96, UNIPHIER_PIN_DRV_1BIT,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "PORT10", 0,
-                            97, UNIPHIER_PIN_DRV_4_8,
+                            97, UNIPHIER_PIN_DRV_1BIT,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "PORT11", 0,
-                            98, UNIPHIER_PIN_DRV_4_8,
+                            98, UNIPHIER_PIN_DRV_1BIT,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "PORT12", 0,
-                            99, UNIPHIER_PIN_DRV_4_8,
+                            99, UNIPHIER_PIN_DRV_1BIT,
                             99, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "PORT13", 0,
-                            100, UNIPHIER_PIN_DRV_4_8,
+                            100, UNIPHIER_PIN_DRV_1BIT,
                             100, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "PORT14", 0,
-                            101, UNIPHIER_PIN_DRV_4_8,
+                            101, UNIPHIER_PIN_DRV_1BIT,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "PORT15", 0,
-                            102, UNIPHIER_PIN_DRV_4_8,
+                            102, UNIPHIER_PIN_DRV_1BIT,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(103, "PORT16", 0,
-                            103, UNIPHIER_PIN_DRV_4_8,
+                            103, UNIPHIER_PIN_DRV_1BIT,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(104, "PORT17", 0,
-                            104, UNIPHIER_PIN_DRV_4_8,
+                            104, UNIPHIER_PIN_DRV_1BIT,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(105, "T0HPD", 0,
-                            105, UNIPHIER_PIN_DRV_4_8,
+                            105, UNIPHIER_PIN_DRV_1BIT,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(106, "T1HPD", 0,
-                            106, UNIPHIER_PIN_DRV_4_8,
+                            106, UNIPHIER_PIN_DRV_1BIT,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(107, "R0HPD", 0,
-                            107, UNIPHIER_PIN_DRV_4_8,
+                            107, UNIPHIER_PIN_DRV_1BIT,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(108, "R1HPD", 0,
-                            108, UNIPHIER_PIN_DRV_4_8,
+                            108, UNIPHIER_PIN_DRV_1BIT,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(109, "XPERST", 0,
-                            109, UNIPHIER_PIN_DRV_4_8,
+                            109, UNIPHIER_PIN_DRV_1BIT,
                             109, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(110, "XPEWAKE", 0,
-                            110, UNIPHIER_PIN_DRV_4_8,
+                            110, UNIPHIER_PIN_DRV_1BIT,
                             110, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(111, "XPECLKRQ", 0,
-                            111, UNIPHIER_PIN_DRV_4_8,
+                            111, UNIPHIER_PIN_DRV_1BIT,
                             111, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(112, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             112, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(113, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             113, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(114, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             114, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             115, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "SDA2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             116, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(117, "SCL2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             117, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(118, "SDA3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             118, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(119, "SCL3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             119, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(120, "SPISYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             120, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "SPISCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             121, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "SPITXD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             122, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "SPIRXD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             123, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             124, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             125, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(126, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             126, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "USB1OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             127, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(128, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             128, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "USB2OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             129, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(130, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "SMTD0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "SMTCLK0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(136, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             136, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(137, "SMTD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             137, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(138, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             138, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(139, "SMTCLK1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             139, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(140, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             140, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(141, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             141, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             142, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(143, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             143, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(144, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             144, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(145, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             145, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(146, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             146, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(147, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             147, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(148, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             148, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(149, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             149, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(150, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             150, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(151, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             151, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(152, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             152, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(153, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             153, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(154, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             154, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(155, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             155, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(156, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             156, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(157, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             157, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(158, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             158, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(159, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             159, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(160, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             160, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             161, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             162, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             163, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(164, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             164, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(165, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             165, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(166, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             166, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(167, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             167, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(168, "CH7CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             168, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(169, "CH7PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             169, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(170, "CH7VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             170, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(171, "CH7DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             171, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(172, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             172, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(173, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             173, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(174, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             174, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(175, "AI1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             175, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(176, "AI1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             176, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(177, "AI1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             177, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(178, "AI1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             178, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(179, "AI2ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             179, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(180, "AI2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             180, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(181, "AI2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             181, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(182, "AI2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             182, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(183, "AI2D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             183, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(184, "AI2D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             184, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(185, "AI2D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             185, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(186, "AI3ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             186, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(187, "AI3BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             187, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(188, "AI3LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             188, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(189, "AI3D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             189, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(190, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             190, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(191, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             191, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(192, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             192, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(193, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             193, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(194, "AO1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             194, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(195, "AO1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             195, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(196, "AO1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             196, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(197, "AO1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             197, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(198, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             198, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(199, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             199, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(200, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             200, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(201, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             201, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(202, "AO2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             202, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(203, "AO2D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             203, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(204, "AO2D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             204, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(205, "AO2D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             205, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(206, "AO3DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             206, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(207, "AO3BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             207, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(208, "AO3LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             208, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(209, "AO3DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             209, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(210, "AO4DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             210, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(211, "AO4BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             211, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(212, "AO4LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             212, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(213, "AO4DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             213, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(214, "VI1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             214, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(215, "VI1C0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             215, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(216, "VI1C1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             216, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(217, "VI1C2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             217, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(218, "VI1C3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             218, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(219, "VI1C4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             219, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(220, "VI1C5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             220, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(221, "VI1C6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             221, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(222, "VI1C7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             222, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(223, "VI1C8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             223, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(224, "VI1C9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             224, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(225, "VI1Y0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             225, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(226, "VI1Y1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             226, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(227, "VI1Y2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             227, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(228, "VI1Y3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             228, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(229, "VI1Y4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             229, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(230, "VI1Y5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             230, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(231, "VI1Y6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             231, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(232, "VI1Y7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             232, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(233, "VI1Y8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             233, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(234, "VI1Y9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             234, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(235, "VI1DE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             235, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(236, "VI1HSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             236, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(237, "VI1VSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             237, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(238, "VO1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             238, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(239, "VO1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             239, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(240, "VO1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             240, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(241, "VO1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             241, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(242, "VO1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             242, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(243, "VO1D4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             243, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(244, "VO1D5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             244, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(245, "VO1D6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             245, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(246, "VO1D7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             246, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(247, "SDCD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             247, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(248, "SDWP", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             248, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(249, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             249, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(250, "SDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_8_12_16_20,
+                            10, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(251, "SDCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_8_12_16_20,
+                            11, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(252, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            48, UNIPHIER_PIN_DRV_8_12_16_20,
+                            12, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(253, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_8_12_16_20,
+                            13, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(254, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            56, UNIPHIER_PIN_DRV_8_12_16_20,
+                            14, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(255, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            60, UNIPHIER_PIN_DRV_8_12_16_20,
+                            15, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
 };
 
 static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42};
-static const unsigned emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0};
+static const int emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0};
 static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46};
-static const unsigned emmc_dat8_muxvals[] = {0, 0, 0, 0};
+static const int emmc_dat8_muxvals[] = {0, 0, 0, 0};
 static const unsigned i2c0_pins[] = {112, 113};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {114, 115};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {116, 117};
-static const unsigned i2c2_muxvals[] = {0, 0};
+static const int i2c2_muxvals[] = {0, 0};
 static const unsigned i2c3_pins[] = {118, 119};
-static const unsigned i2c3_muxvals[] = {0, 0};
+static const int i2c3_muxvals[] = {0, 0};
 static const unsigned i2c5_pins[] = {87, 88};
-static const unsigned i2c5_muxvals[] = {2, 2};
+static const int i2c5_muxvals[] = {2, 2};
 static const unsigned i2c5b_pins[] = {196, 197};
-static const unsigned i2c5b_muxvals[] = {2, 2};
+static const int i2c5b_muxvals[] = {2, 2};
 static const unsigned i2c5c_pins[] = {215, 216};
-static const unsigned i2c5c_muxvals[] = {2, 2};
+static const int i2c5c_muxvals[] = {2, 2};
 static const unsigned i2c6_pins[] = {101, 102};
-static const unsigned i2c6_muxvals[] = {2, 2};
+static const int i2c6_muxvals[] = {2, 2};
 static const unsigned nand_pins[] = {19, 20, 21, 22, 23, 24, 25, 28, 29, 30,
                                     31, 32, 33, 34, 35};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {26, 27};
-static const unsigned nand_cs1_muxvals[] = {0, 0};
+static const int nand_cs1_muxvals[] = {0, 0};
 static const unsigned sd_pins[] = {250, 251, 252, 253, 254, 255, 256, 257, 258};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+                                          14, 15, 16, 17};
+static const int system_bus_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                        0};
+static const unsigned system_bus_cs0_pins[] = {105};
+static const int system_bus_cs0_muxvals[] = {1};
+static const unsigned system_bus_cs1_pins[] = {18};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned system_bus_cs2_pins[] = {106};
+static const int system_bus_cs2_muxvals[] = {1};
+static const unsigned system_bus_cs3_pins[] = {100};
+static const int system_bus_cs3_muxvals[] = {1};
+static const unsigned system_bus_cs4_pins[] = {101};
+static const int system_bus_cs4_muxvals[] = {1};
+static const unsigned system_bus_cs5_pins[] = {102};
+static const int system_bus_cs5_muxvals[] = {1};
+static const unsigned system_bus_cs6_pins[] = {69};
+static const int system_bus_cs6_muxvals[] = {5};
+static const unsigned system_bus_cs7_pins[] = {70};
+static const int system_bus_cs7_muxvals[] = {5};
 static const unsigned uart0_pins[] = {47, 48};
-static const unsigned uart0_muxvals[] = {0, 0};
+static const int uart0_muxvals[] = {0, 0};
 static const unsigned uart0b_pins[] = {227, 228};
-static const unsigned uart0b_muxvals[] = {3, 3};
+static const int uart0b_muxvals[] = {3, 3};
 static const unsigned uart1_pins[] = {49, 50};
-static const unsigned uart1_muxvals[] = {0, 0};
+static const int uart1_muxvals[] = {0, 0};
 static const unsigned uart2_pins[] = {51, 52};
-static const unsigned uart2_muxvals[] = {0, 0};
+static const int uart2_muxvals[] = {0, 0};
 static const unsigned uart3_pins[] = {53, 54};
-static const unsigned uart3_muxvals[] = {0, 0};
+static const int uart3_muxvals[] = {0, 0};
 static const unsigned usb0_pins[] = {124, 125};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {126, 127};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {128, 129};
-static const unsigned usb2_muxvals[] = {0, 0};
+static const int usb2_muxvals[] = {0, 0};
 static const unsigned port_range0_pins[] = {
        89, 90, 91, 92, 93, 94, 95, 96,                 /* PORT0x */
        97, 98, 99, 100, 101, 102, 103, 104,            /* PORT1x */
@@ -853,7 +870,7 @@ static const unsigned port_range0_pins[] = {
        179, 180, 181, 182, 186, 187, 188, 189,         /* PORT13x */
        4, 5, 6, 7, 8, 9, 10, 11,                       /* PORT14x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
@@ -886,7 +903,7 @@ static const unsigned port_range1_pins[] = {
        105, 106, 18, 27, 36, 128, 132, 137,            /* PORT29x */
        183, 184, 185, 84, 47, 48, 51, 52,              /* PORT30x */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15, 15, 15,                                     /* PORT175-177 */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT18x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT19x */
@@ -907,7 +924,7 @@ static const unsigned xirq_pins[] = {
        76, 77, 78, 79, 80, 81, 82, 83,                 /* XIRQ8-15 */
        84, 85, 86, 87, 88,                             /* XIRQ16-20 */
 };
-static const unsigned xirq_muxvals[] = {
+static const int xirq_muxvals[] = {
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ8-15 */
        14, 14, 14, 14, 14,                             /* XIRQ16-20 */
@@ -915,11 +932,11 @@ static const unsigned xirq_muxvals[] = {
 static const unsigned xirq_alternatives_pins[] = {
        91, 92, 239, 144, 240, 156, 241, 106, 128,
 };
-static const unsigned xirq_alternatives_muxvals[] = {
+static const int xirq_alternatives_muxvals[] = {
        14, 14, 14, 14, 14, 14, 14, 14, 14,
 };
 
-static const struct uniphier_pinctrl_group ph1_pro5_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_pro5_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(emmc),
@@ -933,6 +950,15 @@ static const struct uniphier_pinctrl_group ph1_pro5_groups[] = {
        UNIPHIER_PINCTRL_GROUP(i2c5c),
        UNIPHIER_PINCTRL_GROUP(i2c6),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs0),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs4),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs5),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs6),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs7),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart0b),
        UNIPHIER_PINCTRL_GROUP(uart1),
@@ -1213,6 +1239,15 @@ static const char * const i2c5_groups[] = {"i2c5", "i2c5b", "i2c5c"};
 static const char * const i2c6_groups[] = {"i2c6"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs0",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3",
+                                                "system_bus_cs4",
+                                                "system_bus_cs5",
+                                                "system_bus_cs6",
+                                                "system_bus_cs7"};
 static const char * const uart0_groups[] = {"uart0", "uart0b"};
 static const char * const uart1_groups[] = {"uart1"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -1291,7 +1326,7 @@ static const char * const xirq_groups[] = {
        "xirq18b", "xirq18c", "xirq19b", "xirq20b",
 };
 
-static const struct uniphier_pinmux_function ph1_pro5_functions[] = {
+static const struct uniphier_pinmux_function uniphier_pro5_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
@@ -1301,6 +1336,7 @@ static const struct uniphier_pinmux_function ph1_pro5_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(i2c6),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -1312,43 +1348,36 @@ static const struct uniphier_pinmux_function ph1_pro5_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_pro5_pindata = {
-       .groups = ph1_pro5_groups,
-       .groups_count = ARRAY_SIZE(ph1_pro5_groups),
-       .functions = ph1_pro5_functions,
-       .functions_count = ARRAY_SIZE(ph1_pro5_functions),
-       .mux_bits = 4,
-       .reg_stride = 8,
-       .load_pinctrl = true,
-};
-
-static struct pinctrl_desc ph1_pro5_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_pro5_pins,
-       .npins = ARRAY_SIZE(ph1_pro5_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_pro5_pindata = {
+       .pins = uniphier_pro5_pins,
+       .npins = ARRAY_SIZE(uniphier_pro5_pins),
+       .groups = uniphier_pro5_groups,
+       .groups_count = ARRAY_SIZE(uniphier_pro5_groups),
+       .functions = uniphier_pro5_functions,
+       .functions_count = ARRAY_SIZE(uniphier_pro5_functions),
+       .caps = UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE,
 };
 
-static int ph1_pro5_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_pro5_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_pro5_pinctrl_desc,
-                                     &ph1_pro5_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_pro5_pindata);
 }
 
-static const struct of_device_id ph1_pro5_pinctrl_match[] = {
+static const struct of_device_id uniphier_pro5_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-pro5-pinctrl" },
        { .compatible = "socionext,ph1-pro5-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_pro5_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_pro5_pinctrl_match);
 
-static struct platform_driver ph1_pro5_pinctrl_driver = {
-       .probe = ph1_pro5_pinctrl_probe,
+static struct platform_driver uniphier_pro5_pinctrl_driver = {
+       .probe = uniphier_pro5_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_pro5_pinctrl_match,
+               .name = "uniphier-pro5-pinctrl",
+               .of_match_table = uniphier_pro5_pinctrl_match,
        },
 };
-module_platform_driver(ph1_pro5_pinctrl_driver);
+module_platform_driver(uniphier_pro5_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-Pro5 pinctrl driver");
index e868030ff31c3543d6ab6a31b9bcb6454a7a2a71..85ca5e2d8a9c6b941c0889cb008c1b7b3a8cbe9a 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "proxstream2-pinctrl"
-
-static const struct pinctrl_pin_desc proxstream2_pins[] = {
+static const struct pinctrl_pin_desc uniphier_pxs2_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "ED0", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_4_8,
+                            0, UNIPHIER_PIN_DRV_1BIT,
                             0, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "ED1", UNIPHIER_PIN_IECTRL_NONE,
-                            1, UNIPHIER_PIN_DRV_4_8,
+                            1, UNIPHIER_PIN_DRV_1BIT,
                             1, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "ED2", UNIPHIER_PIN_IECTRL_NONE,
-                            2, UNIPHIER_PIN_DRV_4_8,
+                            2, UNIPHIER_PIN_DRV_1BIT,
                             2, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "ED3", UNIPHIER_PIN_IECTRL_NONE,
-                            3, UNIPHIER_PIN_DRV_4_8,
+                            3, UNIPHIER_PIN_DRV_1BIT,
                             3, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "ED4", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_4_8,
+                            4, UNIPHIER_PIN_DRV_1BIT,
                             4, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "ED5", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_4_8,
+                            5, UNIPHIER_PIN_DRV_1BIT,
                             5, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "ED6", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_4_8,
+                            6, UNIPHIER_PIN_DRV_1BIT,
                             6, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "ED7", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_4_8,
+                            7, UNIPHIER_PIN_DRV_1BIT,
                             7, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(13, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "XECS1", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(16, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(17, "SMTD0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(18, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(19, "SMTCLK0CG", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(20, "SMTDET0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(21, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(22, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(23, "SMTD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(24, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             24, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(25, "SMTCLK1CG", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             25, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(26, "SMTDET1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             26, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(27, "XIRQ18", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             27, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(28, "XIRQ19", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             28, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(29, "XIRQ20", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             29, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(30, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(33, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(34, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(35, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(36, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(37, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(38, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(39, "NFD0", UNIPHIER_PIN_IECTRL_NONE,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(40, "NFD1", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(41, "NFD2", UNIPHIER_PIN_IECTRL_NONE,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(42, "NFD3", UNIPHIER_PIN_IECTRL_NONE,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(43, "NFD4", UNIPHIER_PIN_IECTRL_NONE,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(44, "NFD5", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(45, "NFD6", UNIPHIER_PIN_IECTRL_NONE,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(46, "NFD7", UNIPHIER_PIN_IECTRL_NONE,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(47, "SDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(48, "SDCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(49, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(50, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(51, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(52, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(53, "SDCD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             53, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(54, "SDWP", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             54, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(55, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "USB1OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "USB2OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "USB3OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "XIRQ9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "XIRQ10", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "XIRQ16", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "STS0CLKO", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "STS0SYNCO", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "STS0VALO", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "STS0DATAO", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "XIRQ17", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "PORT163", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "PORT165", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "PORT166", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "PORT132", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "PORT133", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "AI2ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "AI2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             99, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "AI2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             100, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "AI2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "AI2D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(103, "AI2D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(104, "AI2D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(105, "AO3DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(106, "AO3BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(107, "AO3LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(108, "AO3DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(109, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             109, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(110, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             110, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(111, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             111, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(112, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             112, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(113, "TXD2", 0,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(114, "RXD2", 0,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "TXD1", 0,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "RXD1", 0,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(117, "PORT190", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(118, "VI1HSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             118, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(119, "VI1VSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             119, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(120, "VI1DE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             120, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             121, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             122, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "VI1G2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             123, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "VI1G3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             124, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "VI1G4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             125, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(126, "VI1G5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             126, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "VI1G6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             127, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(128, "VI1G7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             128, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "VI1G8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             129, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(130, "VI1G9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "VI1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "PORT05", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "PORT06", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "VI1R2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "VI1R3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(136, "VI1R4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             136, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(137, "VI1R5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             137, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(138, "VI1R6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             138, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(139, "VI1R7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             139, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(140, "VI1R8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             140, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(141, "VI1R9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             141, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "LPST", UNIPHIER_PIN_IECTRL_NONE,
-                            142, UNIPHIER_PIN_DRV_4_8,
+                            142, UNIPHIER_PIN_DRV_1BIT,
                             142, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(143, "MDC", 0,
-                            143, UNIPHIER_PIN_DRV_4_8,
+                            143, UNIPHIER_PIN_DRV_1BIT,
                             143, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(144, "MDIO", 0,
-                            144, UNIPHIER_PIN_DRV_4_8,
+                            144, UNIPHIER_PIN_DRV_1BIT,
                             144, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(145, "MDIO_INTL", 0,
-                            145, UNIPHIER_PIN_DRV_4_8,
+                            145, UNIPHIER_PIN_DRV_1BIT,
                             145, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(146, "PHYRSTL", 0,
-                            146, UNIPHIER_PIN_DRV_4_8,
+                            146, UNIPHIER_PIN_DRV_1BIT,
                             146, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(147, "RGMII_RXCLK", 0,
-                            147, UNIPHIER_PIN_DRV_4_8,
+                            147, UNIPHIER_PIN_DRV_1BIT,
                             147, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(148, "RGMII_RXD0", 0,
-                            148, UNIPHIER_PIN_DRV_4_8,
+                            148, UNIPHIER_PIN_DRV_1BIT,
                             148, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(149, "RGMII_RXD1", 0,
-                            149, UNIPHIER_PIN_DRV_4_8,
+                            149, UNIPHIER_PIN_DRV_1BIT,
                             149, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(150, "RGMII_RXD2", 0,
-                            150, UNIPHIER_PIN_DRV_4_8,
+                            150, UNIPHIER_PIN_DRV_1BIT,
                             150, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(151, "RGMII_RXD3", 0,
-                            151, UNIPHIER_PIN_DRV_4_8,
+                            151, UNIPHIER_PIN_DRV_1BIT,
                             151, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(152, "RGMII_RXCTL", 0,
-                            152, UNIPHIER_PIN_DRV_4_8,
+                            152, UNIPHIER_PIN_DRV_1BIT,
                             152, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(153, "RGMII_TXCLK", 0,
-                            153, UNIPHIER_PIN_DRV_4_8,
+                            153, UNIPHIER_PIN_DRV_1BIT,
                             153, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(154, "RGMII_TXD0", 0,
-                            154, UNIPHIER_PIN_DRV_4_8,
+                            154, UNIPHIER_PIN_DRV_1BIT,
                             154, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(155, "RGMII_TXD1", 0,
-                            155, UNIPHIER_PIN_DRV_4_8,
+                            155, UNIPHIER_PIN_DRV_1BIT,
                             155, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(156, "RGMII_TXD2", 0,
-                            156, UNIPHIER_PIN_DRV_4_8,
+                            156, UNIPHIER_PIN_DRV_1BIT,
                             156, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(157, "RGMII_TXD3", 0,
-                            157, UNIPHIER_PIN_DRV_4_8,
+                            157, UNIPHIER_PIN_DRV_1BIT,
                             157, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(158, "RGMII_TXCTL", 0,
-                            158, UNIPHIER_PIN_DRV_4_8,
+                            158, UNIPHIER_PIN_DRV_1BIT,
                             158, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(159, "SDA3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             159, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(160, "SCL3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             160, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             161, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             162, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             163, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(164, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             164, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(165, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             165, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(166, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             166, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(167, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             167, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(168, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             168, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(169, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             169, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(170, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             170, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(171, "SDA2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             171, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(172, "SCL2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             172, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(173, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             173, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(174, "AI1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             174, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(175, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             175, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(176, "AO2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             176, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(177, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             177, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(178, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             178, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(179, "PORT222", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             179, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(180, "PORT223", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             180, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(181, "PORT224", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             181, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(182, "PORT225", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             182, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(183, "PORT226", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             183, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(184, "PORT227", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             184, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(185, "PORT230", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             185, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(186, "FANPWM", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             186, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(187, "HRDDCSDA0", 0,
-                            187, UNIPHIER_PIN_DRV_4_8,
+                            187, UNIPHIER_PIN_DRV_1BIT,
                             187, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(188, "HRDDCSCL0", 0,
-                            188, UNIPHIER_PIN_DRV_4_8,
+                            188, UNIPHIER_PIN_DRV_1BIT,
                             188, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(189, "HRDDCSDA1", 0,
-                            189, UNIPHIER_PIN_DRV_4_8,
+                            189, UNIPHIER_PIN_DRV_1BIT,
                             189, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(190, "HRDDCSCL1", 0,
-                            190, UNIPHIER_PIN_DRV_4_8,
+                            190, UNIPHIER_PIN_DRV_1BIT,
                             190, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(191, "HTDDCSDA0", 0,
-                            191, UNIPHIER_PIN_DRV_4_8,
+                            191, UNIPHIER_PIN_DRV_1BIT,
                             191, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(192, "HTDDCSCL0", 0,
-                            192, UNIPHIER_PIN_DRV_4_8,
+                            192, UNIPHIER_PIN_DRV_1BIT,
                             192, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(193, "HTDDCSDA1", 0,
-                            193, UNIPHIER_PIN_DRV_4_8,
+                            193, UNIPHIER_PIN_DRV_1BIT,
                             193, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(194, "HTDDCSCL1", 0,
-                            194, UNIPHIER_PIN_DRV_4_8,
+                            194, UNIPHIER_PIN_DRV_1BIT,
                             194, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(195, "PORT241", 0,
-                            195, UNIPHIER_PIN_DRV_4_8,
+                            195, UNIPHIER_PIN_DRV_1BIT,
                             195, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(196, "PORT242", 0,
-                            196, UNIPHIER_PIN_DRV_4_8,
+                            196, UNIPHIER_PIN_DRV_1BIT,
                             196, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(197, "PORT243", 0,
-                            197, UNIPHIER_PIN_DRV_4_8,
+                            197, UNIPHIER_PIN_DRV_1BIT,
                             197, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(198, "MVSYNC", 0,
-                            198, UNIPHIER_PIN_DRV_4_8,
+                            198, UNIPHIER_PIN_DRV_1BIT,
                             198, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(199, "SPISYNC0", UNIPHIER_PIN_IECTRL_NONE,
-                            199, UNIPHIER_PIN_DRV_4_8,
+                            199, UNIPHIER_PIN_DRV_1BIT,
                             199, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(200, "SPISCLK0", UNIPHIER_PIN_IECTRL_NONE,
-                            200, UNIPHIER_PIN_DRV_4_8,
+                            200, UNIPHIER_PIN_DRV_1BIT,
                             200, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(201, "SPITXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            201, UNIPHIER_PIN_DRV_4_8,
+                            201, UNIPHIER_PIN_DRV_1BIT,
                             201, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(202, "SPIRXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            202, UNIPHIER_PIN_DRV_4_8,
+                            202, UNIPHIER_PIN_DRV_1BIT,
                             202, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(203, "CK54EXI", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             203, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(204, "AEXCKA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             204, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(205, "AEXCKA2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             205, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(206, "CK27EXI", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             206, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(207, "STCDIN", 0,
-                            207, UNIPHIER_PIN_DRV_4_8,
+                            207, UNIPHIER_PIN_DRV_1BIT,
                             207, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(208, "PHSYNI", 0,
-                            208, UNIPHIER_PIN_DRV_4_8,
+                            208, UNIPHIER_PIN_DRV_1BIT,
                             208, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(209, "PVSYNI", 0,
-                            209, UNIPHIER_PIN_DRV_4_8,
+                            209, UNIPHIER_PIN_DRV_1BIT,
                             209, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(210, "MVSYN", UNIPHIER_PIN_IECTRL_NONE,
-                            210, UNIPHIER_PIN_DRV_4_8,
+                            210, UNIPHIER_PIN_DRV_1BIT,
                             210, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(211, "STCV", UNIPHIER_PIN_IECTRL_NONE,
-                            211, UNIPHIER_PIN_DRV_4_8,
+                            211, UNIPHIER_PIN_DRV_1BIT,
                             211, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(212, "PORT262", UNIPHIER_PIN_IECTRL_NONE,
-                            212, UNIPHIER_PIN_DRV_4_8,
+                            212, UNIPHIER_PIN_DRV_1BIT,
                             212, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(213, "USB0VBUS_IRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             213, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(214, "USB1VBUS_IRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             214, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(215, "PORT265", UNIPHIER_PIN_IECTRL_NONE,
-                            215, UNIPHIER_PIN_DRV_4_8,
+                            215, UNIPHIER_PIN_DRV_1BIT,
                             215, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(216, "CK25O", 0,
-                            216, UNIPHIER_PIN_DRV_4_8,
+                            216, UNIPHIER_PIN_DRV_1BIT,
                             216, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(217, "TXD0", 0,
-                            217, UNIPHIER_PIN_DRV_4_8,
+                            217, UNIPHIER_PIN_DRV_1BIT,
                             217, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(218, "RXD0", 0,
-                            218, UNIPHIER_PIN_DRV_4_8,
+                            218, UNIPHIER_PIN_DRV_1BIT,
                             218, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(219, "TXD3", 0,
-                            219, UNIPHIER_PIN_DRV_4_8,
+                            219, UNIPHIER_PIN_DRV_1BIT,
                             219, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(220, "RXD3", 0,
-                            220, UNIPHIER_PIN_DRV_4_8,
+                            220, UNIPHIER_PIN_DRV_1BIT,
                             220, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(221, "PORT273", 0,
-                            221, UNIPHIER_PIN_DRV_4_8,
+                            221, UNIPHIER_PIN_DRV_1BIT,
                             221, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(222, "STCDOUTC", 0,
-                            222, UNIPHIER_PIN_DRV_4_8,
+                            222, UNIPHIER_PIN_DRV_1BIT,
                             222, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(223, "PORT274", 0,
-                            223, UNIPHIER_PIN_DRV_4_8,
+                            223, UNIPHIER_PIN_DRV_1BIT,
                             223, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(224, "PORT275", 0,
-                            224, UNIPHIER_PIN_DRV_4_8,
+                            224, UNIPHIER_PIN_DRV_1BIT,
                             224, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(225, "PORT276", 0,
-                            225, UNIPHIER_PIN_DRV_4_8,
+                            225, UNIPHIER_PIN_DRV_1BIT,
                             225, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(226, "PORT277", 0,
-                            226, UNIPHIER_PIN_DRV_4_8,
+                            226, UNIPHIER_PIN_DRV_1BIT,
                             226, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(227, "PORT280", 0,
-                            227, UNIPHIER_PIN_DRV_4_8,
+                            227, UNIPHIER_PIN_DRV_1BIT,
                             227, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(228, "PORT281", 0,
-                            228, UNIPHIER_PIN_DRV_4_8,
+                            228, UNIPHIER_PIN_DRV_1BIT,
                             228, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(229, "PORT282", 0,
-                            229, UNIPHIER_PIN_DRV_4_8,
+                            229, UNIPHIER_PIN_DRV_1BIT,
                             229, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(230, "PORT283", 0,
-                            230, UNIPHIER_PIN_DRV_4_8,
+                            230, UNIPHIER_PIN_DRV_1BIT,
                             230, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(231, "PORT284", 0,
-                            231, UNIPHIER_PIN_DRV_4_8,
+                            231, UNIPHIER_PIN_DRV_1BIT,
                             231, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(232, "PORT285", 0,
-                            232, UNIPHIER_PIN_DRV_4_8,
+                            232, UNIPHIER_PIN_DRV_1BIT,
                             232, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(233, "T0HPD", 0,
-                            233, UNIPHIER_PIN_DRV_4_8,
+                            233, UNIPHIER_PIN_DRV_1BIT,
                             233, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(234, "T1HPD", 0,
-                            234, UNIPHIER_PIN_DRV_4_8,
+                            234, UNIPHIER_PIN_DRV_1BIT,
                             234, UNIPHIER_PIN_PULL_DOWN),
 };
 
 static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42};
-static const unsigned emmc_muxvals[] = {9, 9, 9, 9, 9, 9, 9};
+static const int emmc_muxvals[] = {9, 9, 9, 9, 9, 9, 9};
 static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46};
-static const unsigned emmc_dat8_muxvals[] = {9, 9, 9, 9};
+static const int emmc_dat8_muxvals[] = {9, 9, 9, 9};
+static const unsigned ether_mii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                         150, 151, 152, 153, 154, 155, 156,
+                                         158, 159, 199, 200, 201, 202};
+static const int ether_mii_muxvals[] = {8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10,
+                                       10, 10, 10, 10, 10, 12, 12, 12, 12};
+static const unsigned ether_rgmii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                           150, 151, 152, 153, 154, 155, 156,
+                                           157, 158};
+static const int ether_rgmii_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                                         8, 8, 8, 8};
+static const unsigned ether_rmii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                          150, 152, 154, 155, 158};
+static const int ether_rmii_muxvals[] = {8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9};
 static const unsigned i2c0_pins[] = {109, 110};
-static const unsigned i2c0_muxvals[] = {8, 8};
+static const int i2c0_muxvals[] = {8, 8};
 static const unsigned i2c1_pins[] = {111, 112};
-static const unsigned i2c1_muxvals[] = {8, 8};
+static const int i2c1_muxvals[] = {8, 8};
 static const unsigned i2c2_pins[] = {171, 172};
-static const unsigned i2c2_muxvals[] = {8, 8};
+static const int i2c2_muxvals[] = {8, 8};
 static const unsigned i2c3_pins[] = {159, 160};
-static const unsigned i2c3_muxvals[] = {8, 8};
+static const int i2c3_muxvals[] = {8, 8};
 static const unsigned i2c5_pins[] = {183, 184};
-static const unsigned i2c5_muxvals[] = {11, 11};
+static const int i2c5_muxvals[] = {11, 11};
 static const unsigned i2c6_pins[] = {185, 186};
-static const unsigned i2c6_muxvals[] = {11, 11};
+static const int i2c6_muxvals[] = {11, 11};
 static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41,
                                     42, 43, 44, 45, 46};
-static const unsigned nand_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-                                       8, 8};
+static const int nand_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
 static const unsigned nand_cs1_pins[] = {37, 38};
-static const unsigned nand_cs1_muxvals[] = {8, 8};
+static const int nand_cs1_muxvals[] = {8, 8};
 static const unsigned sd_pins[] = {47, 48, 49, 50, 51, 52, 53, 54, 55};
-static const unsigned sd_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8};
+static const int sd_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8};
+static const unsigned system_bus_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+                                          11, 12, 13};
+static const int system_bus_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                                        8};
+static const unsigned system_bus_cs1_pins[] = {14};
+static const int system_bus_cs1_muxvals[] = {8};
 static const unsigned uart0_pins[] = {217, 218};
-static const unsigned uart0_muxvals[] = {8, 8};
+static const int uart0_muxvals[] = {8, 8};
 static const unsigned uart0b_pins[] = {179, 180};
-static const unsigned uart0b_muxvals[] = {10, 10};
+static const int uart0b_muxvals[] = {10, 10};
 static const unsigned uart1_pins[] = {115, 116};
-static const unsigned uart1_muxvals[] = {8, 8};
+static const int uart1_muxvals[] = {8, 8};
 static const unsigned uart2_pins[] = {113, 114};
-static const unsigned uart2_muxvals[] = {8, 8};
+static const int uart2_muxvals[] = {8, 8};
 static const unsigned uart3_pins[] = {219, 220};
-static const unsigned uart3_muxvals[] = {8, 8};
+static const int uart3_muxvals[] = {8, 8};
 static const unsigned uart3b_pins[] = {181, 182};
-static const unsigned uart3b_muxvals[] = {10, 10};
+static const int uart3b_muxvals[] = {10, 10};
 static const unsigned usb0_pins[] = {56, 57};
-static const unsigned usb0_muxvals[] = {8, 8};
+static const int usb0_muxvals[] = {8, 8};
 static const unsigned usb1_pins[] = {58, 59};
-static const unsigned usb1_muxvals[] = {8, 8};
+static const int usb1_muxvals[] = {8, 8};
 static const unsigned usb2_pins[] = {60, 61};
-static const unsigned usb2_muxvals[] = {8, 8};
+static const int usb2_muxvals[] = {8, 8};
 static const unsigned usb3_pins[] = {62, 63};
-static const unsigned usb3_muxvals[] = {8, 8};
+static const int usb3_muxvals[] = {8, 8};
 static const unsigned port_range0_pins[] = {
        127, 128, 129, 130, 131, 132, 133, 134,         /* PORT0x */
        135, 136, 137, 138, 139, 140, 141, 142,         /* PORT1x */
@@ -786,7 +802,7 @@ static const unsigned port_range0_pins[] = {
        61, 62, 63, 64, 65, 66, 67, 68,                 /* PORT9x */
        69, 70, 71, 76, 77, 78, 79, 80,                 /* PORT10x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
@@ -818,7 +834,7 @@ static const unsigned port_range1_pins[] = {
        218, 219, 220, 221, 223, 224, 225, 226,         /* PORT27x */
        227, 228, 229, 230, 231, 232, 233, 234,         /* PORT28x */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT12x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT13x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
@@ -842,15 +858,18 @@ static const unsigned xirq_pins[] = {
        126, 72, 73, 92, 177, 93, 94, 176,              /* XIRQ8-15 */
        74, 91, 27, 28, 29, 75, 20, 26,                 /* XIRQ16-23 */
 };
-static const unsigned xirq_muxvals[] = {
+static const int xirq_muxvals[] = {
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ8-15 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
 };
 
-static const struct uniphier_pinctrl_group proxstream2_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_pxs2_groups[] = {
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_mii),
+       UNIPHIER_PINCTRL_GROUP(ether_rgmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -860,6 +879,8 @@ static const struct uniphier_pinctrl_group proxstream2_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart0b),
        UNIPHIER_PINCTRL_GROUP(uart1),
@@ -1124,6 +1145,9 @@ static const struct uniphier_pinctrl_group proxstream2_groups[] = {
 };
 
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_mii_groups[] = {"ether_mii"};
+static const char * const ether_rgmii_groups[] = {"ether_rgmii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
@@ -1132,6 +1156,8 @@ static const char * const i2c5_groups[] = {"i2c5"};
 static const char * const i2c6_groups[] = {"i2c6"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1"};
 static const char * const uart0_groups[] = {"uart0", "uart0b"};
 static const char * const uart1_groups[] = {"uart1"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -1208,8 +1234,11 @@ static const char * const xirq_groups[] = {
        "xirq20", "xirq21", "xirq22", "xirq23",
 };
 
-static const struct uniphier_pinmux_function proxstream2_functions[] = {
+static const struct uniphier_pinmux_function uniphier_pxs2_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_mii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rgmii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
@@ -1218,6 +1247,7 @@ static const struct uniphier_pinmux_function proxstream2_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(i2c6),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -1230,43 +1260,36 @@ static const struct uniphier_pinmux_function proxstream2_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata proxstream2_pindata = {
-       .groups = proxstream2_groups,
-       .groups_count = ARRAY_SIZE(proxstream2_groups),
-       .functions = proxstream2_functions,
-       .functions_count = ARRAY_SIZE(proxstream2_functions),
-       .mux_bits = 8,
-       .reg_stride = 4,
-       .load_pinctrl = false,
-};
-
-static struct pinctrl_desc proxstream2_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = proxstream2_pins,
-       .npins = ARRAY_SIZE(proxstream2_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_pxs2_pindata = {
+       .pins = uniphier_pxs2_pins,
+       .npins = ARRAY_SIZE(uniphier_pxs2_pins),
+       .groups = uniphier_pxs2_groups,
+       .groups_count = ARRAY_SIZE(uniphier_pxs2_groups),
+       .functions = uniphier_pxs2_functions,
+       .functions_count = ARRAY_SIZE(uniphier_pxs2_functions),
+       .caps = 0,
 };
 
-static int proxstream2_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_pxs2_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &proxstream2_pinctrl_desc,
-                                     &proxstream2_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_pxs2_pindata);
 }
 
-static const struct of_device_id proxstream2_pinctrl_match[] = {
+static const struct of_device_id uniphier_pxs2_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-pxs2-pinctrl" },
        { .compatible = "socionext,proxstream2-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, proxstream2_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_pxs2_pinctrl_match);
 
-static struct platform_driver proxstream2_pinctrl_driver = {
-       .probe = proxstream2_pinctrl_probe,
+static struct platform_driver uniphier_pxs2_pinctrl_driver = {
+       .probe = uniphier_pxs2_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = proxstream2_pinctrl_match,
+               .name = "uniphier-pxs2-pinctrl",
+               .of_match_table = uniphier_pxs2_pinctrl_match,
        },
 };
-module_platform_driver(proxstream2_pinctrl_driver);
+module_platform_driver(uniphier_pxs2_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier ProXstream2 pinctrl driver");
index ceb7a9899bde310739a0b52c149f94d6b20a1556..da689d880f469af338fa66b6378dbd6d939107a4 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-sld8-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_sld8_pins[] = {
+static const struct pinctrl_pin_desc uniphier_sld8_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "PCA00", 0,
-                            15, UNIPHIER_PIN_DRV_4_8,
+                            15, UNIPHIER_PIN_DRV_1BIT,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "PCA01", 0,
-                            16, UNIPHIER_PIN_DRV_4_8,
+                            16, UNIPHIER_PIN_DRV_1BIT,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "PCA02", 0,
-                            17, UNIPHIER_PIN_DRV_4_8,
+                            17, UNIPHIER_PIN_DRV_1BIT,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "PCA03", 0,
-                            18, UNIPHIER_PIN_DRV_4_8,
+                            18, UNIPHIER_PIN_DRV_1BIT,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "PCA04", 0,
-                            19, UNIPHIER_PIN_DRV_4_8,
+                            19, UNIPHIER_PIN_DRV_1BIT,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "PCA05", 0,
-                            20, UNIPHIER_PIN_DRV_4_8,
+                            20, UNIPHIER_PIN_DRV_1BIT,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "PCA06", 0,
-                            21, UNIPHIER_PIN_DRV_4_8,
+                            21, UNIPHIER_PIN_DRV_1BIT,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "PCA07", 0,
-                            22, UNIPHIER_PIN_DRV_4_8,
+                            22, UNIPHIER_PIN_DRV_1BIT,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "PCA08", 0,
-                            23, UNIPHIER_PIN_DRV_4_8,
+                            23, UNIPHIER_PIN_DRV_1BIT,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "PCA09", 0,
-                            24, UNIPHIER_PIN_DRV_4_8,
+                            24, UNIPHIER_PIN_DRV_1BIT,
                             24, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "PCA10", 0,
-                            25, UNIPHIER_PIN_DRV_4_8,
+                            25, UNIPHIER_PIN_DRV_1BIT,
                             25, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "PCA11", 0,
-                            26, UNIPHIER_PIN_DRV_4_8,
+                            26, UNIPHIER_PIN_DRV_1BIT,
                             26, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "PCA12", 0,
-                            27, UNIPHIER_PIN_DRV_4_8,
+                            27, UNIPHIER_PIN_DRV_1BIT,
                             27, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(13, "PCA13", 0,
-                            28, UNIPHIER_PIN_DRV_4_8,
+                            28, UNIPHIER_PIN_DRV_1BIT,
                             28, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "PCA14", 0,
-                            29, UNIPHIER_PIN_DRV_4_8,
+                            29, UNIPHIER_PIN_DRV_1BIT,
                             29, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "XNFRE_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(16, "XNFWE_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(17, "NFALE_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(18, "NFCLE_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(19, "XNFWP_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(20, "XNFCE0_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(21, "NANDRYBY0_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(22, "XNFCE1_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             119, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(23, "NANDRYBY1_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             120, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(24, "NFD0_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             121, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(25, "NFD1_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             122, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(26, "NFD2_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             123, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(27, "NFD3_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             124, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(28, "NFD4_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_8_12_16_20,
+                            6, UNIPHIER_PIN_DRV_2BIT,
                             125, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(29, "NFD5_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_8_12_16_20,
+                            7, UNIPHIER_PIN_DRV_2BIT,
                             126, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(30, "NFD6_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_8_12_16_20,
+                            8, UNIPHIER_PIN_DRV_2BIT,
                             127, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "NFD7_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_8_12_16_20,
+                            9, UNIPHIER_PIN_DRV_2BIT,
                             128, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "SDCLK", 8,
-                            40, UNIPHIER_PIN_DRV_8_12_16_20,
+                            10, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(33, "SDCMD", 8,
-                            44, UNIPHIER_PIN_DRV_8_12_16_20,
+                            11, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(34, "SDDAT0", 8,
-                            48, UNIPHIER_PIN_DRV_8_12_16_20,
+                            12, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(35, "SDDAT1", 8,
-                            52, UNIPHIER_PIN_DRV_8_12_16_20,
+                            13, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(36, "SDDAT2", 8,
-                            56, UNIPHIER_PIN_DRV_8_12_16_20,
+                            14, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(37, "SDDAT3", 8,
-                            60, UNIPHIER_PIN_DRV_8_12_16_20,
+                            15, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(38, "SDCD", 8,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             129, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(39, "SDWP", 8,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(40, "SDVOLC", 9,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(41, "USB0VBUS", 0,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(42, "USB0OD", 0,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(43, "USB1VBUS", 0,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(44, "USB1OD", 0,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(45, "PCRESET", 0,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(46, "PCREG", 0,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(47, "PCCE2", 0,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(48, "PCVS1", 0,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(49, "PCCD2", 0,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(50, "PCCD1", 0,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(51, "PCREADY", 0,
-                            47, UNIPHIER_PIN_DRV_4_8,
+                            47, UNIPHIER_PIN_DRV_1BIT,
                             47, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(52, "PCDOE", 0,
-                            48, UNIPHIER_PIN_DRV_4_8,
+                            48, UNIPHIER_PIN_DRV_1BIT,
                             48, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(53, "PCCE1", 0,
-                            49, UNIPHIER_PIN_DRV_4_8,
+                            49, UNIPHIER_PIN_DRV_1BIT,
                             49, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(54, "PCWE", 0,
-                            50, UNIPHIER_PIN_DRV_4_8,
+                            50, UNIPHIER_PIN_DRV_1BIT,
                             50, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(55, "PCOE", 0,
-                            51, UNIPHIER_PIN_DRV_4_8,
+                            51, UNIPHIER_PIN_DRV_1BIT,
                             51, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "PCWAIT", 0,
-                            52, UNIPHIER_PIN_DRV_4_8,
+                            52, UNIPHIER_PIN_DRV_1BIT,
                             52, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "PCIOWR", 0,
-                            53, UNIPHIER_PIN_DRV_4_8,
+                            53, UNIPHIER_PIN_DRV_1BIT,
                             53, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "PCIORD", 0,
-                            54, UNIPHIER_PIN_DRV_4_8,
+                            54, UNIPHIER_PIN_DRV_1BIT,
                             54, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "HS0DIN0", 0,
-                            55, UNIPHIER_PIN_DRV_4_8,
+                            55, UNIPHIER_PIN_DRV_1BIT,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "HS0DIN1", 0,
-                            56, UNIPHIER_PIN_DRV_4_8,
+                            56, UNIPHIER_PIN_DRV_1BIT,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "HS0DIN2", 0,
-                            57, UNIPHIER_PIN_DRV_4_8,
+                            57, UNIPHIER_PIN_DRV_1BIT,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "HS0DIN3", 0,
-                            58, UNIPHIER_PIN_DRV_4_8,
+                            58, UNIPHIER_PIN_DRV_1BIT,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "HS0DIN4", 0,
-                            59, UNIPHIER_PIN_DRV_4_8,
+                            59, UNIPHIER_PIN_DRV_1BIT,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "HS0DIN5", 0,
-                            60, UNIPHIER_PIN_DRV_4_8,
+                            60, UNIPHIER_PIN_DRV_1BIT,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "HS0DIN6", 0,
-                            61, UNIPHIER_PIN_DRV_4_8,
+                            61, UNIPHIER_PIN_DRV_1BIT,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "HS0DIN7", 0,
-                            62, UNIPHIER_PIN_DRV_4_8,
+                            62, UNIPHIER_PIN_DRV_1BIT,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "HS0BCLKIN", 0,
-                            63, UNIPHIER_PIN_DRV_4_8,
+                            63, UNIPHIER_PIN_DRV_1BIT,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "HS0VALIN", 0,
-                            64, UNIPHIER_PIN_DRV_4_8,
+                            64, UNIPHIER_PIN_DRV_1BIT,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "HS0SYNCIN", 0,
-                            65, UNIPHIER_PIN_DRV_4_8,
+                            65, UNIPHIER_PIN_DRV_1BIT,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "HSDOUT0", 0,
-                            66, UNIPHIER_PIN_DRV_4_8,
+                            66, UNIPHIER_PIN_DRV_1BIT,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "HSDOUT1", 0,
-                            67, UNIPHIER_PIN_DRV_4_8,
+                            67, UNIPHIER_PIN_DRV_1BIT,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "HSDOUT2", 0,
-                            68, UNIPHIER_PIN_DRV_4_8,
+                            68, UNIPHIER_PIN_DRV_1BIT,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "HSDOUT3", 0,
-                            69, UNIPHIER_PIN_DRV_4_8,
+                            69, UNIPHIER_PIN_DRV_1BIT,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "HSDOUT4", 0,
-                            70, UNIPHIER_PIN_DRV_4_8,
+                            70, UNIPHIER_PIN_DRV_1BIT,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "HSDOUT5", 0,
-                            71, UNIPHIER_PIN_DRV_4_8,
+                            71, UNIPHIER_PIN_DRV_1BIT,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "HSDOUT6", 0,
-                            72, UNIPHIER_PIN_DRV_4_8,
+                            72, UNIPHIER_PIN_DRV_1BIT,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "HSDOUT7", 0,
-                            73, UNIPHIER_PIN_DRV_4_8,
+                            73, UNIPHIER_PIN_DRV_1BIT,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "HSBCLKOUT", 0,
-                            74, UNIPHIER_PIN_DRV_4_8,
+                            74, UNIPHIER_PIN_DRV_1BIT,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "HSVALOUT", 0,
-                            75, UNIPHIER_PIN_DRV_4_8,
+                            75, UNIPHIER_PIN_DRV_1BIT,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "HSSYNCOUT", 0,
-                            76, UNIPHIER_PIN_DRV_4_8,
+                            76, UNIPHIER_PIN_DRV_1BIT,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "HS1DIN0", 0,
-                            77, UNIPHIER_PIN_DRV_4_8,
+                            77, UNIPHIER_PIN_DRV_1BIT,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "HS1DIN1", 0,
-                            78, UNIPHIER_PIN_DRV_4_8,
+                            78, UNIPHIER_PIN_DRV_1BIT,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "HS1DIN2", 0,
-                            79, UNIPHIER_PIN_DRV_4_8,
+                            79, UNIPHIER_PIN_DRV_1BIT,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "HS1DIN3", 0,
-                            80, UNIPHIER_PIN_DRV_4_8,
+                            80, UNIPHIER_PIN_DRV_1BIT,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "HS1DIN4", 0,
-                            81, UNIPHIER_PIN_DRV_4_8,
+                            81, UNIPHIER_PIN_DRV_1BIT,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "HS1DIN5", 0,
-                            82, UNIPHIER_PIN_DRV_4_8,
+                            82, UNIPHIER_PIN_DRV_1BIT,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "HS1DIN6", 0,
-                            83, UNIPHIER_PIN_DRV_4_8,
+                            83, UNIPHIER_PIN_DRV_1BIT,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "HS1DIN7", 0,
-                            84, UNIPHIER_PIN_DRV_4_8,
+                            84, UNIPHIER_PIN_DRV_1BIT,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "HS1BCLKIN", 0,
-                            85, UNIPHIER_PIN_DRV_4_8,
+                            85, UNIPHIER_PIN_DRV_1BIT,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "HS1VALIN", 0,
-                            86, UNIPHIER_PIN_DRV_4_8,
+                            86, UNIPHIER_PIN_DRV_1BIT,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "HS1SYNCIN", 0,
-                            87, UNIPHIER_PIN_DRV_4_8,
+                            87, UNIPHIER_PIN_DRV_1BIT,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "AGCI", 3,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "AGCR", 4,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "AGCBS", 5,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "IECOUT", 0,
-                            88, UNIPHIER_PIN_DRV_4_8,
+                            88, UNIPHIER_PIN_DRV_1BIT,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "ASMCK", 0,
-                            89, UNIPHIER_PIN_DRV_4_8,
+                            89, UNIPHIER_PIN_DRV_1BIT,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "ABCKO", UNIPHIER_PIN_IECTRL_NONE,
-                            90, UNIPHIER_PIN_DRV_4_8,
+                            90, UNIPHIER_PIN_DRV_1BIT,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "ALRCKO", UNIPHIER_PIN_IECTRL_NONE,
-                            91, UNIPHIER_PIN_DRV_4_8,
+                            91, UNIPHIER_PIN_DRV_1BIT,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "ASDOUT0", UNIPHIER_PIN_IECTRL_NONE,
-                            92, UNIPHIER_PIN_DRV_4_8,
+                            92, UNIPHIER_PIN_DRV_1BIT,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "ASDOUT1", UNIPHIER_PIN_IECTRL_NONE,
-                            93, UNIPHIER_PIN_DRV_4_8,
+                            93, UNIPHIER_PIN_DRV_1BIT,
                             93, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(101, "ARCOUT", 0,
-                            94, UNIPHIER_PIN_DRV_4_8,
+                            94, UNIPHIER_PIN_DRV_1BIT,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "SDA0", 10,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(103, "SCL0", 10,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(104, "SDA1", 11,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(105, "SCL1", 11,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(106, "DMDSDA0", 12,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(107, "DMDSCL0", 12,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(108, "DMDSDA1", 13,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(109, "DMDSCL1", 13,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(110, "SBO0", UNIPHIER_PIN_IECTRL_NONE,
-                            95, UNIPHIER_PIN_DRV_4_8,
+                            95, UNIPHIER_PIN_DRV_1BIT,
                             95, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(111, "SBI0", UNIPHIER_PIN_IECTRL_NONE,
-                            96, UNIPHIER_PIN_DRV_4_8,
+                            96, UNIPHIER_PIN_DRV_1BIT,
                             96, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(112, "SBO1", 0,
-                            97, UNIPHIER_PIN_DRV_4_8,
+                            97, UNIPHIER_PIN_DRV_1BIT,
                             97, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(113, "SBI1", 0,
-                            98, UNIPHIER_PIN_DRV_4_8,
+                            98, UNIPHIER_PIN_DRV_1BIT,
                             98, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(114, "TXD1", 0,
-                            99, UNIPHIER_PIN_DRV_4_8,
+                            99, UNIPHIER_PIN_DRV_1BIT,
                             99, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "RXD1", 0,
-                            100, UNIPHIER_PIN_DRV_4_8,
+                            100, UNIPHIER_PIN_DRV_1BIT,
                             100, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "HIN", 1,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(117, "VIN", 2,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(118, "TCON0", 0,
-                            101, UNIPHIER_PIN_DRV_4_8,
+                            101, UNIPHIER_PIN_DRV_1BIT,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(119, "TCON1", 0,
-                            102, UNIPHIER_PIN_DRV_4_8,
+                            102, UNIPHIER_PIN_DRV_1BIT,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(120, "TCON2", 0,
-                            103, UNIPHIER_PIN_DRV_4_8,
+                            103, UNIPHIER_PIN_DRV_1BIT,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "TCON3", 0,
-                            104, UNIPHIER_PIN_DRV_4_8,
+                            104, UNIPHIER_PIN_DRV_1BIT,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "TCON4", 0,
-                            105, UNIPHIER_PIN_DRV_4_8,
+                            105, UNIPHIER_PIN_DRV_1BIT,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "TCON5", 0,
-                            106, UNIPHIER_PIN_DRV_4_8,
+                            106, UNIPHIER_PIN_DRV_1BIT,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "TCON6", 0,
-                            107, UNIPHIER_PIN_DRV_4_8,
+                            107, UNIPHIER_PIN_DRV_1BIT,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "TCON7", 0,
-                            108, UNIPHIER_PIN_DRV_4_8,
+                            108, UNIPHIER_PIN_DRV_1BIT,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(126, "TCON8", 0,
-                            109, UNIPHIER_PIN_DRV_4_8,
+                            109, UNIPHIER_PIN_DRV_1BIT,
                             109, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "PWMA", 0,
-                            110, UNIPHIER_PIN_DRV_4_8,
+                            110, UNIPHIER_PIN_DRV_1BIT,
                             110, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(128, "XIRQ0", 0,
-                            111, UNIPHIER_PIN_DRV_4_8,
+                            111, UNIPHIER_PIN_DRV_1BIT,
                             111, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "XIRQ1", 0,
-                            112, UNIPHIER_PIN_DRV_4_8,
+                            112, UNIPHIER_PIN_DRV_1BIT,
                             112, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(130, "XIRQ2", 0,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "XIRQ3", 0,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "XIRQ4", 0,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "XIRQ5", 0,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "XIRQ6", 0,
-                            117, UNIPHIER_PIN_DRV_4_8,
+                            117, UNIPHIER_PIN_DRV_1BIT,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "XIRQ7", 0,
-                            118, UNIPHIER_PIN_DRV_4_8,
+                            118, UNIPHIER_PIN_DRV_1BIT,
                             118, UNIPHIER_PIN_PULL_DOWN),
+       /* dedicated pins */
+       UNIPHIER_PINCTRL_PIN(136, "ED0", -1,
+                            0, UNIPHIER_PIN_DRV_1BIT,
+                            0, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(137, "ED1", -1,
+                            1, UNIPHIER_PIN_DRV_1BIT,
+                            1, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(138, "ED2", -1,
+                            2, UNIPHIER_PIN_DRV_1BIT,
+                            2, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(139, "ED3", -1,
+                            3, UNIPHIER_PIN_DRV_1BIT,
+                            3, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(140, "ED4", -1,
+                            4, UNIPHIER_PIN_DRV_1BIT,
+                            4, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(141, "ED5", -1,
+                            5, UNIPHIER_PIN_DRV_1BIT,
+                            5, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(142, "ED6", -1,
+                            6, UNIPHIER_PIN_DRV_1BIT,
+                            6, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(143, "ED7", -1,
+                            7, UNIPHIER_PIN_DRV_1BIT,
+                            7, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(144, "XERWE0", -1,
+                            8, UNIPHIER_PIN_DRV_1BIT,
+                            8, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(145, "XERWE1", -1,
+                            9, UNIPHIER_PIN_DRV_1BIT,
+                            9, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(146, "ERXW", -1,
+                            10, UNIPHIER_PIN_DRV_1BIT,
+                            10, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(147, "ES0", -1,
+                            11, UNIPHIER_PIN_DRV_1BIT,
+                            11, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(148, "ES1", -1,
+                            12, UNIPHIER_PIN_DRV_1BIT,
+                            12, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(149, "ES2", -1,
+                            13, UNIPHIER_PIN_DRV_1BIT,
+                            13, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(150, "XECS1", -1,
+                            14, UNIPHIER_PIN_DRV_1BIT,
+                            14, UNIPHIER_PIN_PULL_DOWN),
 };
 
 static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27};
-static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
+static const int emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
 static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31};
-static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const int emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const unsigned ether_mii_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14,
+                                         61, 63, 64, 65, 66, 67, 68};
+static const int ether_mii_muxvals[] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+                                       13, 13, 27, 27, 27, 27, 27, 27, 27};
+static const unsigned ether_rmii_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13,
+                                          14};
+static const int ether_rmii_muxvals[] = {13, 13, 13, 13, 13, 13, 13, 13, 13,
+                                        13, 13, 13};
 static const unsigned i2c0_pins[] = {102, 103};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {104, 105};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {108, 109};
-static const unsigned i2c2_muxvals[] = {2, 2};
+static const int i2c2_muxvals[] = {2, 2};
 static const unsigned i2c3_pins[] = {108, 109};
-static const unsigned i2c3_muxvals[] = {3, 3};
+static const int i2c3_muxvals[] = {3, 3};
 static const unsigned nand_pins[] = {15, 16, 17, 18, 19, 20, 21, 24, 25, 26,
                                     27, 28, 29, 30, 31};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {22, 23};
-static const unsigned nand_cs1_muxvals[] = {0, 0};
+static const int nand_cs1_muxvals[] = {0, 0};
 static const unsigned sd_pins[] = {32, 33, 34, 35, 36, 37, 38, 39, 40};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {136, 137, 138, 139, 140, 141, 142,
+                                          143, 144, 145, 146, 147, 148, 149};
+static const int system_bus_muxvals[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1,
+                                        -1, -1, -1, -1, -1};
+static const unsigned system_bus_cs1_pins[] = {150};
+static const int system_bus_cs1_muxvals[] = {-1};
+static const unsigned system_bus_cs2_pins[] = {10};
+static const int system_bus_cs2_muxvals[] = {1};
+static const unsigned system_bus_cs3_pins[] = {11};
+static const int system_bus_cs3_muxvals[] = {1};
+static const unsigned system_bus_cs4_pins[] = {12};
+static const int system_bus_cs4_muxvals[] = {1};
+static const unsigned system_bus_cs5_pins[] = {13};
+static const int system_bus_cs5_muxvals[] = {1};
 static const unsigned uart0_pins[] = {70, 71};
-static const unsigned uart0_muxvals[] = {3, 3};
+static const int uart0_muxvals[] = {3, 3};
 static const unsigned uart1_pins[] = {114, 115};
-static const unsigned uart1_muxvals[] = {0, 0};
+static const int uart1_muxvals[] = {0, 0};
 static const unsigned uart2_pins[] = {112, 113};
-static const unsigned uart2_muxvals[] = {1, 1};
+static const int uart2_muxvals[] = {1, 1};
 static const unsigned uart3_pins[] = {110, 111};
-static const unsigned uart3_muxvals[] = {1, 1};
+static const int uart3_muxvals[] = {1, 1};
 static const unsigned usb0_pins[] = {41, 42};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {43, 44};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {114, 115};
-static const unsigned usb2_muxvals[] = {1, 1};
+static const int usb2_muxvals[] = {1, 1};
 static const unsigned port_range0_pins[] = {
        0, 1, 2, 3, 4, 5, 6, 7,                         /* PORT0x */
        8, 9, 10, 11, 12, 13, 14, 15,                   /* PORT1x */
@@ -481,7 +546,7 @@ static const unsigned port_range0_pins[] = {
        48, 49, 46, 45, 123, 124, 125, 126,             /* PORT11x */
        47, 127, 20, 56, 22,                            /* PORT120-124 */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
@@ -499,39 +564,41 @@ static const unsigned port_range0_muxvals[] = {
 static const unsigned port_range1_pins[] = {
        116, 117,                                       /* PORT130-131 */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15, 15,                                         /* PORT130-131 */
 };
 static const unsigned port_range2_pins[] = {
        102, 103, 104, 105, 106, 107, 108, 109,         /* PORT14x */
 };
-static const unsigned port_range2_muxvals[] = {
+static const int port_range2_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
 };
 static const unsigned port_range3_pins[] = {
        23,                                             /* PORT166 */
 };
-static const unsigned port_range3_muxvals[] = {
+static const int port_range3_muxvals[] = {
        15,                                             /* PORT166 */
 };
 static const unsigned xirq_range0_pins[] = {
        128, 129, 130, 131, 132, 133, 134, 135,         /* XIRQ0-7 */
        82, 87, 88, 50, 51,                             /* XIRQ8-12 */
 };
-static const unsigned xirq_range0_muxvals[] = {
+static const int xirq_range0_muxvals[] = {
        0, 0, 0, 0, 0, 0, 0, 0,                         /* XIRQ0-7 */
        14, 14, 14, 14, 14,                             /* XIRQ8-12 */
 };
 static const unsigned xirq_range1_pins[] = {
        52, 58,                                         /* XIRQ14-15 */
 };
-static const unsigned xirq_range1_muxvals[] = {
+static const int xirq_range1_muxvals[] = {
        14, 14,                                         /* XIRQ14-15 */
 };
 
-static const struct uniphier_pinctrl_group ph1_sld8_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_sld8_groups[] = {
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_mii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -539,6 +606,12 @@ static const struct uniphier_pinctrl_group ph1_sld8_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs4),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs5),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart1),
        UNIPHIER_PINCTRL_GROUP(uart2),
@@ -682,12 +755,20 @@ static const struct uniphier_pinctrl_group ph1_sld8_groups[] = {
 };
 
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_mii_groups[] = {"ether_mii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
 static const char * const i2c3_groups[] = {"i2c3"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3",
+                                                "system_bus_cs4",
+                                                "system_bus_cs5"};
 static const char * const uart0_groups[] = {"uart0"};
 static const char * const uart1_groups[] = {"uart1"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -736,14 +817,17 @@ static const char * const xirq_groups[] = {
        "xirq12", /* none*/ "xirq14", "xirq15",
 };
 
-static const struct uniphier_pinmux_function ph1_sld8_functions[] = {
+static const struct uniphier_pinmux_function uniphier_sld8_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_mii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
        UNIPHIER_PINMUX_FUNCTION(i2c3),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -755,43 +839,36 @@ static const struct uniphier_pinmux_function ph1_sld8_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_sld8_pindata = {
-       .groups = ph1_sld8_groups,
-       .groups_count = ARRAY_SIZE(ph1_sld8_groups),
-       .functions = ph1_sld8_functions,
-       .functions_count = ARRAY_SIZE(ph1_sld8_functions),
-       .mux_bits = 8,
-       .reg_stride = 4,
-       .load_pinctrl = false,
-};
-
-static struct pinctrl_desc ph1_sld8_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_sld8_pins,
-       .npins = ARRAY_SIZE(ph1_sld8_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_sld8_pindata = {
+       .pins = uniphier_sld8_pins,
+       .npins = ARRAY_SIZE(uniphier_sld8_pins),
+       .groups = uniphier_sld8_groups,
+       .groups_count = ARRAY_SIZE(uniphier_sld8_groups),
+       .functions = uniphier_sld8_functions,
+       .functions_count = ARRAY_SIZE(uniphier_sld8_functions),
+       .caps = 0,
 };
 
-static int ph1_sld8_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_sld8_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_sld8_pinctrl_desc,
-                                     &ph1_sld8_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_sld8_pindata);
 }
 
-static const struct of_device_id ph1_sld8_pinctrl_match[] = {
+static const struct of_device_id uniphier_sld8_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-sld8-pinctrl" },
        { .compatible = "socionext,ph1-sld8-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_sld8_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_sld8_pinctrl_match);
 
-static struct platform_driver ph1_sld8_pinctrl_driver = {
-       .probe = ph1_sld8_pinctrl_probe,
+static struct platform_driver uniphier_sld8_pinctrl_driver = {
+       .probe = uniphier_sld8_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_sld8_pinctrl_match,
+               .name = "uniphier-sld8-pinctrl",
+               .of_match_table = uniphier_sld8_pinctrl_match,
        },
 };
-module_platform_driver(ph1_sld8_pinctrl_driver);
+module_platform_driver(uniphier_sld8_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-sLD8 pinctrl driver");
index a21154f4b453334d80796b892b770d795aab731d..923f36cb245da94a9d2cde3560d2b1a46481eabb 100644 (file)
 #ifndef __PINCTRL_UNIPHIER_H__
 #define __PINCTRL_UNIPHIER_H__
 
+#include <linux/bitops.h>
 #include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 
+struct platform_device;
+
 #define UNIPHIER_PINCTRL_PINMUX_BASE   0x0
 #define UNIPHIER_PINCTRL_LOAD_PINMUX   0x700
 #define UNIPHIER_PINCTRL_DRVCTRL_BASE  0x800
 #define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x900
+#define UNIPHIER_PINCTRL_DRV3CTRL_BASE 0x980
 #define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0xa00
 #define UNIPHIER_PINCTRL_IECTRL                0xd00
 
 #define UNIPHIER_PIN_DRVCTRL_MASK      ((1UL << (UNIPHIER_PIN_DRVCTRL_BITS)) \
                                         - 1)
 
-/* supported drive strength (mA) */
-#define UNIPHIER_PIN_DRV_STR_SHIFT     ((UNIPHIER_PIN_DRVCTRL_SHIFT) + \
+/* drive control type */
+#define UNIPHIER_PIN_DRV_TYPE_SHIFT    ((UNIPHIER_PIN_DRVCTRL_SHIFT) + \
                                         (UNIPHIER_PIN_DRVCTRL_BITS))
-#define UNIPHIER_PIN_DRV_STR_BITS      3
-#define UNIPHIER_PIN_DRV_STR_MASK      ((1UL << (UNIPHIER_PIN_DRV_STR_BITS)) \
+#define UNIPHIER_PIN_DRV_TYPE_BITS     3
+#define UNIPHIER_PIN_DRV_TYPE_MASK     ((1UL << (UNIPHIER_PIN_DRV_TYPE_BITS)) \
                                         - 1)
 
 /* pull-up / pull-down register number */
-#define UNIPHIER_PIN_PUPDCTRL_SHIFT    ((UNIPHIER_PIN_DRV_STR_SHIFT) + \
-                                        (UNIPHIER_PIN_DRV_STR_BITS))
+#define UNIPHIER_PIN_PUPDCTRL_SHIFT    ((UNIPHIER_PIN_DRV_TYPE_SHIFT) + \
+                                        (UNIPHIER_PIN_DRV_TYPE_BITS))
 #define UNIPHIER_PIN_PUPDCTRL_BITS     9
 #define UNIPHIER_PIN_PUPDCTRL_MASK     ((1UL << (UNIPHIER_PIN_PUPDCTRL_BITS))\
                                         - 1)
 
 #define UNIPHIER_PIN_IECTRL_NONE       (UNIPHIER_PIN_IECTRL_MASK)
 
-/* selectable drive strength */
-enum uniphier_pin_drv_str {
-       UNIPHIER_PIN_DRV_4_8,           /* 2 level control: 4/8 mA */
-       UNIPHIER_PIN_DRV_8_12_16_20,    /* 4 level control: 8/12/16/20 mA */
-       UNIPHIER_PIN_DRV_FIXED_4,       /* fixed to 4mA */
-       UNIPHIER_PIN_DRV_FIXED_5,       /* fixed to 5mA */
-       UNIPHIER_PIN_DRV_FIXED_8,       /* fixed to 8mA */
+/* drive control type */
+enum uniphier_pin_drv_type {
+       UNIPHIER_PIN_DRV_1BIT,          /* 2 level control: 4/8 mA */
+       UNIPHIER_PIN_DRV_2BIT,          /* 4 level control: 8/12/16/20 mA */
+       UNIPHIER_PIN_DRV_3BIT,          /* 8 level control: 4/5/7/9/11/12/14/16 mA */
+       UNIPHIER_PIN_DRV_FIXED4,        /* fixed to 4mA */
+       UNIPHIER_PIN_DRV_FIXED5,        /* fixed to 5mA */
+       UNIPHIER_PIN_DRV_FIXED8,        /* fixed to 8mA */
        UNIPHIER_PIN_DRV_NONE,          /* no support (input only pin) */
 };
 
@@ -89,17 +94,17 @@ enum uniphier_pin_pull_dir {
        (((x) & (UNIPHIER_PIN_IECTRL_MASK)) << (UNIPHIER_PIN_IECTRL_SHIFT))
 #define UNIPHIER_PIN_DRVCTRL(x) \
        (((x) & (UNIPHIER_PIN_DRVCTRL_MASK)) << (UNIPHIER_PIN_DRVCTRL_SHIFT))
-#define UNIPHIER_PIN_DRV_STR(x) \
-       (((x) & (UNIPHIER_PIN_DRV_STR_MASK)) << (UNIPHIER_PIN_DRV_STR_SHIFT))
+#define UNIPHIER_PIN_DRV_TYPE(x) \
+       (((x) & (UNIPHIER_PIN_DRV_TYPE_MASK)) << (UNIPHIER_PIN_DRV_TYPE_SHIFT))
 #define UNIPHIER_PIN_PUPDCTRL(x) \
        (((x) & (UNIPHIER_PIN_PUPDCTRL_MASK)) << (UNIPHIER_PIN_PUPDCTRL_SHIFT))
 #define UNIPHIER_PIN_PULL_DIR(x) \
        (((x) & (UNIPHIER_PIN_PULL_DIR_MASK)) << (UNIPHIER_PIN_PULL_DIR_SHIFT))
 
-#define UNIPHIER_PIN_ATTR_PACKED(iectrl, drvctrl, drv_str, pupdctrl, pull_dir)\
+#define UNIPHIER_PIN_ATTR_PACKED(iectrl, drvctrl, drv_type, pupdctrl, pull_dir)\
                                (UNIPHIER_PIN_IECTRL(iectrl) |          \
                                 UNIPHIER_PIN_DRVCTRL(drvctrl) |        \
-                                UNIPHIER_PIN_DRV_STR(drv_str) |        \
+                                UNIPHIER_PIN_DRV_TYPE(drv_type) |      \
                                 UNIPHIER_PIN_PUPDCTRL(pupdctrl) |      \
                                 UNIPHIER_PIN_PULL_DIR(pull_dir))
 
@@ -115,10 +120,10 @@ static inline unsigned int uniphier_pin_get_drvctrl(void *drv_data)
                                                UNIPHIER_PIN_DRVCTRL_MASK;
 }
 
-static inline unsigned int uniphier_pin_get_drv_str(void *drv_data)
+static inline unsigned int uniphier_pin_get_drv_type(void *drv_data)
 {
-       return ((unsigned long)drv_data >> UNIPHIER_PIN_DRV_STR_SHIFT) &
-                                               UNIPHIER_PIN_DRV_STR_MASK;
+       return ((unsigned long)drv_data >> UNIPHIER_PIN_DRV_TYPE_SHIFT) &
+                                               UNIPHIER_PIN_DRV_TYPE_MASK;
 }
 
 static inline unsigned int uniphier_pin_get_pupdctrl(void *drv_data)
@@ -143,7 +148,7 @@ struct uniphier_pinctrl_group {
        const char *name;
        const unsigned *pins;
        unsigned num_pins;
-       const unsigned *muxvals;
+       const int *muxvals;
        enum uniphier_pinmux_gpio_range_type range_type;
 };
 
@@ -154,13 +159,15 @@ struct uniphier_pinmux_function {
 };
 
 struct uniphier_pinctrl_socdata {
+       const struct pinctrl_pin_desc *pins;
+       unsigned int npins;
        const struct uniphier_pinctrl_group *groups;
        int groups_count;
        const struct uniphier_pinmux_function *functions;
        int functions_count;
-       unsigned mux_bits;
-       unsigned reg_stride;
-       bool load_pinctrl;
+       unsigned int caps;
+#define UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL    BIT(1)
+#define UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE  BIT(0)
 };
 
 #define UNIPHIER_PINCTRL_PIN(a, b, c, d, e, f, g)                      \
@@ -205,11 +212,7 @@ struct uniphier_pinctrl_socdata {
                .num_groups = ARRAY_SIZE(func##_groups),                \
        }
 
-struct platform_device;
-struct pinctrl_desc;
-
 int uniphier_pinctrl_probe(struct platform_device *pdev,
-                          struct pinctrl_desc *desc,
                           struct uniphier_pinctrl_socdata *socdata);
 
 #endif /* __PINCTRL_UNIPHIER_H__ */
index 72e97d7a520912693e31f2334aba46c0ea8175fa..1a8bf76a925fa86e12c00e9c2a1e097a5dda333a 100644 (file)
@@ -77,6 +77,20 @@ config DA8XX_REMOTEPROC
          It's safe to say n here if you're not interested in multimedia
          offloading.
 
+config QCOM_MDT_LOADER
+       tristate
+
+config QCOM_Q6V5_PIL
+       tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
+       depends on OF && ARCH_QCOM
+       depends on QCOM_SMEM
+       select MFD_SYSCON
+       select QCOM_MDT_LOADER
+       select REMOTEPROC
+       help
+         Say y here to support the Qualcomm Peripherial Image Loader for the
+         Hexagon V5 based remote processors.
+
 config ST_REMOTEPROC
        tristate "ST remoteproc support"
        depends on ARCH_STI
index 279cb2edc880939d5745ffd65de77e21fc1d323c..92d3758bd15cc7c7c65b6f6c21d5c1d06c2d2a42 100644 (file)
@@ -11,4 +11,6 @@ obj-$(CONFIG_OMAP_REMOTEPROC)         += omap_remoteproc.o
 obj-$(CONFIG_STE_MODEM_RPROC)          += ste_modem_rproc.o
 obj-$(CONFIG_WKUP_M3_RPROC)            += wkup_m3_rproc.o
 obj-$(CONFIG_DA8XX_REMOTEPROC)         += da8xx_remoteproc.o
+obj-$(CONFIG_QCOM_MDT_LOADER)          += qcom_mdt_loader.o
+obj-$(CONFIG_QCOM_Q6V5_PIL)            += qcom_q6v5_pil.o
 obj-$(CONFIG_ST_REMOTEPROC)            += st_remoteproc.o
diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/remoteproc/qcom_mdt_loader.c
new file mode 100644 (file)
index 0000000..114e8e4
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2015 Sony Mobile Communications Inc
+ * Copyright (c) 2012-2013, 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 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.
+ */
+
+#include <linux/elf.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/remoteproc.h>
+#include <linux/slab.h>
+
+#include "remoteproc_internal.h"
+#include "qcom_mdt_loader.h"
+
+/**
+ * qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc
+ * @rproc:     remoteproc handle
+ * @fw:                firmware header
+ * @tablesz:   outgoing size of the table
+ *
+ * Returns a dummy table.
+ */
+struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc,
+                                              const struct firmware *fw,
+                                              int *tablesz)
+{
+       static struct resource_table table = { .ver = 1, };
+
+       *tablesz = sizeof(table);
+       return &table;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table);
+
+/**
+ * qcom_mdt_parse() - extract useful parameters from the mdt header
+ * @fw:                firmware handle
+ * @fw_addr:   optional reference for base of the firmware's memory region
+ * @fw_size:   optional reference for size of the firmware's memory region
+ * @fw_relocate: optional reference for flagging if the firmware is relocatable
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr,
+                  size_t *fw_size, bool *fw_relocate)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
+       phys_addr_t max_addr = 0;
+       bool relocate = false;
+       int i;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
+                       relocate = true;
+
+               if (phdr->p_paddr < min_addr)
+                       min_addr = phdr->p_paddr;
+
+               if (phdr->p_paddr + phdr->p_memsz > max_addr)
+                       max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
+       }
+
+       if (fw_addr)
+               *fw_addr = min_addr;
+       if (fw_size)
+               *fw_size = max_addr - min_addr;
+       if (fw_relocate)
+               *fw_relocate = relocate;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_parse);
+
+/**
+ * qcom_mdt_load() - load the firmware which header is defined in fw
+ * @rproc:     rproc handle
+ * @fw:                frimware object for the header
+ * @firmware:  filename of the firmware, for building .bXX names
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+int qcom_mdt_load(struct rproc *rproc,
+                 const struct firmware *fw,
+                 const char *firmware)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       size_t fw_name_len;
+       char *fw_name;
+       void *ptr;
+       int ret;
+       int i;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       fw_name_len = strlen(firmware);
+       if (fw_name_len <= 4)
+               return -EINVAL;
+
+       fw_name = kstrdup(firmware, GFP_KERNEL);
+       if (!fw_name)
+               return -ENOMEM;
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               ptr = rproc_da_to_va(rproc, phdr->p_paddr, phdr->p_memsz);
+               if (!ptr) {
+                       dev_err(&rproc->dev, "segment outside memory range\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (phdr->p_filesz) {
+                       sprintf(fw_name + fw_name_len - 3, "b%02d", i);
+                       ret = request_firmware(&fw, fw_name, &rproc->dev);
+                       if (ret) {
+                               dev_err(&rproc->dev, "failed to load %s\n",
+                                       fw_name);
+                               break;
+                       }
+
+                       memcpy(ptr, fw->data, fw->size);
+
+                       release_firmware(fw);
+               }
+
+               if (phdr->p_memsz > phdr->p_filesz)
+                       memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+       }
+
+       kfree(fw_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_load);
+
+MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_mdt_loader.h b/drivers/remoteproc/qcom_mdt_loader.h
new file mode 100644 (file)
index 0000000..c5d7122
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __QCOM_MDT_LOADER_H__
+#define __QCOM_MDT_LOADER_H__
+
+#define QCOM_MDT_TYPE_MASK     (7 << 24)
+#define QCOM_MDT_TYPE_HASH     (2 << 24)
+#define QCOM_MDT_RELOCATABLE   BIT(27)
+
+struct resource_table * qcom_mdt_find_rsc_table(struct rproc *rproc, const struct firmware *fw, int *tablesz);
+int qcom_mdt_load(struct rproc *rproc, const struct firmware *fw, const char *fw_name);
+
+int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate);
+
+#endif
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
new file mode 100644 (file)
index 0000000..2479188
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd.
+ * Copyright (C) 2014 Sony Mobile Communications AB
+ * Copyright (c) 2012-2013, 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 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/remoteproc.h>
+#include <linux/reset.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
+
+#include "remoteproc_internal.h"
+#include "qcom_mdt_loader.h"
+
+#include <linux/qcom_scm.h>
+
+#define MBA_FIRMWARE_NAME              "mba.b00"
+#define MPSS_FIRMWARE_NAME             "modem.mdt"
+
+#define MPSS_CRASH_REASON_SMEM         421
+
+/* RMB Status Register Values */
+#define RMB_PBL_SUCCESS                        0x1
+
+#define RMB_MBA_XPU_UNLOCKED           0x1
+#define RMB_MBA_XPU_UNLOCKED_SCRIBBLED 0x2
+#define RMB_MBA_META_DATA_AUTH_SUCCESS 0x3
+#define RMB_MBA_AUTH_COMPLETE          0x4
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE_REG              0x00
+#define RMB_PBL_STATUS_REG             0x04
+#define RMB_MBA_COMMAND_REG            0x08
+#define RMB_MBA_STATUS_REG             0x0C
+#define RMB_PMI_META_DATA_REG          0x10
+#define RMB_PMI_CODE_START_REG         0x14
+#define RMB_PMI_CODE_LENGTH_REG                0x18
+
+#define RMB_CMD_META_DATA_READY                0x1
+#define RMB_CMD_LOAD_READY             0x2
+
+/* QDSP6SS Register Offsets */
+#define QDSP6SS_RESET_REG              0x014
+#define QDSP6SS_GFMUX_CTL_REG          0x020
+#define QDSP6SS_PWR_CTL_REG            0x030
+
+/* AXI Halt Register Offsets */
+#define AXI_HALTREQ_REG                        0x0
+#define AXI_HALTACK_REG                        0x4
+#define AXI_IDLE_REG                   0x8
+
+#define HALT_ACK_TIMEOUT_MS            100
+
+/* QDSP6SS_RESET */
+#define Q6SS_STOP_CORE                 BIT(0)
+#define Q6SS_CORE_ARES                 BIT(1)
+#define Q6SS_BUS_ARES_ENABLE           BIT(2)
+
+/* QDSP6SS_GFMUX_CTL */
+#define Q6SS_CLK_ENABLE                        BIT(1)
+
+/* QDSP6SS_PWR_CTL */
+#define Q6SS_L2DATA_SLP_NRET_N_0       BIT(0)
+#define Q6SS_L2DATA_SLP_NRET_N_1       BIT(1)
+#define Q6SS_L2DATA_SLP_NRET_N_2       BIT(2)
+#define Q6SS_L2TAG_SLP_NRET_N          BIT(16)
+#define Q6SS_ETB_SLP_NRET_N            BIT(17)
+#define Q6SS_L2DATA_STBY_N             BIT(18)
+#define Q6SS_SLP_RET_N                 BIT(19)
+#define Q6SS_CLAMP_IO                  BIT(20)
+#define QDSS_BHS_ON                    BIT(21)
+#define QDSS_LDO_BYP                   BIT(22)
+
+struct q6v5 {
+       struct device *dev;
+       struct rproc *rproc;
+
+       void __iomem *reg_base;
+       void __iomem *rmb_base;
+
+       struct regmap *halt_map;
+       u32 halt_q6;
+       u32 halt_modem;
+       u32 halt_nc;
+
+       struct reset_control *mss_restart;
+
+       struct qcom_smem_state *state;
+       unsigned stop_bit;
+
+       struct regulator_bulk_data supply[4];
+
+       struct clk *ahb_clk;
+       struct clk *axi_clk;
+       struct clk *rom_clk;
+
+       struct completion start_done;
+       struct completion stop_done;
+       bool running;
+
+       phys_addr_t mba_phys;
+       void *mba_region;
+       size_t mba_size;
+
+       phys_addr_t mpss_phys;
+       phys_addr_t mpss_reloc;
+       void *mpss_region;
+       size_t mpss_size;
+};
+
+enum {
+       Q6V5_SUPPLY_CX,
+       Q6V5_SUPPLY_MX,
+       Q6V5_SUPPLY_MSS,
+       Q6V5_SUPPLY_PLL,
+};
+
+static int q6v5_regulator_init(struct q6v5 *qproc)
+{
+       int ret;
+
+       qproc->supply[Q6V5_SUPPLY_CX].supply = "cx";
+       qproc->supply[Q6V5_SUPPLY_MX].supply = "mx";
+       qproc->supply[Q6V5_SUPPLY_MSS].supply = "mss";
+       qproc->supply[Q6V5_SUPPLY_PLL].supply = "pll";
+
+       ret = devm_regulator_bulk_get(qproc->dev,
+                                     ARRAY_SIZE(qproc->supply), qproc->supply);
+       if (ret < 0) {
+               dev_err(qproc->dev, "failed to get supplies\n");
+               return ret;
+       }
+
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_CX].consumer, 100000);
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 100000);
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_PLL].consumer, 10000);
+
+       return 0;
+}
+
+static int q6v5_regulator_enable(struct q6v5 *qproc)
+{
+       struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer;
+       struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer;
+       int ret;
+
+       /* TODO: Q6V5_SUPPLY_CX is supposed to be set to super-turbo here */
+
+       ret = regulator_set_voltage(mx, 1050000, INT_MAX);
+       if (ret)
+               return ret;
+
+       regulator_set_voltage(mss, 1000000, 1150000);
+
+       return regulator_bulk_enable(ARRAY_SIZE(qproc->supply), qproc->supply);
+}
+
+static void q6v5_regulator_disable(struct q6v5 *qproc)
+{
+       struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer;
+       struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer;
+
+       /* TODO: Q6V5_SUPPLY_CX corner votes should be released */
+
+       regulator_bulk_disable(ARRAY_SIZE(qproc->supply), qproc->supply);
+       regulator_set_voltage(mx, 0, INT_MAX);
+       regulator_set_voltage(mss, 0, 1150000);
+}
+
+static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
+{
+       struct q6v5 *qproc = rproc->priv;
+
+       memcpy(qproc->mba_region, fw->data, fw->size);
+
+       return 0;
+}
+
+static const struct rproc_fw_ops q6v5_fw_ops = {
+       .find_rsc_table = qcom_mdt_find_rsc_table,
+       .load = q6v5_load,
+};
+
+static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms)
+{
+       unsigned long timeout;
+       s32 val;
+
+       timeout = jiffies + msecs_to_jiffies(ms);
+       for (;;) {
+               val = readl(qproc->rmb_base + RMB_PBL_STATUS_REG);
+               if (val)
+                       break;
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+       }
+
+       return val;
+}
+
+static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms)
+{
+
+       unsigned long timeout;
+       s32 val;
+
+       timeout = jiffies + msecs_to_jiffies(ms);
+       for (;;) {
+               val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG);
+               if (val < 0)
+                       break;
+
+               if (!status && val)
+                       break;
+               else if (status && val == status)
+                       break;
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+       }
+
+       return val;
+}
+
+static int q6v5proc_reset(struct q6v5 *qproc)
+{
+       u32 val;
+       int ret;
+
+       /* Assert resets, stop core */
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
+       val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE);
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
+
+       /* Enable power block headswitch, and wait for it to stabilize */
+       val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= QDSS_BHS_ON | QDSS_LDO_BYP;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       udelay(1);
+
+       /*
+        * Turn on memories. L2 banks should be done individually
+        * to minimize inrush current.
+        */
+       val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N |
+               Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= Q6SS_L2DATA_SLP_NRET_N_2;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= Q6SS_L2DATA_SLP_NRET_N_1;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= Q6SS_L2DATA_SLP_NRET_N_0;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+       /* Remove IO clamp */
+       val &= ~Q6SS_CLAMP_IO;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+       /* Bring core out of reset */
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
+       val &= ~Q6SS_CORE_ARES;
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
+
+       /* Turn on core clock */
+       val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
+       val |= Q6SS_CLK_ENABLE;
+       writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
+
+       /* Start core execution */
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
+       val &= ~Q6SS_STOP_CORE;
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
+
+       /* Wait for PBL status */
+       ret = q6v5_rmb_pbl_wait(qproc, 1000);
+       if (ret == -ETIMEDOUT) {
+               dev_err(qproc->dev, "PBL boot timed out\n");
+       } else if (ret != RMB_PBL_SUCCESS) {
+               dev_err(qproc->dev, "PBL returned unexpected status %d\n", ret);
+               ret = -EINVAL;
+       } else {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
+                                  struct regmap *halt_map,
+                                  u32 offset)
+{
+       unsigned long timeout;
+       unsigned int val;
+       int ret;
+
+       /* Check if we're already idle */
+       ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
+       if (!ret && val)
+               return;
+
+       /* Assert halt request */
+       regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
+
+       /* Wait for halt */
+       timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
+       for (;;) {
+               ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
+               if (ret || val || time_after(jiffies, timeout))
+                       break;
+
+               msleep(1);
+       }
+
+       ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
+       if (ret || !val)
+               dev_err(qproc->dev, "port failed halt\n");
+
+       /* Clear halt request (port will remain halted until reset) */
+       regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
+}
+
+static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
+{
+       DEFINE_DMA_ATTRS(attrs);
+       dma_addr_t phys;
+       void *ptr;
+       int ret;
+
+       dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &attrs);
+       ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, &attrs);
+       if (!ptr) {
+               dev_err(qproc->dev, "failed to allocate mdt buffer\n");
+               return -ENOMEM;
+       }
+
+       memcpy(ptr, fw->data, fw->size);
+
+       writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG);
+       writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
+
+       ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_META_DATA_AUTH_SUCCESS, 1000);
+       if (ret == -ETIMEDOUT)
+               dev_err(qproc->dev, "MPSS header authentication timed out\n");
+       else if (ret < 0)
+               dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
+
+       dma_free_attrs(qproc->dev, fw->size, ptr, phys, &attrs);
+
+       return ret < 0 ? ret : 0;
+}
+
+static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       struct elf32_hdr *ehdr;
+       phys_addr_t boot_addr;
+       phys_addr_t fw_addr;
+       bool relocate;
+       size_t size;
+       int ret;
+       int i;
+
+       ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
+       if (ret) {
+               dev_err(qproc->dev, "failed to parse mdt header\n");
+               return ret;
+       }
+
+       if (relocate)
+               boot_addr = qproc->mpss_phys;
+       else
+               boot_addr = fw_addr;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+       for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
+               if (!size) {
+                       writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG);
+                       writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
+               }
+
+               size += phdr->p_memsz;
+               writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
+       }
+
+       ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_AUTH_COMPLETE, 10000);
+       if (ret == -ETIMEDOUT)
+               dev_err(qproc->dev, "MPSS authentication timed out\n");
+       else if (ret < 0)
+               dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret);
+
+       return ret < 0 ? ret : 0;
+}
+
+static int q6v5_mpss_load(struct q6v5 *qproc)
+{
+       const struct firmware *fw;
+       phys_addr_t fw_addr;
+       bool relocate;
+       int ret;
+
+       ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev);
+       if (ret < 0) {
+               dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n");
+               return ret;
+       }
+
+       ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
+       if (ret) {
+               dev_err(qproc->dev, "failed to parse mdt header\n");
+               goto release_firmware;
+       }
+
+       if (relocate)
+               qproc->mpss_reloc = fw_addr;
+
+       /* Initialize the RMB validator */
+       writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
+
+       ret = q6v5_mpss_init_image(qproc, fw);
+       if (ret)
+               goto release_firmware;
+
+       ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME);
+       if (ret)
+               goto release_firmware;
+
+       ret = q6v5_mpss_validate(qproc, fw);
+
+release_firmware:
+       release_firmware(fw);
+
+       return ret < 0 ? ret : 0;
+}
+
+static int q6v5_start(struct rproc *rproc)
+{
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+       int ret;
+
+       ret = q6v5_regulator_enable(qproc);
+       if (ret) {
+               dev_err(qproc->dev, "failed to enable supplies\n");
+               return ret;
+       }
+
+       ret = reset_control_deassert(qproc->mss_restart);
+       if (ret) {
+               dev_err(qproc->dev, "failed to deassert mss restart\n");
+               goto disable_vdd;
+       }
+
+       ret = clk_prepare_enable(qproc->ahb_clk);
+       if (ret)
+               goto assert_reset;
+
+       ret = clk_prepare_enable(qproc->axi_clk);
+       if (ret)
+               goto disable_ahb_clk;
+
+       ret = clk_prepare_enable(qproc->rom_clk);
+       if (ret)
+               goto disable_axi_clk;
+
+       writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
+
+       ret = q6v5proc_reset(qproc);
+       if (ret)
+               goto halt_axi_ports;
+
+       ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
+       if (ret == -ETIMEDOUT) {
+               dev_err(qproc->dev, "MBA boot timed out\n");
+               goto halt_axi_ports;
+       } else if (ret != RMB_MBA_XPU_UNLOCKED &&
+                  ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) {
+               dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret);
+               ret = -EINVAL;
+               goto halt_axi_ports;
+       }
+
+       dev_info(qproc->dev, "MBA booted, loading mpss\n");
+
+       ret = q6v5_mpss_load(qproc);
+       if (ret)
+               goto halt_axi_ports;
+
+       ret = wait_for_completion_timeout(&qproc->start_done,
+                                         msecs_to_jiffies(5000));
+       if (ret == 0) {
+               dev_err(qproc->dev, "start timed out\n");
+               ret = -ETIMEDOUT;
+               goto halt_axi_ports;
+       }
+
+       qproc->running = true;
+
+       /* TODO: All done, release the handover resources */
+
+       return 0;
+
+halt_axi_ports:
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
+
+       clk_disable_unprepare(qproc->rom_clk);
+disable_axi_clk:
+       clk_disable_unprepare(qproc->axi_clk);
+disable_ahb_clk:
+       clk_disable_unprepare(qproc->ahb_clk);
+assert_reset:
+       reset_control_assert(qproc->mss_restart);
+disable_vdd:
+       q6v5_regulator_disable(qproc);
+
+       return ret;
+}
+
+static int q6v5_stop(struct rproc *rproc)
+{
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+       int ret;
+
+       qproc->running = false;
+
+       qcom_smem_state_update_bits(qproc->state,
+                                   BIT(qproc->stop_bit), BIT(qproc->stop_bit));
+
+       ret = wait_for_completion_timeout(&qproc->stop_done,
+                                         msecs_to_jiffies(5000));
+       if (ret == 0)
+               dev_err(qproc->dev, "timed out on wait\n");
+
+       qcom_smem_state_update_bits(qproc->state, BIT(qproc->stop_bit), 0);
+
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
+
+       reset_control_assert(qproc->mss_restart);
+       clk_disable_unprepare(qproc->rom_clk);
+       clk_disable_unprepare(qproc->axi_clk);
+       clk_disable_unprepare(qproc->ahb_clk);
+       q6v5_regulator_disable(qproc);
+
+       return 0;
+}
+
+static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+       struct q6v5 *qproc = rproc->priv;
+       int offset;
+
+       offset = da - qproc->mpss_reloc;
+       if (offset < 0 || offset + len > qproc->mpss_size)
+               return NULL;
+
+       return qproc->mpss_region + offset;
+}
+
+static const struct rproc_ops q6v5_ops = {
+       .start = q6v5_start,
+       .stop = q6v5_stop,
+       .da_to_va = q6v5_da_to_va,
+};
+
+static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+       size_t len;
+       char *msg;
+
+       /* Sometimes the stop triggers a watchdog rather than a stop-ack */
+       if (!qproc->running) {
+               complete(&qproc->stop_done);
+               return IRQ_HANDLED;
+       }
+
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(qproc->dev, "watchdog received: %s\n", msg);
+       else
+               dev_err(qproc->dev, "watchdog without message\n");
+
+       rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
+
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+       size_t len;
+       char *msg;
+
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(qproc->dev, "fatal error received: %s\n", msg);
+       else
+               dev_err(qproc->dev, "fatal error without message\n");
+
+       rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
+
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+
+       complete(&qproc->start_done);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+
+       complete(&qproc->stop_done);
+       return IRQ_HANDLED;
+}
+
+static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
+{
+       struct of_phandle_args args;
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
+       qproc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(qproc->reg_base))
+               return PTR_ERR(qproc->reg_base);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
+       qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(qproc->rmb_base))
+               return PTR_ERR(qproc->rmb_base);
+
+       ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
+                                              "qcom,halt-regs", 3, 0, &args);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
+               return -EINVAL;
+       }
+
+       qproc->halt_map = syscon_node_to_regmap(args.np);
+       of_node_put(args.np);
+       if (IS_ERR(qproc->halt_map))
+               return PTR_ERR(qproc->halt_map);
+
+       qproc->halt_q6 = args.args[0];
+       qproc->halt_modem = args.args[1];
+       qproc->halt_nc = args.args[2];
+
+       return 0;
+}
+
+static int q6v5_init_clocks(struct q6v5 *qproc)
+{
+       qproc->ahb_clk = devm_clk_get(qproc->dev, "iface");
+       if (IS_ERR(qproc->ahb_clk)) {
+               dev_err(qproc->dev, "failed to get iface clock\n");
+               return PTR_ERR(qproc->ahb_clk);
+       }
+
+       qproc->axi_clk = devm_clk_get(qproc->dev, "bus");
+       if (IS_ERR(qproc->axi_clk)) {
+               dev_err(qproc->dev, "failed to get bus clock\n");
+               return PTR_ERR(qproc->axi_clk);
+       }
+
+       qproc->rom_clk = devm_clk_get(qproc->dev, "mem");
+       if (IS_ERR(qproc->rom_clk)) {
+               dev_err(qproc->dev, "failed to get mem clock\n");
+               return PTR_ERR(qproc->rom_clk);
+       }
+
+       return 0;
+}
+
+static int q6v5_init_reset(struct q6v5 *qproc)
+{
+       qproc->mss_restart = devm_reset_control_get(qproc->dev, NULL);
+       if (IS_ERR(qproc->mss_restart)) {
+               dev_err(qproc->dev, "failed to acquire mss restart\n");
+               return PTR_ERR(qproc->mss_restart);
+       }
+
+       return 0;
+}
+
+static int q6v5_request_irq(struct q6v5 *qproc,
+                            struct platform_device *pdev,
+                            const char *name,
+                            irq_handler_t thread_fn)
+{
+       int ret;
+
+       ret = platform_get_irq_byname(pdev, name);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "no %s IRQ defined\n", name);
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, ret,
+                                       NULL, thread_fn,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       "q6v5", qproc);
+       if (ret)
+               dev_err(&pdev->dev, "request %s IRQ failed\n", name);
+
+       return ret;
+}
+
+static int q6v5_alloc_memory_region(struct q6v5 *qproc)
+{
+       struct device_node *child;
+       struct device_node *node;
+       struct resource r;
+       int ret;
+
+       child = of_get_child_by_name(qproc->dev->of_node, "mba");
+       node = of_parse_phandle(child, "memory-region", 0);
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret) {
+               dev_err(qproc->dev, "unable to resolve mba region\n");
+               return ret;
+       }
+
+       qproc->mba_phys = r.start;
+       qproc->mba_size = resource_size(&r);
+       qproc->mba_region = devm_ioremap_wc(qproc->dev, qproc->mba_phys, qproc->mba_size);
+       if (!qproc->mba_region) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, qproc->mba_size);
+               return -EBUSY;
+       }
+
+       child = of_get_child_by_name(qproc->dev->of_node, "mpss");
+       node = of_parse_phandle(child, "memory-region", 0);
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret) {
+               dev_err(qproc->dev, "unable to resolve mpss region\n");
+               return ret;
+       }
+
+       qproc->mpss_phys = qproc->mpss_reloc = r.start;
+       qproc->mpss_size = resource_size(&r);
+       qproc->mpss_region = devm_ioremap_wc(qproc->dev, qproc->mpss_phys, qproc->mpss_size);
+       if (!qproc->mpss_region) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, qproc->mpss_size);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int q6v5_probe(struct platform_device *pdev)
+{
+       struct q6v5 *qproc;
+       struct rproc *rproc;
+       int ret;
+
+       rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops,
+                           MBA_FIRMWARE_NAME, sizeof(*qproc));
+       if (!rproc) {
+               dev_err(&pdev->dev, "failed to allocate rproc\n");
+               return -ENOMEM;
+       }
+
+       rproc->fw_ops = &q6v5_fw_ops;
+
+       qproc = (struct q6v5 *)rproc->priv;
+       qproc->dev = &pdev->dev;
+       qproc->rproc = rproc;
+       platform_set_drvdata(pdev, qproc);
+
+       init_completion(&qproc->start_done);
+       init_completion(&qproc->stop_done);
+
+       ret = q6v5_init_mem(qproc, pdev);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_alloc_memory_region(qproc);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_init_clocks(qproc);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_regulator_init(qproc);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_init_reset(qproc);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+
+       ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+
+       ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+
+       ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+
+       qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit);
+       if (IS_ERR(qproc->state))
+               goto free_rproc;
+
+       ret = rproc_add(rproc);
+       if (ret)
+               goto free_rproc;
+
+       return 0;
+
+free_rproc:
+       rproc_put(rproc);
+
+       return ret;
+}
+
+static int q6v5_remove(struct platform_device *pdev)
+{
+       struct q6v5 *qproc = platform_get_drvdata(pdev);
+
+       rproc_del(qproc->rproc);
+       rproc_put(qproc->rproc);
+
+       return 0;
+}
+
+static const struct of_device_id q6v5_of_match[] = {
+       { .compatible = "qcom,q6v5-pil", },
+       { },
+};
+
+static struct platform_driver q6v5_driver = {
+       .probe = q6v5_probe,
+       .remove = q6v5_remove,
+       .driver = {
+               .name = "qcom-q6v5-pil",
+               .of_match_table = q6v5_of_match,
+       },
+};
+module_platform_driver(q6v5_driver);
+
+MODULE_DESCRIPTION("Peripheral Image Loader for Hexagon");
+MODULE_LICENSE("GPL v2");
index db3958b3f09454c662fdbdcb4b3592d2f8cd9cb3..fe0539ed9cb5911e105732ef68d226499fa9ffb9 100644 (file)
@@ -1264,11 +1264,6 @@ int rproc_add(struct rproc *rproc)
        if (ret < 0)
                return ret;
 
-       /* expose to rproc_get_by_phandle users */
-       mutex_lock(&rproc_list_mutex);
-       list_add(&rproc->node, &rproc_list);
-       mutex_unlock(&rproc_list_mutex);
-
        dev_info(dev, "%s is available\n", rproc->name);
 
        dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n");
@@ -1276,8 +1271,16 @@ int rproc_add(struct rproc *rproc)
 
        /* create debugfs entries */
        rproc_create_debug_dir(rproc);
+       ret = rproc_add_virtio_devices(rproc);
+       if (ret < 0)
+               return ret;
 
-       return rproc_add_virtio_devices(rproc);
+       /* expose to rproc_get_by_phandle users */
+       mutex_lock(&rproc_list_mutex);
+       list_add(&rproc->node, &rproc_list);
+       mutex_unlock(&rproc_list_mutex);
+
+       return 0;
 }
 EXPORT_SYMBOL(rproc_add);
 
index fac1b51ea0dee9a55738d030efed1aaf1a43e5bc..9d66b4fb174b80231a98737bf3f9fafeb4849c66 100644 (file)
@@ -31,7 +31,7 @@ static void dcssblk_release(struct gendisk *disk, fmode_t mode);
 static blk_qc_t dcssblk_make_request(struct request_queue *q,
                                                struct bio *bio);
 static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
-                        void __pmem **kaddr, pfn_t *pfn, long size);
+                        void **kaddr, pfn_t *pfn, long size);
 
 static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
 
@@ -884,7 +884,7 @@ fail:
 
 static long
 dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
-                       void __pmem **kaddr, pfn_t *pfn, long size)
+                       void **kaddr, pfn_t *pfn, long size)
 {
        struct dcssblk_dev_info *dev_info;
        unsigned long offset, dev_sz;
@@ -894,7 +894,7 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
                return -ENODEV;
        dev_sz = dev_info->end - dev_info->start;
        offset = secnum * 512;
-       *kaddr = (void __pmem *) (dev_info->start + offset);
+       *kaddr = (void *) dev_info->start + offset;
        *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV);
 
        return dev_sz - offset;
index 59c477883a7325ba1810dd833e9c03661156ff58..6201dce3553bf951b5b1f770842e289ced553e95 100644 (file)
@@ -1183,7 +1183,6 @@ static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC,
 #define CRB_NIU_XG_PAUSE_CTL_P1        0x8
 
 #define qla82xx_get_temp_val(x)          ((x) >> 16)
-#define qla82xx_get_temp_val1(x)          ((x) && 0x0000FFFF)
 #define qla82xx_get_temp_state(x)        ((x) & 0xffff)
 #define qla82xx_encode_temp(val, state)  (((val) << 16) | (state))
 
index 24d2745e943778200c64996510814756854fa461..45a1b4ec4ca33000e96faee0cb1cff7933b91580 100644 (file)
@@ -72,10 +72,10 @@ static unsigned long lowmem_deathpending_timeout;
 static unsigned long lowmem_count(struct shrinker *s,
                                  struct shrink_control *sc)
 {
-       return global_page_state(NR_ACTIVE_ANON) +
-               global_page_state(NR_ACTIVE_FILE) +
-               global_page_state(NR_INACTIVE_ANON) +
-               global_page_state(NR_INACTIVE_FILE);
+       return global_node_page_state(NR_ACTIVE_ANON) +
+               global_node_page_state(NR_ACTIVE_FILE) +
+               global_node_page_state(NR_INACTIVE_ANON) +
+               global_node_page_state(NR_INACTIVE_FILE);
 }
 
 static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
@@ -91,8 +91,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
        short selected_oom_score_adj;
        int array_size = ARRAY_SIZE(lowmem_adj);
        int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
-       int other_file = global_page_state(NR_FILE_PAGES) -
-                                               global_page_state(NR_SHMEM) -
+       int other_file = global_node_page_state(NR_FILE_PAGES) -
+                                               global_node_page_state(NR_SHMEM) -
                                                total_swapcache_pages();
 
        if (lowmem_adj_size < array_size)
index f77524294c27cb028f85999953dff15e065688ad..8e52722266fe8d59ef05054a5b63ababac0e2619 100644 (file)
@@ -170,7 +170,8 @@ static inline int is_omitted_entry(struct ll_statahead_info *sai, __u64 index)
  * Insert it into sai_entries tail when init.
  */
 static struct ll_sa_entry *
-ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
+ll_sa_entry_alloc(struct dentry *parent,
+                 struct ll_statahead_info *sai, __u64 index,
                  const char *name, int len)
 {
        struct ll_inode_info *lli;
@@ -217,7 +218,8 @@ ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
        dname = (char *)entry + sizeof(struct ll_sa_entry);
        memcpy(dname, name, len);
        dname[len] = 0;
-       entry->se_qstr.hash = full_name_hash(name, len);
+
+       entry->se_qstr.hash = full_name_hash(parent, name, len);
        entry->se_qstr.len = len;
        entry->se_qstr.name = dname;
 
@@ -898,7 +900,7 @@ static void ll_statahead_one(struct dentry *parent, const char *entry_name,
        int                    rc;
        int                    rc1;
 
-       entry = ll_sa_entry_alloc(sai, sai->sai_index, entry_name,
+       entry = ll_sa_entry_alloc(parent, sai, sai->sai_index, entry_name,
                                  entry_name_len);
        if (IS_ERR(entry))
                return;
index d1a7d6beee60f09187dfab9c021a79b139858c0b..d011135802d59313c109005e4c5f760615740c56 100644 (file)
@@ -1864,7 +1864,8 @@ void osc_dec_unstable_pages(struct ptlrpc_request *req)
        LASSERT(page_count >= 0);
 
        for (i = 0; i < page_count; i++)
-               dec_zone_page_state(desc->bd_iov[i].kiov_page, NR_UNSTABLE_NFS);
+               dec_node_page_state(desc->bd_iov[i].kiov_page,
+                                                       NR_UNSTABLE_NFS);
 
        atomic_sub(page_count, &cli->cl_cache->ccc_unstable_nr);
        LASSERT(atomic_read(&cli->cl_cache->ccc_unstable_nr) >= 0);
@@ -1898,7 +1899,8 @@ void osc_inc_unstable_pages(struct ptlrpc_request *req)
        LASSERT(page_count >= 0);
 
        for (i = 0; i < page_count; i++)
-               inc_zone_page_state(desc->bd_iov[i].kiov_page, NR_UNSTABLE_NFS);
+               inc_node_page_state(desc->bd_iov[i].kiov_page,
+                                                       NR_UNSTABLE_NFS);
 
        LASSERT(atomic_read(&cli->cl_cache->ccc_unstable_nr) >= 0);
        atomic_add(page_count, &cli->cl_cache->ccc_unstable_nr);
index 6e705971d637f3321c74b89b7f81064887aaf424..eb8f8d37cd955b67a1c7ec7146694271f70a88d3 100644 (file)
@@ -79,15 +79,6 @@ config USB_LCD
          To compile this driver as a module, choose M here: the
          module will be called usblcd.
 
-config USB_LED
-       tristate "USB LED driver support"
-       help
-         Say Y here if you want to connect an USBLED device to your 
-         computer's USB port.
-
-         To compile this driver as a module, choose M here: the
-         module will be called usbled.
-
 config USB_CYPRESS_CY7C63
        tristate "Cypress CY7C63xxx USB driver support"
        help
index 2769cf6351b417cf84854d2fdb57aa3d01117ab2..3d79faaad2fbdb05e1c9fe3a71e70c71330ef269 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_USB_IOWARRIOR)           += iowarrior.o
 obj-$(CONFIG_USB_ISIGHTFW)             += isight_firmware.o
 obj-$(CONFIG_USB_LCD)                  += usblcd.o
 obj-$(CONFIG_USB_LD)                   += ldusb.o
-obj-$(CONFIG_USB_LED)                  += usbled.o
 obj-$(CONFIG_USB_LEGOTOWER)            += legousbtower.o
 obj-$(CONFIG_USB_RIO500)               += rio500.o
 obj-$(CONFIG_USB_TEST)                 += usbtest.o
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
deleted file mode 100644 (file)
index bdef0d6..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * USB LED driver
- *
- * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation, version 2.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-
-
-#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
-#define DRIVER_DESC "USB LED Driver"
-
-enum led_type {
-       DELCOM_VISUAL_SIGNAL_INDICATOR,
-       DREAM_CHEEKY_WEBMAIL_NOTIFIER,
-       RISO_KAGAKU_LED
-};
-
-/* the Webmail LED made by RISO KAGAKU CORP. decodes a color index
-   internally, we want to keep the red+green+blue sysfs api, so we decode
-   from 1-bit RGB to the riso kagaku color index according to this table... */
-
-static unsigned const char riso_kagaku_tbl[] = {
-/* R+2G+4B -> riso kagaku color index */
-       [0] = 0, /* black   */
-       [1] = 2, /* red     */
-       [2] = 1, /* green   */
-       [3] = 5, /* yellow  */
-       [4] = 3, /* blue    */
-       [5] = 6, /* magenta */
-       [6] = 4, /* cyan    */
-       [7] = 7  /* white   */
-};
-
-#define RISO_KAGAKU_IX(r,g,b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
-
-/* table of devices that work with this driver */
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x0fc5, 0x1223),
-                       .driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR },
-       { USB_DEVICE(0x1d34, 0x0004),
-                       .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
-       { USB_DEVICE(0x1d34, 0x000a),
-                       .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
-       { USB_DEVICE(0x1294, 0x1320),
-                       .driver_info = RISO_KAGAKU_LED },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-struct usb_led {
-       struct usb_device       *udev;
-       unsigned char           blue;
-       unsigned char           red;
-       unsigned char           green;
-       enum led_type           type;
-};
-
-static void change_color(struct usb_led *led)
-{
-       int retval = 0;
-       unsigned char *buffer;
-       int actlength;
-
-       buffer = kmalloc(8, GFP_KERNEL);
-       if (!buffer) {
-               dev_err(&led->udev->dev, "out of memory\n");
-               return;
-       }
-
-       switch (led->type) {
-       case DELCOM_VISUAL_SIGNAL_INDICATOR: {
-               unsigned char color = 0x07;
-
-               if (led->blue)
-                       color &= ~0x04;
-               if (led->red)
-                       color &= ~0x02;
-               if (led->green)
-                       color &= ~0x01;
-               dev_dbg(&led->udev->dev,
-                       "blue = %d, red = %d, green = %d, color = %.2x\n",
-                       led->blue, led->red, led->green, color);
-
-               retval = usb_control_msg(led->udev,
-                                       usb_sndctrlpipe(led->udev, 0),
-                                       0x12,
-                                       0xc8,
-                                       (0x02 * 0x100) + 0x0a,
-                                       (0x00 * 0x100) + color,
-                                       buffer,
-                                       8,
-                                       2000);
-               break;
-       }
-
-       case DREAM_CHEEKY_WEBMAIL_NOTIFIER:
-               dev_dbg(&led->udev->dev,
-                       "red = %d, green = %d, blue = %d\n",
-                       led->red, led->green, led->blue);
-
-               buffer[0] = led->red;
-               buffer[1] = led->green;
-               buffer[2] = led->blue;
-               buffer[3] = buffer[4] = buffer[5] = 0;
-               buffer[6] = 0x1a;
-               buffer[7] = 0x05;
-
-               retval = usb_control_msg(led->udev,
-                                       usb_sndctrlpipe(led->udev, 0),
-                                       0x09,
-                                       0x21,
-                                       0x200,
-                                       0,
-                                       buffer,
-                                       8,
-                                       2000);
-               break;
-
-       case RISO_KAGAKU_LED:
-               buffer[0] = RISO_KAGAKU_IX(led->red, led->green, led->blue);
-               buffer[1] = 0;
-               buffer[2] = 0;
-               buffer[3] = 0;
-               buffer[4] = 0;
-
-               retval = usb_interrupt_msg(led->udev,
-                       usb_sndctrlpipe(led->udev, 2),
-                       buffer, 5, &actlength, 1000 /*ms timeout*/);
-               break;
-
-       default:
-               dev_err(&led->udev->dev, "unknown device type %d\n", led->type);
-       }
-
-       if (retval)
-               dev_dbg(&led->udev->dev, "retval = %d\n", retval);
-       kfree(buffer);
-}
-
-#define show_set(value)        \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\
-                           char *buf)                                  \
-{                                                                      \
-       struct usb_interface *intf = to_usb_interface(dev);             \
-       struct usb_led *led = usb_get_intfdata(intf);                   \
-                                                                       \
-       return sprintf(buf, "%d\n", led->value);                        \
-}                                                                      \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\
-                          const char *buf, size_t count)               \
-{                                                                      \
-       struct usb_interface *intf = to_usb_interface(dev);             \
-       struct usb_led *led = usb_get_intfdata(intf);                   \
-       int temp = simple_strtoul(buf, NULL, 10);                       \
-                                                                       \
-       led->value = temp;                                              \
-       change_color(led);                                              \
-       return count;                                                   \
-}                                                                      \
-static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);
-show_set(blue);
-show_set(red);
-show_set(green);
-
-static int led_probe(struct usb_interface *interface,
-                    const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct usb_led *dev = NULL;
-       int retval = -ENOMEM;
-
-       dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
-       if (dev == NULL) {
-               dev_err(&interface->dev, "out of memory\n");
-               goto error_mem;
-       }
-
-       dev->udev = usb_get_dev(udev);
-       dev->type = id->driver_info;
-
-       usb_set_intfdata(interface, dev);
-
-       retval = device_create_file(&interface->dev, &dev_attr_blue);
-       if (retval)
-               goto error;
-       retval = device_create_file(&interface->dev, &dev_attr_red);
-       if (retval)
-               goto error;
-       retval = device_create_file(&interface->dev, &dev_attr_green);
-       if (retval)
-               goto error;
-
-       if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) {
-               unsigned char *enable;
-
-               enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL);
-               if (!enable) {
-                       dev_err(&interface->dev, "out of memory\n");
-                       retval = -ENOMEM;
-                       goto error;
-               }
-
-               retval = usb_control_msg(udev,
-                                       usb_sndctrlpipe(udev, 0),
-                                       0x09,
-                                       0x21,
-                                       0x200,
-                                       0,
-                                       enable,
-                                       8,
-                                       2000);
-
-               kfree(enable);
-               if (retval != 8)
-                       goto error;
-       }
-
-       dev_info(&interface->dev, "USB LED device now attached\n");
-       return 0;
-
-error:
-       device_remove_file(&interface->dev, &dev_attr_blue);
-       device_remove_file(&interface->dev, &dev_attr_red);
-       device_remove_file(&interface->dev, &dev_attr_green);
-       usb_set_intfdata(interface, NULL);
-       usb_put_dev(dev->udev);
-       kfree(dev);
-error_mem:
-       return retval;
-}
-
-static void led_disconnect(struct usb_interface *interface)
-{
-       struct usb_led *dev;
-
-       dev = usb_get_intfdata(interface);
-
-       device_remove_file(&interface->dev, &dev_attr_blue);
-       device_remove_file(&interface->dev, &dev_attr_red);
-       device_remove_file(&interface->dev, &dev_attr_green);
-
-       /* first remove the files, then set the pointer to NULL */
-       usb_set_intfdata(interface, NULL);
-
-       usb_put_dev(dev->udev);
-
-       kfree(dev);
-
-       dev_info(&interface->dev, "USB LED now disconnected\n");
-}
-
-static struct usb_driver led_driver = {
-       .name =         "usbled",
-       .probe =        led_probe,
-       .disconnect =   led_disconnect,
-       .id_table =     id_table,
-};
-
-module_usb_driver(led_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
index 188b1ff03f5f23ef837c3ef2135e6bacdf9d1394..d624a527777f6a12d5f63e273008908fbf0cacfc 100644 (file)
@@ -110,6 +110,74 @@ static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
        return (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA;
 }
 
+static void vfio_pci_probe_mmaps(struct vfio_pci_device *vdev)
+{
+       struct resource *res;
+       int bar;
+       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;
+
+               if (!IS_ENABLED(CONFIG_VFIO_PCI_MMAP))
+                       goto no_mmap;
+
+               if (!(res->flags & IORESOURCE_MEM))
+                       goto no_mmap;
+
+               /*
+                * The PCI core shouldn't set up a resource with a
+                * type but zero size. But there may be bugs that
+                * cause us to do that.
+                */
+               if (!resource_size(res))
+                       goto no_mmap;
+
+               if (resource_size(res) >= PAGE_SIZE) {
+                       vdev->bar_mmap_supported[bar] = true;
+                       continue;
+               }
+
+               if (!(res->start & ~PAGE_MASK)) {
+                       /*
+                        * Add a dummy resource to reserve the remainder
+                        * of the exclusive page in case that hot-add
+                        * device's bar is assigned into it.
+                        */
+                       dummy_res = kzalloc(sizeof(*dummy_res), GFP_KERNEL);
+                       if (dummy_res == NULL)
+                               goto no_mmap;
+
+                       dummy_res->resource.name = "vfio sub-page reserved";
+                       dummy_res->resource.start = res->end + 1;
+                       dummy_res->resource.end = res->start + PAGE_SIZE - 1;
+                       dummy_res->resource.flags = res->flags;
+                       if (request_resource(res->parent,
+                                               &dummy_res->resource)) {
+                               kfree(dummy_res);
+                               goto no_mmap;
+                       }
+                       dummy_res->index = bar;
+                       list_add(&dummy_res->res_next,
+                                       &vdev->dummy_resources_list);
+                       vdev->bar_mmap_supported[bar] = true;
+                       continue;
+               }
+               /*
+                * Here we don't handle the case when the BAR is not page
+                * aligned because we can't expect the BAR will be
+                * assigned into the same location in a page in guest
+                * when we passthrough the BAR. And it's hard to access
+                * this BAR in userspace because we have no way to get
+                * the BAR's location in a page.
+                */
+no_mmap:
+               vdev->bar_mmap_supported[bar] = false;
+       }
+}
+
 static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev);
 static void vfio_pci_disable(struct vfio_pci_device *vdev);
 
@@ -218,12 +286,15 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
                }
        }
 
+       vfio_pci_probe_mmaps(vdev);
+
        return 0;
 }
 
 static void vfio_pci_disable(struct vfio_pci_device *vdev)
 {
        struct pci_dev *pdev = vdev->pdev;
+       struct vfio_pci_dummy_resource *dummy_res, *tmp;
        int i, bar;
 
        /* Stop the device from further DMA */
@@ -252,6 +323,13 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
                vdev->barmap[bar] = NULL;
        }
 
+       list_for_each_entry_safe(dummy_res, tmp,
+                                &vdev->dummy_resources_list, res_next) {
+               list_del(&dummy_res->res_next);
+               release_resource(&dummy_res->resource);
+               kfree(dummy_res);
+       }
+
        vdev->needs_reset = true;
 
        /*
@@ -623,9 +701,7 @@ static long vfio_pci_ioctl(void *device_data,
 
                        info.flags = VFIO_REGION_INFO_FLAG_READ |
                                     VFIO_REGION_INFO_FLAG_WRITE;
-                       if (IS_ENABLED(CONFIG_VFIO_PCI_MMAP) &&
-                           pci_resource_flags(pdev, info.index) &
-                           IORESOURCE_MEM && info.size >= PAGE_SIZE) {
+                       if (vdev->bar_mmap_supported[info.index]) {
                                info.flags |= VFIO_REGION_INFO_FLAG_MMAP;
                                if (info.index == vdev->msix_bar) {
                                        ret = msix_sparse_mmap_cap(vdev, &caps);
@@ -1049,16 +1125,16 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
                return -EINVAL;
        if (index >= VFIO_PCI_ROM_REGION_INDEX)
                return -EINVAL;
-       if (!(pci_resource_flags(pdev, index) & IORESOURCE_MEM))
+       if (!vdev->bar_mmap_supported[index])
                return -EINVAL;
 
-       phys_len = pci_resource_len(pdev, index);
+       phys_len = PAGE_ALIGN(pci_resource_len(pdev, index));
        req_len = vma->vm_end - vma->vm_start;
        pgoff = vma->vm_pgoff &
                ((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
        req_start = pgoff << PAGE_SHIFT;
 
-       if (phys_len < PAGE_SIZE || req_start + req_len > phys_len)
+       if (req_start + req_len > phys_len)
                return -EINVAL;
 
        if (index == vdev->msix_bar) {
index 016c14a1b454bfe5a4528a243ef400d539d9b05b..2128de86c80d0a19bec4904ba1a5d5a98d937be0 100644 (file)
@@ -57,9 +57,16 @@ struct vfio_pci_region {
        u32                             flags;
 };
 
+struct vfio_pci_dummy_resource {
+       struct resource         resource;
+       int                     index;
+       struct list_head        res_next;
+};
+
 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];
        u8                      *pci_config_map;
        u8                      *vconfig;
        struct perm_bits        *msi_perm;
@@ -88,6 +95,7 @@ struct vfio_pci_device {
        int                     refcnt;
        struct eventfd_ctx      *err_trigger;
        struct eventfd_ctx      *req_trigger;
+       struct list_head        dummy_resources_list;
 };
 
 #define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX)
index a66479bd0edf968c8209b384264052f79a6ec272..31372fbf6c5bab9edb4de52b62d662ec8e3cc2d1 100644 (file)
@@ -68,6 +68,7 @@ static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id)
        vdev->get_resource = get_amba_resource;
        vdev->get_irq = get_amba_irq;
        vdev->parent_module = THIS_MODULE;
+       vdev->reset_required = false;
 
        ret = vfio_platform_probe_common(vdev, &adev->dev);
        if (ret) {
index b1cc3a768784426fbf7616316aa9731f21b77ddb..6561751a1063ee291ffa7a7c6bb58e2caef56e2b 100644 (file)
 #define DRIVER_AUTHOR   "Antonios Motakis <a.motakis@virtualopensystems.com>"
 #define DRIVER_DESC     "VFIO for platform devices - User Level meta-driver"
 
+static bool reset_required = true;
+module_param(reset_required, bool, 0444);
+MODULE_PARM_DESC(reset_required, "override reset requirement (default: 1)");
+
 /* probing devices from the linux platform bus */
 
 static struct resource *get_platform_resource(struct vfio_platform_device *vdev,
@@ -66,6 +70,7 @@ static int vfio_platform_probe(struct platform_device *pdev)
        vdev->get_resource = get_platform_resource;
        vdev->get_irq = get_platform_irq;
        vdev->parent_module = THIS_MODULE;
+       vdev->reset_required = reset_required;
 
        ret = vfio_platform_probe_common(vdev, &pdev->dev);
        if (ret)
index e65b142d34222dd4ba548e46c44017d2b762cf06..1cf2d462b53debe22347e7060c4f6cc58e45d93d 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/acpi.h>
 #include <linux/iommu.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -27,6 +28,8 @@
 #define DRIVER_AUTHOR   "Antonios Motakis <a.motakis@virtualopensystems.com>"
 #define DRIVER_DESC     "VFIO platform base module"
 
+#define VFIO_PLATFORM_IS_ACPI(vdev) ((vdev)->acpihid != NULL)
+
 static LIST_HEAD(reset_list);
 static DEFINE_MUTEX(driver_lock);
 
@@ -41,7 +44,7 @@ static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat,
                if (!strcmp(iter->compat, compat) &&
                        try_module_get(iter->owner)) {
                        *module = iter->owner;
-                       reset_fn = iter->reset;
+                       reset_fn = iter->of_reset;
                        break;
                }
        }
@@ -49,20 +52,91 @@ static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat,
        return reset_fn;
 }
 
-static void vfio_platform_get_reset(struct vfio_platform_device *vdev)
+static int vfio_platform_acpi_probe(struct vfio_platform_device *vdev,
+                                   struct device *dev)
 {
-       vdev->reset = vfio_platform_lookup_reset(vdev->compat,
-                                               &vdev->reset_module);
-       if (!vdev->reset) {
+       struct acpi_device *adev;
+
+       if (acpi_disabled)
+               return -ENOENT;
+
+       adev = ACPI_COMPANION(dev);
+       if (!adev) {
+               pr_err("VFIO: ACPI companion device not found for %s\n",
+                       vdev->name);
+               return -ENODEV;
+       }
+
+#ifdef CONFIG_ACPI
+       vdev->acpihid = acpi_device_hid(adev);
+#endif
+       return WARN_ON(!vdev->acpihid) ? -EINVAL : 0;
+}
+
+int vfio_platform_acpi_call_reset(struct vfio_platform_device *vdev,
+                                 const char **extra_dbg)
+{
+#ifdef CONFIG_ACPI
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct device *dev = vdev->device;
+       acpi_handle handle = ACPI_HANDLE(dev);
+       acpi_status acpi_ret;
+
+       acpi_ret = acpi_evaluate_object(handle, "_RST", NULL, &buffer);
+       if (ACPI_FAILURE(acpi_ret)) {
+               if (extra_dbg)
+                       *extra_dbg = acpi_format_exception(acpi_ret);
+               return -EINVAL;
+       }
+
+       return 0;
+#else
+       return -ENOENT;
+#endif
+}
+
+bool vfio_platform_acpi_has_reset(struct vfio_platform_device *vdev)
+{
+#ifdef CONFIG_ACPI
+       struct device *dev = vdev->device;
+       acpi_handle handle = ACPI_HANDLE(dev);
+
+       return acpi_has_method(handle, "_RST");
+#else
+       return false;
+#endif
+}
+
+static bool vfio_platform_has_reset(struct vfio_platform_device *vdev)
+{
+       if (VFIO_PLATFORM_IS_ACPI(vdev))
+               return vfio_platform_acpi_has_reset(vdev);
+
+       return vdev->of_reset ? true : false;
+}
+
+static int vfio_platform_get_reset(struct vfio_platform_device *vdev)
+{
+       if (VFIO_PLATFORM_IS_ACPI(vdev))
+               return vfio_platform_acpi_has_reset(vdev) ? 0 : -ENOENT;
+
+       vdev->of_reset = vfio_platform_lookup_reset(vdev->compat,
+                                                   &vdev->reset_module);
+       if (!vdev->of_reset) {
                request_module("vfio-reset:%s", vdev->compat);
-               vdev->reset = vfio_platform_lookup_reset(vdev->compat,
-                                                        &vdev->reset_module);
+               vdev->of_reset = vfio_platform_lookup_reset(vdev->compat,
+                                                       &vdev->reset_module);
        }
+
+       return vdev->of_reset ? 0 : -ENOENT;
 }
 
 static void vfio_platform_put_reset(struct vfio_platform_device *vdev)
 {
-       if (vdev->reset)
+       if (VFIO_PLATFORM_IS_ACPI(vdev))
+               return;
+
+       if (vdev->of_reset)
                module_put(vdev->reset_module);
 }
 
@@ -134,6 +208,21 @@ static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)
        kfree(vdev->regions);
 }
 
+static int vfio_platform_call_reset(struct vfio_platform_device *vdev,
+                                   const char **extra_dbg)
+{
+       if (VFIO_PLATFORM_IS_ACPI(vdev)) {
+               dev_info(vdev->device, "reset\n");
+               return vfio_platform_acpi_call_reset(vdev, extra_dbg);
+       } else if (vdev->of_reset) {
+               dev_info(vdev->device, "reset\n");
+               return vdev->of_reset(vdev);
+       }
+
+       dev_warn(vdev->device, "no reset function found!\n");
+       return -EINVAL;
+}
+
 static void vfio_platform_release(void *device_data)
 {
        struct vfio_platform_device *vdev = device_data;
@@ -141,11 +230,14 @@ static void vfio_platform_release(void *device_data)
        mutex_lock(&driver_lock);
 
        if (!(--vdev->refcnt)) {
-               if (vdev->reset) {
-                       dev_info(vdev->device, "reset\n");
-                       vdev->reset(vdev);
-               } else {
-                       dev_warn(vdev->device, "no reset function found!\n");
+               const char *extra_dbg = NULL;
+               int ret;
+
+               ret = vfio_platform_call_reset(vdev, &extra_dbg);
+               if (ret && vdev->reset_required) {
+                       dev_warn(vdev->device, "reset driver is required and reset call failed in release (%d) %s\n",
+                                ret, extra_dbg ? extra_dbg : "");
+                       WARN_ON(1);
                }
                vfio_platform_regions_cleanup(vdev);
                vfio_platform_irq_cleanup(vdev);
@@ -167,6 +259,8 @@ static int vfio_platform_open(void *device_data)
        mutex_lock(&driver_lock);
 
        if (!vdev->refcnt) {
+               const char *extra_dbg = NULL;
+
                ret = vfio_platform_regions_init(vdev);
                if (ret)
                        goto err_reg;
@@ -175,11 +269,11 @@ static int vfio_platform_open(void *device_data)
                if (ret)
                        goto err_irq;
 
-               if (vdev->reset) {
-                       dev_info(vdev->device, "reset\n");
-                       vdev->reset(vdev);
-               } else {
-                       dev_warn(vdev->device, "no reset function found!\n");
+               ret = vfio_platform_call_reset(vdev, &extra_dbg);
+               if (ret && vdev->reset_required) {
+                       dev_warn(vdev->device, "reset driver is required and reset call failed in open (%d) %s\n",
+                                ret, extra_dbg ? extra_dbg : "");
+                       goto err_rst;
                }
        }
 
@@ -188,6 +282,8 @@ static int vfio_platform_open(void *device_data)
        mutex_unlock(&driver_lock);
        return 0;
 
+err_rst:
+       vfio_platform_irq_cleanup(vdev);
 err_irq:
        vfio_platform_regions_cleanup(vdev);
 err_reg:
@@ -213,7 +309,7 @@ static long vfio_platform_ioctl(void *device_data,
                if (info.argsz < minsz)
                        return -EINVAL;
 
-               if (vdev->reset)
+               if (vfio_platform_has_reset(vdev))
                        vdev->flags |= VFIO_DEVICE_FLAGS_RESET;
                info.flags = vdev->flags;
                info.num_regions = vdev->num_regions;
@@ -312,10 +408,7 @@ static long vfio_platform_ioctl(void *device_data,
                return ret;
 
        } else if (cmd == VFIO_DEVICE_RESET) {
-               if (vdev->reset)
-                       return vdev->reset(vdev);
-               else
-                       return -EINVAL;
+               return vfio_platform_call_reset(vdev, NULL);
        }
 
        return -ENOTTY;
@@ -544,6 +637,37 @@ static const struct vfio_device_ops vfio_platform_ops = {
        .mmap           = vfio_platform_mmap,
 };
 
+int vfio_platform_of_probe(struct vfio_platform_device *vdev,
+                          struct device *dev)
+{
+       int ret;
+
+       ret = device_property_read_string(dev, "compatible",
+                                         &vdev->compat);
+       if (ret)
+               pr_err("VFIO: cannot retrieve compat for %s\n",
+                       vdev->name);
+
+       return ret;
+}
+
+/*
+ * There can be two kernel build combinations. One build where
+ * ACPI is not selected in Kconfig and another one with the ACPI Kconfig.
+ *
+ * In the first case, vfio_platform_acpi_probe will return since
+ * acpi_disabled is 1. DT user will not see any kind of messages from
+ * ACPI.
+ *
+ * In the second case, both DT and ACPI is compiled in but the system is
+ * booting with any of these combinations.
+ *
+ * If the firmware is DT type, then acpi_disabled is 1. The ACPI probe routine
+ * terminates immediately without any messages.
+ *
+ * If the firmware is ACPI type, then acpi_disabled is 0. All other checks are
+ * valid checks. We cannot claim that this system is DT.
+ */
 int vfio_platform_probe_common(struct vfio_platform_device *vdev,
                               struct device *dev)
 {
@@ -553,15 +677,23 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev,
        if (!vdev)
                return -EINVAL;
 
-       ret = device_property_read_string(dev, "compatible", &vdev->compat);
-       if (ret) {
-               pr_err("VFIO: cannot retrieve compat for %s\n", vdev->name);
-               return -EINVAL;
-       }
+       ret = vfio_platform_acpi_probe(vdev, dev);
+       if (ret)
+               ret = vfio_platform_of_probe(vdev, dev);
+
+       if (ret)
+               return ret;
 
        vdev->device = dev;
 
-       group = iommu_group_get(dev);
+       ret = vfio_platform_get_reset(vdev);
+       if (ret && vdev->reset_required) {
+               pr_err("vfio: no reset function found for device %s\n",
+                      vdev->name);
+               return ret;
+       }
+
+       group = vfio_iommu_group_get(dev);
        if (!group) {
                pr_err("VFIO: No IOMMU group for device %s\n", vdev->name);
                return -EINVAL;
@@ -569,12 +701,10 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev,
 
        ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev);
        if (ret) {
-               iommu_group_put(group);
+               vfio_iommu_group_put(group, dev);
                return ret;
        }
 
-       vfio_platform_get_reset(vdev);
-
        mutex_init(&vdev->igate);
 
        return 0;
@@ -589,7 +719,7 @@ struct vfio_platform_device *vfio_platform_remove_common(struct device *dev)
 
        if (vdev) {
                vfio_platform_put_reset(vdev);
-               iommu_group_put(dev->iommu_group);
+               vfio_iommu_group_put(dev->iommu_group, dev);
        }
 
        return vdev;
@@ -611,7 +741,7 @@ void vfio_platform_unregister_reset(const char *compat,
 
        mutex_lock(&driver_lock);
        list_for_each_entry_safe(iter, temp, &reset_list, link) {
-               if (!strcmp(iter->compat, compat) && (iter->reset == fn)) {
+               if (!strcmp(iter->compat, compat) && (iter->of_reset == fn)) {
                        list_del(&iter->link);
                        break;
                }
index 42816dd280cb98ac4e27fabced74c2d9aa1df3d7..85ffe5d9d1abd94e851a456301c4253935767c6e 100644 (file)
@@ -58,6 +58,7 @@ struct vfio_platform_device {
        struct mutex                    igate;
        struct module                   *parent_module;
        const char                      *compat;
+       const char                      *acpihid;
        struct module                   *reset_module;
        struct device                   *device;
 
@@ -71,7 +72,9 @@ struct vfio_platform_device {
        struct resource*
                (*get_resource)(struct vfio_platform_device *vdev, int i);
        int     (*get_irq)(struct vfio_platform_device *vdev, int i);
-       int     (*reset)(struct vfio_platform_device *vdev);
+       int     (*of_reset)(struct vfio_platform_device *vdev);
+
+       bool                            reset_required;
 };
 
 typedef int (*vfio_platform_reset_fn_t)(struct vfio_platform_device *vdev);
@@ -80,7 +83,7 @@ struct vfio_platform_reset_node {
        struct list_head link;
        char *compat;
        struct module *owner;
-       vfio_platform_reset_fn_t reset;
+       vfio_platform_reset_fn_t of_reset;
 };
 
 extern int vfio_platform_probe_common(struct vfio_platform_device *vdev,
@@ -103,7 +106,7 @@ extern void vfio_platform_unregister_reset(const char *compat,
 static struct vfio_platform_reset_node __reset ## _node = {    \
        .owner = THIS_MODULE,                                   \
        .compat = __compat,                                     \
-       .reset = __reset,                                       \
+       .of_reset = __reset,                                    \
 };                                                             \
 __vfio_platform_register_reset(&__reset ## _node)
 
index 6fd6fa5469def0b8624741938d61a9fc1fc02a70..d1d70e0b011bf41a8d49255a2a4359be342041c7 100644 (file)
@@ -1711,8 +1711,8 @@ EXPORT_SYMBOL_GPL(vfio_group_get_external_user);
 
 void vfio_group_put_external_user(struct vfio_group *group)
 {
-       vfio_group_put(group);
        vfio_group_try_dissolve_container(group);
+       vfio_group_put(group);
 }
 EXPORT_SYMBOL_GPL(vfio_group_put_external_user);
 
index 2b6787fcb6261dd2f64bcd765f76660472d28347..12700df0bb513c53290baef5ae9eb5aa6cb0abfd 100644 (file)
 #include <linux/list.h>
 
 struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
+static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry)
+{
+       return v9fs_fid_lookup(dentry->d_parent);
+}
 struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
 void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
 struct p9_fid *v9fs_writeback_fid(struct dentry *dentry);
index c37fb9c0897071d2ad92eaf1308cf1b63420122a..6181ad79e1a543f307ff4245e5159330c8a5fa7c 100644 (file)
@@ -231,7 +231,6 @@ static int v9fs_launder_page(struct page *page)
 /**
  * v9fs_direct_IO - 9P address space operation for direct I/O
  * @iocb: target I/O control block
- * @pos: offset in file to begin the operation
  *
  * The presence of v9fs_direct_IO() in the address space ops vector
  * allowes open() O_DIRECT flags which would have failed otherwise.
index e2e7c749925ad237c57758ed18186f5bed7d497b..7da9a8354fad475adf68393fbd2edfce7e620b61 100644 (file)
@@ -595,7 +595,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
 
        v9ses = v9fs_inode2v9ses(dir);
        inode = d_inode(dentry);
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                retval = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", retval);
@@ -653,7 +653,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        ofid = NULL;
        fid = NULL;
        name = (char *) dentry->d_name.name;
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
@@ -798,7 +798,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
 
        v9ses = v9fs_inode2v9ses(dir);
        /* We can walk d_parent because we hold the dir->i_mutex */
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid))
                return ERR_CAST(dfid);
 
@@ -975,13 +975,13 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (IS_ERR(oldfid))
                return PTR_ERR(oldfid);
 
-       olddirfid = v9fs_fid_clone(old_dentry->d_parent);
+       olddirfid = v9fs_parent_fid(old_dentry);
        if (IS_ERR(olddirfid)) {
                retval = PTR_ERR(olddirfid);
                goto done;
        }
 
-       newdirfid = v9fs_fid_clone(new_dentry->d_parent);
+       newdirfid = v9fs_parent_fid(new_dentry);
        if (IS_ERR(newdirfid)) {
                retval = PTR_ERR(newdirfid);
                goto clunk_olddir;
index 1b51eaa5e2dd05445d0ba3e9c33038bcfbe4d277..2ed04c2fe7af294f62631e4056f13b7dea49ffaf 100644 (file)
@@ -273,7 +273,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
        p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
                 name, flags, omode);
 
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
@@ -389,7 +389,6 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        umode_t mode;
        struct inode *inode;
        struct p9_qid qid;
-       struct dentry *dir_dentry;
        struct posix_acl *dacl = NULL, *pacl = NULL;
 
        p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);
@@ -400,8 +399,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        if (dir->i_mode & S_ISGID)
                omode |= S_ISGID;
 
-       dir_dentry = dentry->d_parent;
-       dfid = v9fs_fid_lookup(dir_dentry);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
@@ -691,7 +689,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
        p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
        v9ses = v9fs_inode2v9ses(dir);
 
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
@@ -762,7 +760,6 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
                struct dentry *dentry)
 {
        int err;
-       struct dentry *dir_dentry;
        struct p9_fid *dfid, *oldfid;
        struct v9fs_session_info *v9ses;
 
@@ -770,8 +767,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
                 dir->i_ino, old_dentry, dentry);
 
        v9ses = v9fs_inode2v9ses(dir);
-       dir_dentry = dentry->d_parent;
-       dfid = v9fs_fid_lookup(dir_dentry);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid))
                return PTR_ERR(dfid);
 
@@ -822,7 +818,6 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        struct p9_fid *fid = NULL, *dfid = NULL;
        struct inode *inode;
        struct p9_qid qid;
-       struct dentry *dir_dentry;
        struct posix_acl *dacl = NULL, *pacl = NULL;
 
        p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %hx MAJOR: %u MINOR: %u\n",
@@ -830,8 +825,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
                 MAJOR(rdev), MINOR(rdev));
 
        v9ses = v9fs_inode2v9ses(dir);
-       dir_dentry = dentry->d_parent;
-       dfid = v9fs_fid_lookup(dir_dentry);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
index fd4cf2c48e48e3d16b3fc525373a65ecb5cad6cc..bec25f7017c0baa95444edbef2a886d7a3467bf3 100644 (file)
@@ -207,7 +207,7 @@ adfs_hash(const struct dentry *parent, struct qstr *qstr)
         */
        qstr->len = i = name_len;
        name = qstr->name;
-       hash = init_name_hash();
+       hash = init_name_hash(parent);
        while (i--) {
                char c;
 
index 00d3002a6780b339cf456417b742bf5c9f991ec8..eb32029bc776b5060eb7f1c38ec8d1f6a38bdba7 100644 (file)
@@ -61,7 +61,7 @@ affs_get_toupper(struct super_block *sb)
  * Note: the dentry argument is the parent dentry.
  */
 static inline int
-__affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
+__affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate)
 {
        const u8 *name = qstr->name;
        unsigned long hash;
@@ -72,7 +72,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
        if (retval)
                return retval;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        len = min(qstr->len, AFFSNAMEMAX);
        for (; len > 0; name++, len--)
                hash = partial_name_hash(toupper(*name), hash);
@@ -84,7 +84,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
 static int
 affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
-       return __affs_hash_dentry(qstr, affs_toupper,
+       return __affs_hash_dentry(dentry, qstr, affs_toupper,
                                  affs_nofilenametruncate(dentry));
 
 }
@@ -92,7 +92,7 @@ affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 static int
 affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
-       return __affs_hash_dentry(qstr, affs_intl_toupper,
+       return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
                                  affs_nofilenametruncate(dentry));
 
 }
index 631f1554c87b7d73b9afc7834392ce6e279c7d6d..708214457d16f757c2d8e1f0c2273848b221f633 100644 (file)
@@ -398,7 +398,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
                }
        }
        qstr.name = name;
-       qstr.hash = full_name_hash(name, qstr.len);
+       qstr.hash = full_name_hash(dentry, name, qstr.len);
 
        if (mutex_lock_interruptible(&sbi->wq_mutex)) {
                kfree(qstr.name);
index 3a3ced779fc738199cb5bb3d25a8f8c76edc754d..5417516f6e59ea0556dc2005a17a9d7d5069b264 100644 (file)
@@ -637,13 +637,12 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
                break;
        case 3:
                /* Delete this handler. */
-               root = dget(file->f_path.dentry->d_sb->s_root);
+               root = file_inode(file)->i_sb->s_root;
                inode_lock(d_inode(root));
 
                kill_node(e);
 
                inode_unlock(d_inode(root));
-               dput(root);
                break;
        default:
                return res;
@@ -665,8 +664,8 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
 {
        Node *e;
        struct inode *inode;
-       struct dentry *root, *dentry;
-       struct super_block *sb = file->f_path.dentry->d_sb;
+       struct super_block *sb = file_inode(file)->i_sb;
+       struct dentry *root = sb->s_root, *dentry;
        int err = 0;
 
        e = create_entry(buffer, count);
@@ -674,7 +673,6 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
        if (IS_ERR(e))
                return PTR_ERR(e);
 
-       root = dget(sb->s_root);
        inode_lock(d_inode(root));
        dentry = lookup_one_len(e->name, root, strlen(e->name));
        err = PTR_ERR(dentry);
@@ -712,7 +710,6 @@ out2:
        dput(dentry);
 out:
        inode_unlock(d_inode(root));
-       dput(root);
 
        if (err) {
                kfree(e);
@@ -753,14 +750,13 @@ static ssize_t bm_status_write(struct file *file, const char __user *buffer,
                break;
        case 3:
                /* Delete all handlers. */
-               root = dget(file->f_path.dentry->d_sb->s_root);
+               root = file_inode(file)->i_sb->s_root;
                inode_lock(d_inode(root));
 
                while (!list_empty(&entries))
                        kill_node(list_entry(entries.next, Node, list));
 
                inode_unlock(d_inode(root));
-               dput(root);
                break;
        default:
                return res;
index d012be4ab977970edd889653e5edc89c03aa45e6..5cbd5391667eed740f98df7b627903ec3a056d22 100644 (file)
@@ -614,7 +614,6 @@ static void init_once(void *foo)
 
        memset(bdev, 0, sizeof(*bdev));
        mutex_init(&bdev->bd_mutex);
-       INIT_LIST_HEAD(&bdev->bd_inodes);
        INIT_LIST_HEAD(&bdev->bd_list);
 #ifdef CONFIG_SYSFS
        INIT_LIST_HEAD(&bdev->bd_holder_disks);
@@ -624,24 +623,13 @@ static void init_once(void *foo)
        mutex_init(&bdev->bd_fsfreeze_mutex);
 }
 
-static inline void __bd_forget(struct inode *inode)
-{
-       list_del_init(&inode->i_devices);
-       inode->i_bdev = NULL;
-       inode->i_mapping = &inode->i_data;
-}
-
 static void bdev_evict_inode(struct inode *inode)
 {
        struct block_device *bdev = &BDEV_I(inode)->bdev;
-       struct list_head *p;
        truncate_inode_pages_final(&inode->i_data);
        invalidate_inode_buffers(inode); /* is it needed here? */
        clear_inode(inode);
        spin_lock(&bdev_lock);
-       while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) {
-               __bd_forget(list_entry(p, struct inode, i_devices));
-       }
        list_del_init(&bdev->bd_list);
        spin_unlock(&bdev_lock);
 }
@@ -805,7 +793,6 @@ static struct block_device *bd_acquire(struct inode *inode)
                        bdgrab(bdev);
                        inode->i_bdev = bdev;
                        inode->i_mapping = bdev->bd_inode->i_mapping;
-                       list_add(&inode->i_devices, &bdev->bd_inodes);
                }
                spin_unlock(&bdev_lock);
        }
@@ -821,7 +808,8 @@ void bd_forget(struct inode *inode)
        spin_lock(&bdev_lock);
        if (!sb_is_blkdev_sb(inode->i_sb))
                bdev = inode->i_bdev;
-       __bd_forget(inode);
+       inode->i_bdev = NULL;
+       inode->i_mapping = &inode->i_data;
        spin_unlock(&bdev_lock);
 
        if (bdev)
index eccd33941199c1a006ab790f9cbc687e15779e14..125b90f6c796cb1f763f0e65cbc0a3c9a671437b 100644 (file)
@@ -93,7 +93,6 @@ static int cachefiles_histogram_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations cachefiles_histogram_fops = {
-       .owner          = THIS_MODULE,
        .open           = cachefiles_histogram_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index f059b5997072c399fcf6cdccbfcc806d4605a581..99bdef66213a662a64dc8b14823c72e3d361a0ca 100644 (file)
@@ -1164,7 +1164,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
 
                        dname.name = rinfo->dname;
                        dname.len = rinfo->dname_len;
-                       dname.hash = full_name_hash(dname.name, dname.len);
+                       dname.hash = full_name_hash(parent, dname.name, dname.len);
                        vino.ino = le64_to_cpu(rinfo->targeti.in->ino);
                        vino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
 retry_lookup:
@@ -1508,7 +1508,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
 
                dname.name = rde->name;
                dname.len = rde->name_len;
-               dname.hash = full_name_hash(dname.name, dname.len);
+               dname.hash = full_name_hash(parent, dname.name, dname.len);
 
                vino.ino = le64_to_cpu(rde->inode.in->ino);
                vino.snap = le64_to_cpu(rde->inode.in->snapid);
index 2103b823bec0786aa60e48fa3957f252d5010017..4e8678a612b6ffc4465ff90fc8bc12e9f93f465d 100644 (file)
@@ -3204,7 +3204,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                WARN_ON(1);
                goto release;  /* hrm... */
        }
-       dname.hash = full_name_hash(dname.name, dname.len);
+       dname.hash = full_name_hash(parent, dname.name, dname.len);
        dentry = d_lookup(parent, &dname);
        dput(parent);
        if (!dentry)
index 788e19195991a4d7e0291f885e6f5cad68178426..6c58e13fed2f1d647e9b4cc58e1fc3660aff95d3 100644 (file)
@@ -244,7 +244,6 @@ static int cifs_debug_data_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations cifs_debug_data_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_debug_data_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -361,7 +360,6 @@ static int cifs_stats_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations cifs_stats_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_stats_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -447,7 +445,6 @@ static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
 }
 
 static const struct file_operations cifsFYI_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifsFYI_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -479,7 +476,6 @@ static ssize_t cifs_linux_ext_proc_write(struct file *file,
 }
 
 static const struct file_operations cifs_linux_ext_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_linux_ext_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -511,7 +507,6 @@ static ssize_t cifs_lookup_cache_proc_write(struct file *file,
 }
 
 static const struct file_operations cifs_lookup_cache_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_lookup_cache_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -543,7 +538,6 @@ static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
 }
 
 static const struct file_operations traceSMB_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = traceSMB_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -655,7 +649,6 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
 }
 
 static const struct file_operations cifs_security_flags_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_security_flags_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 3182273a34079e2e7768ec819b39a41006c2e9c9..1418daa03d959f7144f6ae0f0eabb0fdcb1f8d34 100644 (file)
@@ -46,6 +46,9 @@
 #define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
 #define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
 #define CIFS_MOUNT_MAP_SFM_CHR 0x800000 /* SFM/MAC mapping for illegal chars */
+#define CIFS_MOUNT_USE_PREFIX_PATH 0x1000000 /* make subpath with unaccessible
+                                             * root mountable
+                                             */
 
 struct cifs_sb_info {
        struct rb_root tlink_tree;
@@ -67,5 +70,6 @@ struct cifs_sb_info {
        struct backing_dev_info bdi;
        struct delayed_work prune_tlinks;
        struct rcu_head rcu;
+       char *prepath;
 };
 #endif                         /* _CIFS_FS_SB_H */
index 6aeb8d4616a40a4673a63c49b6c77752e67b1ce4..8347c90cf483cefbce4995a107666bba61ae7ef4 100644 (file)
@@ -743,24 +743,26 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 
        memcpy(ses->auth_key.response + baselen, tiblob, tilen);
 
+       mutex_lock(&ses->server->srv_mutex);
+
        rc = crypto_hmacmd5_alloc(ses->server);
        if (rc) {
                cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        /* calculate ntlmv2_hash */
        rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
        if (rc) {
                cifs_dbg(VFS, "could not get v2 hash rc %d\n", rc);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        /* calculate first part of the client response (CR1) */
        rc = CalcNTLMv2_response(ses, ntlmv2_hash);
        if (rc) {
                cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        /* now calculate the session key for NTLMv2 */
@@ -769,13 +771,13 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
        if (rc) {
                cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
                         __func__);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
@@ -783,7 +785,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
                CIFS_HMAC_MD5_HASH_SIZE);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
@@ -791,6 +793,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
        if (rc)
                cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
 
+unlock:
+       mutex_unlock(&ses->server->srv_mutex);
 setup_ntlmv2_rsp_ret:
        kfree(tiblob);
 
index 5d841f39c4b70e853e5b74d1cb6e01e7d112fd25..6bbec5e784cd493c7d88cec2a345ced6eb7bff61 100644 (file)
@@ -689,6 +689,14 @@ cifs_do_mount(struct file_system_type *fs_type,
                goto out_cifs_sb;
        }
 
+       if (volume_info->prepath) {
+               cifs_sb->prepath = kstrdup(volume_info->prepath, GFP_KERNEL);
+               if (cifs_sb->prepath == NULL) {
+                       root = ERR_PTR(-ENOMEM);
+                       goto out_cifs_sb;
+               }
+       }
+
        cifs_setup_cifs_sb(volume_info, cifs_sb);
 
        rc = cifs_mount(cifs_sb, volume_info);
@@ -727,7 +735,11 @@ cifs_do_mount(struct file_system_type *fs_type,
                sb->s_flags |= MS_ACTIVE;
        }
 
-       root = cifs_get_root(volume_info, sb);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+               root = dget(sb->s_root);
+       else
+               root = cifs_get_root(volume_info, sb);
+
        if (IS_ERR(root))
                goto out_super;
 
index 7d2b15c060909b103e96a90a330c6f0ed7ecd2d0..7ae03283bd61c128c6c804805c30c6c25da79f31 100644 (file)
@@ -1228,6 +1228,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
        vol->ops = &smb1_operations;
        vol->vals = &smb1_values;
 
+       vol->echo_interval = SMB_ECHO_INTERVAL_DEFAULT;
+
        if (!mountdata)
                goto cifs_parse_mount_err;
 
@@ -2049,7 +2051,7 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
        if (!match_security(server, vol))
                return 0;
 
-       if (server->echo_interval != vol->echo_interval)
+       if (server->echo_interval != vol->echo_interval * HZ)
                return 0;
 
        return 1;
@@ -3483,6 +3485,44 @@ cifs_get_volume_info(char *mount_data, const char *devname)
        return volume_info;
 }
 
+static int
+cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
+                                       unsigned int xid,
+                                       struct cifs_tcon *tcon,
+                                       struct cifs_sb_info *cifs_sb,
+                                       char *full_path)
+{
+       int rc;
+       char *s;
+       char sep, tmp;
+
+       sep = CIFS_DIR_SEP(cifs_sb);
+       s = full_path;
+
+       rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
+       while (rc == 0) {
+               /* skip separators */
+               while (*s == sep)
+                       s++;
+               if (!*s)
+                       break;
+               /* next separator */
+               while (*s && *s != sep)
+                       s++;
+
+               /*
+                * temporarily null-terminate the path at the end of
+                * the current component
+                */
+               tmp = *s;
+               *s = 0;
+               rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
+                                                    full_path);
+               *s = tmp;
+       }
+       return rc;
+}
+
 int
 cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
 {
@@ -3620,6 +3660,16 @@ remote_path_check:
                        kfree(full_path);
                        goto mount_fail_check;
                }
+
+               rc = cifs_are_all_path_components_accessible(server,
+                                                            xid, tcon, cifs_sb,
+                                                            full_path);
+               if (rc != 0) {
+                       cifs_dbg(VFS, "cannot query dirs between root and final path, "
+                                "enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+                       rc = 0;
+               }
                kfree(full_path);
        }
 
@@ -3889,6 +3939,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
 
        bdi_destroy(&cifs_sb->bdi);
        kfree(cifs_sb->mountdata);
+       kfree(cifs_sb->prepath);
        call_rcu(&cifs_sb->rcu, delayed_free);
 }
 
index fb0903fffc22c8738c34f958beb7784400a93339..4e532536cbc638a86eab7b6c9f99df33da6d80b3 100644 (file)
@@ -84,6 +84,7 @@ build_path_from_dentry(struct dentry *direntry)
        struct dentry *temp;
        int namelen;
        int dfsplen;
+       int pplen = 0;
        char *full_path;
        char dirsep;
        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
@@ -95,8 +96,12 @@ build_path_from_dentry(struct dentry *direntry)
                dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
        else
                dfsplen = 0;
+
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+               pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
+
 cifs_bp_rename_retry:
-       namelen = dfsplen;
+       namelen = dfsplen + pplen;
        seq = read_seqbegin(&rename_lock);
        rcu_read_lock();
        for (temp = direntry; !IS_ROOT(temp);) {
@@ -137,7 +142,7 @@ cifs_bp_rename_retry:
                }
        }
        rcu_read_unlock();
-       if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
+       if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) {
                cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n",
                         namelen, dfsplen);
                /* presumably this is only possible if racing with a rename
@@ -153,6 +158,17 @@ cifs_bp_rename_retry:
           those safely to '/' if any are found in the middle of the prepath */
        /* BB test paths to Windows with '/' in the midst of prepath */
 
+       if (pplen) {
+               int i;
+
+               cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath);
+               memcpy(full_path+dfsplen+1, cifs_sb->prepath, pplen-1);
+               full_path[dfsplen] = '\\';
+               for (i = 0; i < pplen-1; i++)
+                       if (full_path[dfsplen+1+i] == '/')
+                               full_path[dfsplen+1+i] = CIFS_DIR_SEP(cifs_sb);
+       }
+
        if (dfsplen) {
                strncpy(full_path, tcon->treeName, dfsplen);
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
@@ -229,6 +245,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
                                goto cifs_create_get_file_info;
                        }
 
+                       if (S_ISDIR(newinode->i_mode)) {
+                               CIFSSMBClose(xid, tcon, fid->netfid);
+                               iput(newinode);
+                               rc = -EISDIR;
+                               goto out;
+                       }
+
                        if (!S_ISREG(newinode->i_mode)) {
                                /*
                                 * The server may allow us to open things like
@@ -399,10 +422,14 @@ cifs_create_set_dentry:
        if (rc != 0) {
                cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n",
                         rc);
-               if (server->ops->close)
-                       server->ops->close(xid, tcon, fid);
-               goto out;
+               goto out_err;
        }
+
+       if (S_ISDIR(newinode->i_mode)) {
+               rc = -EISDIR;
+               goto out_err;
+       }
+
        d_drop(direntry);
        d_add(direntry, newinode);
 
@@ -410,6 +437,13 @@ out:
        kfree(buf);
        kfree(full_path);
        return rc;
+
+out_err:
+       if (server->ops->close)
+               server->ops->close(xid, tcon, fid);
+       if (newinode)
+               iput(newinode);
+       goto out;
 }
 
 int
@@ -856,7 +890,7 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
        wchar_t c;
        int i, charlen;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (i = 0; i < q->len; i += charlen) {
                charlen = codepage->char2uni(&q->name[i], q->len - i, &c);
                /* error out if we can't convert the character */
index 514dadb0575d5fd9f5698c8bde27a4a362a2b785..b87efd0c92d60adc82e54adcdafc4cab91007802 100644 (file)
@@ -1002,10 +1002,26 @@ struct inode *cifs_root_iget(struct super_block *sb)
        struct inode *inode = NULL;
        long rc;
        struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+       char *path = NULL;
+       int len;
+
+       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+           && cifs_sb->prepath) {
+               len = strlen(cifs_sb->prepath);
+               path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
+               if (path == NULL)
+                       return ERR_PTR(-ENOMEM);
+               path[0] = '/';
+               memcpy(path+1, cifs_sb->prepath, len);
+       } else {
+               path = kstrdup("", GFP_KERNEL);
+               if (path == NULL)
+                       return ERR_PTR(-ENOMEM);
+       }
 
        xid = get_xid();
        if (tcon->unix_ext) {
-               rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
+               rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
                /* some servers mistakenly claim POSIX support */
                if (rc != -EOPNOTSUPP)
                        goto iget_no_retry;
@@ -1013,7 +1029,8 @@ struct inode *cifs_root_iget(struct super_block *sb)
                tcon->unix_ext = false;
        }
 
-       rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
+       convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
+       rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
 
 iget_no_retry:
        if (!inode) {
@@ -1042,6 +1059,7 @@ iget_no_retry:
        }
 
 out:
+       kfree(path);
        /* can not call macro free_xid here since in a void func
         * TODO: This is no longer true
         */
index 3525ed756173d40009017ca11c9ae04cbd97f34a..d203c0329626cd41ee05fd75da9ee4439304bdc1 100644 (file)
@@ -1044,6 +1044,9 @@ smb2_new_lease_key(struct cifs_fid *fid)
        get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
 }
 
+#define SMB2_SYMLINK_STRUCT_SIZE \
+       (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
+
 static int
 smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
                   const char *full_path, char **target_path,
@@ -1056,7 +1059,10 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        struct cifs_fid fid;
        struct smb2_err_rsp *err_buf = NULL;
        struct smb2_symlink_err_rsp *symlink;
-       unsigned int sub_len, sub_offset;
+       unsigned int sub_len;
+       unsigned int sub_offset;
+       unsigned int print_len;
+       unsigned int print_offset;
 
        cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
 
@@ -1077,11 +1083,33 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
                kfree(utf16_path);
                return -ENOENT;
        }
+
+       if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
+           get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) {
+               kfree(utf16_path);
+               return -ENOENT;
+       }
+
        /* open must fail on symlink - reset rc */
        rc = 0;
        symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
        sub_len = le16_to_cpu(symlink->SubstituteNameLength);
        sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
+       print_len = le16_to_cpu(symlink->PrintNameLength);
+       print_offset = le16_to_cpu(symlink->PrintNameOffset);
+
+       if (get_rfc1002_length(err_buf) + 4 <
+                       SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
+               kfree(utf16_path);
+               return -ENOENT;
+       }
+
+       if (get_rfc1002_length(err_buf) + 4 <
+                       SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
+               kfree(utf16_path);
+               return -ENOENT;
+       }
+
        *target_path = cifs_strndup_from_utf16(
                                (char *)symlink->PathBuffer + sub_offset,
                                sub_len, true, cifs_sb->local_nls);
@@ -1515,6 +1543,8 @@ struct smb_version_operations smb20_operations = {
        .rename = smb2_rename_path,
        .create_hardlink = smb2_create_hardlink,
        .query_symlink = smb2_query_symlink,
+       .query_mf_symlink = smb3_query_mf_symlink,
+       .create_mf_symlink = smb3_create_mf_symlink,
        .open = smb2_open_file,
        .set_fid = smb2_set_fid,
        .close = smb2_close_file,
index f36a4040afb8019ee689bc3058957af1c75b758a..b0b9cda41928087a53212f1085dc268dbfd6f432 100644 (file)
@@ -35,7 +35,6 @@ const struct inode_operations coda_ioctl_inode_operations = {
 };
 
 const struct file_operations coda_ioctl_operations = {
-       .owner          = THIS_MODULE,
        .unlocked_ioctl = coda_pioctl,
        .llseek         = noop_llseek,
 };
index bbc1252a59f5f1431ee779e16780f19a5f47a5d8..c30cf49b69d2f3de59e61ef273478d797cccc1b7 100644 (file)
@@ -80,11 +80,11 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf
 
        count = attr->show(item, buffer->page);
 
-       buffer->needs_read_fill = 0;
        BUG_ON(count > (ssize_t)SIMPLE_ATTR_SIZE);
-       if (count >= 0)
+       if (count >= 0) {
+               buffer->needs_read_fill = 0;
                buffer->count = count;
-       else
+       else
                ret = count;
        return ret;
 }
index 432b9e6dd63b90b7a98a4820f1c45e257d007517..993dc6fe0416e17e8a0ca5c8a432b8daf574df86 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -75,13 +75,13 @@ static long dax_map_atomic(struct block_device *bdev, struct blk_dax_ctl *dax)
        struct request_queue *q = bdev->bd_queue;
        long rc = -EIO;
 
-       dax->addr = (void __pmem *) ERR_PTR(-EIO);
+       dax->addr = ERR_PTR(-EIO);
        if (blk_queue_enter(q, true) != 0)
                return rc;
 
        rc = bdev_direct_access(bdev, dax);
        if (rc < 0) {
-               dax->addr = (void __pmem *) ERR_PTR(rc);
+               dax->addr = ERR_PTR(rc);
                blk_queue_exit(q);
                return rc;
        }
@@ -147,12 +147,12 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
                      struct buffer_head *bh)
 {
        loff_t pos = start, max = start, bh_max = start;
-       bool hole = false, need_wmb = false;
+       bool hole = false;
        struct block_device *bdev = NULL;
        int rw = iov_iter_rw(iter), rc;
        long map_len = 0;
        struct blk_dax_ctl dax = {
-               .addr = (void __pmem *) ERR_PTR(-EIO),
+               .addr = ERR_PTR(-EIO),
        };
        unsigned blkbits = inode->i_blkbits;
        sector_t file_blks = (i_size_read(inode) + (1 << blkbits) - 1)
@@ -218,7 +218,6 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
 
                if (iov_iter_rw(iter) == WRITE) {
                        len = copy_from_iter_pmem(dax.addr, max - pos, iter);
-                       need_wmb = true;
                } else if (!hole)
                        len = copy_to_iter((void __force *) dax.addr, max - pos,
                                        iter);
@@ -235,8 +234,6 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
                        dax.addr += len;
        }
 
-       if (need_wmb)
-               wmb_pmem();
        dax_unmap_atomic(bdev, &dax);
 
        return (pos == start) ? rc : pos - start;
@@ -788,7 +785,6 @@ int dax_writeback_mapping_range(struct address_space *mapping,
                                return ret;
                }
        }
-       wmb_pmem();
        return 0;
 }
 EXPORT_SYMBOL_GPL(dax_writeback_mapping_range);
@@ -1187,7 +1183,6 @@ int __dax_zero_page_range(struct block_device *bdev, sector_t sector,
                if (dax_map_atomic(bdev, &dax) < 0)
                        return PTR_ERR(dax.addr);
                clear_pmem(dax.addr + offset, length);
-               wmb_pmem();
                dax_unmap_atomic(bdev, &dax);
        }
        return 0;
index d6847d7b123d4ca0fe4a9100b751b673d8801cd9..b90cf8e09d5b90525330917a834b3153f86528df 100644 (file)
@@ -104,11 +104,9 @@ static unsigned int d_hash_shift __read_mostly;
 
 static struct hlist_bl_head *dentry_hashtable __read_mostly;
 
-static inline struct hlist_bl_head *d_hash(const struct dentry *parent,
-                                       unsigned int hash)
+static inline struct hlist_bl_head *d_hash(unsigned int hash)
 {
-       hash += (unsigned long) parent / L1_CACHE_BYTES;
-       return dentry_hashtable + hash_32(hash, d_hash_shift);
+       return dentry_hashtable + (hash >> (32 - d_hash_shift));
 }
 
 #define IN_LOOKUP_SHIFT 10
@@ -226,10 +224,9 @@ static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char
 
 static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount)
 {
-       const unsigned char *cs;
        /*
         * Be careful about RCU walk racing with rename:
-        * use ACCESS_ONCE to fetch the name pointer.
+        * use 'lockless_dereference' to fetch the name pointer.
         *
         * NOTE! Even if a rename will mean that the length
         * was not loaded atomically, we don't care. The
@@ -243,8 +240,8 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c
         * early because the data cannot match (there can
         * be no NUL in the ct/tcount data)
         */
-       cs = ACCESS_ONCE(dentry->d_name.name);
-       smp_read_barrier_depends();
+       const unsigned char *cs = lockless_dereference(dentry->d_name.name);
+
        return dentry_string_cmp(cs, ct, tcount);
 }
 
@@ -335,44 +332,21 @@ static inline void dentry_rcuwalk_invalidate(struct dentry *dentry)
 
 /*
  * Release the dentry's inode, using the filesystem
- * d_iput() operation if defined. Dentry has no refcount
- * and is unhashed.
- */
-static void dentry_iput(struct dentry * dentry)
-       __releases(dentry->d_lock)
-       __releases(dentry->d_inode->i_lock)
-{
-       struct inode *inode = dentry->d_inode;
-       if (inode) {
-               __d_clear_type_and_inode(dentry);
-               hlist_del_init(&dentry->d_u.d_alias);
-               spin_unlock(&dentry->d_lock);
-               spin_unlock(&inode->i_lock);
-               if (!inode->i_nlink)
-                       fsnotify_inoderemove(inode);
-               if (dentry->d_op && dentry->d_op->d_iput)
-                       dentry->d_op->d_iput(dentry, inode);
-               else
-                       iput(inode);
-       } else {
-               spin_unlock(&dentry->d_lock);
-       }
-}
-
-/*
- * Release the dentry's inode, using the filesystem
- * d_iput() operation if defined. dentry remains in-use.
+ * d_iput() operation if defined.
  */
 static void dentry_unlink_inode(struct dentry * dentry)
        __releases(dentry->d_lock)
        __releases(dentry->d_inode->i_lock)
 {
        struct inode *inode = dentry->d_inode;
+       bool hashed = !d_unhashed(dentry);
 
-       raw_write_seqcount_begin(&dentry->d_seq);
+       if (hashed)
+               raw_write_seqcount_begin(&dentry->d_seq);
        __d_clear_type_and_inode(dentry);
        hlist_del_init(&dentry->d_u.d_alias);
-       raw_write_seqcount_end(&dentry->d_seq);
+       if (hashed)
+               raw_write_seqcount_end(&dentry->d_seq);
        spin_unlock(&dentry->d_lock);
        spin_unlock(&inode->i_lock);
        if (!inode->i_nlink)
@@ -488,7 +462,7 @@ void __d_drop(struct dentry *dentry)
                if (unlikely(IS_ROOT(dentry)))
                        b = &dentry->d_sb->s_anon;
                else
-                       b = d_hash(dentry->d_parent, dentry->d_name.hash);
+                       b = d_hash(dentry->d_name.hash);
 
                hlist_bl_lock(b);
                __hlist_bl_del(&dentry->d_hash);
@@ -573,12 +547,10 @@ static void __dentry_kill(struct dentry *dentry)
        dentry_unlist(dentry, parent);
        if (parent)
                spin_unlock(&parent->d_lock);
-       dentry_iput(dentry);
-       /*
-        * dentry_iput drops the locks, at which point nobody (except
-        * transient RCU lookups) can reach this dentry.
-        */
-       BUG_ON(dentry->d_lockref.count > 0);
+       if (dentry->d_inode)
+               dentry_unlink_inode(dentry);
+       else
+               spin_unlock(&dentry->d_lock);
        this_cpu_dec(nr_dentry);
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
@@ -622,7 +594,6 @@ static struct dentry *dentry_kill(struct dentry *dentry)
 
 failed:
        spin_unlock(&dentry->d_lock);
-       cpu_relax();
        return dentry; /* try again with same dentry */
 }
 
@@ -796,6 +767,8 @@ void dput(struct dentry *dentry)
                return;
 
 repeat:
+       might_sleep();
+
        rcu_read_lock();
        if (likely(fast_dput(dentry))) {
                rcu_read_unlock();
@@ -829,8 +802,10 @@ repeat:
 
 kill_it:
        dentry = dentry_kill(dentry);
-       if (dentry)
+       if (dentry) {
+               cond_resched();
                goto repeat;
+       }
 }
 EXPORT_SYMBOL(dput);
 
@@ -1595,6 +1570,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
 {
        struct dentry *dentry;
        char *dname;
+       int err;
 
        dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
        if (!dentry)
@@ -1653,6 +1629,16 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
        INIT_LIST_HEAD(&dentry->d_child);
        d_set_d_op(dentry, dentry->d_sb->s_d_op);
 
+       if (dentry->d_op && dentry->d_op->d_init) {
+               err = dentry->d_op->d_init(dentry);
+               if (err) {
+                       if (dname_external(dentry))
+                               kfree(external_name(dentry));
+                       kmem_cache_free(dentry_cache, dentry);
+                       return NULL;
+               }
+       }
+
        this_cpu_inc(nr_dentry);
 
        return dentry;
@@ -1716,7 +1702,7 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
        struct qstr q;
 
        q.name = name;
-       q.hash_len = hashlen_string(name);
+       q.hash_len = hashlen_string(parent, name);
        return d_alloc(parent, &q);
 }
 EXPORT_SYMBOL(d_alloc_name);
@@ -1729,7 +1715,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
                                DCACHE_OP_REVALIDATE    |
                                DCACHE_OP_WEAK_REVALIDATE       |
                                DCACHE_OP_DELETE        |
-                               DCACHE_OP_SELECT_INODE  |
                                DCACHE_OP_REAL));
        dentry->d_op = op;
        if (!op)
@@ -1746,8 +1731,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
                dentry->d_flags |= DCACHE_OP_DELETE;
        if (op->d_prune)
                dentry->d_flags |= DCACHE_OP_PRUNE;
-       if (op->d_select_inode)
-               dentry->d_flags |= DCACHE_OP_SELECT_INODE;
        if (op->d_real)
                dentry->d_flags |= DCACHE_OP_REAL;
 
@@ -1815,7 +1798,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
        raw_write_seqcount_begin(&dentry->d_seq);
        __d_set_inode_and_type(dentry, inode, add_flags);
        raw_write_seqcount_end(&dentry->d_seq);
-       __fsnotify_d_instantiate(dentry);
+       fsnotify_update_flags(dentry);
        spin_unlock(&dentry->d_lock);
 }
 
@@ -2067,42 +2050,19 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
 }
 EXPORT_SYMBOL(d_add_ci);
 
-/*
- * Do the slow-case of the dentry name compare.
- *
- * Unlike the dentry_cmp() function, we need to atomically
- * load the name and length information, so that the
- * filesystem can rely on them, and can use the 'name' and
- * 'len' information without worrying about walking off the
- * end of memory etc.
- *
- * Thus the read_seqcount_retry() and the "duplicate" info
- * in arguments (the low-level filesystem should not look
- * at the dentry inode or name contents directly, since
- * rename can change them while we're in RCU mode).
- */
-enum slow_d_compare {
-       D_COMP_OK,
-       D_COMP_NOMATCH,
-       D_COMP_SEQRETRY,
-};
 
-static noinline enum slow_d_compare slow_dentry_cmp(
-               const struct dentry *parent,
-               struct dentry *dentry,
-               unsigned int seq,
-               const struct qstr *name)
+static inline bool d_same_name(const struct dentry *dentry,
+                               const struct dentry *parent,
+                               const struct qstr *name)
 {
-       int tlen = dentry->d_name.len;
-       const char *tname = dentry->d_name.name;
-
-       if (read_seqcount_retry(&dentry->d_seq, seq)) {
-               cpu_relax();
-               return D_COMP_SEQRETRY;
+       if (likely(!(parent->d_flags & DCACHE_OP_COMPARE))) {
+               if (dentry->d_name.len != name->len)
+                       return false;
+               return dentry_cmp(dentry, name->name, name->len) == 0;
        }
-       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
-               return D_COMP_NOMATCH;
-       return D_COMP_OK;
+       return parent->d_op->d_compare(parent, dentry,
+                                      dentry->d_name.len, dentry->d_name.name,
+                                      name) == 0;
 }
 
 /**
@@ -2140,7 +2100,7 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
 {
        u64 hashlen = name->hash_len;
        const unsigned char *str = name->name;
-       struct hlist_bl_head *b = d_hash(parent, hashlen_hash(hashlen));
+       struct hlist_bl_head *b = d_hash(hashlen_hash(hashlen));
        struct hlist_bl_node *node;
        struct dentry *dentry;
 
@@ -2181,6 +2141,9 @@ seqretry:
                 * dentry compare, we will do seqretries until it is stable,
                 * and if we end up with a successful lookup, we actually
                 * want to exit RCU lookup anyway.
+                *
+                * Note that raw_seqcount_begin still *does* smp_rmb(), so
+                * we are still guaranteed NUL-termination of ->d_name.name.
                 */
                seq = raw_seqcount_begin(&dentry->d_seq);
                if (dentry->d_parent != parent)
@@ -2189,24 +2152,28 @@ seqretry:
                        continue;
 
                if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
+                       int tlen;
+                       const char *tname;
                        if (dentry->d_name.hash != hashlen_hash(hashlen))
                                continue;
-                       *seqp = seq;
-                       switch (slow_dentry_cmp(parent, dentry, seq, name)) {
-                       case D_COMP_OK:
-                               return dentry;
-                       case D_COMP_NOMATCH:
-                               continue;
-                       default:
+                       tlen = dentry->d_name.len;
+                       tname = dentry->d_name.name;
+                       /* we want a consistent (name,len) pair */
+                       if (read_seqcount_retry(&dentry->d_seq, seq)) {
+                               cpu_relax();
                                goto seqretry;
                        }
+                       if (parent->d_op->d_compare(parent, dentry,
+                                                   tlen, tname, name) != 0)
+                               continue;
+               } else {
+                       if (dentry->d_name.hash_len != hashlen)
+                               continue;
+                       if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0)
+                               continue;
                }
-
-               if (dentry->d_name.hash_len != hashlen)
-                       continue;
                *seqp = seq;
-               if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
-                       return dentry;
+               return dentry;
        }
        return NULL;
 }
@@ -2254,10 +2221,8 @@ EXPORT_SYMBOL(d_lookup);
  */
 struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
 {
-       unsigned int len = name->len;
        unsigned int hash = name->hash;
-       const unsigned char *str = name->name;
-       struct hlist_bl_head *b = d_hash(parent, hash);
+       struct hlist_bl_head *b = d_hash(hash);
        struct hlist_bl_node *node;
        struct dentry *found = NULL;
        struct dentry *dentry;
@@ -2295,21 +2260,8 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
                if (d_unhashed(dentry))
                        goto next;
 
-               /*
-                * It is safe to compare names since d_move() cannot
-                * change the qstr (protected by d_lock).
-                */
-               if (parent->d_flags & DCACHE_OP_COMPARE) {
-                       int tlen = dentry->d_name.len;
-                       const char *tname = dentry->d_name.name;
-                       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
-                               goto next;
-               } else {
-                       if (dentry->d_name.len != len)
-                               goto next;
-                       if (dentry_cmp(dentry, str, len))
-                               goto next;
-               }
+               if (!d_same_name(dentry, parent, name))
+                       goto next;
 
                dentry->d_lockref.count++;
                found = dentry;
@@ -2337,7 +2289,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
         * calculate the standard hash first, as the d_op->d_hash()
         * routine may choose to leave the hash value unchanged.
         */
-       name->hash = full_name_hash(name->name, name->len);
+       name->hash = full_name_hash(dir, name->name, name->len);
        if (dir->d_flags & DCACHE_OP_HASH) {
                int err = dir->d_op->d_hash(dir, name);
                if (unlikely(err < 0))
@@ -2410,7 +2362,7 @@ static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b)
 
 static void _d_rehash(struct dentry * entry)
 {
-       __d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash));
+       __d_rehash(entry, d_hash(entry->d_name.hash));
 }
 
 /**
@@ -2462,9 +2414,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
                                const struct qstr *name,
                                wait_queue_head_t *wq)
 {
-       unsigned int len = name->len;
        unsigned int hash = name->hash;
-       const unsigned char *str = name->name;
        struct hlist_bl_head *b = in_lookup_hash(parent, hash);
        struct hlist_bl_node *node;
        struct dentry *new = d_alloc(parent, name);
@@ -2515,17 +2465,8 @@ retry:
                        continue;
                if (dentry->d_parent != parent)
                        continue;
-               if (parent->d_flags & DCACHE_OP_COMPARE) {
-                       int tlen = dentry->d_name.len;
-                       const char *tname = dentry->d_name.name;
-                       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
-                               continue;
-               } else {
-                       if (dentry->d_name.len != len)
-                               continue;
-                       if (dentry_cmp(dentry, str, len))
-                               continue;
-               }
+               if (!d_same_name(dentry, parent, name))
+                       continue;
                hlist_bl_unlock(b);
                /* now we can try to grab a reference */
                if (!lockref_get_not_dead(&dentry->d_lockref)) {
@@ -2552,17 +2493,8 @@ retry:
                        goto mismatch;
                if (unlikely(d_unhashed(dentry)))
                        goto mismatch;
-               if (parent->d_flags & DCACHE_OP_COMPARE) {
-                       int tlen = dentry->d_name.len;
-                       const char *tname = dentry->d_name.name;
-                       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
-                               goto mismatch;
-               } else {
-                       if (unlikely(dentry->d_name.len != len))
-                               goto mismatch;
-                       if (unlikely(dentry_cmp(dentry, str, len)))
-                               goto mismatch;
-               }
+               if (unlikely(!d_same_name(dentry, parent, name)))
+                       goto mismatch;
                /* OK, it *is* a hashed match; return it */
                spin_unlock(&dentry->d_lock);
                dput(new);
@@ -2615,7 +2547,7 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
                raw_write_seqcount_begin(&dentry->d_seq);
                __d_set_inode_and_type(dentry, inode, add_flags);
                raw_write_seqcount_end(&dentry->d_seq);
-               __fsnotify_d_instantiate(dentry);
+               fsnotify_update_flags(dentry);
        }
        _d_rehash(dentry);
        if (dir)
@@ -2658,8 +2590,6 @@ EXPORT_SYMBOL(d_add);
 struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)
 {
        struct dentry *alias;
-       int len = entry->d_name.len;
-       const char *name = entry->d_name.name;
        unsigned int hash = entry->d_name.hash;
 
        spin_lock(&inode->i_lock);
@@ -2673,9 +2603,7 @@ struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)
                        continue;
                if (alias->d_parent != entry->d_parent)
                        continue;
-               if (alias->d_name.len != len)
-                       continue;
-               if (dentry_cmp(alias, name, len))
+               if (!d_same_name(alias, entry->d_parent, &entry->d_name))
                        continue;
                spin_lock(&alias->d_lock);
                if (!d_unhashed(alias)) {
@@ -2874,7 +2802,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
         * for the same hash queue because of how unlikely it is.
         */
        __d_drop(dentry);
-       __d_rehash(dentry, d_hash(target->d_parent, target->d_name.hash));
+       __d_rehash(dentry, d_hash(target->d_name.hash));
 
        /*
         * Unhash the target (d_delete() is not usable here).  If exchanging
@@ -2882,8 +2810,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
         */
        __d_drop(target);
        if (exchange) {
-               __d_rehash(target,
-                          d_hash(dentry->d_parent, dentry->d_name.hash));
+               __d_rehash(target, d_hash(dentry->d_name.hash));
        }
 
        /* Switch the names.. */
@@ -2906,8 +2833,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
                list_move(&target->d_child, &target->d_parent->d_subdirs);
                list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
                if (exchange)
-                       fsnotify_d_move(target);
-               fsnotify_d_move(dentry);
+                       fsnotify_update_flags(target);
+               fsnotify_update_flags(dentry);
        }
 
        write_seqcount_end(&target->d_seq);
index 4bc1f68243c1a67db2446097aa18b7ef21ead440..72361baf9da71f2f27cd32c58d8dada0972e1992 100644 (file)
@@ -621,9 +621,6 @@ void debugfs_remove(struct dentry *dentry)
                return;
 
        parent = dentry->d_parent;
-       if (!parent || d_really_is_negative(parent))
-               return;
-
        inode_lock(d_inode(parent));
        ret = __debugfs_remove(dentry, parent);
        inode_unlock(d_inode(parent));
@@ -654,10 +651,6 @@ void debugfs_remove_recursive(struct dentry *dentry)
        if (IS_ERR_OR_NULL(dentry))
                return;
 
-       parent = dentry->d_parent;
-       if (!parent || d_really_is_negative(parent))
-               return;
-
        parent = dentry;
  down:
        inode_lock(d_inode(parent));
index 9cb54a38832de664b3ced0c4b876ececb7c907dd..a5e607e8f056dc7c1cac815573c01d6a2601caf1 100644 (file)
@@ -65,7 +65,7 @@ static int efivarfs_d_compare(const struct dentry *parent,
 
 static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(dentry);
        const unsigned char *s = qstr->name;
        unsigned int len = qstr->len;
 
@@ -98,7 +98,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
        q.name = name;
        q.len = strlen(name);
 
-       err = efivarfs_d_hash(NULL, &q);
+       err = efivarfs_d_hash(parent, &q);
        if (err)
                return ERR_PTR(err);
 
index 11562161e24acbf449d734bcb67c46fd77ccdfb8..f418f55c2bbe1bf011f4d401731da533cbb75666 100644 (file)
@@ -2350,7 +2350,6 @@ static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations ext4_seq_mb_groups_fops = {
-       .owner          = THIS_MODULE,
        .open           = ext4_mb_seq_groups_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 1420a3c614afb1a4c06e87471163acf01b3b98d8..73bcfd41f5f262453e729fc11c4604b5109de842 100644 (file)
@@ -359,7 +359,6 @@ static int name##_open(struct inode *inode, struct file *file) \
 } \
 \
 static const struct file_operations ext4_seq_##name##_fops = { \
-       .owner          = THIS_MODULE, \
        .open           = name##_open, \
        .read           = seq_read, \
        .llseek         = seq_lseek, \
index b97c065cbe744b1eed931e3dd5754d8815ef3e6c..1b86d3f638efcf87435da17af79811237fc584a9 100644 (file)
@@ -961,7 +961,6 @@ static int _name##_open_fs(struct inode *inode, struct file *file)  \
 }                                                                      \
                                                                        \
 static const struct file_operations f2fs_seq_##_name##_fops = {                \
-       .owner = THIS_MODULE,                                           \
        .open = _name##_open_fs,                                        \
        .read = seq_read,                                               \
        .llseek = seq_lseek,                                            \
index 3bcf57925dca80d4cb55565568469aa04b001e9d..da04c0298fab40c1df4d22dd2492ec8d7ef26a4d 100644 (file)
@@ -1589,7 +1589,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 
        /*
         * GFP_KERNEL is ok here, because while we do hold the
-        * supeblock lock, memory pressure can't call back into
+        * superblock lock, memory pressure can't call back into
         * the filesystem, since we're only just about to mount
         * it and have no inodes etc active!
         */
@@ -1726,7 +1726,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        sbi->dir_entries = bpb.fat_dir_entries;
        if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
                if (!silent)
-                       fat_msg(sb, KERN_ERR, "bogus directory-entries per block"
+                       fat_msg(sb, KERN_ERR, "bogus number of directory entries"
                               " (%u)", sbi->dir_entries);
                goto out_invalid;
        }
index b7e2b33aa79356b7762512dbe5940b5fca7de1d7..1337c0c7527d543f5d5585bec256ad56b7c32a4e 100644 (file)
@@ -154,7 +154,7 @@ static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
 
        error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
        if (!error)
-               qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
+               qstr->hash = full_name_hash(dentry, msdos_name, MSDOS_NAME);
        return 0;
 }
 
index 7092584f424af63e66e43cf8ad365343fc18daa9..6ccdf3f34f90f4789d0f217d74e7a748337e9758 100644 (file)
@@ -107,7 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr)
  */
 static int vfat_hash(const struct dentry *dentry, struct qstr *qstr)
 {
-       qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
+       qstr->hash = full_name_hash(dentry, qstr->name, vfat_striptail_len(qstr));
        return 0;
 }
 
@@ -127,7 +127,7 @@ static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
        name = qstr->name;
        len = vfat_striptail_len(qstr);
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        while (len--)
                hash = partial_name_hash(nls_tolower(t, *name++), hash);
        qstr->hash = end_name_hash(hash);
index 8dc1cd5c1efed3df229ec4f63251d529ff410983..ce49df1020dd1948639c0985326d35adc7f86aa2 100644 (file)
@@ -5,12 +5,21 @@ config VXFS_FS
          FreeVxFS is a file system driver that support the VERITAS VxFS(TM)
          file system format.  VERITAS VxFS(TM) is the standard file system
          of SCO UnixWare (and possibly others) and optionally available
-         for Sunsoft Solaris, HP-UX and many other operating systems.
-         Currently only readonly access is supported.
+         for Sunsoft Solaris, HP-UX and many other operating systems. However
+         these particular OS implementations of vxfs may differ in on-disk
+         data endianess and/or superblock offset. The vxfs module has been
+         tested with SCO UnixWare and HP-UX B.10.20 (pa-risc 1.1 arch.)
+         Currently only readonly access is supported and VxFX versions
+         2, 3 and 4. Tests were performed with HP-UX VxFS version 3.
 
          NOTE: the file system type as used by mount(1), mount(2) and
          fstab(5) is 'vxfs' as it describes the file system format, not
          the actual driver.
 
+         There is a userspace utility for HP-UX logical volumes which makes
+         creating HP-UX logical volumes easy from HP-UX disk block device file
+         or regular file with image of the disk. See:
+                https://sourceforge.net/projects/linux-vxfs/
+
          To compile this as a module, choose M here: the module will be
          called freevxfs.  If unsure, say N.
index c8a92652612aad1352ba491b50a165624ceaba7a..a41ea0ba694337b69e679f8fba3a20b6803cde80 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2001 Christoph Hellwig.
+ * Copyright (c) 2016 Krzysztof Blaszkowski
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 #include <linux/types.h>
 
-
-/*
- * Data types for use with the VxFS ondisk format.
- */
-typedef        int32_t         vx_daddr_t;
-typedef int32_t                vx_ino_t;
-
 /*
  * Superblock magic number (vxfs_super->vs_magic).
  */
@@ -60,6 +54,14 @@ typedef int32_t              vx_ino_t;
  */
 #define VXFS_NEFREE            32
 
+enum vxfs_byte_order {
+       VXFS_BO_LE,
+       VXFS_BO_BE,
+};
+
+typedef __u16 __bitwise __fs16;
+typedef __u32 __bitwise __fs32;
+typedef __u64 __bitwise __fs64;
 
 /*
  * VxFS superblock (disk).
@@ -71,83 +73,83 @@ struct vxfs_sb {
         * Lots of this fields are no more used by version 2
         * and never filesystems.
         */
-       u_int32_t       vs_magic;               /* Magic number */
-       int32_t         vs_version;             /* VxFS version */
-       u_int32_t       vs_ctime;               /* create time - secs */
-       u_int32_t       vs_cutime;              /* create time - usecs */
-       int32_t         __unused1;              /* unused */
-       int32_t         __unused2;              /* unused */
-       vx_daddr_t      vs_old_logstart;        /* obsolete */
-       vx_daddr_t      vs_old_logend;          /* obsolete */
-       int32_t         vs_bsize;               /* block size */
-       int32_t         vs_size;                /* number of blocks */
-       int32_t         vs_dsize;               /* number of data blocks */
-       u_int32_t       vs_old_ninode;          /* obsolete */
-       int32_t         vs_old_nau;             /* obsolete */
-       int32_t         __unused3;              /* unused */
-       int32_t         vs_old_defiextsize;     /* obsolete */
-       int32_t         vs_old_ilbsize;         /* obsolete */
-       int32_t         vs_immedlen;            /* size of immediate data area */
-       int32_t         vs_ndaddr;              /* number of direct extentes */
-       vx_daddr_t      vs_firstau;             /* address of first AU */
-       vx_daddr_t      vs_emap;                /* offset of extent map in AU */
-       vx_daddr_t      vs_imap;                /* offset of inode map in AU */
-       vx_daddr_t      vs_iextop;              /* offset of ExtOp. map in AU */
-       vx_daddr_t      vs_istart;              /* offset of inode list in AU */
-       vx_daddr_t      vs_bstart;              /* offset of fdblock in AU */
-       vx_daddr_t      vs_femap;               /* aufirst + emap */
-       vx_daddr_t      vs_fimap;               /* aufirst + imap */
-       vx_daddr_t      vs_fiextop;             /* aufirst + iextop */
-       vx_daddr_t      vs_fistart;             /* aufirst + istart */
-       vx_daddr_t      vs_fbstart;             /* aufirst + bstart */
-       int32_t         vs_nindir;              /* number of entries in indir */
-       int32_t         vs_aulen;               /* length of AU in blocks */
-       int32_t         vs_auimlen;             /* length of imap in blocks */
-       int32_t         vs_auemlen;             /* length of emap in blocks */
-       int32_t         vs_auilen;              /* length of ilist in blocks */
-       int32_t         vs_aupad;               /* length of pad in blocks */
-       int32_t         vs_aublocks;            /* data blocks in AU */
-       int32_t         vs_maxtier;             /* log base 2 of aublocks */
-       int32_t         vs_inopb;               /* number of inodes per blk */
-       int32_t         vs_old_inopau;          /* obsolete */
-       int32_t         vs_old_inopilb;         /* obsolete */
-       int32_t         vs_old_ndiripau;        /* obsolete */
-       int32_t         vs_iaddrlen;            /* size of indirect addr ext. */
-       int32_t         vs_bshift;              /* log base 2 of bsize */
-       int32_t         vs_inoshift;            /* log base 2 of inobp */
-       int32_t         vs_bmask;               /* ~( bsize - 1 ) */
-       int32_t         vs_boffmask;            /* bsize - 1 */
-       int32_t         vs_old_inomask;         /* old_inopilb - 1 */
-       int32_t         vs_checksum;            /* checksum of V1 data */
+       __fs32          vs_magic;               /* Magic number */
+       __fs32          vs_version;             /* VxFS version */
+       __fs32          vs_ctime;               /* create time - secs */
+       __fs32          vs_cutime;              /* create time - usecs */
+       __fs32          __unused1;              /* unused */
+       __fs32          __unused2;              /* unused */
+       __fs32          vs_old_logstart;        /* obsolete */
+       __fs32          vs_old_logend;          /* obsolete */
+       __fs32          vs_bsize;               /* block size */
+       __fs32          vs_size;                /* number of blocks */
+       __fs32          vs_dsize;               /* number of data blocks */
+       __fs32          vs_old_ninode;          /* obsolete */
+       __fs32          vs_old_nau;             /* obsolete */
+       __fs32          __unused3;              /* unused */
+       __fs32          vs_old_defiextsize;     /* obsolete */
+       __fs32          vs_old_ilbsize;         /* obsolete */
+       __fs32          vs_immedlen;            /* size of immediate data area */
+       __fs32          vs_ndaddr;              /* number of direct extentes */
+       __fs32          vs_firstau;             /* address of first AU */
+       __fs32          vs_emap;                /* offset of extent map in AU */
+       __fs32          vs_imap;                /* offset of inode map in AU */
+       __fs32          vs_iextop;              /* offset of ExtOp. map in AU */
+       __fs32          vs_istart;              /* offset of inode list in AU */
+       __fs32          vs_bstart;              /* offset of fdblock in AU */
+       __fs32          vs_femap;               /* aufirst + emap */
+       __fs32          vs_fimap;               /* aufirst + imap */
+       __fs32          vs_fiextop;             /* aufirst + iextop */
+       __fs32          vs_fistart;             /* aufirst + istart */
+       __fs32          vs_fbstart;             /* aufirst + bstart */
+       __fs32          vs_nindir;              /* number of entries in indir */
+       __fs32          vs_aulen;               /* length of AU in blocks */
+       __fs32          vs_auimlen;             /* length of imap in blocks */
+       __fs32          vs_auemlen;             /* length of emap in blocks */
+       __fs32          vs_auilen;              /* length of ilist in blocks */
+       __fs32          vs_aupad;               /* length of pad in blocks */
+       __fs32          vs_aublocks;            /* data blocks in AU */
+       __fs32          vs_maxtier;             /* log base 2 of aublocks */
+       __fs32          vs_inopb;               /* number of inodes per blk */
+       __fs32          vs_old_inopau;          /* obsolete */
+       __fs32          vs_old_inopilb;         /* obsolete */
+       __fs32          vs_old_ndiripau;        /* obsolete */
+       __fs32          vs_iaddrlen;            /* size of indirect addr ext. */
+       __fs32          vs_bshift;              /* log base 2 of bsize */
+       __fs32          vs_inoshift;            /* log base 2 of inobp */
+       __fs32          vs_bmask;               /* ~( bsize - 1 ) */
+       __fs32          vs_boffmask;            /* bsize - 1 */
+       __fs32          vs_old_inomask;         /* old_inopilb - 1 */
+       __fs32          vs_checksum;            /* checksum of V1 data */
        
        /*
         * Version 1, writable
         */
-       int32_t         vs_free;                /* number of free blocks */
-       int32_t         vs_ifree;               /* number of free inodes */
-       int32_t         vs_efree[VXFS_NEFREE];  /* number of free extents by size */
-       int32_t         vs_flags;               /* flags ?!? */
-       u_int8_t        vs_mod;                 /* filesystem has been changed */
-       u_int8_t        vs_clean;               /* clean FS */
-       u_int16_t       __unused4;              /* unused */
-       u_int32_t       vs_firstlogid;          /* mount time log ID */
-       u_int32_t       vs_wtime;               /* last time written - sec */
-       u_int32_t       vs_wutime;              /* last time written - usec */
-       u_int8_t        vs_fname[6];            /* FS name */
-       u_int8_t        vs_fpack[6];            /* FS pack name */
-       int32_t         vs_logversion;          /* log format version */
-       int32_t         __unused5;              /* unused */
+       __fs32          vs_free;                /* number of free blocks */
+       __fs32          vs_ifree;               /* number of free inodes */
+       __fs32          vs_efree[VXFS_NEFREE];  /* number of free extents by size */
+       __fs32          vs_flags;               /* flags ?!? */
+       __u8            vs_mod;                 /* filesystem has been changed */
+       __u8            vs_clean;               /* clean FS */
+       __fs16          __unused4;              /* unused */
+       __fs32          vs_firstlogid;          /* mount time log ID */
+       __fs32          vs_wtime;               /* last time written - sec */
+       __fs32          vs_wutime;              /* last time written - usec */
+       __u8            vs_fname[6];            /* FS name */
+       __u8            vs_fpack[6];            /* FS pack name */
+       __fs32          vs_logversion;          /* log format version */
+       __u32           __unused5;              /* unused */
        
        /*
         * Version 2, Read-only
         */
-       vx_daddr_t      vs_oltext[2];           /* OLT extent and replica */
-       int32_t         vs_oltsize;             /* OLT extent size */
-       int32_t         vs_iauimlen;            /* size of inode map */
-       int32_t         vs_iausize;             /* size of IAU in blocks */
-       int32_t         vs_dinosize;            /* size of inode in bytes */
-       int32_t         vs_old_dniaddr;         /* indir levels per inode */
-       int32_t         vs_checksum2;           /* checksum of V2 RO */
+       __fs32          vs_oltext[2];           /* OLT extent and replica */
+       __fs32          vs_oltsize;             /* OLT extent size */
+       __fs32          vs_iauimlen;            /* size of inode map */
+       __fs32          vs_iausize;             /* size of IAU in blocks */
+       __fs32          vs_dinosize;            /* size of inode in bytes */
+       __fs32          vs_old_dniaddr;         /* indir levels per inode */
+       __fs32          vs_checksum2;           /* checksum of V2 RO */
 
        /*
         * Actually much more...
@@ -168,8 +170,32 @@ struct vxfs_sb_info {
        ino_t                   vsi_fshino;     /* fileset header inode */
        daddr_t                 vsi_oltext;     /* OLT extent */
        daddr_t                 vsi_oltsize;    /* OLT size */
+       enum vxfs_byte_order    byte_order;
 };
 
+static inline u16 fs16_to_cpu(struct vxfs_sb_info *sbi, __fs16 a)
+{
+       if (sbi->byte_order == VXFS_BO_BE)
+               return be16_to_cpu((__force __be16)a);
+       else
+               return le16_to_cpu((__force __le16)a);
+}
+
+static inline u32 fs32_to_cpu(struct vxfs_sb_info *sbi, __fs32 a)
+{
+       if (sbi->byte_order == VXFS_BO_BE)
+               return be32_to_cpu((__force __be32)a);
+       else
+               return le32_to_cpu((__force __le32)a);
+}
+
+static inline u64 fs64_to_cpu(struct vxfs_sb_info *sbi, __fs64 a)
+{
+       if (sbi->byte_order == VXFS_BO_BE)
+               return be64_to_cpu((__force __be64)a);
+       else
+               return le64_to_cpu((__force __le64)a);
+}
 
 /*
  * File modes.  File types above 0xf000 are vxfs internal only, they should
@@ -247,13 +273,6 @@ enum {
 #define VXFS_ISIMMED(ip)       VXFS_IS_ORG((ip), VXFS_ORG_IMMED)
 #define VXFS_ISTYPED(ip)       VXFS_IS_ORG((ip), VXFS_ORG_TYPED)
 
-
-/*
- * Get filesystem private data from VFS inode.
- */
-#define VXFS_INO(ip) \
-       ((struct vxfs_inode_info *)(ip)->i_private)
-
 /*
  * Get filesystem private data from VFS superblock.
  */
index f86fd3cacd5ab77f6741ce9fcb1dc2d8ee746c01..1fd41cf98b9fce33ffaf318a3a1c0abde5edfd0f 100644 (file)
@@ -68,8 +68,9 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
 {
        struct super_block *sb = ip->i_sb;
        struct vxfs_inode_info *vip = VXFS_INO(ip);
+       struct vxfs_sb_info *sbi = VXFS_SBI(sb);
        unsigned long bsize = sb->s_blocksize;
-       u32 indsize = vip->vii_ext4.ve4_indsize;
+       u32 indsize = fs32_to_cpu(sbi, vip->vii_ext4.ve4_indsize);
        int i;
 
        if (indsize > sb->s_blocksize)
@@ -77,22 +78,24 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
 
        for (i = 0; i < VXFS_NDADDR; i++) {
                struct direct *d = vip->vii_ext4.ve4_direct + i;
-               if (bn >= 0 && bn < d->size)
-                       return (bn + d->extent);
-               bn -= d->size;
+               if (bn >= 0 && bn < fs32_to_cpu(sbi, d->size))
+                       return (bn + fs32_to_cpu(sbi, d->extent));
+               bn -= fs32_to_cpu(sbi, d->size);
        }
 
        if ((bn / (indsize * indsize * bsize / 4)) == 0) {
                struct buffer_head *buf;
                daddr_t bno;
-               u32 *indir;
+               __fs32 *indir;
 
-               buf = sb_bread(sb, vip->vii_ext4.ve4_indir[0]);
+               buf = sb_bread(sb,
+                       fs32_to_cpu(sbi, vip->vii_ext4.ve4_indir[0]));
                if (!buf || !buffer_mapped(buf))
                        goto fail_buf;
 
-               indir = (u32 *)buf->b_data;
-               bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
+               indir = (__fs32 *)buf->b_data;
+               bno = fs32_to_cpu(sbi, indir[(bn / indsize) % (indsize * bn)]) +
+                       (bn % indsize);
 
                brelse(buf);
                return bno;
@@ -127,6 +130,7 @@ fail_buf:
 static daddr_t
 vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
 {
+       struct vxfs_sb_info             *sbi = VXFS_SBI(ip->i_sb);
        struct buffer_head              *bp = NULL;
        daddr_t                         pblock = 0;
        int                             i;
@@ -142,24 +146,27 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
 
                typ = ((struct vxfs_typed *)bp->b_data) +
                        (i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
-               off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+               off = fs64_to_cpu(sbi, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK;
 
                if (block < off) {
                        brelse(bp);
                        continue;
                }
 
-               switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
+               switch ((u_int32_t)(fs64_to_cpu(sbi, typ->vt_hdr) >>
+                               VXFS_TYPED_TYPESHIFT)) {
                case VXFS_TYPED_INDIRECT:
-                       pblock = vxfs_bmap_indir(ip, typ->vt_block,
-                                       typ->vt_size, block - off);
+                       pblock = vxfs_bmap_indir(ip,
+                                       fs32_to_cpu(sbi, typ->vt_block),
+                                       fs32_to_cpu(sbi, typ->vt_size),
+                                       block - off);
                        if (pblock == -2)
                                break;
                        goto out;
                case VXFS_TYPED_DATA:
-                       if ((block - off) >= typ->vt_size)
+                       if ((block - off) >= fs32_to_cpu(sbi, typ->vt_size))
                                break;
-                       pblock = (typ->vt_block + block - off);
+                       pblock = fs32_to_cpu(sbi, typ->vt_block) + block - off;
                        goto out;
                case VXFS_TYPED_INDIRECT_DEV4:
                case VXFS_TYPED_DATA_DEV4: {
@@ -167,13 +174,15 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
                                (struct vxfs_typed_dev4 *)typ;
 
                        printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
-                       printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
-                              (unsigned long long) typ4->vd4_block,
-                              (unsigned long long) typ4->vd4_size,
-                              typ4->vd4_dev);
+                       printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
+                              fs64_to_cpu(sbi, typ4->vd4_block),
+                              fs64_to_cpu(sbi, typ4->vd4_size),
+                              fs32_to_cpu(sbi, typ4->vd4_dev));
                        goto fail;
                }
                default:
+                       printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__,
+                               __LINE__, fs64_to_cpu(sbi, typ->vt_hdr));
                        BUG();
                }
                brelse(bp);
@@ -201,28 +210,33 @@ static daddr_t
 vxfs_bmap_typed(struct inode *ip, long iblock)
 {
        struct vxfs_inode_info          *vip = VXFS_INO(ip);
+       struct vxfs_sb_info             *sbi = VXFS_SBI(ip->i_sb);
        daddr_t                         pblock = 0;
        int                             i;
 
        for (i = 0; i < VXFS_NTYPED; i++) {
                struct vxfs_typed       *typ = vip->vii_org.typed + i;
-               int64_t                 off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+               u64                     hdr = fs64_to_cpu(sbi, typ->vt_hdr);
+               int64_t                 off = (hdr & VXFS_TYPED_OFFSETMASK);
 
 #ifdef DIAGNOSTIC
                vxfs_typdump(typ);
 #endif
                if (iblock < off)
                        continue;
-               switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
+               switch ((u32)(hdr >> VXFS_TYPED_TYPESHIFT)) {
                case VXFS_TYPED_INDIRECT:
-                       pblock = vxfs_bmap_indir(ip, typ->vt_block,
-                                       typ->vt_size, iblock - off);
+                       pblock = vxfs_bmap_indir(ip,
+                                       fs32_to_cpu(sbi, typ->vt_block),
+                                       fs32_to_cpu(sbi, typ->vt_size),
+                                       iblock - off);
                        if (pblock == -2)
                                break;
                        return (pblock);
                case VXFS_TYPED_DATA:
-                       if ((iblock - off) < typ->vt_size)
-                               return (typ->vt_block + iblock - off);
+                       if ((iblock - off) < fs32_to_cpu(sbi, typ->vt_size))
+                               return (fs32_to_cpu(sbi, typ->vt_block) +
+                                               iblock - off);
                        break;
                case VXFS_TYPED_INDIRECT_DEV4:
                case VXFS_TYPED_DATA_DEV4: {
@@ -230,10 +244,10 @@ vxfs_bmap_typed(struct inode *ip, long iblock)
                                (struct vxfs_typed_dev4 *)typ;
 
                        printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
-                       printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
-                              (unsigned long long) typ4->vd4_block,
-                              (unsigned long long) typ4->vd4_size,
-                              typ4->vd4_dev);
+                       printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
+                              fs64_to_cpu(sbi, typ4->vd4_block),
+                              fs64_to_cpu(sbi, typ4->vd4_size),
+                              fs32_to_cpu(sbi, typ4->vd4_dev));
                        return 0;
                }
                default:
index aaf1fb098639553fc6ad7a8d6c9e0ccd7162a9ce..acc5477b3f2325242788801afff810fb5736fe4f 100644 (file)
@@ -48,9 +48,9 @@
  * Linux driver for now.
  */
 struct vxfs_dirblk {
-       u_int16_t       d_free;         /* free space in dirblock */
-       u_int16_t       d_nhash;        /* no of hash chains */
-       u_int16_t       d_hash[1];      /* hash chain */
+       __fs16          d_free;         /* free space in dirblock */
+       __fs16          d_nhash;        /* no of hash chains */
+       __fs16          d_hash[1];      /* hash chain */
 };
 
 /*
@@ -63,10 +63,10 @@ struct vxfs_dirblk {
  * VxFS directory entry.
  */
 struct vxfs_direct {
-       vx_ino_t        d_ino;                  /* inode number */
-       u_int16_t       d_reclen;               /* record length */
-       u_int16_t       d_namelen;              /* d_name length */
-       u_int16_t       d_hashnext;             /* next hash entry */
+       __fs32          d_ino;                  /* inode number */
+       __fs16          d_reclen;               /* record length */
+       __fs16          d_namelen;              /* d_name length */
+       __fs16          d_hashnext;             /* next hash entry */
        char            d_name[VXFS_NAMELEN];   /* name */
 };
 
@@ -87,6 +87,7 @@ struct vxfs_direct {
 /*
  * VXFS_DIRBLKOV is the overhead of a specific dirblock.
  */
-#define VXFS_DIRBLKOV(dbp)     ((sizeof(short) * dbp->d_nhash) + 4)
+#define VXFS_DIRBLKOV(sbi, dbp)        \
+       ((sizeof(short) * fs16_to_cpu(sbi, dbp->d_nhash)) + 4)
 
 #endif /* _VXFS_DIR_H_ */
index e3dcb4467d92752af6980549fb740f97d11d1f47..f5c428e210245d9594ebc5f270318a2c60ee9224 100644 (file)
@@ -52,14 +52,10 @@ extern int                  vxfs_read_fshead(struct super_block *);
 
 /* vxfs_inode.c */
 extern const struct address_space_operations vxfs_immed_aops;
-extern struct kmem_cache       *vxfs_inode_cachep;
 extern void                    vxfs_dumpi(struct vxfs_inode_info *, ino_t);
-extern struct inode *          vxfs_get_fake_inode(struct super_block *,
-                                       struct vxfs_inode_info *);
-extern void                    vxfs_put_fake_inode(struct inode *);
-extern struct vxfs_inode_info *        vxfs_blkiget(struct super_block *, u_long, ino_t);
-extern struct vxfs_inode_info *        vxfs_stiget(struct super_block *, ino_t);
-extern struct inode *          vxfs_iget(struct super_block *, ino_t);
+extern struct inode            *vxfs_blkiget(struct super_block *, u_long, ino_t);
+extern struct inode            *vxfs_stiget(struct super_block *, ino_t);
+extern struct inode            *vxfs_iget(struct super_block *, ino_t);
 extern void                    vxfs_evict_inode(struct inode *);
 
 /* vxfs_lookup.c */
index c9a6a94e58e9cd289ea14a689d9344c7e291bdd4..a4610a77649e59120ad3011207e4b448dbd4849a 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2001 Christoph Hellwig.
+ * Copyright (c) 2016 Krzysztof Blaszkowski
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -108,31 +109,26 @@ vxfs_read_fshead(struct super_block *sbp)
 {
        struct vxfs_sb_info             *infp = VXFS_SBI(sbp);
        struct vxfs_fsh                 *pfp, *sfp;
-       struct vxfs_inode_info          *vip, *tip;
+       struct vxfs_inode_info          *vip;
 
-       vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
-       if (!vip) {
+       infp->vsi_fship = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
+       if (!infp->vsi_fship) {
                printk(KERN_ERR "vxfs: unable to read fsh inode\n");
                return -EINVAL;
        }
+
+       vip = VXFS_INO(infp->vsi_fship);
        if (!VXFS_ISFSH(vip)) {
                printk(KERN_ERR "vxfs: fsh list inode is of wrong type (%x)\n",
                                vip->vii_mode & VXFS_TYPE_MASK); 
-               goto out_free_fship;
+               goto out_iput_fship;
        }
 
-
 #ifdef DIAGNOSTIC
        printk("vxfs: fsh inode dump:\n");
        vxfs_dumpi(vip, infp->vsi_fshino);
 #endif
 
-       infp->vsi_fship = vxfs_get_fake_inode(sbp, vip);
-       if (!infp->vsi_fship) {
-               printk(KERN_ERR "vxfs: unable to get fsh inode\n");
-               goto out_free_fship;
-       }
-
        sfp = vxfs_getfsh(infp->vsi_fship, 0);
        if (!sfp) {
                printk(KERN_ERR "vxfs: unable to get structural fsh\n");
@@ -153,14 +149,10 @@ vxfs_read_fshead(struct super_block *sbp)
        vxfs_dumpfsh(pfp);
 #endif
 
-       tip = vxfs_blkiget(sbp, infp->vsi_iext, sfp->fsh_ilistino[0]);
-       if (!tip)
-               goto out_free_pfp;
-
-       infp->vsi_stilist = vxfs_get_fake_inode(sbp, tip);
+       infp->vsi_stilist = vxfs_blkiget(sbp, infp->vsi_iext,
+                       fs32_to_cpu(infp, sfp->fsh_ilistino[0]));
        if (!infp->vsi_stilist) {
                printk(KERN_ERR "vxfs: unable to get structural list inode\n");
-               kfree(tip);
                goto out_free_pfp;
        }
        if (!VXFS_ISILT(VXFS_INO(infp->vsi_stilist))) {
@@ -169,13 +161,9 @@ vxfs_read_fshead(struct super_block *sbp)
                goto out_iput_stilist;
        }
 
-       tip = vxfs_stiget(sbp, pfp->fsh_ilistino[0]);
-       if (!tip)
-               goto out_iput_stilist;
-       infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
+       infp->vsi_ilist = vxfs_stiget(sbp, fs32_to_cpu(infp, pfp->fsh_ilistino[0]));
        if (!infp->vsi_ilist) {
                printk(KERN_ERR "vxfs: unable to get inode list inode\n");
-               kfree(tip);
                goto out_iput_stilist;
        }
        if (!VXFS_ISILT(VXFS_INO(infp->vsi_ilist))) {
@@ -184,6 +172,8 @@ vxfs_read_fshead(struct super_block *sbp)
                goto out_iput_ilist;
        }
 
+       kfree(pfp);
+       kfree(sfp);
        return 0;
 
  out_iput_ilist:
@@ -197,7 +187,4 @@ vxfs_read_fshead(struct super_block *sbp)
  out_iput_fship:
        iput(infp->vsi_fship);
        return -EINVAL;
- out_free_fship:
-       kfree(vip);
-       return -EINVAL;
 }
index ead0d640c18144fdbcb348e2ec1b4ff25f05c969..e026f0c4915969c5c170586afd525713aec8a14f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2001 Christoph Hellwig.
+ * Copyright (c) 2016 Krzysztof Blaszkowski
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * Fileset header 
  */
 struct vxfs_fsh {
-       u_int32_t       fsh_version;            /* fileset header version */
-       u_int32_t       fsh_fsindex;            /* fileset index */
-       u_int32_t       fsh_time;               /* modification time - sec */
-       u_int32_t       fsh_utime;              /* modification time - usec */
-       u_int32_t       fsh_extop;              /* extop flags */
-       vx_ino_t        fsh_ninodes;            /* allocated inodes */
-       u_int32_t       fsh_nau;                /* number of IAUs */
-       u_int32_t       fsh_old_ilesize;        /* old size of ilist */
-       u_int32_t       fsh_dflags;             /* flags */
-       u_int32_t       fsh_quota;              /* quota limit */
-       vx_ino_t        fsh_maxinode;           /* maximum inode number */
-       vx_ino_t        fsh_iauino;             /* IAU inode */
-       vx_ino_t        fsh_ilistino[2];        /* ilist inodes */
-       vx_ino_t        fsh_lctino;             /* link count table inode */
+       __fs32          fsh_version;            /* fileset header version */
+       __fs32          fsh_fsindex;            /* fileset index */
+       __fs32          fsh_time;               /* modification time - sec */
+       __fs32          fsh_utime;              /* modification time - usec */
+       __fs32          fsh_extop;              /* extop flags */
+       __fs32          fsh_ninodes;            /* allocated inodes */
+       __fs32          fsh_nau;                /* number of IAUs */
+       __fs32          fsh_old_ilesize;        /* old size of ilist */
+       __fs32          fsh_dflags;             /* flags */
+       __fs32          fsh_quota;              /* quota limit */
+       __fs32          fsh_maxinode;           /* maximum inode number */
+       __fs32          fsh_iauino;             /* IAU inode */
+       __fs32          fsh_ilistino[2];        /* ilist inodes */
+       __fs32          fsh_lctino;             /* link count table inode */
 
        /*
         * Slightly more fields follow, but they
index 3e2ccade61edb4e4a9a7d27d9229d5ed37175dbc..1f41b25ef38b26bcee2397f555e1ba122bac6d5f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2001 Christoph Hellwig.
+ * Copyright (c) 2016 Krzysztof Blaszkowski
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,9 +43,6 @@
 #include "vxfs_extern.h"
 
 
-struct kmem_cache              *vxfs_inode_cachep;
-
-
 #ifdef DIAGNOSTIC
 /*
  * Dump inode contents (partially).
@@ -68,6 +66,83 @@ vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
 }
 #endif
 
+/**
+ * vxfs_transmod - mode for a VxFS inode
+ * @vip:       VxFS inode
+ *
+ * Description:
+ *  vxfs_transmod returns a Linux mode_t for a given
+ *  VxFS inode structure.
+ */
+static __inline__ umode_t
+vxfs_transmod(struct vxfs_inode_info *vip)
+{
+       umode_t                 ret = vip->vii_mode & ~VXFS_TYPE_MASK;
+
+       if (VXFS_ISFIFO(vip))
+               ret |= S_IFIFO;
+       if (VXFS_ISCHR(vip))
+               ret |= S_IFCHR;
+       if (VXFS_ISDIR(vip))
+               ret |= S_IFDIR;
+       if (VXFS_ISBLK(vip))
+               ret |= S_IFBLK;
+       if (VXFS_ISLNK(vip))
+               ret |= S_IFLNK;
+       if (VXFS_ISREG(vip))
+               ret |= S_IFREG;
+       if (VXFS_ISSOC(vip))
+               ret |= S_IFSOCK;
+
+       return (ret);
+}
+
+static inline void dip2vip_cpy(struct vxfs_sb_info *sbi,
+               struct vxfs_inode_info *vip, struct vxfs_dinode *dip)
+{
+       struct inode *inode = &vip->vfs_inode;
+
+       vip->vii_mode = fs32_to_cpu(sbi, dip->vdi_mode);
+       vip->vii_nlink = fs32_to_cpu(sbi, dip->vdi_nlink);
+       vip->vii_uid = fs32_to_cpu(sbi, dip->vdi_uid);
+       vip->vii_gid = fs32_to_cpu(sbi, dip->vdi_gid);
+       vip->vii_size = fs64_to_cpu(sbi, dip->vdi_size);
+       vip->vii_atime = fs32_to_cpu(sbi, dip->vdi_atime);
+       vip->vii_autime = fs32_to_cpu(sbi, dip->vdi_autime);
+       vip->vii_mtime = fs32_to_cpu(sbi, dip->vdi_mtime);
+       vip->vii_mutime = fs32_to_cpu(sbi, dip->vdi_mutime);
+       vip->vii_ctime = fs32_to_cpu(sbi, dip->vdi_ctime);
+       vip->vii_cutime = fs32_to_cpu(sbi, dip->vdi_cutime);
+       vip->vii_orgtype = dip->vdi_orgtype;
+
+       vip->vii_blocks = fs32_to_cpu(sbi, dip->vdi_blocks);
+       vip->vii_gen = fs32_to_cpu(sbi, dip->vdi_gen);
+
+       if (VXFS_ISDIR(vip))
+               vip->vii_dotdot = fs32_to_cpu(sbi, dip->vdi_dotdot);
+       else if (!VXFS_ISREG(vip) && !VXFS_ISLNK(vip))
+               vip->vii_rdev = fs32_to_cpu(sbi, dip->vdi_rdev);
+
+       /* don't endian swap the fields that differ by orgtype */
+       memcpy(&vip->vii_org, &dip->vdi_org, sizeof(vip->vii_org));
+
+       inode->i_mode = vxfs_transmod(vip);
+       i_uid_write(inode, (uid_t)vip->vii_uid);
+       i_gid_write(inode, (gid_t)vip->vii_gid);
+
+       set_nlink(inode, vip->vii_nlink);
+       inode->i_size = vip->vii_size;
+
+       inode->i_atime.tv_sec = vip->vii_atime;
+       inode->i_ctime.tv_sec = vip->vii_ctime;
+       inode->i_mtime.tv_sec = vip->vii_mtime;
+       inode->i_atime.tv_nsec = 0;
+       inode->i_ctime.tv_nsec = 0;
+       inode->i_mtime.tv_nsec = 0;
+
+       inode->i_blocks = vip->vii_blocks;
+       inode->i_generation = vip->vii_gen;
+}
 
 /**
  * vxfs_blkiget - find inode based on extent #
@@ -85,50 +160,55 @@ vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
  *  buffercache.  This function should not be used outside the
  *  read_super() method, otherwise the data may be incoherent.
  */
-struct vxfs_inode_info *
+struct inode *
 vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
 {
        struct buffer_head              *bp;
+       struct inode                    *inode;
        u_long                          block, offset;
 
+       inode = new_inode(sbp);
+       if (!inode)
+               return NULL;
+       inode->i_ino = get_next_ino();
+
        block = extent + ((ino * VXFS_ISIZE) / sbp->s_blocksize);
        offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE);
        bp = sb_bread(sbp, block);
 
        if (bp && buffer_mapped(bp)) {
-               struct vxfs_inode_info  *vip;
+               struct vxfs_inode_info  *vip = VXFS_INO(inode);
                struct vxfs_dinode      *dip;
 
-               if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
-                       goto fail;
                dip = (struct vxfs_dinode *)(bp->b_data + offset);
-               memcpy(vip, dip, sizeof(*vip));
+               dip2vip_cpy(VXFS_SBI(sbp), vip, dip);
+               vip->vfs_inode.i_mapping->a_ops = &vxfs_aops;
 #ifdef DIAGNOSTIC
                vxfs_dumpi(vip, ino);
 #endif
                brelse(bp);
-               return (vip);
+               return inode;
        }
 
-fail:
        printk(KERN_WARNING "vxfs: unable to read block %ld\n", block);
        brelse(bp);
+       iput(inode);
        return NULL;
 }
 
 /**
  * __vxfs_iget - generic find inode facility
- * @sbp:               VFS superblock
- * @ino:               inode number
  * @ilistp:            inode list
+ * @vip:               VxFS inode to fill in
+ * @ino:               inode number
  *
  * Description:
  *  Search the for inode number @ino in the filesystem
  *  described by @sbp.  Use the specified inode table (@ilistp).
- *  Returns the matching VxFS inode on success, else an error code.
+ *  Returns the matching inode on success, else an error code.
  */
-static struct vxfs_inode_info *
-__vxfs_iget(ino_t ino, struct inode *ilistp)
+static int
+__vxfs_iget(struct inode *ilistp, struct vxfs_inode_info *vip, ino_t ino)
 {
        struct page                     *pp;
        u_long                          offset;
@@ -137,28 +217,22 @@ __vxfs_iget(ino_t ino, struct inode *ilistp)
        pp = vxfs_get_page(ilistp->i_mapping, ino * VXFS_ISIZE / PAGE_SIZE);
 
        if (!IS_ERR(pp)) {
-               struct vxfs_inode_info  *vip;
                struct vxfs_dinode      *dip;
                caddr_t                 kaddr = (char *)page_address(pp);
 
-               if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
-                       goto fail;
                dip = (struct vxfs_dinode *)(kaddr + offset);
-               memcpy(vip, dip, sizeof(*vip));
+               dip2vip_cpy(VXFS_SBI(ilistp->i_sb), vip, dip);
+               vip->vfs_inode.i_mapping->a_ops = &vxfs_aops;
 #ifdef DIAGNOSTIC
                vxfs_dumpi(vip, ino);
 #endif
                vxfs_put_page(pp);
-               return (vip);
+               return 0;
        }
 
-       printk(KERN_WARNING "vxfs: error on page %p\n", pp);
-       return ERR_CAST(pp);
-
-fail:
-       printk(KERN_WARNING "vxfs: unable to read inode %ld\n", (unsigned long)ino);
-       vxfs_put_page(pp);
-       return ERR_PTR(-ENOMEM);
+       printk(KERN_WARNING "vxfs: error on page 0x%p for inode %ld\n",
+               pp, (unsigned long)ino);
+       return PTR_ERR(pp);
 }
 
 /**
@@ -169,116 +243,26 @@ fail:
  * Description:
  *  Find inode @ino in the filesystem described by @sbp using
  *  the structural inode list.
- *  Returns the matching VxFS inode on success, else a NULL pointer.
- */
-struct vxfs_inode_info *
-vxfs_stiget(struct super_block *sbp, ino_t ino)
-{
-       struct vxfs_inode_info *vip;
-
-       vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
-       return IS_ERR(vip) ? NULL : vip;
-}
-
-/**
- * vxfs_transmod - mode for a VxFS inode
- * @vip:       VxFS inode
- *
- * Description:
- *  vxfs_transmod returns a Linux mode_t for a given
- *  VxFS inode structure.
- */
-static __inline__ umode_t
-vxfs_transmod(struct vxfs_inode_info *vip)
-{
-       umode_t                 ret = vip->vii_mode & ~VXFS_TYPE_MASK;
-
-       if (VXFS_ISFIFO(vip))
-               ret |= S_IFIFO;
-       if (VXFS_ISCHR(vip))
-               ret |= S_IFCHR;
-       if (VXFS_ISDIR(vip))
-               ret |= S_IFDIR;
-       if (VXFS_ISBLK(vip))
-               ret |= S_IFBLK;
-       if (VXFS_ISLNK(vip))
-               ret |= S_IFLNK;
-       if (VXFS_ISREG(vip))
-               ret |= S_IFREG;
-       if (VXFS_ISSOC(vip))
-               ret |= S_IFSOCK;
-
-       return (ret);
-}
-
-/**
- * vxfs_iinit- helper to fill inode fields
- * @ip:                VFS inode
- * @vip:       VxFS inode
- *
- * Description:
- *  vxfs_instino is a helper function to fill in all relevant
- *  fields in @ip from @vip.
- */
-static void
-vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip)
-{
-
-       ip->i_mode = vxfs_transmod(vip);
-       i_uid_write(ip, (uid_t)vip->vii_uid);
-       i_gid_write(ip, (gid_t)vip->vii_gid);
-
-       set_nlink(ip, vip->vii_nlink);
-       ip->i_size = vip->vii_size;
-
-       ip->i_atime.tv_sec = vip->vii_atime;
-       ip->i_ctime.tv_sec = vip->vii_ctime;
-       ip->i_mtime.tv_sec = vip->vii_mtime;
-       ip->i_atime.tv_nsec = 0;
-       ip->i_ctime.tv_nsec = 0;
-       ip->i_mtime.tv_nsec = 0;
-
-       ip->i_blocks = vip->vii_blocks;
-       ip->i_generation = vip->vii_gen;
-
-       ip->i_private = vip;
-       
-}
-
-/**
- * vxfs_get_fake_inode - get fake inode structure
- * @sbp:               filesystem superblock
- * @vip:               fspriv inode
- *
- * Description:
- *  vxfs_fake_inode gets a fake inode (not in the inode hash) for a
- *  superblock, vxfs_inode pair.
- *  Returns the filled VFS inode.
+ *  Returns the matching inode on success, else a NULL pointer.
  */
 struct inode *
-vxfs_get_fake_inode(struct super_block *sbp, struct vxfs_inode_info *vip)
+vxfs_stiget(struct super_block *sbp, ino_t ino)
 {
-       struct inode                    *ip = NULL;
-
-       if ((ip = new_inode(sbp))) {
-               ip->i_ino = get_next_ino();
-               vxfs_iinit(ip, vip);
-               ip->i_mapping->a_ops = &vxfs_aops;
+       struct inode *inode;
+       int error;
+
+       inode = new_inode(sbp);
+       if (!inode)
+               return NULL;
+       inode->i_ino = get_next_ino();
+
+       error = __vxfs_iget(VXFS_SBI(sbp)->vsi_stilist, VXFS_INO(inode), ino);
+       if (error) {
+               iput(inode);
+               return NULL;
        }
-       return (ip);
-}
 
-/**
- * vxfs_put_fake_inode - free faked inode
- * *ip:                        VFS inode
- *
- * Description:
- *  vxfs_put_fake_inode frees all data associated with @ip.
- */
-void
-vxfs_put_fake_inode(struct inode *ip)
-{
-       iput(ip);
+       return inode;
 }
 
 /**
@@ -296,6 +280,7 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
        struct vxfs_inode_info          *vip;
        const struct address_space_operations   *aops;
        struct inode *ip;
+       int error;
 
        ip = iget_locked(sbp, ino);
        if (!ip)
@@ -303,14 +288,13 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
        if (!(ip->i_state & I_NEW))
                return ip;
 
-       vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist);
-       if (IS_ERR(vip)) {
+       vip = VXFS_INO(ip);
+       error = __vxfs_iget(VXFS_SBI(sbp)->vsi_ilist, vip, ino);
+       if (error) {
                iget_failed(ip);
-               return ERR_CAST(vip);
+               return ERR_PTR(error);
        }
 
-       vxfs_iinit(ip, vip);
-
        if (VXFS_ISIMMED(vip))
                aops = &vxfs_immed_aops;
        else
@@ -341,12 +325,6 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
        return ip;
 }
 
-static void vxfs_i_callback(struct rcu_head *head)
-{
-       struct inode *inode = container_of(head, struct inode, i_rcu);
-       kmem_cache_free(vxfs_inode_cachep, inode->i_private);
-}
-
 /**
  * vxfs_evict_inode - remove inode from main memory
  * @ip:                inode to discard.
@@ -360,5 +338,4 @@ vxfs_evict_inode(struct inode *ip)
 {
        truncate_inode_pages_final(&ip->i_data);
        clear_inode(ip);
-       call_rcu(&ip->i_rcu, vxfs_i_callback);
 }
index 240aeb11263fac0919f47bde21dd4f009715fba8..f012abed125d61e1c3dd2cbb279c27b2aa7e2130 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2001 Christoph Hellwig.
+ * Copyright (c) 2016 Krzysztof Blaszkowski
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,74 +67,74 @@ enum {
  * Data stored immediately in the inode.
  */
 struct vxfs_immed {
-       u_int8_t        vi_immed[VXFS_NIMMED];
+       __u8                    vi_immed[VXFS_NIMMED];
 };
 
 struct vxfs_ext4 {
-       u_int32_t               ve4_spare;              /* ?? */
-       u_int32_t               ve4_indsize;            /* Indirect extent size */
-       vx_daddr_t              ve4_indir[VXFS_NIADDR]; /* Indirect extents */
+       __fs32                  ve4_spare;              /* ?? */
+       __fs32                  ve4_indsize;            /* Indirect extent size */
+       __fs32                  ve4_indir[VXFS_NIADDR]; /* Indirect extents */
        struct direct {                                 /* Direct extents */
-               vx_daddr_t      extent;                 /* Extent number */
-               int32_t         size;                   /* Size of extent */
+               __fs32          extent;                 /* Extent number */
+               __fs32          size;                   /* Size of extent */
        } ve4_direct[VXFS_NDADDR];
 };
 
 struct vxfs_typed {
-       u_int64_t       vt_hdr;         /* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
-       vx_daddr_t      vt_block;       /* Extent block */
-       int32_t         vt_size;        /* Size in blocks */
+       __fs64          vt_hdr;         /* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
+       __fs32          vt_block;       /* Extent block */
+       __fs32          vt_size;        /* Size in blocks */
 };
 
 struct vxfs_typed_dev4 {
-       u_int64_t       vd4_hdr;        /* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
-       u_int64_t       vd4_block;      /* Extent block */
-       u_int64_t       vd4_size;       /* Size in blocks */
-       int32_t         vd4_dev;        /* Device ID */
-       u_int32_t       __pad1;
+       __fs64          vd4_hdr;        /* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
+       __fs64          vd4_block;      /* Extent block */
+       __fs64          vd4_size;       /* Size in blocks */
+       __fs32          vd4_dev;        /* Device ID */
+       __u8            __pad1;
 };
 
 /*
  * The inode as contained on the physical device.
  */
 struct vxfs_dinode {
-       int32_t         vdi_mode;
-       u_int32_t       vdi_nlink;      /* Link count */
-       u_int32_t       vdi_uid;        /* UID */
-       u_int32_t       vdi_gid;        /* GID */
-       u_int64_t       vdi_size;       /* Inode size in bytes */
-       u_int32_t       vdi_atime;      /* Last time accessed - sec */
-       u_int32_t       vdi_autime;     /* Last time accessed - usec */
-       u_int32_t       vdi_mtime;      /* Last modify time - sec */
-       u_int32_t       vdi_mutime;     /* Last modify time - usec */
-       u_int32_t       vdi_ctime;      /* Create time - sec */
-       u_int32_t       vdi_cutime;     /* Create time - usec */
-       u_int8_t        vdi_aflags;     /* Allocation flags */
-       u_int8_t        vdi_orgtype;    /* Organisation type */
-       u_int16_t       vdi_eopflags;
-       u_int32_t       vdi_eopdata;
+       __fs32          vdi_mode;
+       __fs32          vdi_nlink;      /* Link count */
+       __fs32          vdi_uid;        /* UID */
+       __fs32          vdi_gid;        /* GID */
+       __fs64          vdi_size;       /* Inode size in bytes */
+       __fs32          vdi_atime;      /* Last time accessed - sec */
+       __fs32          vdi_autime;     /* Last time accessed - usec */
+       __fs32          vdi_mtime;      /* Last modify time - sec */
+       __fs32          vdi_mutime;     /* Last modify time - usec */
+       __fs32          vdi_ctime;      /* Create time - sec */
+       __fs32          vdi_cutime;     /* Create time - usec */
+       __u8            vdi_aflags;     /* Allocation flags */
+       __u8            vdi_orgtype;    /* Organisation type */
+       __fs16          vdi_eopflags;
+       __fs32          vdi_eopdata;
        union {
-               u_int32_t               rdev;
-               u_int32_t               dotdot;
+               __fs32                  rdev;
+               __fs32                  dotdot;
                struct {
-                       u_int32_t       reserved;
-                       u_int32_t       fixextsize;
+                       __u32           reserved;
+                       __fs32          fixextsize;
                } i_regular;
                struct {
-                       u_int32_t       matchino;
-                       u_int32_t       fsetindex;
+                       __fs32          matchino;
+                       __fs32          fsetindex;
                } i_vxspec;
-               u_int64_t               align;
+               __u64                   align;
        } vdi_ftarea;
-       u_int32_t       vdi_blocks;     /* How much blocks does inode occupy */
-       u_int32_t       vdi_gen;        /* Inode generation */
-       u_int64_t       vdi_version;    /* Version */
+       __fs32          vdi_blocks;     /* How much blocks does inode occupy */
+       __fs32          vdi_gen;        /* Inode generation */
+       __fs64          vdi_version;    /* Version */
        union {
                struct vxfs_immed       immed;
                struct vxfs_ext4        ext4;
                struct vxfs_typed       typed[VXFS_NTYPED];
        } vdi_org;
-       u_int32_t       vdi_iattrino;
+       __fs32          vdi_iattrino;
 };
 
 #define vdi_rdev       vdi_ftarea.rdev
@@ -149,32 +150,45 @@ struct vxfs_dinode {
 
 /*
  * The inode as represented in the main memory.
- *
- * TBD: This should become a separate structure...
  */
-#define vxfs_inode_info        vxfs_dinode
-
-#define vii_mode       vdi_mode
-#define vii_uid                vdi_uid
-#define vii_gid                vdi_gid
-#define vii_nlink      vdi_nlink
-#define vii_size       vdi_size
-#define vii_atime      vdi_atime
-#define vii_ctime      vdi_ctime
-#define vii_mtime      vdi_mtime
-#define vii_blocks     vdi_blocks
-#define vii_org                vdi_org
-#define vii_orgtype    vdi_orgtype
-#define vii_gen                vdi_gen
-
-#define vii_rdev       vdi_ftarea.rdev
-#define vii_dotdot     vdi_ftarea.dotdot
-#define vii_fixextsize vdi_ftarea.regular.fixextsize
-#define vii_matchino   vdi_ftarea.vxspec.matchino
-#define vii_fsetindex  vdi_ftarea.vxspec.fsetindex
-
-#define vii_immed      vdi_org.immed
-#define vii_ext4       vdi_org.ext4
-#define vii_typed      vdi_org.typed
+struct vxfs_inode_info {
+       struct inode    vfs_inode;
+
+       __u32           vii_mode;
+       __u32           vii_nlink;      /* Link count */
+       __u32           vii_uid;        /* UID */
+       __u32           vii_gid;        /* GID */
+       __u64           vii_size;       /* Inode size in bytes */
+       __u32           vii_atime;      /* Last time accessed - sec */
+       __u32           vii_autime;     /* Last time accessed - usec */
+       __u32           vii_mtime;      /* Last modify time - sec */
+       __u32           vii_mutime;     /* Last modify time - usec */
+       __u32           vii_ctime;      /* Create time - sec */
+       __u32           vii_cutime;     /* Create time - usec */
+       __u8            vii_orgtype;    /* Organisation type */
+       union {
+               __u32                   rdev;
+               __u32                   dotdot;
+       } vii_ftarea;
+       __u32           vii_blocks;     /* How much blocks does inode occupy */
+       __u32           vii_gen;        /* Inode generation */
+       union {
+               struct vxfs_immed       immed;
+               struct vxfs_ext4        ext4;
+               struct vxfs_typed       typed[VXFS_NTYPED];
+       } vii_org;
+};
+
+#define vii_rdev       vii_ftarea.rdev
+#define vii_dotdot     vii_ftarea.dotdot
+
+#define vii_immed      vii_org.immed
+#define vii_ext4       vii_org.ext4
+#define vii_typed      vii_org.typed
+
+static inline struct vxfs_inode_info *VXFS_INO(struct inode *inode)
+{
+       return container_of(inode, struct vxfs_inode_info, vfs_inode);
+}
 
 #endif /* _VXFS_INODE_H_ */
index 6d576b97f2c8ff9abcda09e58ccc55a088e78f2f..ce4785fd81c63cd5f8f8a8fe12b7b5df73dcfc47 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2001 Christoph Hellwig.
+ * Copyright (c) 2016 Krzysztof Blaszkowski
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,33 +62,6 @@ const struct file_operations vxfs_dir_operations = {
        .iterate_shared =       vxfs_readdir,
 };
 
-static inline u_long
-dir_blocks(struct inode *ip)
-{
-       u_long                  bsize = ip->i_sb->s_blocksize;
-       return (ip->i_size + bsize - 1) & ~(bsize - 1);
-}
-
-/*
- * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
- *
- * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
- */
-static inline int
-vxfs_match(int len, const char * const name, struct vxfs_direct *de)
-{
-       if (len != de->d_namelen)
-               return 0;
-       if (!de->d_ino)
-               return 0;
-       return !memcmp(name, de->d_name, len);
-}
-
-static inline struct vxfs_direct *
-vxfs_next_entry(struct vxfs_direct *de)
-{
-       return ((struct vxfs_direct *)((char*)de + de->d_reclen));
-}
 
 /**
  * vxfs_find_entry - find a mathing directory entry for a dentry
@@ -106,50 +80,64 @@ vxfs_next_entry(struct vxfs_direct *de)
 static struct vxfs_direct *
 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
 {
-       u_long                          npages, page, nblocks, pblocks, block;
-       u_long                          bsize = ip->i_sb->s_blocksize;
-       const char                      *name = dp->d_name.name;
-       int                             namelen = dp->d_name.len;
-
-       npages = dir_pages(ip);
-       nblocks = dir_blocks(ip);
-       pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
-       
-       for (page = 0; page < npages; page++) {
-               caddr_t                 kaddr;
-               struct page             *pp;
+       u_long bsize = ip->i_sb->s_blocksize;
+       const char *name = dp->d_name.name;
+       int namelen = dp->d_name.len;
+       loff_t limit = VXFS_DIRROUND(ip->i_size);
+       struct vxfs_direct *de_exit = NULL;
+       loff_t pos = 0;
+       struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
 
-               pp = vxfs_get_page(ip->i_mapping, page);
+       while (pos < limit) {
+               struct page *pp;
+               char *kaddr;
+               int pg_ofs = pos & ~PAGE_MASK;
+
+               pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
                if (IS_ERR(pp))
-                       continue;
-               kaddr = (caddr_t)page_address(pp);
-
-               for (block = 0; block <= nblocks && block <= pblocks; block++) {
-                       caddr_t                 baddr, limit;
-                       struct vxfs_dirblk      *dbp;
-                       struct vxfs_direct      *de;
-
-                       baddr = kaddr + (block * bsize);
-                       limit = baddr + bsize - VXFS_DIRLEN(1);
-                       
-                       dbp = (struct vxfs_dirblk *)baddr;
-                       de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
-
-                       for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
-                               if (!de->d_reclen)
-                                       break;
-                               if (!de->d_ino)
-                                       continue;
-                               if (vxfs_match(namelen, name, de)) {
-                                       *ppp = pp;
-                                       return (de);
-                               }
+                       return NULL;
+               kaddr = (char *)page_address(pp);
+
+               while (pg_ofs < PAGE_SIZE && pos < limit) {
+                       struct vxfs_direct *de;
+
+                       if ((pos & (bsize - 1)) < 4) {
+                               struct vxfs_dirblk *dbp =
+                                       (struct vxfs_dirblk *)
+                                        (kaddr + (pos & ~PAGE_MASK));
+                               int overhead = VXFS_DIRBLKOV(sbi, dbp);
+
+                               pos += overhead;
+                               pg_ofs += overhead;
+                       }
+                       de = (struct vxfs_direct *)(kaddr + pg_ofs);
+
+                       if (!de->d_reclen) {
+                               pos += bsize - 1;
+                               pos &= ~(bsize - 1);
+                               break;
+                       }
+
+                       pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
+                       pos += fs16_to_cpu(sbi, de->d_reclen);
+                       if (!de->d_ino)
+                               continue;
+
+                       if (namelen != fs16_to_cpu(sbi, de->d_namelen))
+                               continue;
+                       if (!memcmp(name, de->d_name, namelen)) {
+                               *ppp = pp;
+                               de_exit = de;
+                               break;
                        }
                }
-               vxfs_put_page(pp);
+               if (!de_exit)
+                       vxfs_put_page(pp);
+               else
+                       break;
        }
 
-       return NULL;
+       return de_exit;
 }
 
 /**
@@ -173,7 +161,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
 
        de = vxfs_find_entry(dip, dp, &pp);
        if (de) {
-               ino = de->d_ino;
+               ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
                kunmap(pp);
                put_page(pp);
        }
@@ -233,74 +221,80 @@ vxfs_readdir(struct file *fp, struct dir_context *ctx)
        struct inode            *ip = file_inode(fp);
        struct super_block      *sbp = ip->i_sb;
        u_long                  bsize = sbp->s_blocksize;
-       u_long                  page, npages, block, pblocks, nblocks, offset;
-       loff_t                  pos;
+       loff_t                  pos, limit;
+       struct vxfs_sb_info     *sbi = VXFS_SBI(sbp);
 
        if (ctx->pos == 0) {
                if (!dir_emit_dot(fp, ctx))
-                       return 0;
-               ctx->pos = 1;
+                       goto out;
+               ctx->pos++;
        }
        if (ctx->pos == 1) {
                if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
-                       return 0;
-               ctx->pos = 2;
+                       goto out;
+               ctx->pos++;
        }
-       pos = ctx->pos - 2;
-       
-       if (pos > VXFS_DIRROUND(ip->i_size))
-               return 0;
 
-       npages = dir_pages(ip);
-       nblocks = dir_blocks(ip);
-       pblocks = VXFS_BLOCK_PER_PAGE(sbp);
+       limit = VXFS_DIRROUND(ip->i_size);
+       if (ctx->pos > limit)
+               goto out;
 
-       page = pos >> PAGE_SHIFT;
-       offset = pos & ~PAGE_MASK;
-       block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
+       pos = ctx->pos & ~3L;
 
-       for (; page < npages; page++, block = 0) {
-               char                    *kaddr;
-               struct page             *pp;
+       while (pos < limit) {
+               struct page *pp;
+               char *kaddr;
+               int pg_ofs = pos & ~PAGE_MASK;
+               int rc = 0;
 
-               pp = vxfs_get_page(ip->i_mapping, page);
+               pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
                if (IS_ERR(pp))
-                       continue;
+                       return -ENOMEM;
+
                kaddr = (char *)page_address(pp);
 
-               for (; block <= nblocks && block <= pblocks; block++) {
-                       char                    *baddr, *limit;
-                       struct vxfs_dirblk      *dbp;
-                       struct vxfs_direct      *de;
+               while (pg_ofs < PAGE_SIZE && pos < limit) {
+                       struct vxfs_direct *de;
 
-                       baddr = kaddr + (block * bsize);
-                       limit = baddr + bsize - VXFS_DIRLEN(1);
-       
-                       dbp = (struct vxfs_dirblk *)baddr;
-                       de = (struct vxfs_direct *)
-                               (offset ?
-                                (kaddr + offset) :
-                                (baddr + VXFS_DIRBLKOV(dbp)));
-
-                       for (; (char *)de <= limit; de = vxfs_next_entry(de)) {
-                               if (!de->d_reclen)
-                                       break;
-                               if (!de->d_ino)
-                                       continue;
-
-                               offset = (char *)de - kaddr;
-                               ctx->pos = ((page << PAGE_SHIFT) | offset) + 2;
-                               if (!dir_emit(ctx, de->d_name, de->d_namelen,
-                                       de->d_ino, DT_UNKNOWN)) {
-                                       vxfs_put_page(pp);
-                                       return 0;
-                               }
+                       if ((pos & (bsize - 1)) < 4) {
+                               struct vxfs_dirblk *dbp =
+                                       (struct vxfs_dirblk *)
+                                        (kaddr + (pos & ~PAGE_MASK));
+                               int overhead = VXFS_DIRBLKOV(sbi, dbp);
+
+                               pos += overhead;
+                               pg_ofs += overhead;
+                       }
+                       de = (struct vxfs_direct *)(kaddr + pg_ofs);
+
+                       if (!de->d_reclen) {
+                               pos += bsize - 1;
+                               pos &= ~(bsize - 1);
+                               break;
+                       }
+
+                       pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
+                       pos += fs16_to_cpu(sbi, de->d_reclen);
+                       if (!de->d_ino)
+                               continue;
+
+                       rc = dir_emit(ctx, de->d_name,
+                                       fs16_to_cpu(sbi, de->d_namelen),
+                                       fs32_to_cpu(sbi, de->d_ino),
+                                       DT_UNKNOWN);
+                       if (!rc) {
+                               /* the dir entry was not read, fix pos. */
+                               pos -= fs16_to_cpu(sbi, de->d_reclen);
+                               break;
                        }
-                       offset = 0;
                }
                vxfs_put_page(pp);
-               offset = 0;
+               if (!rc)
+                       break;
        }
-       ctx->pos = ((page << PAGE_SHIFT) | offset) + 2;
+
+       ctx->pos = pos | 2;
+
+out:
        return 0;
 }
index 0495008479034b2f0828609272ee2716341aed9b..813da66851510b92786a2b201bf627a58bdaa524 100644 (file)
@@ -43,14 +43,14 @@ static inline void
 vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
 {
        BUG_ON(infp->vsi_fshino);
-       infp->vsi_fshino = fshp->olt_fsino[0];
+       infp->vsi_fshino = fs32_to_cpu(infp, fshp->olt_fsino[0]);
 }
 
 static inline void
 vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
 {
        BUG_ON(infp->vsi_iext);
-       infp->vsi_iext = ilistp->olt_iext[0]; 
+       infp->vsi_iext = fs32_to_cpu(infp, ilistp->olt_iext[0]);
 }
 
 static inline u_long
@@ -81,13 +81,12 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
        struct vxfs_olt         *op;
        char                    *oaddr, *eaddr;
 
-
        bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
        if (!bp || !bp->b_data)
                goto fail;
 
        op = (struct vxfs_olt *)bp->b_data;
-       if (op->olt_magic != VXFS_OLT_MAGIC) {
+       if (fs32_to_cpu(infp, op->olt_magic) != VXFS_OLT_MAGIC) {
                printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
                goto fail;
        }
@@ -102,14 +101,14 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
                goto fail;
        }
 
-       oaddr = bp->b_data + op->olt_size;
+       oaddr = bp->b_data + fs32_to_cpu(infp, op->olt_size);
        eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
 
        while (oaddr < eaddr) {
                struct vxfs_oltcommon   *ocp =
                        (struct vxfs_oltcommon *)oaddr;
                
-               switch (ocp->olt_type) {
+               switch (fs32_to_cpu(infp, ocp->olt_type)) {
                case VXFS_OLT_FSHEAD:
                        vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
                        break;
@@ -118,11 +117,11 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
                        break;
                }
 
-               oaddr += ocp->olt_size;
+               oaddr += fs32_to_cpu(infp, ocp->olt_size);
        }
 
        brelse(bp);
-       return 0;
+       return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL;
 
 fail:
        brelse(bp);
index b7b3af50261583f3c0f86b7fdc4328a0f833bd11..0c0b0c9fa5579b4b54ccb67c5bf3b214916ac767 100644 (file)
@@ -63,83 +63,83 @@ enum {
  * the initial inode list, the fileset header or the device configuration.
  */
 struct vxfs_olt {
-       u_int32_t       olt_magic;      /* magic number                 */
-       u_int32_t       olt_size;       /* size of this entry           */
-       u_int32_t       olt_checksum;   /* checksum of extent           */
-       u_int32_t       __unused1;      /* ???                          */
-       u_int32_t       olt_mtime;      /* time of last mod. (sec)      */
-       u_int32_t       olt_mutime;     /* time of last mod. (usec)     */
-       u_int32_t       olt_totfree;    /* free space in OLT extent     */
-       vx_daddr_t      olt_extents[2]; /* addr of this extent, replica */
-       u_int32_t       olt_esize;      /* size of this extent          */
-       vx_daddr_t      olt_next[2];    /* addr of next extent, replica */
-       u_int32_t       olt_nsize;      /* size of next extent          */
-       u_int32_t       __unused2;      /* align to 8 byte boundary     */
+       __fs32          olt_magic;      /* magic number                 */
+       __fs32          olt_size;       /* size of this entry           */
+       __fs32          olt_checksum;   /* checksum of extent           */
+       __u32           __unused1;      /* ???                          */
+       __fs32          olt_mtime;      /* time of last mod. (sec)      */
+       __fs32          olt_mutime;     /* time of last mod. (usec)     */
+       __fs32          olt_totfree;    /* free space in OLT extent     */
+       __fs32          olt_extents[2]; /* addr of this extent, replica */
+       __fs32          olt_esize;      /* size of this extent          */
+       __fs32          olt_next[2];    /* addr of next extent, replica */
+       __fs32          olt_nsize;      /* size of next extent          */
+       __u32           __unused2;      /* align to 8 byte boundary     */
 };
 
 /*
  * VxFS common OLT entry (on disk).
  */
 struct vxfs_oltcommon {
-       u_int32_t       olt_type;       /* type of this record          */
-       u_int32_t       olt_size;       /* size of this record          */
+       __fs32          olt_type;       /* type of this record          */
+       __fs32          olt_size;       /* size of this record          */
 };
 
 /*
  * VxFS free OLT entry (on disk).
  */
 struct vxfs_oltfree {
-       u_int32_t       olt_type;       /* type of this record          */
-       u_int32_t       olt_fsize;      /* size of this free record     */
+       __fs32          olt_type;       /* type of this record          */
+       __fs32          olt_fsize;      /* size of this free record     */
 };
 
 /*
  * VxFS initial-inode list (on disk).
  */
 struct vxfs_oltilist {
-       u_int32_t       olt_type;       /* type of this record          */
-       u_int32_t       olt_size;       /* size of this record          */
-       vx_ino_t        olt_iext[2];    /* initial inode list, replica  */
+       __fs32  olt_type;       /* type of this record          */
+       __fs32  olt_size;       /* size of this record          */
+       __fs32          olt_iext[2];    /* initial inode list, replica  */
 };
 
 /*
  * Current Usage Table 
  */
 struct vxfs_oltcut {
-       u_int32_t       olt_type;       /* type of this record          */
-       u_int32_t       olt_size;       /* size of this record          */
-       vx_ino_t        olt_cutino;     /* inode of current usage table */
-       u_int32_t       __pad;          /* unused, 8 byte align         */
+       __fs32          olt_type;       /* type of this record          */
+       __fs32          olt_size;       /* size of this record          */
+       __fs32          olt_cutino;     /* inode of current usage table */
+       __u8            __pad;          /* unused, 8 byte align         */
 };
 
 /*
  * Inodes containing Superblock, Intent log and OLTs 
  */
 struct vxfs_oltsb {
-       u_int32_t       olt_type;       /* type of this record          */
-       u_int32_t       olt_size;       /* size of this record          */
-       vx_ino_t        olt_sbino;      /* inode of superblock file     */
-       u_int32_t       __unused1;      /* ???                          */
-       vx_ino_t        olt_logino[2];  /* inode of log file,replica    */
-       vx_ino_t        olt_oltino[2];  /* inode of OLT, replica        */
+       __fs32          olt_type;       /* type of this record          */
+       __fs32          olt_size;       /* size of this record          */
+       __fs32          olt_sbino;      /* inode of superblock file     */
+       __u32           __unused1;      /* ???                          */
+       __fs32          olt_logino[2];  /* inode of log file,replica    */
+       __fs32          olt_oltino[2];  /* inode of OLT, replica        */
 };
 
 /*
  * Inode containing device configuration + it's replica 
  */
 struct vxfs_oltdev {
-       u_int32_t       olt_type;       /* type of this record          */
-       u_int32_t       olt_size;       /* size of this record          */
-       vx_ino_t        olt_devino[2];  /* inode of device config files */
+       __fs32          olt_type;       /* type of this record          */
+       __fs32          olt_size;       /* size of this record          */
+       __fs32          olt_devino[2];  /* inode of device config files */
 };
 
 /*
  * Fileset header 
  */
 struct vxfs_oltfshead {
-       u_int32_t       olt_type;       /* type number                  */
-       u_int32_t       olt_size;       /* size of this record          */
-       vx_ino_t        olt_fsino[2];   /* inodes of fileset header     */
+       __fs32          olt_type;       /* type number                  */
+       __fs32          olt_size;       /* size of this record          */
+       __fs32          olt_fsino[2];   /* inodes of fileset header     */
 };
 
 #endif /* _VXFS_OLT_H_ */
index 7ca8c75d50d3fdc5f9079599465e04f99058d45d..455ce5b77e9bf9eea279dccdf4a31a2a2154cd74 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2001 Christoph Hellwig.
+ * Copyright (c) 2016 Krzysztof Blaszkowski
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "vxfs_inode.h"
 
 
-MODULE_AUTHOR("Christoph Hellwig");
+MODULE_AUTHOR("Christoph Hellwig, Krzysztof Blaszkowski");
 MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver");
 MODULE_LICENSE("Dual BSD/GPL");
 
-
-
-static void            vxfs_put_super(struct super_block *);
-static int             vxfs_statfs(struct dentry *, struct kstatfs *);
-static int             vxfs_remount(struct super_block *, int *, char *);
-
-static const struct super_operations vxfs_super_ops = {
-       .evict_inode =          vxfs_evict_inode,
-       .put_super =            vxfs_put_super,
-       .statfs =               vxfs_statfs,
-       .remount_fs =           vxfs_remount,
-};
+static struct kmem_cache *vxfs_inode_cachep;
 
 /**
  * vxfs_put_super - free superblock resources
@@ -79,9 +69,9 @@ vxfs_put_super(struct super_block *sbp)
 {
        struct vxfs_sb_info     *infp = VXFS_SBI(sbp);
 
-       vxfs_put_fake_inode(infp->vsi_fship);
-       vxfs_put_fake_inode(infp->vsi_ilist);
-       vxfs_put_fake_inode(infp->vsi_stilist);
+       iput(infp->vsi_fship);
+       iput(infp->vsi_ilist);
+       iput(infp->vsi_stilist);
 
        brelse(infp->vsi_bp);
        kfree(infp);
@@ -109,14 +99,15 @@ static int
 vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
 {
        struct vxfs_sb_info             *infp = VXFS_SBI(dentry->d_sb);
+       struct vxfs_sb *raw_sb = infp->vsi_raw;
 
        bufp->f_type = VXFS_SUPER_MAGIC;
        bufp->f_bsize = dentry->d_sb->s_blocksize;
-       bufp->f_blocks = infp->vsi_raw->vs_dsize;
-       bufp->f_bfree = infp->vsi_raw->vs_free;
+       bufp->f_blocks = fs32_to_cpu(infp, raw_sb->vs_dsize);
+       bufp->f_bfree = fs32_to_cpu(infp, raw_sb->vs_free);
        bufp->f_bavail = 0;
        bufp->f_files = 0;
-       bufp->f_ffree = infp->vsi_raw->vs_ifree;
+       bufp->f_ffree = fs32_to_cpu(infp, raw_sb->vs_ifree);
        bufp->f_namelen = VXFS_NAMELEN;
 
        return 0;
@@ -129,6 +120,81 @@ static int vxfs_remount(struct super_block *sb, int *flags, char *data)
        return 0;
 }
 
+static struct inode *vxfs_alloc_inode(struct super_block *sb)
+{
+       struct vxfs_inode_info *vi;
+
+       vi = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL);
+       if (!vi)
+               return NULL;
+       inode_init_once(&vi->vfs_inode);
+       return &vi->vfs_inode;
+}
+
+static void vxfs_i_callback(struct rcu_head *head)
+{
+       struct inode *inode = container_of(head, struct inode, i_rcu);
+
+       kmem_cache_free(vxfs_inode_cachep, VXFS_INO(inode));
+}
+
+static void vxfs_destroy_inode(struct inode *inode)
+{
+       call_rcu(&inode->i_rcu, vxfs_i_callback);
+}
+
+static const struct super_operations vxfs_super_ops = {
+       .alloc_inode            = vxfs_alloc_inode,
+       .destroy_inode          = vxfs_destroy_inode,
+       .evict_inode            = vxfs_evict_inode,
+       .put_super              = vxfs_put_super,
+       .statfs                 = vxfs_statfs,
+       .remount_fs             = vxfs_remount,
+};
+
+static int vxfs_try_sb_magic(struct super_block *sbp, int silent,
+               unsigned blk, __fs32 magic)
+{
+       struct buffer_head *bp;
+       struct vxfs_sb *rsbp;
+       struct vxfs_sb_info *infp = VXFS_SBI(sbp);
+       int rc = -ENOMEM;
+
+       bp = sb_bread(sbp, blk);
+       do {
+               if (!bp || !buffer_mapped(bp)) {
+                       if (!silent) {
+                               printk(KERN_WARNING
+                                       "vxfs: unable to read disk superblock at %u\n",
+                                       blk);
+                       }
+                       break;
+               }
+
+               rc = -EINVAL;
+               rsbp = (struct vxfs_sb *)bp->b_data;
+               if (rsbp->vs_magic != magic) {
+                       if (!silent)
+                               printk(KERN_NOTICE
+                                       "vxfs: WRONG superblock magic %08x at %u\n",
+                                       rsbp->vs_magic, blk);
+                       break;
+               }
+
+               rc = 0;
+               infp->vsi_raw = rsbp;
+               infp->vsi_bp = bp;
+       } while (0);
+
+       if (rc) {
+               infp->vsi_raw = NULL;
+               infp->vsi_bp = NULL;
+               brelse(bp);
+       }
+
+       return rc;
+}
+
 /**
  * vxfs_read_super - read superblock into memory and initialize filesystem
  * @sbp:               VFS superblock (to fill)
@@ -149,10 +215,10 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 {
        struct vxfs_sb_info     *infp;
        struct vxfs_sb          *rsbp;
-       struct buffer_head      *bp = NULL;
        u_long                  bsize;
        struct inode *root;
        int ret = -EINVAL;
+       u32 j;
 
        sbp->s_flags |= MS_RDONLY;
 
@@ -168,42 +234,43 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
                goto out;
        }
 
-       bp = sb_bread(sbp, 1);
-       if (!bp || !buffer_mapped(bp)) {
-               if (!silent) {
-                       printk(KERN_WARNING
-                               "vxfs: unable to read disk superblock\n");
-               }
-               goto out;
-       }
+       sbp->s_op = &vxfs_super_ops;
+       sbp->s_fs_info = infp;
 
-       rsbp = (struct vxfs_sb *)bp->b_data;
-       if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
+       if (!vxfs_try_sb_magic(sbp, silent, 1,
+                       (__force __fs32)cpu_to_le32(VXFS_SUPER_MAGIC))) {
+               /* Unixware, x86 */
+               infp->byte_order = VXFS_BO_LE;
+       } else if (!vxfs_try_sb_magic(sbp, silent, 8,
+                       (__force __fs32)cpu_to_be32(VXFS_SUPER_MAGIC))) {
+               /* HP-UX, parisc */
+               infp->byte_order = VXFS_BO_BE;
+       } else {
                if (!silent)
-                       printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
+                       printk(KERN_NOTICE "vxfs: can't find superblock.\n");
                goto out;
        }
 
-       if ((rsbp->vs_version < 2 || rsbp->vs_version > 4) && !silent) {
-               printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n",
-                      rsbp->vs_version);
+       rsbp = infp->vsi_raw;
+       j = fs32_to_cpu(infp, rsbp->vs_version);
+       if ((j < 2 || j > 4) && !silent) {
+               printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", j);
                goto out;
        }
 
 #ifdef DIAGNOSTIC
-       printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", rsbp->vs_version);
-       printk(KERN_DEBUG "vxfs: blocksize: %d\n", rsbp->vs_bsize);
+       printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", j);
+       printk(KERN_DEBUG "vxfs: blocksize: %d\n",
+               fs32_to_cpu(infp, rsbp->vs_bsize));
 #endif
 
-       sbp->s_magic = rsbp->vs_magic;
-       sbp->s_fs_info = infp;
+       sbp->s_magic = fs32_to_cpu(infp, rsbp->vs_magic);
 
-       infp->vsi_raw = rsbp;
-       infp->vsi_bp = bp;
-       infp->vsi_oltext = rsbp->vs_oltext[0];
-       infp->vsi_oltsize = rsbp->vs_oltsize;
+       infp->vsi_oltext = fs32_to_cpu(infp, rsbp->vs_oltext[0]);
+       infp->vsi_oltsize = fs32_to_cpu(infp, rsbp->vs_oltsize);
 
-       if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) {
+       j = fs32_to_cpu(infp, rsbp->vs_bsize);
+       if (!sb_set_blocksize(sbp, j)) {
                printk(KERN_WARNING "vxfs: unable to set final block size\n");
                goto out;
        }
@@ -218,7 +285,6 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
                goto out;
        }
 
-       sbp->s_op = &vxfs_super_ops;
        root = vxfs_iget(sbp, VXFS_ROOT_INO);
        if (IS_ERR(root)) {
                ret = PTR_ERR(root);
@@ -233,11 +299,11 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
        return 0;
        
 out_free_ilist:
-       vxfs_put_fake_inode(infp->vsi_fship);
-       vxfs_put_fake_inode(infp->vsi_ilist);
-       vxfs_put_fake_inode(infp->vsi_stilist);
+       iput(infp->vsi_fship);
+       iput(infp->vsi_ilist);
+       iput(infp->vsi_stilist);
 out:
-       brelse(bp);
+       brelse(infp->vsi_bp);
        kfree(infp);
        return ret;
 }
index 6f9c9f6f515792acc6fd80f51c568d66a1b05389..56c8fda436c0aa0d6a0883415baa4271f1265e84 100644 (file)
@@ -1807,8 +1807,8 @@ static struct wb_writeback_work *get_next_work_item(struct bdi_writeback *wb)
  */
 static unsigned long get_nr_dirty_pages(void)
 {
-       return global_page_state(NR_FILE_DIRTY) +
-               global_page_state(NR_UNSTABLE_NFS) +
+       return global_node_page_state(NR_FILE_DIRTY) +
+               global_node_page_state(NR_UNSTABLE_NFS) +
                get_nr_dirty_inodes();
 }
 
index 7d637e2335fda427a891cdb000b02985f9967b62..15a3d042247e91f9e44880536bd5f774b7f19969 100644 (file)
@@ -99,7 +99,6 @@ static int fscache_histogram_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations fscache_histogram_fops = {
-       .owner          = THIS_MODULE,
        .open           = fscache_histogram_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 6b028b7c42509b6cdf319ea3513679c33cf57fc4..5d5ddaa84b215fd79956db4dac8292c374ee72ed 100644 (file)
@@ -404,7 +404,6 @@ static int fscache_objlist_release(struct inode *inode, struct file *file)
 }
 
 const struct file_operations fscache_objlist_fops = {
-       .owner          = THIS_MODULE,
        .open           = fscache_objlist_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 7cfa0aacdf6d53c41768150f80f27bc2b7cb18c0..7ac6e839b065b5327a0590732b542fda2ed3ab0d 100644 (file)
@@ -295,7 +295,6 @@ static int fscache_stats_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations fscache_stats_fops = {
-       .owner          = THIS_MODULE,
        .open           = fscache_stats_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index cbece1221417bb0ad5c60a143c724e6b3a5b06e8..a94d2ed81ab4af4bf7cc8316d5f7517a9902c3a2 100644 (file)
@@ -99,19 +99,6 @@ void fuse_request_free(struct fuse_req *req)
        kmem_cache_free(fuse_req_cachep, req);
 }
 
-static void block_sigs(sigset_t *oldset)
-{
-       sigset_t mask;
-
-       siginitsetinv(&mask, sigmask(SIGKILL));
-       sigprocmask(SIG_BLOCK, &mask, oldset);
-}
-
-static void restore_sigs(sigset_t *oldset)
-{
-       sigprocmask(SIG_SETMASK, oldset, NULL);
-}
-
 void __fuse_get_request(struct fuse_req *req)
 {
        atomic_inc(&req->count);
@@ -151,15 +138,9 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
        atomic_inc(&fc->num_waiting);
 
        if (fuse_block_alloc(fc, for_background)) {
-               sigset_t oldset;
-               int intr;
-
-               block_sigs(&oldset);
-               intr = wait_event_interruptible_exclusive(fc->blocked_waitq,
-                               !fuse_block_alloc(fc, for_background));
-               restore_sigs(&oldset);
                err = -EINTR;
-               if (intr)
+               if (wait_event_killable_exclusive(fc->blocked_waitq,
+                               !fuse_block_alloc(fc, for_background)))
                        goto out;
        }
        /* Matches smp_wmb() in fuse_set_initialized() */
@@ -446,14 +427,9 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
        }
 
        if (!test_bit(FR_FORCE, &req->flags)) {
-               sigset_t oldset;
-
                /* Only fatal signals may interrupt this */
-               block_sigs(&oldset);
-               err = wait_event_interruptible(req->waitq,
+               err = wait_event_killable(req->waitq,
                                        test_bit(FR_FINISHED, &req->flags));
-               restore_sigs(&oldset);
-
                if (!err)
                        return;
 
@@ -1525,7 +1501,6 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
                goto err;
        fuse_copy_finish(cs);
        buf[outarg.namelen] = 0;
-       name.hash = full_name_hash(name.name, name.len);
 
        down_read(&fc->killsb);
        err = -ENOENT;
@@ -1576,7 +1551,6 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
                goto err;
        fuse_copy_finish(cs);
        buf[outarg.namelen] = 0;
-       name.hash = full_name_hash(name.name, name.len);
 
        down_read(&fc->killsb);
        err = -ENOENT;
index cca7b048c07b26e4919769fed461b46771005a19..5f1627725791d9b51091766c5128b80190389c0d 100644 (file)
@@ -955,6 +955,7 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
        if (!dir)
                goto unlock;
 
+       name->hash = full_name_hash(dir, name->name, name->len);
        entry = d_lookup(dir, name);
        dput(dir);
        if (!entry)
@@ -1204,7 +1205,7 @@ static int fuse_direntplus_link(struct file *file,
 
        fc = get_fuse_conn(dir);
 
-       name.hash = full_name_hash(name.name, name.len);
+       name.hash = full_name_hash(parent, name.name, name.len);
        dentry = d_lookup(parent, &name);
        if (!dentry) {
 retry:
index 9154f8679024f25b33a7dac1607877da2ce3fab9..f394aff59c363a34c43eea0eec32293e21570986 100644 (file)
@@ -417,6 +417,10 @@ static int fuse_flush(struct file *file, fl_owner_t id)
        fuse_sync_writes(inode);
        inode_unlock(inode);
 
+       err = filemap_check_errors(file->f_mapping);
+       if (err)
+               return err;
+
        req = fuse_get_req_nofail_nopages(fc, file);
        memset(&inarg, 0, sizeof(inarg));
        inarg.fh = ff->fh;
@@ -462,6 +466,16 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
                goto out;
 
        fuse_sync_writes(inode);
+
+       /*
+        * Due to implementation of fuse writeback
+        * filemap_write_and_wait_range() does not catch errors.
+        * We have to do this directly after fuse_sync_writes()
+        */
+       err = filemap_check_errors(file->f_mapping);
+       if (err)
+               goto out;
+
        err = sync_inode_metadata(inode, 1);
        if (err)
                goto out;
@@ -562,7 +576,6 @@ static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io)
  */
 static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
 {
-       bool is_sync = is_sync_kiocb(io->iocb);
        int left;
 
        spin_lock(&io->lock);
@@ -572,11 +585,11 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
                io->bytes = pos;
 
        left = --io->reqs;
-       if (!left && is_sync)
+       if (!left && io->blocking)
                complete(io->done);
        spin_unlock(&io->lock);
 
-       if (!left && !is_sync) {
+       if (!left && !io->blocking) {
                ssize_t res = fuse_get_res_by_io(io);
 
                if (res >= 0) {
@@ -1452,7 +1465,7 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
        list_del(&req->writepages_entry);
        for (i = 0; i < req->num_pages; i++) {
                dec_wb_stat(&bdi->wb, WB_WRITEBACK);
-               dec_zone_page_state(req->pages[i], NR_WRITEBACK_TEMP);
+               dec_node_page_state(req->pages[i], NR_WRITEBACK_TEMP);
                wb_writeout_inc(&bdi->wb);
        }
        wake_up(&fi->page_waitq);
@@ -1642,7 +1655,7 @@ static int fuse_writepage_locked(struct page *page)
        req->inode = inode;
 
        inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
-       inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
+       inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP);
 
        spin_lock(&fc->lock);
        list_add(&req->writepages_entry, &fi->writepages);
@@ -1756,7 +1769,7 @@ static bool fuse_writepage_in_flight(struct fuse_req *new_req,
                spin_unlock(&fc->lock);
 
                dec_wb_stat(&bdi->wb, WB_WRITEBACK);
-               dec_zone_page_state(page, NR_WRITEBACK_TEMP);
+               dec_node_page_state(page, NR_WRITEBACK_TEMP);
                wb_writeout_inc(&bdi->wb);
                fuse_writepage_free(fc, new_req);
                fuse_request_free(new_req);
@@ -1855,7 +1868,7 @@ static int fuse_writepages_fill(struct page *page,
        req->page_descs[req->num_pages].length = PAGE_SIZE;
 
        inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
-       inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
+       inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP);
 
        err = 0;
        if (is_writeback && fuse_writepage_in_flight(req, page)) {
@@ -2850,7 +2863,6 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        size_t count = iov_iter_count(iter);
        loff_t offset = iocb->ki_pos;
        struct fuse_io_priv *io;
-       bool is_sync = is_sync_kiocb(iocb);
 
        pos = offset;
        inode = file->f_mapping->host;
@@ -2885,17 +2897,16 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
         */
        io->async = async_dio;
        io->iocb = iocb;
+       io->blocking = is_sync_kiocb(iocb);
 
        /*
-        * We cannot asynchronously extend the size of a file. We have no method
-        * to wait on real async I/O requests, so we must submit this request
-        * synchronously.
+        * We cannot asynchronously extend the size of a file.
+        * In such case the aio will behave exactly like sync io.
         */
-       if (!is_sync && (offset + count > i_size) &&
-           iov_iter_rw(iter) == WRITE)
-               io->async = false;
+       if ((offset + count > i_size) && iov_iter_rw(iter) == WRITE)
+               io->blocking = true;
 
-       if (io->async && is_sync) {
+       if (io->async && io->blocking) {
                /*
                 * Additional reference to keep io around after
                 * calling fuse_aio_complete()
@@ -2915,7 +2926,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
                fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
 
                /* we have a non-extending, async request, so return */
-               if (!is_sync)
+               if (!io->blocking)
                        return -EIOCBQUEUED;
 
                wait_for_completion(&wait);
index 929c383432b034f3f695e0cc83e55e9b48c35898..5db5d24f91a5929dd7c291c833b7049778336da3 100644 (file)
@@ -259,6 +259,7 @@ struct fuse_io_priv {
        struct kiocb *iocb;
        struct file *file;
        struct completion *done;
+       bool blocking;
 };
 
 #define FUSE_IO_PRIV_SYNC(f) \
index 9961d8432ce335ba445df4a36824cd12912f1419..9b7cb37b4ba8362f495bbae3af46ea05e2b86073 100644 (file)
@@ -942,7 +942,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
                FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
                FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
-               FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
+               FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
                FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
                FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
                FUSE_PARALLEL_DIROPS;
index 8eed66af5b828d1f9bf1d791685f51d8a0aa0496..02a3845363f7d93601cb3b53b912e7df8f8179d5 100644 (file)
@@ -128,7 +128,7 @@ static ssize_t hfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
-       struct inode *inode = file_inode(file)->i_mapping->host;
+       struct inode *inode = mapping->host;
        size_t count = iov_iter_count(iter);
        ssize_t ret;
 
index 85b610c3909fbad5b5da73343f29cd9b2b84b96d..ec9f164c35a585478b97864d3dad94c3596ad9bc 100644 (file)
@@ -59,7 +59,7 @@ int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
        if (len > HFS_NAMELEN)
                len = HFS_NAMELEN;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (; len; len--)
                hash = partial_name_hash(caseorder[*name++], hash);
        this->hash = end_name_hash(hash);
index ef9fefe364a68781758b50a211a00a7635d0d6bc..19462d773fe2443c3c483249630c646dc1f3c3f9 100644 (file)
@@ -126,7 +126,7 @@ static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
-       struct inode *inode = file_inode(file)->i_mapping->host;
+       struct inode *inode = mapping->host;
        size_t count = iov_iter_count(iter);
        ssize_t ret;
 
index e8ef121a4d8b5be7ca35bfe18aa4de4b925dfb59..c13c8a240be307a1e1f6151a543b5c485e4c483c 100644 (file)
@@ -346,7 +346,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
 
        casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        astr = str->name;
        len = str->len;
        while (len > 0) {
index fa27980f2229216c47c2378ce7431f18bd5a793e..60e6d334d79abbf2323dcd5e55316ffb8d9f5332 100644 (file)
@@ -26,7 +26,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
                /*return -ENOENT;*/
        x:
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (i = 0; i < l; i++)
                hash = partial_name_hash(hpfs_upcase(hpfs_sb(dentry->d_sb)->sb_cp_table,qstr->name[i]), hash);
        qstr->hash = end_name_hash(hash);
index 116a333e9c773c10b76a8030c268284869c2533e..0f56deb24ce6547c1aaa13e6a731779c09047077 100644 (file)
@@ -590,6 +590,7 @@ static long ioctl_file_dedupe_range(struct file *file, void __user *arg)
                goto out;
        }
 
+       same->dest_count = count;
        ret = vfs_dedupe_file_range(file, same);
        if (ret)
                goto out;
index 2ce5b75ee9a5b7d3bc14d00d47464632e8d285a7..44af14b2e91663b76427afee24c2788d2b2aeb93 100644 (file)
@@ -361,7 +361,6 @@ static int zisofs_readpage(struct file *file, struct page *page)
 
 const struct address_space_operations zisofs_aops = {
        .readpage = zisofs_readpage,
-       /* No sync_page operation supported? */
        /* No bmap operation supported */
 };
 
index 131dedc920d8db28b00a19b09dd33ca438a7d81d..761fade7680f8c92ffbc31f218578ad1fa04479d 100644 (file)
@@ -174,7 +174,7 @@ struct iso9660_options{
  * Compute the hash for the isofs name corresponding to the dentry.
  */
 static int
-isofs_hashi_common(struct qstr *qstr, int ms)
+isofs_hashi_common(const struct dentry *dentry, struct qstr *qstr, int ms)
 {
        const char *name;
        int len;
@@ -188,7 +188,7 @@ isofs_hashi_common(struct qstr *qstr, int ms)
                        len--;
        }
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        while (len--) {
                c = tolower(*name++);
                hash = partial_name_hash(c, hash);
@@ -231,7 +231,7 @@ static int isofs_dentry_cmp_common(
 static int
 isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
 {
-       return isofs_hashi_common(qstr, 0);
+       return isofs_hashi_common(dentry, qstr, 0);
 }
 
 static int
@@ -246,7 +246,7 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
  * Compute the hash for the isofs name corresponding to the dentry.
  */
 static int
-isofs_hash_common(struct qstr *qstr, int ms)
+isofs_hash_common(const struct dentry *dentry, struct qstr *qstr, int ms)
 {
        const char *name;
        int len;
@@ -258,7 +258,7 @@ isofs_hash_common(struct qstr *qstr, int ms)
                        len--;
        }
 
-       qstr->hash = full_name_hash(name, len);
+       qstr->hash = full_name_hash(dentry, name, len);
 
        return 0;
 }
@@ -266,13 +266,13 @@ isofs_hash_common(struct qstr *qstr, int ms)
 static int
 isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
 {
-       return isofs_hash_common(qstr, 1);
+       return isofs_hash_common(dentry, qstr, 1);
 }
 
 static int
 isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
 {
-       return isofs_hashi_common(qstr, 1);
+       return isofs_hashi_common(dentry, qstr, 1);
 }
 
 static int
index 84c4bf3631a25b85143856c43b6adcae673b94c4..30eb33ff81892586a227a366669c2a133eaadf4a 100644 (file)
@@ -81,6 +81,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
        struct jffs2_full_dirent *fd = NULL, *fd_list;
        uint32_t ino = 0;
        struct inode *inode = NULL;
+       unsigned int nhash;
 
        jffs2_dbg(1, "jffs2_lookup()\n");
 
@@ -89,11 +90,14 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
 
        dir_f = JFFS2_INODE_INFO(dir_i);
 
+       /* The 'nhash' on the fd_list is not the same as the dentry hash */
+       nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len);
+
        mutex_lock(&dir_f->sem);
 
        /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
-       for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) {
-               if (fd_list->nhash == target->d_name.hash &&
+       for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) {
+               if (fd_list->nhash == nhash &&
                    (!fd || fd_list->version > fd->version) &&
                    strlen(fd_list->name) == target->d_name.len &&
                    !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) {
index bfebbf13698c0e0d255e20f5ebf26de7fd6b5845..06a71dbd4833e3bdf4ea5277bc50e15ee40c45ad 100644 (file)
@@ -674,7 +674,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r
                }
        }
 
-       fd->nhash = full_name_hash(fd->name, rd->nsize);
+       fd->nhash = full_name_hash(NULL, fd->name, rd->nsize);
        fd->next = NULL;
        fd->name[rd->nsize] = '\0';
 
index 9ad5ba4b299be2f41cca834e97480a309c4e7b16..90431dd613b8db1bd699c6cc1eaff6a5608fde46 100644 (file)
@@ -1100,7 +1100,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
        fd->next = NULL;
        fd->version = je32_to_cpu(rd->version);
        fd->ino = je32_to_cpu(rd->ino);
-       fd->nhash = full_name_hash(fd->name, checkedlen);
+       fd->nhash = full_name_hash(NULL, fd->name, checkedlen);
        fd->type = rd->type;
        jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
 
index bc5385471a6e3f2b1088d93bed109b185f4d8256..be7c8a6a574806fd0d4189695083c15b65e5f492 100644 (file)
@@ -476,7 +476,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                fd->next = NULL;
                                fd->version = je32_to_cpu(spd->version);
                                fd->ino = je32_to_cpu(spd->ino);
-                               fd->nhash = full_name_hash(fd->name, checkedlen);
+                               fd->nhash = full_name_hash(NULL, fd->name, checkedlen);
                                fd->type = spd->type;
 
                                jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
index 7fb187ab2682ff3433f7f26eebb68dd5e8ad9e21..cda9a361368e8e2c9949e577718691e931bd06bd 100644 (file)
@@ -245,7 +245,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
 
        fd->version = je32_to_cpu(rd->version);
        fd->ino = je32_to_cpu(rd->ino);
-       fd->nhash = full_name_hash(name, namelen);
+       fd->nhash = full_name_hash(NULL, name, namelen);
        fd->type = rd->type;
        memcpy(fd->name, name, namelen);
        fd->name[namelen]=0;
@@ -598,7 +598,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                jffs2_add_fd_to_list(c, fd, &dir_f->dents);
                mutex_unlock(&dir_f->sem);
        } else {
-               uint32_t nhash = full_name_hash(name, namelen);
+               uint32_t nhash = full_name_hash(NULL, name, namelen);
 
                fd = dir_f->dents;
                /* We don't actually want to reserve any space, but we do
index dd824d9b0b1a11877b2c901d335b2c746709bd08..a37eb5f8cbc07ee40709d2bf68280f49946bf891 100644 (file)
@@ -58,7 +58,6 @@ static ssize_t jfs_loglevel_proc_write(struct file *file,
 }
 
 static const struct file_operations jfs_loglevel_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_loglevel_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index a74752146ec901d133323537e4ceeb0d253364ed..a21ea8b3e5fa6762c80247137f332e3d3a651be1 100644 (file)
@@ -2517,7 +2517,6 @@ static int jfs_lmstats_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_lmstats_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_lmstats_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index e7fa9e5130403dae8e19ec8405d1eb6837e59db6..489aaa1403e57c0c0886ba2f127bc16dc0dc2274 100644 (file)
@@ -830,7 +830,6 @@ static int jfs_mpstat_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_mpstat_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_mpstat_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index eddf2b6eda85b2c9131330812fe6139a2739dac8..2e58978d6f45a80c616af32562f139e99ef339c8 100644 (file)
@@ -3040,7 +3040,6 @@ static int jfs_txanchor_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_txanchor_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_txanchor_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -3081,7 +3080,6 @@ static int jfs_txstats_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_txstats_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_txstats_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 5ad7748860ce6ceaea7d6f02d689484efcf34cd0..5cde6d2fcfca6e5930015290c75994df309ade08 100644 (file)
@@ -3894,7 +3894,6 @@ static int jfs_xtstat_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_xtstat_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_xtstat_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 539deddecbb037618d8944236ced8e730785fba5..04baf0dfc40c0b3d7a61966feeb37e8fc2de5ff1 100644 (file)
@@ -1564,7 +1564,7 @@ static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
        unsigned long hash;
        int i;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dir);
        for (i=0; i < this->len; i++)
                hash = partial_name_hash(tolower(this->name[i]), hash);
        this->hash = end_name_hash(hash);
index 8a652404eef680f77ebc49fad7636e1f950b82df..e57174d436830a4111a1bfdf7c9b7fa11a124908 100644 (file)
@@ -336,11 +336,11 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
  */
 static unsigned int kernfs_name_hash(const char *name, const void *ns)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(ns);
        unsigned int len = strlen(name);
        while (len--)
                hash = partial_name_hash(*name++, hash);
-       hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31));
+       hash = end_name_hash(hash);
        hash &= 0x7fffffffU;
        /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
        if (hash < 2)
index 2a0a98480e39d0d0002f19e373fa4b4b64271d56..8f72cb237ef345d326064e42eb50e728152dd693 100644 (file)
@@ -64,7 +64,6 @@ static const struct file_operations lockd_end_grace_operations = {
        .read           = nlm_end_grace_read,
        .llseek         = default_llseek,
        .release        = simple_transaction_release,
-       .owner          = THIS_MODULE,
 };
 
 int __init
index 2d5336bd4efdb20e706a8ffea28d9c2476a54ffe..bcd754d216bd1be454ceddd61fc1cdb08b2c9734 100644 (file)
@@ -95,7 +95,7 @@ static int beyond_eof(struct inode *inode, loff_t bix)
  * of each character and pick a prime nearby, preferably a bit-sparse
  * one.
  */
-static u32 hash_32(const char *s, int len, u32 seed)
+static u32 logfs_hash_32(const char *s, int len, u32 seed)
 {
        u32 hash = seed;
        int i;
@@ -159,7 +159,7 @@ static struct page *logfs_get_dd_page(struct inode *dir, struct dentry *dentry)
        struct qstr *name = &dentry->d_name;
        struct page *page;
        struct logfs_disk_dentry *dd;
-       u32 hash = hash_32(name->name, name->len, 0);
+       u32 hash = logfs_hash_32(name->name, name->len, 0);
        pgoff_t index;
        int round;
 
@@ -370,7 +370,7 @@ static int logfs_write_dir(struct inode *dir, struct dentry *dentry,
 {
        struct page *page;
        struct logfs_disk_dentry *dd;
-       u32 hash = hash_32(dentry->d_name.name, dentry->d_name.len, 0);
+       u32 hash = logfs_hash_32(dentry->d_name.name, dentry->d_name.len, 0);
        pgoff_t index;
        int round, err;
 
index 70580ab1445c89f8379756fc16e33223aca4ab0d..68a896c804b77d01e6c025bf52c4beebe7c54afd 100644 (file)
@@ -1449,9 +1449,8 @@ static int follow_dotdot(struct nameidata *nd)
 }
 
 /*
- * This looks up the name in dcache, possibly revalidates the old dentry and
- * allocates a new one if not found or not valid.  In the need_lookup argument
- * returns whether i_op->lookup is necessary.
+ * This looks up the name in dcache and possibly revalidates the found dentry.
+ * NULL is returned if the dentry does not exist in the cache.
  */
 static struct dentry *lookup_dcache(const struct qstr *name,
                                    struct dentry *dir,
@@ -1890,9 +1889,9 @@ static inline unsigned int fold_hash(unsigned long x, unsigned long y)
  * payload bytes, to match the way that hash_name() iterates until it
  * finds the delimiter after the name.
  */
-unsigned int full_name_hash(const char *name, unsigned int len)
+unsigned int full_name_hash(const void *salt, const char *name, unsigned int len)
 {
-       unsigned long a, x = 0, y = 0;
+       unsigned long a, x = 0, y = (unsigned long)salt;
 
        for (;;) {
                if (!len)
@@ -1911,15 +1910,19 @@ done:
 EXPORT_SYMBOL(full_name_hash);
 
 /* Return the "hash_len" (hash and length) of a null-terminated string */
-u64 hashlen_string(const char *name)
+u64 hashlen_string(const void *salt, const char *name)
 {
-       unsigned long a = 0, x = 0, y = 0, adata, mask, len;
+       unsigned long a = 0, x = 0, y = (unsigned long)salt;
+       unsigned long adata, mask, len;
        const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
 
-       len = -sizeof(unsigned long);
+       len = 0;
+       goto inside;
+
        do {
                HASH_MIX(x, y, a);
                len += sizeof(unsigned long);
+inside:
                a = load_unaligned_zeropad(name+len);
        } while (!has_zero(a, &adata, &constants));
 
@@ -1935,15 +1938,19 @@ EXPORT_SYMBOL(hashlen_string);
  * Calculate the length and hash of the path component, and
  * return the "hash_len" as the result.
  */
-static inline u64 hash_name(const char *name)
+static inline u64 hash_name(const void *salt, const char *name)
 {
-       unsigned long a = 0, b, x = 0, y = 0, adata, bdata, mask, len;
+       unsigned long a = 0, b, x = 0, y = (unsigned long)salt;
+       unsigned long adata, bdata, mask, len;
        const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
 
-       len = -sizeof(unsigned long);
+       len = 0;
+       goto inside;
+
        do {
                HASH_MIX(x, y, a);
                len += sizeof(unsigned long);
+inside:
                a = load_unaligned_zeropad(name+len);
                b = a ^ REPEAT_BYTE('/');
        } while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants)));
@@ -1959,9 +1966,9 @@ static inline u64 hash_name(const char *name)
 #else  /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */
 
 /* Return the hash of a string of known length */
-unsigned int full_name_hash(const char *name, unsigned int len)
+unsigned int full_name_hash(const void *salt, const char *name, unsigned int len)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(salt);
        while (len--)
                hash = partial_name_hash((unsigned char)*name++, hash);
        return end_name_hash(hash);
@@ -1969,9 +1976,9 @@ unsigned int full_name_hash(const char *name, unsigned int len)
 EXPORT_SYMBOL(full_name_hash);
 
 /* Return the "hash_len" (hash and length) of a null-terminated string */
-u64 hashlen_string(const char *name)
+u64 hashlen_string(const void *salt, const char *name)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(salt);
        unsigned long len = 0, c;
 
        c = (unsigned char)*name;
@@ -1988,9 +1995,9 @@ EXPORT_SYMBOL(hashlen_string);
  * We know there's a real path component here of at least
  * one character.
  */
-static inline u64 hash_name(const char *name)
+static inline u64 hash_name(const void *salt, const char *name)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(salt);
        unsigned long len = 0, c;
 
        c = (unsigned char)*name;
@@ -2030,7 +2037,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                if (err)
                        return err;
 
-               hash_len = hash_name(name);
+               hash_len = hash_name(nd->path.dentry, name);
 
                type = LAST_NORM;
                if (name[0] == '.') switch (hashlen_len(hash_len)) {
@@ -2388,33 +2395,6 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
 }
 EXPORT_SYMBOL(vfs_path_lookup);
 
-/**
- * lookup_hash - lookup single pathname component on already hashed name
- * @name:      name and hash to lookup
- * @base:      base directory to lookup from
- *
- * The name must have been verified and hashed (see lookup_one_len()).  Using
- * this after just full_name_hash() is unsafe.
- *
- * This function also doesn't check for search permission on base directory.
- *
- * Use lookup_one_len_unlocked() instead, unless you really know what you are
- * doing.
- *
- * Do not hold i_mutex; this helper takes i_mutex if necessary.
- */
-struct dentry *lookup_hash(const struct qstr *name, struct dentry *base)
-{
-       struct dentry *ret;
-
-       ret = lookup_dcache(name, base, 0);
-       if (!ret)
-               ret = lookup_slow(name, base, 0);
-
-       return ret;
-}
-EXPORT_SYMBOL(lookup_hash);
-
 /**
  * lookup_one_len - filesystem helper to lookup single pathname component
  * @name:      pathname component to lookup
@@ -2436,7 +2416,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 
        this.name = name;
        this.len = len;
-       this.hash = full_name_hash(name, len);
+       this.hash = full_name_hash(base, name, len);
        if (!len)
                return ERR_PTR(-EACCES);
 
@@ -2486,10 +2466,11 @@ struct dentry *lookup_one_len_unlocked(const char *name,
        struct qstr this;
        unsigned int c;
        int err;
+       struct dentry *ret;
 
        this.name = name;
        this.len = len;
-       this.hash = full_name_hash(name, len);
+       this.hash = full_name_hash(base, name, len);
        if (!len)
                return ERR_PTR(-EACCES);
 
@@ -2517,7 +2498,10 @@ struct dentry *lookup_one_len_unlocked(const char *name,
        if (err)
                return ERR_PTR(err);
 
-       return lookup_hash(&this, base);
+       ret = lookup_dcache(&this, base, 0);
+       if (!ret)
+               ret = lookup_slow(&this, base, 0);
+       return ret;
 }
 EXPORT_SYMBOL(lookup_one_len_unlocked);
 
@@ -4328,7 +4312,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         * Check source == target.
         * On overlayfs need to look at underlying inodes.
         */
-       if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))
+       if (d_real_inode(old_dentry) == d_real_inode(new_dentry))
                return 0;
 
        error = may_delete(old_dir, old_dentry, is_dir);
index bfdad003ee56f69a8eb55dbd5023b384d4b55fdc..9add7ab747a53338f081aa3cc97c8c3d9ebdc4d7 100644 (file)
@@ -139,7 +139,7 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
                int i;
 
                t = NCP_IO_TABLE(sb);
-               hash = init_name_hash();
+               hash = init_name_hash(dentry);
                for (i=0; i<this->len ; i++)
                        hash = partial_name_hash(ncp_tolower(t, this->name[i]),
                                                                        hash);
index 0c96528db94af35ba362f71a7af4eca26e41f8c9..487c5607d52f4c5c853a1f13cc8fbb545e9e79a2 100644 (file)
@@ -1102,7 +1102,6 @@ static const struct file_operations nfs_server_list_fops = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release_net,
-       .owner          = THIS_MODULE,
 };
 
 static int nfs_volume_list_open(struct inode *inode, struct file *file);
@@ -1123,7 +1122,6 @@ static const struct file_operations nfs_volume_list_fops = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release_net,
-       .owner          = THIS_MODULE,
 };
 
 /*
index 19d93d0cd400f5ac175a9d257ec8a8ced0e04c21..baaa38859899eb6b97e234f2f94f92d83fee1520 100644 (file)
@@ -232,7 +232,7 @@ int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int le
         * in a page cache page which kmemleak does not scan.
         */
        kmemleak_not_leak(string->name);
-       string->hash = full_name_hash(name, len);
+       string->hash = full_name_hash(NULL, name, len);
        return 0;
 }
 
@@ -502,7 +502,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
                if (filename.len == 2 && filename.name[1] == '.')
                        return;
        }
-       filename.hash = full_name_hash(filename.name, filename.len);
+       filename.hash = full_name_hash(parent, filename.name, filename.len);
 
        dentry = d_lookup(parent, &filename);
 again:
@@ -734,7 +734,7 @@ struct page *get_cache_page(nfs_readdir_descriptor_t *desc)
        struct page *page;
 
        for (;;) {
-               page = read_cache_page(file_inode(desc->file)->i_mapping,
+               page = read_cache_page(desc->file->f_mapping,
                        desc->page_index, (filler_t *)nfs_readdir_filler, desc);
                if (IS_ERR(page) || grab_page(page))
                        break;
@@ -1397,19 +1397,18 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
        if (IS_ERR(label))
                goto out;
 
-       /* Protect against concurrent sillydeletes */
        trace_nfs_lookup_enter(dir, dentry, flags);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
        if (error == -ENOENT)
                goto no_entry;
        if (error < 0) {
                res = ERR_PTR(error);
-               goto out_unblock_sillyrename;
+               goto out_label;
        }
        inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
        res = ERR_CAST(inode);
        if (IS_ERR(res))
-               goto out_unblock_sillyrename;
+               goto out_label;
 
        /* Success: notify readdir to use READDIRPLUS */
        nfs_advise_use_readdirplus(dir);
@@ -1418,11 +1417,11 @@ no_entry:
        res = d_splice_alias(inode, dentry);
        if (res != NULL) {
                if (IS_ERR(res))
-                       goto out_unblock_sillyrename;
+                       goto out_label;
                dentry = res;
        }
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-out_unblock_sillyrename:
+out_label:
        trace_nfs_lookup_exit(dir, dentry, flags, error);
        nfs4_label_free(label);
 out:
index c7326c2af2c3d33df7a96497c427664d90f7861f..e6210ead71d06d941d7f7083899eec321b8cc7ae 100644 (file)
@@ -244,9 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
 /**
  * nfs_direct_IO - NFS address space operation for direct I/O
  * @iocb: target I/O control block
- * @iov: array of vectors that define I/O buffer
- * @pos: offset in file to begin the operation
- * @nr_segs: size of iovec array
+ * @iter: I/O buffer
  *
  * The presence of this routine in the address space ops vector means
  * the NFS client supports direct I/O. However, for most direct IO, we
index 5154fa65a2f2a20efad5eeb9667bd10974f8aaed..5ea04d87fc653db7bf578853b1e97b165812864e 100644 (file)
@@ -623,7 +623,7 @@ void nfs_mark_page_unstable(struct page *page, struct nfs_commit_info *cinfo)
        if (!cinfo->dreq) {
                struct inode *inode = page_file_mapping(page)->host;
 
-               inc_zone_page_state(page, NR_UNSTABLE_NFS);
+               inc_node_page_state(page, NR_UNSTABLE_NFS);
                inc_wb_stat(&inode_to_bdi(inode)->wb, WB_RECLAIMABLE);
                __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
        }
index 9c150b15378223697b8b088dd58e9e7a7ae53562..cfb8f7ce5cf6dbda09066ebc1cd21b0f6ee5757d 100644 (file)
@@ -1235,8 +1235,8 @@ DECLARE_EVENT_CLASS(nfs4_idmap_event,
                                len = 0;
                        __entry->error = error < 0 ? error : 0;
                        __entry->id = id;
-                       memcpy(__get_dynamic_array(name), name, len);
-                       ((char *)__get_dynamic_array(name))[len] = 0;
+                       memcpy(__get_str(name), name, len);
+                       __get_str(name)[len] = 0;
                ),
 
                TP_printk(
index 0b9e5cc9a74705f3cade3c431b479eaa6e01e08c..31c7763b94d58803c832e08f2d046f27de7c9c2f 100644 (file)
@@ -707,9 +707,9 @@ TRACE_EVENT(nfs_sillyrename_unlink,
                        __entry->dev = dir->i_sb->s_dev;
                        __entry->dir = NFS_FILEID(dir);
                        __entry->error = error;
-                       memcpy(__get_dynamic_array(name),
+                       memcpy(__get_str(name),
                                data->args.name.name, len);
-                       ((char *)__get_dynamic_array(name))[len] = 0;
+                       __get_str(name)[len] = 0;
                ),
 
                TP_printk(
index e1c74d3db64de48851c0d758ade6df2741da9d30..593fa21a02c07a9dca3f45ce0ef8f87edad61a5f 100644 (file)
@@ -898,7 +898,7 @@ nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg,
 static void
 nfs_clear_page_commit(struct page *page)
 {
-       dec_zone_page_state(page, NR_UNSTABLE_NFS);
+       dec_node_page_state(page, NR_UNSTABLE_NFS);
        dec_wb_stat(&inode_to_bdi(page_file_mapping(page)->host)->wb,
                    WB_RECLAIMABLE);
 }
index 9690cb4dd5887b020ffc897ba93888f302db3a56..e7787777620e9d236043499d2c7adb871610a035 100644 (file)
@@ -158,7 +158,6 @@ static const struct file_operations exports_proc_operations = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release,
-       .owner          = THIS_MODULE,
 };
 
 static int exports_nfsd_open(struct inode *inode, struct file *file)
@@ -171,7 +170,6 @@ static const struct file_operations exports_nfsd_operations = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release,
-       .owner          = THIS_MODULE,
 };
 
 static int export_features_show(struct seq_file *m, void *v)
@@ -217,7 +215,6 @@ static const struct file_operations pool_stats_operations = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = nfsd_pool_stats_release,
-       .owner          = THIS_MODULE,
 };
 
 static struct file_operations reply_cache_stats_operations = {
index cd90878a76aaa8498933a087e6959f532d0f5a47..d97338bb6a39864173e499ac76b43b1b2fb9e8f7 100644 (file)
@@ -84,7 +84,6 @@ static int nfsd_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations nfsd_proc_fops = {
-       .owner = THIS_MODULE,
        .open = nfsd_proc_open,
        .read  = seq_read,
        .llseek = seq_lseek,
index f40972d6df9060d154058a91d9423c2f2ad875de..e01287c964a88ab4db60472e1e084449bcd166e3 100644 (file)
@@ -1854,7 +1854,7 @@ int ntfs_read_inode_mount(struct inode *vi)
        /* Need this to sanity check attribute list references to $MFT. */
        vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
 
-       /* Provides readpage() and sync_page() for map_mft_record(). */
+       /* Provides readpage() for map_mft_record(). */
        vi->i_mapping->a_ops = &ntfs_mst_aops;
 
        ctx = ntfs_attr_get_search_ctx(ni, m);
index 443abecf01b7d45cfb19be0ee63032b156ae718b..358258364616cd3c2fee997daca2a192719cb045 100644 (file)
@@ -253,7 +253,7 @@ handle_name:
                err = (signed)nls_name.len;
                goto err_out;
        }
-       nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
+       nls_name.hash = full_name_hash(dent, nls_name.name, nls_name.len);
 
        dent = d_add_ci(dent, dent_inode, &nls_name);
        kfree(nls_name.name);
index e97a37179614e78427733046de6e837520603d18..af2adfcb0f6f5ce403cadbef5a97c0fb7d14cce3 100644 (file)
@@ -2426,7 +2426,7 @@ static int ocfs2_dio_end_io(struct kiocb *iocb,
 static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct file *file = iocb->ki_filp;
-       struct inode *inode = file_inode(file)->i_mapping->host;
+       struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        get_block_t *get_block;
 
index 004f2cbe8f71e7c4ffb8833f8cc1e249680f99c4..8107d0d0c3f6e8857f4cbbfd8f14f3573b0267c2 100644 (file)
@@ -47,7 +47,7 @@
 #define DLM_HASH_BUCKETS       (DLM_HASH_PAGES * DLM_BUCKETS_PER_PAGE)
 
 /* Intended to make it easier for us to switch out hash functions */
-#define dlm_lockid_hash(_n, _l) full_name_hash(_n, _l)
+#define dlm_lockid_hash(_n, _l) full_name_hash(NULL, _n, _l)
 
 enum dlm_mle_type {
        DLM_MLE_BLOCK = 0,
index ab6a6cdcf91c856d5ff1fcc04692a6abb9f141f4..87e577a49b0d567550e09912c179a719a7ee692c 100644 (file)
@@ -483,7 +483,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
        struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
        struct ocfs2_global_disk_dqblk dqblk;
        s64 spacechange, inodechange;
-       time_t olditime, oldbtime;
+       time64_t olditime, oldbtime;
 
        err = sb->s_op->quota_read(sb, type, (char *)&dqblk,
                                   sizeof(struct ocfs2_global_disk_dqblk),
index d2053853951e04182bed402df1817fac262f67da..5bb44f7a78ee812e2deacf76cd1a9d633705f709 100644 (file)
@@ -7344,7 +7344,7 @@ const struct xattr_handler ocfs2_xattr_trusted_handler = {
  * 'user' attributes support
  */
 static int ocfs2_xattr_user_get(const struct xattr_handler *handler,
-                               struct dentry *unusde, struct inode *inode,
+                               struct dentry *unused, struct inode *inode,
                                const char *name, void *buffer, size_t size)
 {
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
index 93ae3cdee4ab093c8a23c0505a45d5673ccbc6b6..bf66cf1a9f5c4e186c14b7217414a51b5109c7b4 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -840,13 +840,13 @@ EXPORT_SYMBOL(file_path);
 int vfs_open(const struct path *path, struct file *file,
             const struct cred *cred)
 {
-       struct inode *inode = vfs_select_inode(path->dentry, file->f_flags);
+       struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags);
 
-       if (IS_ERR(inode))
-               return PTR_ERR(inode);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
 
        file->f_path = *path;
-       return do_dentry_open(file, inode, NULL, cred);
+       return do_dentry_open(file, d_backing_inode(dentry), NULL, cred);
 }
 
 struct file *dentry_open(const struct path *path, int flags,
index 8f2fa94cc4f62ef36c54cbf9c7b72dcf61b621be..2e63e6d0a68e514c423d85a5ea27c09f3062f55d 100644 (file)
@@ -291,7 +291,7 @@ int orangefs_permission(struct inode *inode, int mask)
 }
 
 /* ORANGEDS2 implementation of VFS inode operations for files */
-struct inode_operations orangefs_file_inode_operations = {
+const struct inode_operations orangefs_file_inode_operations = {
        .get_acl = orangefs_get_acl,
        .set_acl = orangefs_set_acl,
        .setattr = orangefs_setattr,
index 5a60c508af4ed7e8492a69e8c18276c9981fb62d..7e8dfa97c44a4a2b2b9b6575cc8815b41fac1672 100644 (file)
@@ -405,12 +405,8 @@ static int orangefs_rename(struct inode *old_dir,
        int ret;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
-                    "orangefs_rename: called (%s/%s => %s/%s) ct=%d\n",
-                    old_dentry->d_parent->d_name.name,
-                    old_dentry->d_name.name,
-                    new_dentry->d_parent->d_name.name,
-                    new_dentry->d_name.name,
-                    d_count(new_dentry));
+                    "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
+                    old_dentry, new_dentry, d_count(new_dentry));
 
        new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
        if (!new_op)
@@ -442,7 +438,7 @@ static int orangefs_rename(struct inode *old_dir,
 }
 
 /* ORANGEFS implementation of VFS inode operations for directories */
-struct inode_operations orangefs_dir_inode_operations = {
+const struct inode_operations orangefs_dir_inode_operations = {
        .lookup = orangefs_lookup,
        .get_acl = orangefs_get_acl,
        .set_acl = orangefs_set_acl,
index c1181e5529afa83015155b9025b3985c35d4db4f..4b6e132d5a0f59de3556ab207aeab24f70b55d71 100644 (file)
@@ -557,10 +557,10 @@ extern int hash_table_size;
 
 extern const struct address_space_operations orangefs_address_operations;
 extern struct backing_dev_info orangefs_backing_dev_info;
-extern struct inode_operations orangefs_file_inode_operations;
+extern const struct inode_operations orangefs_file_inode_operations;
 extern const struct file_operations orangefs_file_operations;
-extern struct inode_operations orangefs_symlink_inode_operations;
-extern struct inode_operations orangefs_dir_inode_operations;
+extern const struct inode_operations orangefs_symlink_inode_operations;
+extern const struct inode_operations orangefs_dir_inode_operations;
 extern const struct file_operations orangefs_dir_operations;
 extern const struct dentry_operations orangefs_dentry_operations;
 extern const struct file_operations orangefs_devreq_file_operations;
index 6418dd6386801a366b7df9012b11b61edf40d9c3..8fecf823f5ba2e0241441f96e4d48693ef9d58a2 100644 (file)
@@ -8,7 +8,7 @@
 #include "orangefs-kernel.h"
 #include "orangefs-bufmap.h"
 
-struct inode_operations orangefs_symlink_inode_operations = {
+const struct inode_operations orangefs_symlink_inode_operations = {
        .readlink = generic_readlink,
        .get_link = simple_get_link,
        .setattr = orangefs_setattr,
index 80aa6f1eb336996e15c964d72a3d5d05cdc19b46..54e5d6681786780812c9a5adddc27dd782b40bbb 100644 (file)
@@ -292,6 +292,7 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
                goto out_cleanup;
 
        ovl_dentry_update(dentry, newdentry);
+       ovl_inode_update(d_inode(dentry), d_inode(newdentry));
        newdentry = NULL;
 
        /*
index 5c9d2d80ff70bf851e835c97adf775bbac963641..12bcd07b9e32c516f89605a7247da493d3ccedad 100644 (file)
@@ -138,9 +138,12 @@ static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
        int err;
        enum ovl_path_type type;
        struct path realpath;
+       const struct cred *old_cred;
 
        type = ovl_path_real(dentry, &realpath);
+       old_cred = ovl_override_creds(dentry->d_sb);
        err = vfs_getattr(&realpath, stat);
+       revert_creds(old_cred);
        if (err)
                return err;
 
@@ -158,6 +161,22 @@ static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
        return 0;
 }
 
+/* Common operations required to be done after creation of file on upper */
+static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
+                           struct dentry *newdentry, bool hardlink)
+{
+       ovl_dentry_version_inc(dentry->d_parent);
+       ovl_dentry_update(dentry, newdentry);
+       if (!hardlink) {
+               ovl_inode_update(inode, d_inode(newdentry));
+               ovl_copyattr(newdentry->d_inode, inode);
+       } else {
+               WARN_ON(ovl_inode_real(inode, NULL) != d_inode(newdentry));
+               inc_nlink(inode);
+       }
+       d_instantiate(dentry, inode);
+}
+
 static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
                            struct kstat *stat, const char *link,
                            struct dentry *hardlink)
@@ -177,10 +196,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
        if (err)
                goto out_dput;
 
-       ovl_dentry_version_inc(dentry->d_parent);
-       ovl_dentry_update(dentry, newdentry);
-       ovl_copyattr(newdentry->d_inode, inode);
-       d_instantiate(dentry, inode);
+       ovl_instantiate(dentry, inode, newdentry, !!hardlink);
        newdentry = NULL;
 out_dput:
        dput(newdentry);
@@ -291,23 +307,29 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry)
 {
        int err;
        struct dentry *ret = NULL;
+       enum ovl_path_type type = ovl_path_type(dentry);
        LIST_HEAD(list);
 
        err = ovl_check_empty_dir(dentry, &list);
-       if (err)
+       if (err) {
                ret = ERR_PTR(err);
-       else {
-               /*
-                * If no upperdentry then skip clearing whiteouts.
-                *
-                * Can race with copy-up, since we don't hold the upperdir
-                * mutex.  Doesn't matter, since copy-up can't create a
-                * non-empty directory from an empty one.
-                */
-               if (ovl_dentry_upper(dentry))
-                       ret = ovl_clear_empty(dentry, &list);
+               goto out_free;
        }
 
+       /*
+        * When removing an empty opaque directory, then it makes no sense to
+        * replace it with an exact replica of itself.
+        *
+        * If no upperdentry then skip clearing whiteouts.
+        *
+        * Can race with copy-up, since we don't hold the upperdir mutex.
+        * Doesn't matter, since copy-up can't create a non-empty directory
+        * from an empty one.
+        */
+       if (OVL_TYPE_UPPER(type) && OVL_TYPE_MERGE(type))
+               ret = ovl_clear_empty(dentry, &list);
+
+out_free:
        ovl_cache_free(&list);
 
        return ret;
@@ -347,7 +369,23 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
        if (err)
                goto out_dput2;
 
-       if (S_ISDIR(stat->mode)) {
+       /*
+        * mode could have been mutilated due to umask (e.g. sgid directory)
+        */
+       if (!hardlink &&
+           !S_ISLNK(stat->mode) && newdentry->d_inode->i_mode != stat->mode) {
+               struct iattr attr = {
+                       .ia_valid = ATTR_MODE,
+                       .ia_mode = stat->mode,
+               };
+               inode_lock(newdentry->d_inode);
+               err = notify_change(newdentry, &attr, NULL);
+               inode_unlock(newdentry->d_inode);
+               if (err)
+                       goto out_cleanup;
+       }
+
+       if (!hardlink && S_ISDIR(stat->mode)) {
                err = ovl_set_opaque(newdentry);
                if (err)
                        goto out_cleanup;
@@ -363,10 +401,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
                if (err)
                        goto out_cleanup;
        }
-       ovl_dentry_version_inc(dentry->d_parent);
-       ovl_dentry_update(dentry, newdentry);
-       ovl_copyattr(newdentry->d_inode, inode);
-       d_instantiate(dentry, inode);
+       ovl_instantiate(dentry, inode, newdentry, !!hardlink);
        newdentry = NULL;
 out_dput2:
        dput(upper);
@@ -382,52 +417,42 @@ out_cleanup:
        goto out_dput2;
 }
 
-static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
-                             const char *link, struct dentry *hardlink)
+static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
+                             struct kstat *stat, const char *link,
+                             struct dentry *hardlink)
 {
        int err;
-       struct inode *inode;
-       struct kstat stat = {
-               .mode = mode,
-               .rdev = rdev,
-       };
-
-       err = -ENOMEM;
-       inode = ovl_new_inode(dentry->d_sb, mode, dentry->d_fsdata);
-       if (!inode)
-               goto out;
+       const struct cred *old_cred;
+       struct cred *override_cred;
 
        err = ovl_copy_up(dentry->d_parent);
        if (err)
-               goto out_iput;
-
-       if (!ovl_dentry_is_opaque(dentry)) {
-               err = ovl_create_upper(dentry, inode, &stat, link, hardlink);
-       } else {
-               const struct cred *old_cred;
-               struct cred *override_cred;
-
-               old_cred = ovl_override_creds(dentry->d_sb);
-
-               err = -ENOMEM;
-               override_cred = prepare_creds();
-               if (override_cred) {
-                       override_cred->fsuid = old_cred->fsuid;
-                       override_cred->fsgid = old_cred->fsgid;
-                       put_cred(override_creds(override_cred));
-                       put_cred(override_cred);
+               return err;
 
-                       err = ovl_create_over_whiteout(dentry, inode, &stat,
-                                                      link, hardlink);
-               }
-               revert_creds(old_cred);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       err = -ENOMEM;
+       override_cred = prepare_creds();
+       if (override_cred) {
+               override_cred->fsuid = inode->i_uid;
+               override_cred->fsgid = inode->i_gid;
+               put_cred(override_creds(override_cred));
+               put_cred(override_cred);
+
+               if (!ovl_dentry_is_opaque(dentry))
+                       err = ovl_create_upper(dentry, inode, stat, link,
+                                               hardlink);
+               else
+                       err = ovl_create_over_whiteout(dentry, inode, stat,
+                                                       link, hardlink);
        }
+       revert_creds(old_cred);
+       if (!err) {
+               struct inode *realinode = d_inode(ovl_dentry_upper(dentry));
 
-       if (!err)
-               inode = NULL;
-out_iput:
-       iput(inode);
-out:
+               WARN_ON(inode->i_mode != realinode->i_mode);
+               WARN_ON(!uid_eq(inode->i_uid, realinode->i_uid));
+               WARN_ON(!gid_eq(inode->i_gid, realinode->i_gid));
+       }
        return err;
 }
 
@@ -435,13 +460,30 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
                             const char *link)
 {
        int err;
+       struct inode *inode;
+       struct kstat stat = {
+               .rdev = rdev,
+       };
 
        err = ovl_want_write(dentry);
-       if (!err) {
-               err = ovl_create_or_link(dentry, mode, rdev, link, NULL);
-               ovl_drop_write(dentry);
-       }
+       if (err)
+               goto out;
+
+       err = -ENOMEM;
+       inode = ovl_new_inode(dentry->d_sb, mode);
+       if (!inode)
+               goto out_drop_write;
+
+       inode_init_owner(inode, dentry->d_parent->d_inode, mode);
+       stat.mode = inode->i_mode;
 
+       err = ovl_create_or_link(dentry, inode, &stat, link, NULL);
+       if (err)
+               iput(inode);
+
+out_drop_write:
+       ovl_drop_write(dentry);
+out:
        return err;
 }
 
@@ -476,7 +518,7 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
                    struct dentry *new)
 {
        int err;
-       struct dentry *upper;
+       struct inode *inode;
 
        err = ovl_want_write(old);
        if (err)
@@ -486,8 +528,12 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
        if (err)
                goto out_drop_write;
 
-       upper = ovl_dentry_upper(old);
-       err = ovl_create_or_link(new, upper->d_inode->i_mode, 0, NULL, upper);
+       inode = d_inode(old);
+       ihold(inode);
+
+       err = ovl_create_or_link(new, inode, NULL, NULL, ovl_dentry_upper(old));
+       if (err)
+               iput(inode);
 
 out_drop_write:
        ovl_drop_write(old);
@@ -511,24 +557,10 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
                return -EROFS;
 
        if (is_dir) {
-               if (OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) {
-                       opaquedir = ovl_check_empty_and_clear(dentry);
-                       err = PTR_ERR(opaquedir);
-                       if (IS_ERR(opaquedir))
-                               goto out;
-               } else {
-                       LIST_HEAD(list);
-
-                       /*
-                        * When removing an empty opaque directory, then it
-                        * makes no sense to replace it with an exact replica of
-                        * itself.  But emptiness still needs to be checked.
-                        */
-                       err = ovl_check_empty_dir(dentry, &list);
-                       ovl_cache_free(&list);
-                       if (err)
-                               goto out;
-               }
+               opaquedir = ovl_check_empty_and_clear(dentry);
+               err = PTR_ERR(opaquedir);
+               if (IS_ERR(opaquedir))
+                       goto out;
        }
 
        err = ovl_lock_rename_workdir(workdir, upperdir);
@@ -633,6 +665,8 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
 {
        enum ovl_path_type type;
        int err;
+       const struct cred *old_cred;
+
 
        err = ovl_check_sticky(dentry);
        if (err)
@@ -647,14 +681,18 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
                goto out_drop_write;
 
        type = ovl_path_type(dentry);
-       if (OVL_TYPE_PURE_UPPER(type)) {
-               err = ovl_remove_upper(dentry, is_dir);
-       } else {
-               const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
 
+       old_cred = ovl_override_creds(dentry->d_sb);
+       if (OVL_TYPE_PURE_UPPER(type))
+               err = ovl_remove_upper(dentry, is_dir);
+       else
                err = ovl_remove_and_whiteout(dentry, is_dir);
-
-               revert_creds(old_cred);
+       revert_creds(old_cred);
+       if (!err) {
+               if (is_dir)
+                       clear_nlink(dentry->d_inode);
+               else
+                       drop_nlink(dentry->d_inode);
        }
 out_drop_write:
        ovl_drop_write(dentry);
@@ -760,8 +798,7 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
        old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
        new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
 
-       if (old_opaque || new_opaque)
-               old_cred = ovl_override_creds(old->d_sb);
+       old_cred = ovl_override_creds(old->d_sb);
 
        if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
                opaquedir = ovl_check_empty_and_clear(new);
@@ -891,8 +928,7 @@ out_dput_old:
 out_unlock:
        unlock_rename(new_upperdir, old_upperdir);
 out_revert_creds:
-       if (old_opaque || new_opaque)
-               revert_creds(old_cred);
+       revert_creds(old_cred);
 out_drop_write:
        ovl_drop_write(old);
 out:
@@ -913,8 +949,10 @@ const struct inode_operations ovl_dir_inode_operations = {
        .mknod          = ovl_mknod,
        .permission     = ovl_permission,
        .getattr        = ovl_dir_getattr,
-       .setxattr       = ovl_setxattr,
+       .setxattr       = generic_setxattr,
        .getxattr       = ovl_getxattr,
        .listxattr      = ovl_listxattr,
        .removexattr    = ovl_removexattr,
+       .get_acl        = ovl_get_acl,
+       .update_time    = ovl_update_time,
 };
index d1cdc60dd68fa25aa74e2474a09e07aab08b7e26..1b885c156028d3a4209cf51b6898006c28ac0ee6 100644 (file)
@@ -41,6 +41,7 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
 {
        int err;
        struct dentry *upperdentry;
+       const struct cred *old_cred;
 
        /*
         * Check for permissions before trying to copy-up.  This is redundant
@@ -84,7 +85,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
                        attr->ia_valid &= ~ATTR_MODE;
 
                inode_lock(upperdentry->d_inode);
+               old_cred = ovl_override_creds(dentry->d_sb);
                err = notify_change(upperdentry, attr, NULL);
+               revert_creds(old_cred);
                if (!err)
                        ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
                inode_unlock(upperdentry->d_inode);
@@ -102,96 +105,46 @@ static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
                         struct kstat *stat)
 {
        struct path realpath;
+       const struct cred *old_cred;
+       int err;
 
        ovl_path_real(dentry, &realpath);
-       return vfs_getattr(&realpath, stat);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       err = vfs_getattr(&realpath, stat);
+       revert_creds(old_cred);
+       return err;
 }
 
 int ovl_permission(struct inode *inode, int mask)
 {
-       struct ovl_entry *oe;
-       struct dentry *alias = NULL;
-       struct inode *realinode;
-       struct dentry *realdentry;
        bool is_upper;
+       struct inode *realinode = ovl_inode_real(inode, &is_upper);
+       const struct cred *old_cred;
        int err;
 
-       if (S_ISDIR(inode->i_mode)) {
-               oe = inode->i_private;
-       } else if (mask & MAY_NOT_BLOCK) {
-               return -ECHILD;
-       } else {
-               /*
-                * For non-directories find an alias and get the info
-                * from there.
-                */
-               alias = d_find_any_alias(inode);
-               if (WARN_ON(!alias))
-                       return -ENOENT;
-
-               oe = alias->d_fsdata;
-       }
-
-       realdentry = ovl_entry_real(oe, &is_upper);
-
-       if (ovl_is_default_permissions(inode)) {
-               struct kstat stat;
-               struct path realpath = { .dentry = realdentry };
-
-               if (mask & MAY_NOT_BLOCK)
-                       return -ECHILD;
-
-               realpath.mnt = ovl_entry_mnt_real(oe, inode, is_upper);
-
-               err = vfs_getattr(&realpath, &stat);
-               if (err)
-                       goto out_dput;
-
-               err = -ESTALE;
-               if ((stat.mode ^ inode->i_mode) & S_IFMT)
-                       goto out_dput;
-
-               inode->i_mode = stat.mode;
-               inode->i_uid = stat.uid;
-               inode->i_gid = stat.gid;
-
-               err = generic_permission(inode, mask);
-               goto out_dput;
-       }
-
        /* Careful in RCU walk mode */
-       realinode = ACCESS_ONCE(realdentry->d_inode);
        if (!realinode) {
                WARN_ON(!(mask & MAY_NOT_BLOCK));
-               err = -ENOENT;
-               goto out_dput;
+               return -ECHILD;
        }
 
-       if (mask & MAY_WRITE) {
-               umode_t mode = realinode->i_mode;
-
-               /*
-                * Writes will always be redirected to upper layer, so
-                * ignore lower layer being read-only.
-                *
-                * If the overlay itself is read-only then proceed
-                * with the permission check, don't return EROFS.
-                * This will only happen if this is the lower layer of
-                * another overlayfs.
-                *
-                * If upper fs becomes read-only after the overlay was
-                * constructed return EROFS to prevent modification of
-                * upper layer.
-                */
-               err = -EROFS;
-               if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) &&
-                   (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
-                       goto out_dput;
+       /*
+        * Check overlay inode with the creds of task and underlying inode
+        * with creds of mounter
+        */
+       err = generic_permission(inode, mask);
+       if (err)
+               return err;
+
+       old_cred = ovl_override_creds(inode->i_sb);
+       if (!is_upper && !special_file(realinode->i_mode) && mask & MAY_WRITE) {
+               mask &= ~(MAY_WRITE | MAY_APPEND);
+               /* Make sure mounter can read file for copy up later */
+               mask |= MAY_READ;
        }
+       err = inode_permission(realinode, mask);
+       revert_creds(old_cred);
 
-       err = __inode_permission(realinode, mask);
-out_dput:
-       dput(alias);
        return err;
 }
 
@@ -201,6 +154,8 @@ static const char *ovl_get_link(struct dentry *dentry,
 {
        struct dentry *realdentry;
        struct inode *realinode;
+       const struct cred *old_cred;
+       const char *p;
 
        if (!dentry)
                return ERR_PTR(-ECHILD);
@@ -211,13 +166,18 @@ static const char *ovl_get_link(struct dentry *dentry,
        if (WARN_ON(!realinode->i_op->get_link))
                return ERR_PTR(-EPERM);
 
-       return realinode->i_op->get_link(realdentry, realinode, done);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       p = realinode->i_op->get_link(realdentry, realinode, done);
+       revert_creds(old_cred);
+       return p;
 }
 
 static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
 {
        struct path realpath;
        struct inode *realinode;
+       const struct cred *old_cred;
+       int err;
 
        ovl_path_real(dentry, &realpath);
        realinode = realpath.dentry->d_inode;
@@ -225,15 +185,17 @@ static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
        if (!realinode->i_op->readlink)
                return -EINVAL;
 
-       touch_atime(&realpath);
-
-       return realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
+       revert_creds(old_cred);
+       return err;
 }
 
-
 static bool ovl_is_private_xattr(const char *name)
 {
-       return strncmp(name, OVL_XATTR_PRE_NAME, OVL_XATTR_PRE_LEN) == 0;
+#define OVL_XATTR_PRE_NAME OVL_XATTR_PREFIX "."
+       return strncmp(name, OVL_XATTR_PRE_NAME,
+                      sizeof(OVL_XATTR_PRE_NAME) - 1) == 0;
 }
 
 int ovl_setxattr(struct dentry *dentry, struct inode *inode,
@@ -242,21 +204,20 @@ int ovl_setxattr(struct dentry *dentry, struct inode *inode,
 {
        int err;
        struct dentry *upperdentry;
+       const struct cred *old_cred;
 
        err = ovl_want_write(dentry);
        if (err)
                goto out;
 
-       err = -EPERM;
-       if (ovl_is_private_xattr(name))
-               goto out_drop_write;
-
        err = ovl_copy_up(dentry);
        if (err)
                goto out_drop_write;
 
        upperdentry = ovl_dentry_upper(dentry);
+       old_cred = ovl_override_creds(dentry->d_sb);
        err = vfs_setxattr(upperdentry, name, value, size, flags);
+       revert_creds(old_cred);
 
 out_drop_write:
        ovl_drop_write(dentry);
@@ -268,11 +229,16 @@ ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode,
                     const char *name, void *value, size_t size)
 {
        struct dentry *realdentry = ovl_dentry_real(dentry);
+       ssize_t res;
+       const struct cred *old_cred;
 
        if (ovl_is_private_xattr(name))
                return -ENODATA;
 
-       return vfs_getxattr(realdentry, name, value, size);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       res = vfs_getxattr(realdentry, name, value, size);
+       revert_creds(old_cred);
+       return res;
 }
 
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
@@ -280,8 +246,11 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
        struct dentry *realdentry = ovl_dentry_real(dentry);
        ssize_t res;
        int off;
+       const struct cred *old_cred;
 
+       old_cred = ovl_override_creds(dentry->d_sb);
        res = vfs_listxattr(realdentry, list, size);
+       revert_creds(old_cred);
        if (res <= 0 || size == 0)
                return res;
 
@@ -308,6 +277,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
        int err;
        struct path realpath;
        enum ovl_path_type type = ovl_path_real(dentry, &realpath);
+       const struct cred *old_cred;
 
        err = ovl_want_write(dentry);
        if (err)
@@ -329,13 +299,34 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
                ovl_path_upper(dentry, &realpath);
        }
 
+       old_cred = ovl_override_creds(dentry->d_sb);
        err = vfs_removexattr(realpath.dentry, name);
+       revert_creds(old_cred);
 out_drop_write:
        ovl_drop_write(dentry);
 out:
        return err;
 }
 
+struct posix_acl *ovl_get_acl(struct inode *inode, int type)
+{
+       struct inode *realinode = ovl_inode_real(inode, NULL);
+       const struct cred *old_cred;
+       struct posix_acl *acl;
+
+       if (!IS_POSIXACL(realinode))
+               return NULL;
+
+       if (!realinode->i_op->get_acl)
+               return NULL;
+
+       old_cred = ovl_override_creds(inode->i_sb);
+       acl = realinode->i_op->get_acl(realinode, type);
+       revert_creds(old_cred);
+
+       return acl;
+}
+
 static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
                                  struct dentry *realdentry)
 {
@@ -351,46 +342,60 @@ static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
        return true;
 }
 
-struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
+int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
 {
-       int err;
+       int err = 0;
        struct path realpath;
        enum ovl_path_type type;
 
-       if (d_is_dir(dentry))
-               return d_backing_inode(dentry);
-
        type = ovl_path_real(dentry, &realpath);
        if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) {
                err = ovl_want_write(dentry);
-               if (err)
-                       return ERR_PTR(err);
+               if (!err) {
+                       if (file_flags & O_TRUNC)
+                               err = ovl_copy_up_truncate(dentry);
+                       else
+                               err = ovl_copy_up(dentry);
+                       ovl_drop_write(dentry);
+               }
+       }
 
-               if (file_flags & O_TRUNC)
-                       err = ovl_copy_up_truncate(dentry);
-               else
-                       err = ovl_copy_up(dentry);
-               ovl_drop_write(dentry);
-               if (err)
-                       return ERR_PTR(err);
+       return err;
+}
 
-               ovl_path_upper(dentry, &realpath);
+int ovl_update_time(struct inode *inode, struct timespec *ts, int flags)
+{
+       struct dentry *alias;
+       struct path upperpath;
+
+       if (!(flags & S_ATIME))
+               return 0;
+
+       alias = d_find_any_alias(inode);
+       if (!alias)
+               return 0;
+
+       ovl_path_upper(alias, &upperpath);
+       if (upperpath.dentry) {
+               touch_atime(&upperpath);
+               inode->i_atime = d_inode(upperpath.dentry)->i_atime;
        }
 
-       if (realpath.dentry->d_flags & DCACHE_OP_SELECT_INODE)
-               return realpath.dentry->d_op->d_select_inode(realpath.dentry, file_flags);
+       dput(alias);
 
-       return d_backing_inode(realpath.dentry);
+       return 0;
 }
 
 static const struct inode_operations ovl_file_inode_operations = {
        .setattr        = ovl_setattr,
        .permission     = ovl_permission,
        .getattr        = ovl_getattr,
-       .setxattr       = ovl_setxattr,
+       .setxattr       = generic_setxattr,
        .getxattr       = ovl_getxattr,
        .listxattr      = ovl_listxattr,
        .removexattr    = ovl_removexattr,
+       .get_acl        = ovl_get_acl,
+       .update_time    = ovl_update_time,
 };
 
 static const struct inode_operations ovl_symlink_inode_operations = {
@@ -398,29 +403,22 @@ static const struct inode_operations ovl_symlink_inode_operations = {
        .get_link       = ovl_get_link,
        .readlink       = ovl_readlink,
        .getattr        = ovl_getattr,
-       .setxattr       = ovl_setxattr,
+       .setxattr       = generic_setxattr,
        .getxattr       = ovl_getxattr,
        .listxattr      = ovl_listxattr,
        .removexattr    = ovl_removexattr,
+       .update_time    = ovl_update_time,
 };
 
-struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
-                           struct ovl_entry *oe)
+static void ovl_fill_inode(struct inode *inode, umode_t mode)
 {
-       struct inode *inode;
-
-       inode = new_inode(sb);
-       if (!inode)
-               return NULL;
-
        inode->i_ino = get_next_ino();
        inode->i_mode = mode;
-       inode->i_flags |= S_NOATIME | S_NOCMTIME;
+       inode->i_flags |= S_NOCMTIME;
 
        mode &= S_IFMT;
        switch (mode) {
        case S_IFDIR:
-               inode->i_private = oe;
                inode->i_op = &ovl_dir_inode_operations;
                inode->i_fop = &ovl_dir_operations;
                break;
@@ -429,6 +427,10 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
                inode->i_op = &ovl_symlink_inode_operations;
                break;
 
+       default:
+               WARN(1, "illegal file type: %i\n", mode);
+               /* Fall through */
+
        case S_IFREG:
        case S_IFSOCK:
        case S_IFBLK:
@@ -436,11 +438,42 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
        case S_IFIFO:
                inode->i_op = &ovl_file_inode_operations;
                break;
+       }
+}
 
-       default:
-               WARN(1, "illegal file type: %i\n", mode);
-               iput(inode);
-               inode = NULL;
+struct inode *ovl_new_inode(struct super_block *sb, umode_t mode)
+{
+       struct inode *inode;
+
+       inode = new_inode(sb);
+       if (inode)
+               ovl_fill_inode(inode, mode);
+
+       return inode;
+}
+
+static int ovl_inode_test(struct inode *inode, void *data)
+{
+       return ovl_inode_real(inode, NULL) == data;
+}
+
+static int ovl_inode_set(struct inode *inode, void *data)
+{
+       inode->i_private = (void *) (((unsigned long) data) | OVL_ISUPPER_MASK);
+       return 0;
+}
+
+struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode)
+
+{
+       struct inode *inode;
+
+       inode = iget5_locked(sb, (unsigned long) realinode,
+                            ovl_inode_test, ovl_inode_set, realinode);
+       if (inode && inode->i_state & I_NEW) {
+               ovl_fill_inode(inode, realinode->i_mode);
+               set_nlink(inode, realinode->i_nlink);
+               unlock_new_inode(inode);
        }
 
        return inode;
index cfbca53590d078b89ca613e65c3b10486763f656..e4f5c9536bfeaf1346ee908dc8081ee42f726fc1 100644 (file)
@@ -23,9 +23,11 @@ enum ovl_path_type {
 #define OVL_TYPE_MERGE_OR_LOWER(type) \
        (OVL_TYPE_MERGE(type) || !OVL_TYPE_UPPER(type))
 
-#define OVL_XATTR_PRE_NAME "trusted.overlay."
-#define OVL_XATTR_PRE_LEN  16
-#define OVL_XATTR_OPAQUE   OVL_XATTR_PRE_NAME"opaque"
+
+#define OVL_XATTR_PREFIX XATTR_TRUSTED_PREFIX "overlay"
+#define OVL_XATTR_OPAQUE OVL_XATTR_PREFIX ".opaque"
+
+#define OVL_ISUPPER_MASK 1UL
 
 static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
 {
@@ -131,6 +133,16 @@ static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
        return err;
 }
 
+static inline struct inode *ovl_inode_real(struct inode *inode, bool *is_upper)
+{
+       unsigned long x = (unsigned long) READ_ONCE(inode->i_private);
+
+       if (is_upper)
+               *is_upper = x & OVL_ISUPPER_MASK;
+
+       return (struct inode *) (x & ~OVL_ISUPPER_MASK);
+}
+
 enum ovl_path_type ovl_path_type(struct dentry *dentry);
 u64 ovl_dentry_version_get(struct dentry *dentry);
 void ovl_dentry_version_inc(struct dentry *dentry);
@@ -141,11 +153,9 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
 struct dentry *ovl_dentry_upper(struct dentry *dentry);
 struct dentry *ovl_dentry_lower(struct dentry *dentry);
 struct dentry *ovl_dentry_real(struct dentry *dentry);
-struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper);
 struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode,
                                    bool is_upper);
 struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
-bool ovl_is_default_permissions(struct inode *inode);
 void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
 struct dentry *ovl_workdir(struct dentry *dentry);
 int ovl_want_write(struct dentry *dentry);
@@ -155,6 +165,7 @@ void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
 bool ovl_is_whiteout(struct dentry *dentry);
 const struct cred *ovl_override_creds(struct super_block *sb);
 void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
+void ovl_inode_update(struct inode *inode, struct inode *upperinode);
 struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                          unsigned int flags);
 struct file *ovl_path_open(struct path *path, int flags);
@@ -179,15 +190,20 @@ ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode,
                     const char *name, void *value, size_t size);
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
 int ovl_removexattr(struct dentry *dentry, const char *name);
-struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags);
+struct posix_acl *ovl_get_acl(struct inode *inode, int type);
+int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
+int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
 
-struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
-                           struct ovl_entry *oe);
+struct inode *ovl_new_inode(struct super_block *sb, umode_t mode);
+struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode);
 static inline void ovl_copyattr(struct inode *from, struct inode *to)
 {
        to->i_uid = from->i_uid;
        to->i_gid = from->i_gid;
        to->i_mode = from->i_mode;
+       to->i_atime = from->i_atime;
+       to->i_mtime = from->i_mtime;
+       to->i_ctime = from->i_ctime;
 }
 
 /* dir.c */
index 9a7693d5f8fffb38bd4a07804e4627ed7f50361a..4036132842b534934020dd0640b721d81320cee3 100644 (file)
 #include <linux/slab.h>
 #include <linux/parser.h>
 #include <linux/module.h>
-#include <linux/pagemap.h>
 #include <linux/sched.h>
 #include <linux/statfs.h>
 #include <linux/seq_file.h>
+#include <linux/posix_acl_xattr.h>
 #include "overlayfs.h"
 
 MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
@@ -145,18 +145,11 @@ struct dentry *ovl_dentry_real(struct dentry *dentry)
        return realdentry;
 }
 
-struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper)
+static void ovl_inode_init(struct inode *inode, struct inode *realinode,
+                          bool is_upper)
 {
-       struct dentry *realdentry;
-
-       realdentry = ovl_upperdentry_dereference(oe);
-       if (realdentry) {
-               *is_upper = true;
-       } else {
-               realdentry = __ovl_dentry_lower(oe);
-               *is_upper = false;
-       }
-       return realdentry;
+       WRITE_ONCE(inode->i_private, (unsigned long) realinode |
+                  (is_upper ? OVL_ISUPPER_MASK : 0));
 }
 
 struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode,
@@ -178,13 +171,6 @@ struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry)
        return oe->cache;
 }
 
-bool ovl_is_default_permissions(struct inode *inode)
-{
-       struct ovl_fs *ofs = inode->i_sb->s_fs_info;
-
-       return ofs->config.default_permissions;
-}
-
 void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache)
 {
        struct ovl_entry *oe = dentry->d_fsdata;
@@ -235,7 +221,6 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry)
 
        WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode));
        WARN_ON(oe->__upperdentry);
-       BUG_ON(!upperdentry->d_inode);
        /*
         * Make sure upperdentry is consistent before making it visible to
         * ovl_upperdentry_dereference().
@@ -244,6 +229,16 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry)
        oe->__upperdentry = upperdentry;
 }
 
+void ovl_inode_update(struct inode *inode, struct inode *upperinode)
+{
+       WARN_ON(!upperinode);
+       WARN_ON(!inode_unhashed(inode));
+       WRITE_ONCE(inode->i_private,
+                  (unsigned long) upperinode | OVL_ISUPPER_MASK);
+       if (!S_ISDIR(upperinode->i_mode))
+               __insert_inode_hash(inode, (unsigned long) upperinode);
+}
+
 void ovl_dentry_version_inc(struct dentry *dentry)
 {
        struct ovl_entry *oe = dentry->d_fsdata;
@@ -304,7 +299,9 @@ static void ovl_dentry_release(struct dentry *dentry)
        }
 }
 
-static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
+static struct dentry *ovl_d_real(struct dentry *dentry,
+                                const struct inode *inode,
+                                unsigned int open_flags)
 {
        struct dentry *real;
 
@@ -314,6 +311,16 @@ static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
                goto bug;
        }
 
+       if (d_is_negative(dentry))
+               return dentry;
+
+       if (open_flags) {
+               int err = ovl_open_maybe_copy_up(dentry, open_flags);
+
+               if (err)
+                       return ERR_PTR(err);
+       }
+
        real = ovl_dentry_upper(dentry);
        if (real && (!inode || inode == d_inode(real)))
                return real;
@@ -326,11 +333,9 @@ static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
                return real;
 
        /* Handle recursion */
-       if (real->d_flags & DCACHE_OP_REAL)
-               return real->d_op->d_real(real, inode);
-
+       return d_real(real, inode, open_flags);
 bug:
-       WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry,
+       WARN(1, "ovl_d_real(%pd4, %s:%lu): real dentry not found\n", dentry,
             inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0);
        return dentry;
 }
@@ -378,13 +383,11 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
 
 static const struct dentry_operations ovl_dentry_operations = {
        .d_release = ovl_dentry_release,
-       .d_select_inode = ovl_d_select_inode,
        .d_real = ovl_d_real,
 };
 
 static const struct dentry_operations ovl_reval_dentry_operations = {
        .d_release = ovl_dentry_release,
-       .d_select_inode = ovl_d_select_inode,
        .d_real = ovl_d_real,
        .d_revalidate = ovl_dentry_revalidate,
        .d_weak_revalidate = ovl_dentry_weak_revalidate,
@@ -404,7 +407,8 @@ static struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
 static bool ovl_dentry_remote(struct dentry *dentry)
 {
        return dentry->d_flags &
-               (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
+               (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE |
+                DCACHE_OP_REAL);
 }
 
 static bool ovl_dentry_weird(struct dentry *dentry)
@@ -415,12 +419,16 @@ static bool ovl_dentry_weird(struct dentry *dentry)
                                  DCACHE_OP_COMPARE);
 }
 
-static inline struct dentry *ovl_lookup_real(struct dentry *dir,
-                                            struct qstr *name)
+static inline struct dentry *ovl_lookup_real(struct super_block *ovl_sb,
+                                            struct dentry *dir,
+                                            const struct qstr *name)
 {
+       const struct cred *old_cred;
        struct dentry *dentry;
 
-       dentry = lookup_hash(name, dir);
+       old_cred = ovl_override_creds(ovl_sb);
+       dentry = lookup_one_len_unlocked(name->name, dir, name->len);
+       revert_creds(old_cred);
 
        if (IS_ERR(dentry)) {
                if (PTR_ERR(dentry) == -ENOENT)
@@ -473,7 +481,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 
        upperdir = ovl_upperdentry_dereference(poe);
        if (upperdir) {
-               this = ovl_lookup_real(upperdir, &dentry->d_name);
+               this = ovl_lookup_real(dentry->d_sb, upperdir, &dentry->d_name);
                err = PTR_ERR(this);
                if (IS_ERR(this))
                        goto out;
@@ -506,7 +514,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                bool opaque = false;
                struct path lowerpath = poe->lowerstack[i];
 
-               this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name);
+               this = ovl_lookup_real(dentry->d_sb,
+                                      lowerpath.dentry, &dentry->d_name);
                err = PTR_ERR(this);
                if (IS_ERR(this)) {
                        /*
@@ -561,12 +570,19 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 
        if (upperdentry || ctr) {
                struct dentry *realdentry;
+               struct inode *realinode;
 
                realdentry = upperdentry ? upperdentry : stack[0].dentry;
+               realinode = d_inode(realdentry);
 
                err = -ENOMEM;
-               inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode,
-                                     oe);
+               if (upperdentry && !d_is_dir(upperdentry)) {
+                       inode = ovl_get_inode(dentry->d_sb, realinode);
+               } else {
+                       inode = ovl_new_inode(dentry->d_sb, realinode->i_mode);
+                       if (inode)
+                               ovl_inode_init(inode, realinode, !!upperdentry);
+               }
                if (!inode)
                        goto out_free_oe;
                ovl_copyattr(realdentry->d_inode, inode);
@@ -595,7 +611,7 @@ out:
 
 struct file *ovl_path_open(struct path *path, int flags)
 {
-       return dentry_open(path, flags, current_cred());
+       return dentry_open(path, flags | O_NOATIME, current_cred());
 }
 
 static void ovl_put_super(struct super_block *sb)
@@ -678,6 +694,7 @@ static const struct super_operations ovl_super_operations = {
        .statfs         = ovl_statfs,
        .show_options   = ovl_show_options,
        .remount_fs     = ovl_remount,
+       .drop_inode     = generic_delete_inode,
 };
 
 enum {
@@ -950,11 +967,102 @@ static unsigned int ovl_split_lowerdirs(char *str)
        return ctr;
 }
 
+static int ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
+                                  struct dentry *dentry, struct inode *inode,
+                                  const char *name, const void *value,
+                                  size_t size, int flags)
+{
+       struct dentry *workdir = ovl_workdir(dentry);
+       struct inode *realinode = ovl_inode_real(inode, NULL);
+       struct posix_acl *acl = NULL;
+       int err;
+
+       /* Check that everything is OK before copy-up */
+       if (value) {
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+       }
+       err = -EOPNOTSUPP;
+       if (!IS_POSIXACL(d_inode(workdir)))
+               goto out_acl_release;
+       if (!realinode->i_op->set_acl)
+               goto out_acl_release;
+       if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) {
+               err = acl ? -EACCES : 0;
+               goto out_acl_release;
+       }
+       err = -EPERM;
+       if (!inode_owner_or_capable(inode))
+               goto out_acl_release;
+
+       posix_acl_release(acl);
+
+       return ovl_setxattr(dentry, inode, handler->name, value, size, flags);
+
+out_acl_release:
+       posix_acl_release(acl);
+       return err;
+}
+
+static int ovl_other_xattr_set(const struct xattr_handler *handler,
+                              struct dentry *dentry, struct inode *inode,
+                              const char *name, const void *value,
+                              size_t size, int flags)
+{
+       return ovl_setxattr(dentry, inode, name, value, size, flags);
+}
+
+static int ovl_own_xattr_set(const struct xattr_handler *handler,
+                            struct dentry *dentry, struct inode *inode,
+                            const char *name, const void *value,
+                            size_t size, int flags)
+{
+       return -EPERM;
+}
+
+static const struct xattr_handler ovl_posix_acl_access_xattr_handler = {
+       .name = XATTR_NAME_POSIX_ACL_ACCESS,
+       .flags = ACL_TYPE_ACCESS,
+       .set = ovl_posix_acl_xattr_set,
+};
+
+static const struct xattr_handler ovl_posix_acl_default_xattr_handler = {
+       .name = XATTR_NAME_POSIX_ACL_DEFAULT,
+       .flags = ACL_TYPE_DEFAULT,
+       .set = ovl_posix_acl_xattr_set,
+};
+
+static const struct xattr_handler ovl_own_xattr_handler = {
+       .prefix = OVL_XATTR_PREFIX,
+       .set = ovl_own_xattr_set,
+};
+
+static const struct xattr_handler ovl_other_xattr_handler = {
+       .prefix = "", /* catch all */
+       .set = ovl_other_xattr_set,
+};
+
+static const struct xattr_handler *ovl_xattr_handlers[] = {
+       &ovl_posix_acl_access_xattr_handler,
+       &ovl_posix_acl_default_xattr_handler,
+       &ovl_own_xattr_handler,
+       &ovl_other_xattr_handler,
+       NULL
+};
+
+static const struct xattr_handler *ovl_xattr_noacl_handlers[] = {
+       &ovl_own_xattr_handler,
+       &ovl_other_xattr_handler,
+       NULL,
+};
+
 static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct path upperpath = { NULL, NULL };
        struct path workpath = { NULL, NULL };
        struct dentry *root_dentry;
+       struct inode *realinode;
        struct ovl_entry *oe;
        struct ovl_fs *ufs;
        struct path *stack = NULL;
@@ -1061,6 +1169,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                        pr_err("overlayfs: failed to clone upperpath\n");
                        goto out_put_lowerpath;
                }
+               /* Don't inherit atime flags */
+               ufs->upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME);
+
+               sb->s_time_gran = ufs->upper_mnt->mnt_sb->s_time_gran;
 
                ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
                err = PTR_ERR(ufs->workdir);
@@ -1108,7 +1220,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                 * Make lower_mnt R/O.  That way fchmod/fchown on lower file
                 * will fail instead of modifying lower fs.
                 */
-               mnt->mnt_flags |= MNT_READONLY;
+               mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
 
                ufs->lower_mnt[ufs->numlower] = mnt;
                ufs->numlower++;
@@ -1132,7 +1244,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        if (!oe)
                goto out_put_cred;
 
-       root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
+       root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR));
        if (!root_dentry)
                goto out_free_oe;
 
@@ -1151,13 +1263,19 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        root_dentry->d_fsdata = oe;
 
-       ovl_copyattr(ovl_dentry_real(root_dentry)->d_inode,
-                    root_dentry->d_inode);
+       realinode = d_inode(ovl_dentry_real(root_dentry));
+       ovl_inode_init(d_inode(root_dentry), realinode, !!upperpath.dentry);
+       ovl_copyattr(realinode, d_inode(root_dentry));
 
        sb->s_magic = OVERLAYFS_SUPER_MAGIC;
        sb->s_op = &ovl_super_operations;
+       if (IS_ENABLED(CONFIG_FS_POSIX_ACL))
+               sb->s_xattr = ovl_xattr_handlers;
+       else
+               sb->s_xattr = ovl_xattr_noacl_handlers;
        sb->s_root = root_dentry;
        sb->s_fs_info = ufs;
+       sb->s_flags |= MS_POSIXACL;
 
        return 0;
 
index a11eb7196ec8b814ce1e9ed098253e0f6cfd24a5..31370da2ee7ce9ca2944eb22efb4d512681bc9dc 100644 (file)
@@ -1024,23 +1024,107 @@ static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
        char buffer[PROC_NUMBUF];
        int oom_adj = OOM_ADJUST_MIN;
        size_t len;
-       unsigned long flags;
 
        if (!task)
                return -ESRCH;
-       if (lock_task_sighand(task, &flags)) {
-               if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX)
-                       oom_adj = OOM_ADJUST_MAX;
-               else
-                       oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) /
-                                 OOM_SCORE_ADJ_MAX;
-               unlock_task_sighand(task, &flags);
-       }
+       if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX)
+               oom_adj = OOM_ADJUST_MAX;
+       else
+               oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) /
+                         OOM_SCORE_ADJ_MAX;
        put_task_struct(task);
        len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj);
        return simple_read_from_buffer(buf, count, ppos, buffer, len);
 }
 
+static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
+{
+       static DEFINE_MUTEX(oom_adj_mutex);
+       struct mm_struct *mm = NULL;
+       struct task_struct *task;
+       int err = 0;
+
+       task = get_proc_task(file_inode(file));
+       if (!task)
+               return -ESRCH;
+
+       mutex_lock(&oom_adj_mutex);
+       if (legacy) {
+               if (oom_adj < task->signal->oom_score_adj &&
+                               !capable(CAP_SYS_RESOURCE)) {
+                       err = -EACCES;
+                       goto err_unlock;
+               }
+               /*
+                * /proc/pid/oom_adj is provided for legacy purposes, ask users to use
+                * /proc/pid/oom_score_adj instead.
+                */
+               pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
+                         current->comm, task_pid_nr(current), task_pid_nr(task),
+                         task_pid_nr(task));
+       } else {
+               if ((short)oom_adj < task->signal->oom_score_adj_min &&
+                               !capable(CAP_SYS_RESOURCE)) {
+                       err = -EACCES;
+                       goto err_unlock;
+               }
+       }
+
+       /*
+        * Make sure we will check other processes sharing the mm if this is
+        * not vfrok which wants its own oom_score_adj.
+        * pin the mm so it doesn't go away and get reused after task_unlock
+        */
+       if (!task->vfork_done) {
+               struct task_struct *p = find_lock_task_mm(task);
+
+               if (p) {
+                       if (atomic_read(&p->mm->mm_users) > 1) {
+                               mm = p->mm;
+                               atomic_inc(&mm->mm_count);
+                       }
+                       task_unlock(p);
+               }
+       }
+
+       task->signal->oom_score_adj = oom_adj;
+       if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE))
+               task->signal->oom_score_adj_min = (short)oom_adj;
+       trace_oom_score_adj_update(task);
+
+       if (mm) {
+               struct task_struct *p;
+
+               rcu_read_lock();
+               for_each_process(p) {
+                       if (same_thread_group(task, p))
+                               continue;
+
+                       /* do not touch kernel threads or the global init */
+                       if (p->flags & PF_KTHREAD || is_global_init(p))
+                               continue;
+
+                       task_lock(p);
+                       if (!p->vfork_done && process_shares_mm(p, mm)) {
+                               pr_info("updating oom_score_adj for %d (%s) from %d to %d because it shares mm with %d (%s). Report if this is unexpected.\n",
+                                               task_pid_nr(p), p->comm,
+                                               p->signal->oom_score_adj, oom_adj,
+                                               task_pid_nr(task), task->comm);
+                               p->signal->oom_score_adj = oom_adj;
+                               if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE))
+                                       p->signal->oom_score_adj_min = (short)oom_adj;
+                       }
+                       task_unlock(p);
+               }
+               rcu_read_unlock();
+               mmdrop(mm);
+       }
+err_unlock:
+       mutex_unlock(&oom_adj_mutex);
+       put_task_struct(task);
+       return err;
+}
+
 /*
  * /proc/pid/oom_adj exists solely for backwards compatibility with previous
  * kernels.  The effective policy is defined by oom_score_adj, which has a
@@ -1054,10 +1138,8 @@ static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
 static ssize_t oom_adj_write(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
-       struct task_struct *task;
        char buffer[PROC_NUMBUF];
        int oom_adj;
-       unsigned long flags;
        int err;
 
        memset(buffer, 0, sizeof(buffer));
@@ -1077,23 +1159,6 @@ static ssize_t oom_adj_write(struct file *file, const char __user *buf,
                goto out;
        }
 
-       task = get_proc_task(file_inode(file));
-       if (!task) {
-               err = -ESRCH;
-               goto out;
-       }
-
-       task_lock(task);
-       if (!task->mm) {
-               err = -EINVAL;
-               goto err_task_lock;
-       }
-
-       if (!lock_task_sighand(task, &flags)) {
-               err = -ESRCH;
-               goto err_task_lock;
-       }
-
        /*
         * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum
         * value is always attainable.
@@ -1103,27 +1168,7 @@ static ssize_t oom_adj_write(struct file *file, const char __user *buf,
        else
                oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
 
-       if (oom_adj < task->signal->oom_score_adj &&
-           !capable(CAP_SYS_RESOURCE)) {
-               err = -EACCES;
-               goto err_sighand;
-       }
-
-       /*
-        * /proc/pid/oom_adj is provided for legacy purposes, ask users to use
-        * /proc/pid/oom_score_adj instead.
-        */
-       pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
-                 current->comm, task_pid_nr(current), task_pid_nr(task),
-                 task_pid_nr(task));
-
-       task->signal->oom_score_adj = oom_adj;
-       trace_oom_score_adj_update(task);
-err_sighand:
-       unlock_task_sighand(task, &flags);
-err_task_lock:
-       task_unlock(task);
-       put_task_struct(task);
+       err = __set_oom_adj(file, oom_adj, true);
 out:
        return err < 0 ? err : count;
 }
@@ -1140,15 +1185,11 @@ static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
        struct task_struct *task = get_proc_task(file_inode(file));
        char buffer[PROC_NUMBUF];
        short oom_score_adj = OOM_SCORE_ADJ_MIN;
-       unsigned long flags;
        size_t len;
 
        if (!task)
                return -ESRCH;
-       if (lock_task_sighand(task, &flags)) {
-               oom_score_adj = task->signal->oom_score_adj;
-               unlock_task_sighand(task, &flags);
-       }
+       oom_score_adj = task->signal->oom_score_adj;
        put_task_struct(task);
        len = snprintf(buffer, sizeof(buffer), "%hd\n", oom_score_adj);
        return simple_read_from_buffer(buf, count, ppos, buffer, len);
@@ -1157,9 +1198,7 @@ static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
 static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
                                        size_t count, loff_t *ppos)
 {
-       struct task_struct *task;
        char buffer[PROC_NUMBUF];
-       unsigned long flags;
        int oom_score_adj;
        int err;
 
@@ -1180,39 +1219,7 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
                goto out;
        }
 
-       task = get_proc_task(file_inode(file));
-       if (!task) {
-               err = -ESRCH;
-               goto out;
-       }
-
-       task_lock(task);
-       if (!task->mm) {
-               err = -EINVAL;
-               goto err_task_lock;
-       }
-
-       if (!lock_task_sighand(task, &flags)) {
-               err = -ESRCH;
-               goto err_task_lock;
-       }
-
-       if ((short)oom_score_adj < task->signal->oom_score_adj_min &&
-                       !capable(CAP_SYS_RESOURCE)) {
-               err = -EACCES;
-               goto err_sighand;
-       }
-
-       task->signal->oom_score_adj = (short)oom_score_adj;
-       if (has_capability_noaudit(current, CAP_SYS_RESOURCE))
-               task->signal->oom_score_adj_min = (short)oom_score_adj;
-       trace_oom_score_adj_update(task);
-
-err_sighand:
-       unlock_task_sighand(task, &flags);
-err_task_lock:
-       task_unlock(task);
-       put_task_struct(task);
+       err = __set_oom_adj(file, oom_score_adj, false);
 out:
        return err < 0 ? err : count;
 }
index cf301a9ef5123ecd2f9a7f3705bbe026dea7558c..09e18fdf61e5b48dd67234b19972a10dd5131662 100644 (file)
@@ -40,7 +40,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
        si_swapinfo(&i);
        committed = percpu_counter_read_positive(&vm_committed_as);
 
-       cached = global_page_state(NR_FILE_PAGES) -
+       cached = global_node_page_state(NR_FILE_PAGES) -
                        total_swapcache_pages() - i.bufferram;
        if (cached < 0)
                cached = 0;
@@ -138,23 +138,23 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
 #endif
                K(i.totalswap),
                K(i.freeswap),
-               K(global_page_state(NR_FILE_DIRTY)),
-               K(global_page_state(NR_WRITEBACK)),
-               K(global_page_state(NR_ANON_PAGES)),
-               K(global_page_state(NR_FILE_MAPPED)),
+               K(global_node_page_state(NR_FILE_DIRTY)),
+               K(global_node_page_state(NR_WRITEBACK)),
+               K(global_node_page_state(NR_ANON_MAPPED)),
+               K(global_node_page_state(NR_FILE_MAPPED)),
                K(i.sharedram),
                K(global_page_state(NR_SLAB_RECLAIMABLE) +
                                global_page_state(NR_SLAB_UNRECLAIMABLE)),
                K(global_page_state(NR_SLAB_RECLAIMABLE)),
                K(global_page_state(NR_SLAB_UNRECLAIMABLE)),
-               global_page_state(NR_KERNEL_STACK) * THREAD_SIZE / 1024,
+               global_page_state(NR_KERNEL_STACK_KB),
                K(global_page_state(NR_PAGETABLE)),
 #ifdef CONFIG_QUICKLIST
                K(quicklist_total_size()),
 #endif
-               K(global_page_state(NR_UNSTABLE_NFS)),
+               K(global_node_page_state(NR_UNSTABLE_NFS)),
                K(global_page_state(NR_BOUNCE)),
-               K(global_page_state(NR_WRITEBACK_TEMP)),
+               K(global_node_page_state(NR_WRITEBACK_TEMP)),
                K(vm_commit_limit()),
                K(committed),
                (unsigned long)VMALLOC_TOTAL >> 10,
@@ -164,9 +164,9 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
                , atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10)
 #endif
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               , K(global_page_state(NR_ANON_THPS) * HPAGE_PMD_NR)
-               , K(global_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR)
-               , K(global_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR)
+               , K(global_node_page_state(NR_ANON_THPS) * HPAGE_PMD_NR)
+               , K(global_node_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR)
+               , K(global_node_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR)
 #endif
 #ifdef CONFIG_CMA
                , K(totalcma_pages)
index 5e57c3e46e1da6d2338cdce05ec0044d5b158797..b59db94d2ff452b8eb3124fbc5785457d7e6d947 100644 (file)
@@ -623,7 +623,7 @@ static bool proc_sys_fill_cache(struct file *file,
 
        qname.name = table->procname;
        qname.len  = strlen(table->procname);
-       qname.hash = full_name_hash(qname.name, qname.len);
+       qname.hash = full_name_hash(dir, qname.name, qname.len);
 
        child = d_lookup(dir, &qname);
        if (!child) {
index ff21980d0119a58aa41c825258e435aa799042c7..b1322dd9d1364ce035fa4f762b126dda658ce881 100644 (file)
@@ -1133,7 +1133,7 @@ static void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
        else
                dquot->dq_dqb.dqb_curinodes = 0;
        if (dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit)
-               dquot->dq_dqb.dqb_itime = (time_t) 0;
+               dquot->dq_dqb.dqb_itime = (time64_t) 0;
        clear_bit(DQ_INODES_B, &dquot->dq_flags);
 }
 
@@ -1145,7 +1145,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
        else
                dquot->dq_dqb.dqb_curspace = 0;
        if (dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit)
-               dquot->dq_dqb.dqb_btime = (time_t) 0;
+               dquot->dq_dqb.dqb_btime = (time64_t) 0;
        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
 }
 
@@ -1292,7 +1292,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
        if (dquot->dq_dqb.dqb_isoftlimit &&
            newinodes > dquot->dq_dqb.dqb_isoftlimit &&
            dquot->dq_dqb.dqb_itime &&
-           get_seconds() >= dquot->dq_dqb.dqb_itime &&
+           ktime_get_real_seconds() >= dquot->dq_dqb.dqb_itime &&
             !ignore_hardlimit(dquot)) {
                prepare_warning(warn, dquot, QUOTA_NL_ISOFTLONGWARN);
                return -EDQUOT;
@@ -1302,7 +1302,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
            newinodes > dquot->dq_dqb.dqb_isoftlimit &&
            dquot->dq_dqb.dqb_itime == 0) {
                prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
-               dquot->dq_dqb.dqb_itime = get_seconds() +
+               dquot->dq_dqb.dqb_itime = ktime_get_real_seconds() +
                    sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type].dqi_igrace;
        }
 
@@ -1334,7 +1334,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
        if (dquot->dq_dqb.dqb_bsoftlimit &&
            tspace > dquot->dq_dqb.dqb_bsoftlimit &&
            dquot->dq_dqb.dqb_btime &&
-           get_seconds() >= dquot->dq_dqb.dqb_btime &&
+           ktime_get_real_seconds() >= dquot->dq_dqb.dqb_btime &&
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
                        prepare_warning(warn, dquot, QUOTA_NL_BSOFTLONGWARN);
@@ -1346,7 +1346,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
            dquot->dq_dqb.dqb_btime == 0) {
                if (!prealloc) {
                        prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
-                       dquot->dq_dqb.dqb_btime = get_seconds() +
+                       dquot->dq_dqb.dqb_btime = ktime_get_real_seconds() +
                            sb_dqopt(sb)->info[dquot->dq_id.type].dqi_bgrace;
                }
                else
@@ -2695,7 +2695,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di)
                        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
                } else if (!(di->d_fieldmask & QC_SPC_TIMER))
                        /* Set grace only if user hasn't provided his own... */
-                       dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
+                       dm->dqb_btime = ktime_get_real_seconds() + dqi->dqi_bgrace;
        }
        if (check_ilim) {
                if (!dm->dqb_isoftlimit ||
@@ -2704,7 +2704,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di)
                        clear_bit(DQ_INODES_B, &dquot->dq_flags);
                } else if (!(di->d_fieldmask & QC_INO_TIMER))
                        /* Set grace only if user hasn't provided his own... */
-                       dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
+                       dm->dqb_itime = ktime_get_real_seconds() + dqi->dqi_igrace;
        }
        if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit ||
            dm->dqb_isoftlimit)
index 90b60c03b588488cd16b96f2f324f026ee7ee1bf..a42de45ce40dbfea77987cab4a4de00e85c6ae97 100644 (file)
@@ -33,7 +33,7 @@ static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
           function. */
        if (qstr->len > SYSV_NAMELEN) {
                qstr->len = SYSV_NAMELEN;
-               qstr->hash = full_name_hash(qstr->name, qstr->len);
+               qstr->hash = full_name_hash(dentry, qstr->name, qstr->len);
        }
        return 0;
 }
index 4a0e48f9210483adf6b9bee36f220e80d65a09cd..ad40b64c5e2f4295688ec1b3522319b5d1b9b1b1 100644 (file)
@@ -541,9 +541,6 @@ void tracefs_remove(struct dentry *dentry)
                return;
 
        parent = dentry->d_parent;
-       if (!parent || !parent->d_inode)
-               return;
-
        inode_lock(parent->d_inode);
        ret = __tracefs_remove(dentry, parent);
        inode_unlock(parent->d_inode);
@@ -566,10 +563,6 @@ void tracefs_remove_recursive(struct dentry *dentry)
        if (IS_ERR_OR_NULL(dentry))
                return;
 
-       parent = dentry->d_parent;
-       if (!parent || !parent->d_inode)
-               return;
-
        parent = dentry;
  down:
        inode_lock(parent->d_inode);
index 57dcceda17d670431191a1229aca954df3334c4a..fa3bda1a860fe124bfafe4c67e9bc6121eb3b0da 100644 (file)
@@ -279,12 +279,6 @@ struct ufs_dir_entry *ufs_find_entry(struct inode *dir, const struct qstr *qstr,
                        de = (struct ufs_dir_entry *) kaddr;
                        kaddr += ufs_last_byte(dir, n) - reclen;
                        while ((char *) de <= kaddr) {
-                               if (de->d_reclen == 0) {
-                                       ufs_error(dir->i_sb, __func__,
-                                                 "zero-length directory entry");
-                                       ufs_put_page(page);
-                                       goto out;
-                               }
                                if (ufs_match(sb, namelen, name, de))
                                        goto found;
                                de = ufs_next_entry(sb, de);
@@ -414,11 +408,8 @@ ufs_validate_entry(struct super_block *sb, char *base,
 {
        struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset);
        struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask));
-       while ((char*)p < (char*)de) {
-               if (p->d_reclen == 0)
-                       break;
+       while ((char*)p < (char*)de)
                p = ufs_next_entry(sb, p);
-       }
        return (char *)p - base;
 }
 
@@ -469,12 +460,6 @@ ufs_readdir(struct file *file, struct dir_context *ctx)
                de = (struct ufs_dir_entry *)(kaddr+offset);
                limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1);
                for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) {
-                       if (de->d_reclen == 0) {
-                               ufs_error(sb, __func__,
-                                       "zero-length directory entry");
-                               ufs_put_page(page);
-                               return -EIO;
-                       }
                        if (de->d_ino) {
                                unsigned char d_type = DT_UNKNOWN;
 
index 8686df6c76095b907b2e1b78c144f5b1c271a62d..d266e835ecc3eb22f92a7400aa67718501a20fff 100644 (file)
@@ -128,7 +128,6 @@ static int xqm_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations xqm_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = xqm_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
diff --git a/include/dt-bindings/pinctrl/stm32f746-pinfunc.h b/include/dt-bindings/pinctrl/stm32f746-pinfunc.h
new file mode 100644 (file)
index 0000000..6348c6a
--- /dev/null
@@ -0,0 +1,1324 @@
+#ifndef _DT_BINDINGS_STM32F746_PINFUNC_H
+#define _DT_BINDINGS_STM32F746_PINFUNC_H
+
+#define STM32F746_PA0_FUNC_GPIO 0x0
+#define STM32F746_PA0_FUNC_TIM2_CH1_TIM2_ETR 0x2
+#define STM32F746_PA0_FUNC_TIM5_CH1 0x3
+#define STM32F746_PA0_FUNC_TIM8_ETR 0x4
+#define STM32F746_PA0_FUNC_USART2_CTS 0x8
+#define STM32F746_PA0_FUNC_UART4_TX 0x9
+#define STM32F746_PA0_FUNC_SAI2_SD_B 0xb
+#define STM32F746_PA0_FUNC_ETH_MII_CRS 0xc
+#define STM32F746_PA0_FUNC_EVENTOUT 0x10
+#define STM32F746_PA0_FUNC_ANALOG 0x11
+
+#define STM32F746_PA1_FUNC_GPIO 0x100
+#define STM32F746_PA1_FUNC_TIM2_CH2 0x102
+#define STM32F746_PA1_FUNC_TIM5_CH2 0x103
+#define STM32F746_PA1_FUNC_USART2_RTS 0x108
+#define STM32F746_PA1_FUNC_UART4_RX 0x109
+#define STM32F746_PA1_FUNC_QUADSPI_BK1_IO3 0x10a
+#define STM32F746_PA1_FUNC_SAI2_MCLK_B 0x10b
+#define STM32F746_PA1_FUNC_ETH_MII_RX_CLK_ETH_RMII_REF_CLK 0x10c
+#define STM32F746_PA1_FUNC_LCD_R2 0x10f
+#define STM32F746_PA1_FUNC_EVENTOUT 0x110
+#define STM32F746_PA1_FUNC_ANALOG 0x111
+
+#define STM32F746_PA2_FUNC_GPIO 0x200
+#define STM32F746_PA2_FUNC_TIM2_CH3 0x202
+#define STM32F746_PA2_FUNC_TIM5_CH3 0x203
+#define STM32F746_PA2_FUNC_TIM9_CH1 0x204
+#define STM32F746_PA2_FUNC_USART2_TX 0x208
+#define STM32F746_PA2_FUNC_SAI2_SCK_B 0x209
+#define STM32F746_PA2_FUNC_ETH_MDIO 0x20c
+#define STM32F746_PA2_FUNC_LCD_R1 0x20f
+#define STM32F746_PA2_FUNC_EVENTOUT 0x210
+#define STM32F746_PA2_FUNC_ANALOG 0x211
+
+#define STM32F746_PA3_FUNC_GPIO 0x300
+#define STM32F746_PA3_FUNC_TIM2_CH4 0x302
+#define STM32F746_PA3_FUNC_TIM5_CH4 0x303
+#define STM32F746_PA3_FUNC_TIM9_CH2 0x304
+#define STM32F746_PA3_FUNC_USART2_RX 0x308
+#define STM32F746_PA3_FUNC_OTG_HS_ULPI_D0 0x30b
+#define STM32F746_PA3_FUNC_ETH_MII_COL 0x30c
+#define STM32F746_PA3_FUNC_LCD_B5 0x30f
+#define STM32F746_PA3_FUNC_EVENTOUT 0x310
+#define STM32F746_PA3_FUNC_ANALOG 0x311
+
+#define STM32F746_PA4_FUNC_GPIO 0x400
+#define STM32F746_PA4_FUNC_SPI1_NSS_I2S1_WS 0x406
+#define STM32F746_PA4_FUNC_SPI3_NSS_I2S3_WS 0x407
+#define STM32F746_PA4_FUNC_USART2_CK 0x408
+#define STM32F746_PA4_FUNC_OTG_HS_SOF 0x40d
+#define STM32F746_PA4_FUNC_DCMI_HSYNC 0x40e
+#define STM32F746_PA4_FUNC_LCD_VSYNC 0x40f
+#define STM32F746_PA4_FUNC_EVENTOUT 0x410
+#define STM32F746_PA4_FUNC_ANALOG 0x411
+
+#define STM32F746_PA5_FUNC_GPIO 0x500
+#define STM32F746_PA5_FUNC_TIM2_CH1_TIM2_ETR 0x502
+#define STM32F746_PA5_FUNC_TIM8_CH1N 0x504
+#define STM32F746_PA5_FUNC_SPI1_SCK_I2S1_CK 0x506
+#define STM32F746_PA5_FUNC_OTG_HS_ULPI_CK 0x50b
+#define STM32F746_PA5_FUNC_LCD_R4 0x50f
+#define STM32F746_PA5_FUNC_EVENTOUT 0x510
+#define STM32F746_PA5_FUNC_ANALOG 0x511
+
+#define STM32F746_PA6_FUNC_GPIO 0x600
+#define STM32F746_PA6_FUNC_TIM1_BKIN 0x602
+#define STM32F746_PA6_FUNC_TIM3_CH1 0x603
+#define STM32F746_PA6_FUNC_TIM8_BKIN 0x604
+#define STM32F746_PA6_FUNC_SPI1_MISO 0x606
+#define STM32F746_PA6_FUNC_TIM13_CH1 0x60a
+#define STM32F746_PA6_FUNC_DCMI_PIXCLK 0x60e
+#define STM32F746_PA6_FUNC_LCD_G2 0x60f
+#define STM32F746_PA6_FUNC_EVENTOUT 0x610
+#define STM32F746_PA6_FUNC_ANALOG 0x611
+
+#define STM32F746_PA7_FUNC_GPIO 0x700
+#define STM32F746_PA7_FUNC_TIM1_CH1N 0x702
+#define STM32F746_PA7_FUNC_TIM3_CH2 0x703
+#define STM32F746_PA7_FUNC_TIM8_CH1N 0x704
+#define STM32F746_PA7_FUNC_SPI1_MOSI_I2S1_SD 0x706
+#define STM32F746_PA7_FUNC_TIM14_CH1 0x70a
+#define STM32F746_PA7_FUNC_ETH_MII_RX_DV_ETH_RMII_CRS_DV 0x70c
+#define STM32F746_PA7_FUNC_FMC_SDNWE 0x70d
+#define STM32F746_PA7_FUNC_EVENTOUT 0x710
+#define STM32F746_PA7_FUNC_ANALOG 0x711
+
+#define STM32F746_PA8_FUNC_GPIO 0x800
+#define STM32F746_PA8_FUNC_MCO1 0x801
+#define STM32F746_PA8_FUNC_TIM1_CH1 0x802
+#define STM32F746_PA8_FUNC_TIM8_BKIN2 0x804
+#define STM32F746_PA8_FUNC_I2C3_SCL 0x805
+#define STM32F746_PA8_FUNC_USART1_CK 0x808
+#define STM32F746_PA8_FUNC_OTG_FS_SOF 0x80b
+#define STM32F746_PA8_FUNC_LCD_R6 0x80f
+#define STM32F746_PA8_FUNC_EVENTOUT 0x810
+#define STM32F746_PA8_FUNC_ANALOG 0x811
+
+#define STM32F746_PA9_FUNC_GPIO 0x900
+#define STM32F746_PA9_FUNC_TIM1_CH2 0x902
+#define STM32F746_PA9_FUNC_I2C3_SMBA 0x905
+#define STM32F746_PA9_FUNC_SPI2_SCK_I2S2_CK 0x906
+#define STM32F746_PA9_FUNC_USART1_TX 0x908
+#define STM32F746_PA9_FUNC_DCMI_D0 0x90e
+#define STM32F746_PA9_FUNC_EVENTOUT 0x910
+#define STM32F746_PA9_FUNC_ANALOG 0x911
+
+#define STM32F746_PA10_FUNC_GPIO 0xa00
+#define STM32F746_PA10_FUNC_TIM1_CH3 0xa02
+#define STM32F746_PA10_FUNC_USART1_RX 0xa08
+#define STM32F746_PA10_FUNC_OTG_FS_ID 0xa0b
+#define STM32F746_PA10_FUNC_DCMI_D1 0xa0e
+#define STM32F746_PA10_FUNC_EVENTOUT 0xa10
+#define STM32F746_PA10_FUNC_ANALOG 0xa11
+
+#define STM32F746_PA11_FUNC_GPIO 0xb00
+#define STM32F746_PA11_FUNC_TIM1_CH4 0xb02
+#define STM32F746_PA11_FUNC_USART1_CTS 0xb08
+#define STM32F746_PA11_FUNC_CAN1_RX 0xb0a
+#define STM32F746_PA11_FUNC_OTG_FS_DM 0xb0b
+#define STM32F746_PA11_FUNC_LCD_R4 0xb0f
+#define STM32F746_PA11_FUNC_EVENTOUT 0xb10
+#define STM32F746_PA11_FUNC_ANALOG 0xb11
+
+#define STM32F746_PA12_FUNC_GPIO 0xc00
+#define STM32F746_PA12_FUNC_TIM1_ETR 0xc02
+#define STM32F746_PA12_FUNC_USART1_RTS 0xc08
+#define STM32F746_PA12_FUNC_SAI2_FS_B 0xc09
+#define STM32F746_PA12_FUNC_CAN1_TX 0xc0a
+#define STM32F746_PA12_FUNC_OTG_FS_DP 0xc0b
+#define STM32F746_PA12_FUNC_LCD_R5 0xc0f
+#define STM32F746_PA12_FUNC_EVENTOUT 0xc10
+#define STM32F746_PA12_FUNC_ANALOG 0xc11
+
+#define STM32F746_PA13_FUNC_GPIO 0xd00
+#define STM32F746_PA13_FUNC_JTMS_SWDIO 0xd01
+#define STM32F746_PA13_FUNC_EVENTOUT 0xd10
+#define STM32F746_PA13_FUNC_ANALOG 0xd11
+
+#define STM32F746_PA14_FUNC_GPIO 0xe00
+#define STM32F746_PA14_FUNC_JTCK_SWCLK 0xe01
+#define STM32F746_PA14_FUNC_EVENTOUT 0xe10
+#define STM32F746_PA14_FUNC_ANALOG 0xe11
+
+#define STM32F746_PA15_FUNC_GPIO 0xf00
+#define STM32F746_PA15_FUNC_JTDI 0xf01
+#define STM32F746_PA15_FUNC_TIM2_CH1_TIM2_ETR 0xf02
+#define STM32F746_PA15_FUNC_HDMI_CEC 0xf05
+#define STM32F746_PA15_FUNC_SPI1_NSS_I2S1_WS 0xf06
+#define STM32F746_PA15_FUNC_SPI3_NSS_I2S3_WS 0xf07
+#define STM32F746_PA15_FUNC_UART4_RTS 0xf09
+#define STM32F746_PA15_FUNC_EVENTOUT 0xf10
+#define STM32F746_PA15_FUNC_ANALOG 0xf11
+
+
+#define STM32F746_PB0_FUNC_GPIO 0x1000
+#define STM32F746_PB0_FUNC_TIM1_CH2N 0x1002
+#define STM32F746_PB0_FUNC_TIM3_CH3 0x1003
+#define STM32F746_PB0_FUNC_TIM8_CH2N 0x1004
+#define STM32F746_PB0_FUNC_UART4_CTS 0x1009
+#define STM32F746_PB0_FUNC_LCD_R3 0x100a
+#define STM32F746_PB0_FUNC_OTG_HS_ULPI_D1 0x100b
+#define STM32F746_PB0_FUNC_ETH_MII_RXD2 0x100c
+#define STM32F746_PB0_FUNC_EVENTOUT 0x1010
+#define STM32F746_PB0_FUNC_ANALOG 0x1011
+
+#define STM32F746_PB1_FUNC_GPIO 0x1100
+#define STM32F746_PB1_FUNC_TIM1_CH3N 0x1102
+#define STM32F746_PB1_FUNC_TIM3_CH4 0x1103
+#define STM32F746_PB1_FUNC_TIM8_CH3N 0x1104
+#define STM32F746_PB1_FUNC_LCD_R6 0x110a
+#define STM32F746_PB1_FUNC_OTG_HS_ULPI_D2 0x110b
+#define STM32F746_PB1_FUNC_ETH_MII_RXD3 0x110c
+#define STM32F746_PB1_FUNC_EVENTOUT 0x1110
+#define STM32F746_PB1_FUNC_ANALOG 0x1111
+
+#define STM32F746_PB2_FUNC_GPIO 0x1200
+#define STM32F746_PB2_FUNC_SAI1_SD_A 0x1207
+#define STM32F746_PB2_FUNC_SPI3_MOSI_I2S3_SD 0x1208
+#define STM32F746_PB2_FUNC_QUADSPI_CLK 0x120a
+#define STM32F746_PB2_FUNC_EVENTOUT 0x1210
+#define STM32F746_PB2_FUNC_ANALOG 0x1211
+
+#define STM32F746_PB3_FUNC_GPIO 0x1300
+#define STM32F746_PB3_FUNC_JTDO_TRACESWO 0x1301
+#define STM32F746_PB3_FUNC_TIM2_CH2 0x1302
+#define STM32F746_PB3_FUNC_SPI1_SCK_I2S1_CK 0x1306
+#define STM32F746_PB3_FUNC_SPI3_SCK_I2S3_CK 0x1307
+#define STM32F746_PB3_FUNC_EVENTOUT 0x1310
+#define STM32F746_PB3_FUNC_ANALOG 0x1311
+
+#define STM32F746_PB4_FUNC_GPIO 0x1400
+#define STM32F746_PB4_FUNC_NJTRST 0x1401
+#define STM32F746_PB4_FUNC_TIM3_CH1 0x1403
+#define STM32F746_PB4_FUNC_SPI1_MISO 0x1406
+#define STM32F746_PB4_FUNC_SPI3_MISO 0x1407
+#define STM32F746_PB4_FUNC_SPI2_NSS_I2S2_WS 0x1408
+#define STM32F746_PB4_FUNC_EVENTOUT 0x1410
+#define STM32F746_PB4_FUNC_ANALOG 0x1411
+
+#define STM32F746_PB5_FUNC_GPIO 0x1500
+#define STM32F746_PB5_FUNC_TIM3_CH2 0x1503
+#define STM32F746_PB5_FUNC_I2C1_SMBA 0x1505
+#define STM32F746_PB5_FUNC_SPI1_MOSI_I2S1_SD 0x1506
+#define STM32F746_PB5_FUNC_SPI3_MOSI_I2S3_SD 0x1507
+#define STM32F746_PB5_FUNC_CAN2_RX 0x150a
+#define STM32F746_PB5_FUNC_OTG_HS_ULPI_D7 0x150b
+#define STM32F746_PB5_FUNC_ETH_PPS_OUT 0x150c
+#define STM32F746_PB5_FUNC_FMC_SDCKE1 0x150d
+#define STM32F746_PB5_FUNC_DCMI_D10 0x150e
+#define STM32F746_PB5_FUNC_EVENTOUT 0x1510
+#define STM32F746_PB5_FUNC_ANALOG 0x1511
+
+#define STM32F746_PB6_FUNC_GPIO 0x1600
+#define STM32F746_PB6_FUNC_TIM4_CH1 0x1603
+#define STM32F746_PB6_FUNC_HDMI_CEC 0x1604
+#define STM32F746_PB6_FUNC_I2C1_SCL 0x1605
+#define STM32F746_PB6_FUNC_USART1_TX 0x1608
+#define STM32F746_PB6_FUNC_CAN2_TX 0x160a
+#define STM32F746_PB6_FUNC_QUADSPI_BK1_NCS 0x160b
+#define STM32F746_PB6_FUNC_FMC_SDNE1 0x160d
+#define STM32F746_PB6_FUNC_DCMI_D5 0x160e
+#define STM32F746_PB6_FUNC_EVENTOUT 0x1610
+#define STM32F746_PB6_FUNC_ANALOG 0x1611
+
+#define STM32F746_PB7_FUNC_GPIO 0x1700
+#define STM32F746_PB7_FUNC_TIM4_CH2 0x1703
+#define STM32F746_PB7_FUNC_I2C1_SDA 0x1705
+#define STM32F746_PB7_FUNC_USART1_RX 0x1708
+#define STM32F746_PB7_FUNC_FMC_NL 0x170d
+#define STM32F746_PB7_FUNC_DCMI_VSYNC 0x170e
+#define STM32F746_PB7_FUNC_EVENTOUT 0x1710
+#define STM32F746_PB7_FUNC_ANALOG 0x1711
+
+#define STM32F746_PB8_FUNC_GPIO 0x1800
+#define STM32F746_PB8_FUNC_TIM4_CH3 0x1803
+#define STM32F746_PB8_FUNC_TIM10_CH1 0x1804
+#define STM32F746_PB8_FUNC_I2C1_SCL 0x1805
+#define STM32F746_PB8_FUNC_CAN1_RX 0x180a
+#define STM32F746_PB8_FUNC_ETH_MII_TXD3 0x180c
+#define STM32F746_PB8_FUNC_SDMMC1_D4 0x180d
+#define STM32F746_PB8_FUNC_DCMI_D6 0x180e
+#define STM32F746_PB8_FUNC_LCD_B6 0x180f
+#define STM32F746_PB8_FUNC_EVENTOUT 0x1810
+#define STM32F746_PB8_FUNC_ANALOG 0x1811
+
+#define STM32F746_PB9_FUNC_GPIO 0x1900
+#define STM32F746_PB9_FUNC_TIM4_CH4 0x1903
+#define STM32F746_PB9_FUNC_TIM11_CH1 0x1904
+#define STM32F746_PB9_FUNC_I2C1_SDA 0x1905
+#define STM32F746_PB9_FUNC_SPI2_NSS_I2S2_WS 0x1906
+#define STM32F746_PB9_FUNC_CAN1_TX 0x190a
+#define STM32F746_PB9_FUNC_SDMMC1_D5 0x190d
+#define STM32F746_PB9_FUNC_DCMI_D7 0x190e
+#define STM32F746_PB9_FUNC_LCD_B7 0x190f
+#define STM32F746_PB9_FUNC_EVENTOUT 0x1910
+#define STM32F746_PB9_FUNC_ANALOG 0x1911
+
+#define STM32F746_PB10_FUNC_GPIO 0x1a00
+#define STM32F746_PB10_FUNC_TIM2_CH3 0x1a02
+#define STM32F746_PB10_FUNC_I2C2_SCL 0x1a05
+#define STM32F746_PB10_FUNC_SPI2_SCK_I2S2_CK 0x1a06
+#define STM32F746_PB10_FUNC_USART3_TX 0x1a08
+#define STM32F746_PB10_FUNC_OTG_HS_ULPI_D3 0x1a0b
+#define STM32F746_PB10_FUNC_ETH_MII_RX_ER 0x1a0c
+#define STM32F746_PB10_FUNC_LCD_G4 0x1a0f
+#define STM32F746_PB10_FUNC_EVENTOUT 0x1a10
+#define STM32F746_PB10_FUNC_ANALOG 0x1a11
+
+#define STM32F746_PB11_FUNC_GPIO 0x1b00
+#define STM32F746_PB11_FUNC_TIM2_CH4 0x1b02
+#define STM32F746_PB11_FUNC_I2C2_SDA 0x1b05
+#define STM32F746_PB11_FUNC_USART3_RX 0x1b08
+#define STM32F746_PB11_FUNC_OTG_HS_ULPI_D4 0x1b0b
+#define STM32F746_PB11_FUNC_ETH_MII_TX_EN_ETH_RMII_TX_EN 0x1b0c
+#define STM32F746_PB11_FUNC_LCD_G5 0x1b0f
+#define STM32F746_PB11_FUNC_EVENTOUT 0x1b10
+#define STM32F746_PB11_FUNC_ANALOG 0x1b11
+
+#define STM32F746_PB12_FUNC_GPIO 0x1c00
+#define STM32F746_PB12_FUNC_TIM1_BKIN 0x1c02
+#define STM32F746_PB12_FUNC_I2C2_SMBA 0x1c05
+#define STM32F746_PB12_FUNC_SPI2_NSS_I2S2_WS 0x1c06
+#define STM32F746_PB12_FUNC_USART3_CK 0x1c08
+#define STM32F746_PB12_FUNC_CAN2_RX 0x1c0a
+#define STM32F746_PB12_FUNC_OTG_HS_ULPI_D5 0x1c0b
+#define STM32F746_PB12_FUNC_ETH_MII_TXD0_ETH_RMII_TXD0 0x1c0c
+#define STM32F746_PB12_FUNC_OTG_HS_ID 0x1c0d
+#define STM32F746_PB12_FUNC_EVENTOUT 0x1c10
+#define STM32F746_PB12_FUNC_ANALOG 0x1c11
+
+#define STM32F746_PB13_FUNC_GPIO 0x1d00
+#define STM32F746_PB13_FUNC_TIM1_CH1N 0x1d02
+#define STM32F746_PB13_FUNC_SPI2_SCK_I2S2_CK 0x1d06
+#define STM32F746_PB13_FUNC_USART3_CTS 0x1d08
+#define STM32F746_PB13_FUNC_CAN2_TX 0x1d0a
+#define STM32F746_PB13_FUNC_OTG_HS_ULPI_D6 0x1d0b
+#define STM32F746_PB13_FUNC_ETH_MII_TXD1_ETH_RMII_TXD1 0x1d0c
+#define STM32F746_PB13_FUNC_EVENTOUT 0x1d10
+#define STM32F746_PB13_FUNC_ANALOG 0x1d11
+
+#define STM32F746_PB14_FUNC_GPIO 0x1e00
+#define STM32F746_PB14_FUNC_TIM1_CH2N 0x1e02
+#define STM32F746_PB14_FUNC_TIM8_CH2N 0x1e04
+#define STM32F746_PB14_FUNC_SPI2_MISO 0x1e06
+#define STM32F746_PB14_FUNC_USART3_RTS 0x1e08
+#define STM32F746_PB14_FUNC_TIM12_CH1 0x1e0a
+#define STM32F746_PB14_FUNC_OTG_HS_DM 0x1e0d
+#define STM32F746_PB14_FUNC_EVENTOUT 0x1e10
+#define STM32F746_PB14_FUNC_ANALOG 0x1e11
+
+#define STM32F746_PB15_FUNC_GPIO 0x1f00
+#define STM32F746_PB15_FUNC_RTC_REFIN 0x1f01
+#define STM32F746_PB15_FUNC_TIM1_CH3N 0x1f02
+#define STM32F746_PB15_FUNC_TIM8_CH3N 0x1f04
+#define STM32F746_PB15_FUNC_SPI2_MOSI_I2S2_SD 0x1f06
+#define STM32F746_PB15_FUNC_TIM12_CH2 0x1f0a
+#define STM32F746_PB15_FUNC_OTG_HS_DP 0x1f0d
+#define STM32F746_PB15_FUNC_EVENTOUT 0x1f10
+#define STM32F746_PB15_FUNC_ANALOG 0x1f11
+
+
+#define STM32F746_PC0_FUNC_GPIO 0x2000
+#define STM32F746_PC0_FUNC_SAI2_FS_B 0x2009
+#define STM32F746_PC0_FUNC_OTG_HS_ULPI_STP 0x200b
+#define STM32F746_PC0_FUNC_FMC_SDNWE 0x200d
+#define STM32F746_PC0_FUNC_LCD_R5 0x200f
+#define STM32F746_PC0_FUNC_EVENTOUT 0x2010
+#define STM32F746_PC0_FUNC_ANALOG 0x2011
+
+#define STM32F746_PC1_FUNC_GPIO 0x2100
+#define STM32F746_PC1_FUNC_TRACED0 0x2101
+#define STM32F746_PC1_FUNC_SPI2_MOSI_I2S2_SD 0x2106
+#define STM32F746_PC1_FUNC_SAI1_SD_A 0x2107
+#define STM32F746_PC1_FUNC_ETH_MDC 0x210c
+#define STM32F746_PC1_FUNC_EVENTOUT 0x2110
+#define STM32F746_PC1_FUNC_ANALOG 0x2111
+
+#define STM32F746_PC2_FUNC_GPIO 0x2200
+#define STM32F746_PC2_FUNC_SPI2_MISO 0x2206
+#define STM32F746_PC2_FUNC_OTG_HS_ULPI_DIR 0x220b
+#define STM32F746_PC2_FUNC_ETH_MII_TXD2 0x220c
+#define STM32F746_PC2_FUNC_FMC_SDNE0 0x220d
+#define STM32F746_PC2_FUNC_EVENTOUT 0x2210
+#define STM32F746_PC2_FUNC_ANALOG 0x2211
+
+#define STM32F746_PC3_FUNC_GPIO 0x2300
+#define STM32F746_PC3_FUNC_SPI2_MOSI_I2S2_SD 0x2306
+#define STM32F746_PC3_FUNC_OTG_HS_ULPI_NXT 0x230b
+#define STM32F746_PC3_FUNC_ETH_MII_TX_CLK 0x230c
+#define STM32F746_PC3_FUNC_FMC_SDCKE0 0x230d
+#define STM32F746_PC3_FUNC_EVENTOUT 0x2310
+#define STM32F746_PC3_FUNC_ANALOG 0x2311
+
+#define STM32F746_PC4_FUNC_GPIO 0x2400
+#define STM32F746_PC4_FUNC_I2S1_MCK 0x2406
+#define STM32F746_PC4_FUNC_SPDIFRX_IN2 0x2409
+#define STM32F746_PC4_FUNC_ETH_MII_RXD0_ETH_RMII_RXD0 0x240c
+#define STM32F746_PC4_FUNC_FMC_SDNE0 0x240d
+#define STM32F746_PC4_FUNC_EVENTOUT 0x2410
+#define STM32F746_PC4_FUNC_ANALOG 0x2411
+
+#define STM32F746_PC5_FUNC_GPIO 0x2500
+#define STM32F746_PC5_FUNC_SPDIFRX_IN3 0x2509
+#define STM32F746_PC5_FUNC_ETH_MII_RXD1_ETH_RMII_RXD1 0x250c
+#define STM32F746_PC5_FUNC_FMC_SDCKE0 0x250d
+#define STM32F746_PC5_FUNC_EVENTOUT 0x2510
+#define STM32F746_PC5_FUNC_ANALOG 0x2511
+
+#define STM32F746_PC6_FUNC_GPIO 0x2600
+#define STM32F746_PC6_FUNC_TIM3_CH1 0x2603
+#define STM32F746_PC6_FUNC_TIM8_CH1 0x2604
+#define STM32F746_PC6_FUNC_I2S2_MCK 0x2606
+#define STM32F746_PC6_FUNC_USART6_TX 0x2609
+#define STM32F746_PC6_FUNC_SDMMC1_D6 0x260d
+#define STM32F746_PC6_FUNC_DCMI_D0 0x260e
+#define STM32F746_PC6_FUNC_LCD_HSYNC 0x260f
+#define STM32F746_PC6_FUNC_EVENTOUT 0x2610
+#define STM32F746_PC6_FUNC_ANALOG 0x2611
+
+#define STM32F746_PC7_FUNC_GPIO 0x2700
+#define STM32F746_PC7_FUNC_TIM3_CH2 0x2703
+#define STM32F746_PC7_FUNC_TIM8_CH2 0x2704
+#define STM32F746_PC7_FUNC_I2S3_MCK 0x2707
+#define STM32F746_PC7_FUNC_USART6_RX 0x2709
+#define STM32F746_PC7_FUNC_SDMMC1_D7 0x270d
+#define STM32F746_PC7_FUNC_DCMI_D1 0x270e
+#define STM32F746_PC7_FUNC_LCD_G6 0x270f
+#define STM32F746_PC7_FUNC_EVENTOUT 0x2710
+#define STM32F746_PC7_FUNC_ANALOG 0x2711
+
+#define STM32F746_PC8_FUNC_GPIO 0x2800
+#define STM32F746_PC8_FUNC_TRACED1 0x2801
+#define STM32F746_PC8_FUNC_TIM3_CH3 0x2803
+#define STM32F746_PC8_FUNC_TIM8_CH3 0x2804
+#define STM32F746_PC8_FUNC_UART5_RTS 0x2808
+#define STM32F746_PC8_FUNC_USART6_CK 0x2809
+#define STM32F746_PC8_FUNC_SDMMC1_D0 0x280d
+#define STM32F746_PC8_FUNC_DCMI_D2 0x280e
+#define STM32F746_PC8_FUNC_EVENTOUT 0x2810
+#define STM32F746_PC8_FUNC_ANALOG 0x2811
+
+#define STM32F746_PC9_FUNC_GPIO 0x2900
+#define STM32F746_PC9_FUNC_MCO2 0x2901
+#define STM32F746_PC9_FUNC_TIM3_CH4 0x2903
+#define STM32F746_PC9_FUNC_TIM8_CH4 0x2904
+#define STM32F746_PC9_FUNC_I2C3_SDA 0x2905
+#define STM32F746_PC9_FUNC_I2S_CKIN 0x2906
+#define STM32F746_PC9_FUNC_UART5_CTS 0x2908
+#define STM32F746_PC9_FUNC_QUADSPI_BK1_IO0 0x290a
+#define STM32F746_PC9_FUNC_SDMMC1_D1 0x290d
+#define STM32F746_PC9_FUNC_DCMI_D3 0x290e
+#define STM32F746_PC9_FUNC_EVENTOUT 0x2910
+#define STM32F746_PC9_FUNC_ANALOG 0x2911
+
+#define STM32F746_PC10_FUNC_GPIO 0x2a00
+#define STM32F746_PC10_FUNC_SPI3_SCK_I2S3_CK 0x2a07
+#define STM32F746_PC10_FUNC_USART3_TX 0x2a08
+#define STM32F746_PC10_FUNC_UART4_TX 0x2a09
+#define STM32F746_PC10_FUNC_QUADSPI_BK1_IO1 0x2a0a
+#define STM32F746_PC10_FUNC_SDMMC1_D2 0x2a0d
+#define STM32F746_PC10_FUNC_DCMI_D8 0x2a0e
+#define STM32F746_PC10_FUNC_LCD_R2 0x2a0f
+#define STM32F746_PC10_FUNC_EVENTOUT 0x2a10
+#define STM32F746_PC10_FUNC_ANALOG 0x2a11
+
+#define STM32F746_PC11_FUNC_GPIO 0x2b00
+#define STM32F746_PC11_FUNC_SPI3_MISO 0x2b07
+#define STM32F746_PC11_FUNC_USART3_RX 0x2b08
+#define STM32F746_PC11_FUNC_UART4_RX 0x2b09
+#define STM32F746_PC11_FUNC_QUADSPI_BK2_NCS 0x2b0a
+#define STM32F746_PC11_FUNC_SDMMC1_D3 0x2b0d
+#define STM32F746_PC11_FUNC_DCMI_D4 0x2b0e
+#define STM32F746_PC11_FUNC_EVENTOUT 0x2b10
+#define STM32F746_PC11_FUNC_ANALOG 0x2b11
+
+#define STM32F746_PC12_FUNC_GPIO 0x2c00
+#define STM32F746_PC12_FUNC_TRACED3 0x2c01
+#define STM32F746_PC12_FUNC_SPI3_MOSI_I2S3_SD 0x2c07
+#define STM32F746_PC12_FUNC_USART3_CK 0x2c08
+#define STM32F746_PC12_FUNC_UART5_TX 0x2c09
+#define STM32F746_PC12_FUNC_SDMMC1_CK 0x2c0d
+#define STM32F746_PC12_FUNC_DCMI_D9 0x2c0e
+#define STM32F746_PC12_FUNC_EVENTOUT 0x2c10
+#define STM32F746_PC12_FUNC_ANALOG 0x2c11
+
+#define STM32F746_PC13_FUNC_GPIO 0x2d00
+#define STM32F746_PC13_FUNC_EVENTOUT 0x2d10
+#define STM32F746_PC13_FUNC_ANALOG 0x2d11
+
+#define STM32F746_PC14_FUNC_GPIO 0x2e00
+#define STM32F746_PC14_FUNC_EVENTOUT 0x2e10
+#define STM32F746_PC14_FUNC_ANALOG 0x2e11
+
+#define STM32F746_PC15_FUNC_GPIO 0x2f00
+#define STM32F746_PC15_FUNC_EVENTOUT 0x2f10
+#define STM32F746_PC15_FUNC_ANALOG 0x2f11
+
+
+#define STM32F746_PD0_FUNC_GPIO 0x3000
+#define STM32F746_PD0_FUNC_CAN1_RX 0x300a
+#define STM32F746_PD0_FUNC_FMC_D2 0x300d
+#define STM32F746_PD0_FUNC_EVENTOUT 0x3010
+#define STM32F746_PD0_FUNC_ANALOG 0x3011
+
+#define STM32F746_PD1_FUNC_GPIO 0x3100
+#define STM32F746_PD1_FUNC_CAN1_TX 0x310a
+#define STM32F746_PD1_FUNC_FMC_D3 0x310d
+#define STM32F746_PD1_FUNC_EVENTOUT 0x3110
+#define STM32F746_PD1_FUNC_ANALOG 0x3111
+
+#define STM32F746_PD2_FUNC_GPIO 0x3200
+#define STM32F746_PD2_FUNC_TRACED2 0x3201
+#define STM32F746_PD2_FUNC_TIM3_ETR 0x3203
+#define STM32F746_PD2_FUNC_UART5_RX 0x3209
+#define STM32F746_PD2_FUNC_SDMMC1_CMD 0x320d
+#define STM32F746_PD2_FUNC_DCMI_D11 0x320e
+#define STM32F746_PD2_FUNC_EVENTOUT 0x3210
+#define STM32F746_PD2_FUNC_ANALOG 0x3211
+
+#define STM32F746_PD3_FUNC_GPIO 0x3300
+#define STM32F746_PD3_FUNC_SPI2_SCK_I2S2_CK 0x3306
+#define STM32F746_PD3_FUNC_USART2_CTS 0x3308
+#define STM32F746_PD3_FUNC_FMC_CLK 0x330d
+#define STM32F746_PD3_FUNC_DCMI_D5 0x330e
+#define STM32F746_PD3_FUNC_LCD_G7 0x330f
+#define STM32F746_PD3_FUNC_EVENTOUT 0x3310
+#define STM32F746_PD3_FUNC_ANALOG 0x3311
+
+#define STM32F746_PD4_FUNC_GPIO 0x3400
+#define STM32F746_PD4_FUNC_USART2_RTS 0x3408
+#define STM32F746_PD4_FUNC_FMC_NOE 0x340d
+#define STM32F746_PD4_FUNC_EVENTOUT 0x3410
+#define STM32F746_PD4_FUNC_ANALOG 0x3411
+
+#define STM32F746_PD5_FUNC_GPIO 0x3500
+#define STM32F746_PD5_FUNC_USART2_TX 0x3508
+#define STM32F746_PD5_FUNC_FMC_NWE 0x350d
+#define STM32F746_PD5_FUNC_EVENTOUT 0x3510
+#define STM32F746_PD5_FUNC_ANALOG 0x3511
+
+#define STM32F746_PD6_FUNC_GPIO 0x3600
+#define STM32F746_PD6_FUNC_SPI3_MOSI_I2S3_SD 0x3606
+#define STM32F746_PD6_FUNC_SAI1_SD_A 0x3607
+#define STM32F746_PD6_FUNC_USART2_RX 0x3608
+#define STM32F746_PD6_FUNC_FMC_NWAIT 0x360d
+#define STM32F746_PD6_FUNC_DCMI_D10 0x360e
+#define STM32F746_PD6_FUNC_LCD_B2 0x360f
+#define STM32F746_PD6_FUNC_EVENTOUT 0x3610
+#define STM32F746_PD6_FUNC_ANALOG 0x3611
+
+#define STM32F746_PD7_FUNC_GPIO 0x3700
+#define STM32F746_PD7_FUNC_USART2_CK 0x3708
+#define STM32F746_PD7_FUNC_SPDIFRX_IN0 0x3709
+#define STM32F746_PD7_FUNC_FMC_NE1 0x370d
+#define STM32F746_PD7_FUNC_EVENTOUT 0x3710
+#define STM32F746_PD7_FUNC_ANALOG 0x3711
+
+#define STM32F746_PD8_FUNC_GPIO 0x3800
+#define STM32F746_PD8_FUNC_USART3_TX 0x3808
+#define STM32F746_PD8_FUNC_SPDIFRX_IN1 0x3809
+#define STM32F746_PD8_FUNC_FMC_D13 0x380d
+#define STM32F746_PD8_FUNC_EVENTOUT 0x3810
+#define STM32F746_PD8_FUNC_ANALOG 0x3811
+
+#define STM32F746_PD9_FUNC_GPIO 0x3900
+#define STM32F746_PD9_FUNC_USART3_RX 0x3908
+#define STM32F746_PD9_FUNC_FMC_D14 0x390d
+#define STM32F746_PD9_FUNC_EVENTOUT 0x3910
+#define STM32F746_PD9_FUNC_ANALOG 0x3911
+
+#define STM32F746_PD10_FUNC_GPIO 0x3a00
+#define STM32F746_PD10_FUNC_USART3_CK 0x3a08
+#define STM32F746_PD10_FUNC_FMC_D15 0x3a0d
+#define STM32F746_PD10_FUNC_LCD_B3 0x3a0f
+#define STM32F746_PD10_FUNC_EVENTOUT 0x3a10
+#define STM32F746_PD10_FUNC_ANALOG 0x3a11
+
+#define STM32F746_PD11_FUNC_GPIO 0x3b00
+#define STM32F746_PD11_FUNC_I2C4_SMBA 0x3b05
+#define STM32F746_PD11_FUNC_USART3_CTS 0x3b08
+#define STM32F746_PD11_FUNC_QUADSPI_BK1_IO0 0x3b0a
+#define STM32F746_PD11_FUNC_SAI2_SD_A 0x3b0b
+#define STM32F746_PD11_FUNC_FMC_A16_FMC_CLE 0x3b0d
+#define STM32F746_PD11_FUNC_EVENTOUT 0x3b10
+#define STM32F746_PD11_FUNC_ANALOG 0x3b11
+
+#define STM32F746_PD12_FUNC_GPIO 0x3c00
+#define STM32F746_PD12_FUNC_TIM4_CH1 0x3c03
+#define STM32F746_PD12_FUNC_LPTIM1_IN1 0x3c04
+#define STM32F746_PD12_FUNC_I2C4_SCL 0x3c05
+#define STM32F746_PD12_FUNC_USART3_RTS 0x3c08
+#define STM32F746_PD12_FUNC_QUADSPI_BK1_IO1 0x3c0a
+#define STM32F746_PD12_FUNC_SAI2_FS_A 0x3c0b
+#define STM32F746_PD12_FUNC_FMC_A17_FMC_ALE 0x3c0d
+#define STM32F746_PD12_FUNC_EVENTOUT 0x3c10
+#define STM32F746_PD12_FUNC_ANALOG 0x3c11
+
+#define STM32F746_PD13_FUNC_GPIO 0x3d00
+#define STM32F746_PD13_FUNC_TIM4_CH2 0x3d03
+#define STM32F746_PD13_FUNC_LPTIM1_OUT 0x3d04
+#define STM32F746_PD13_FUNC_I2C4_SDA 0x3d05
+#define STM32F746_PD13_FUNC_QUADSPI_BK1_IO3 0x3d0a
+#define STM32F746_PD13_FUNC_SAI2_SCK_A 0x3d0b
+#define STM32F746_PD13_FUNC_FMC_A18 0x3d0d
+#define STM32F746_PD13_FUNC_EVENTOUT 0x3d10
+#define STM32F746_PD13_FUNC_ANALOG 0x3d11
+
+#define STM32F746_PD14_FUNC_GPIO 0x3e00
+#define STM32F746_PD14_FUNC_TIM4_CH3 0x3e03
+#define STM32F746_PD14_FUNC_UART8_CTS 0x3e09
+#define STM32F746_PD14_FUNC_FMC_D0 0x3e0d
+#define STM32F746_PD14_FUNC_EVENTOUT 0x3e10
+#define STM32F746_PD14_FUNC_ANALOG 0x3e11
+
+#define STM32F746_PD15_FUNC_GPIO 0x3f00
+#define STM32F746_PD15_FUNC_TIM4_CH4 0x3f03
+#define STM32F746_PD15_FUNC_UART8_RTS 0x3f09
+#define STM32F746_PD15_FUNC_FMC_D1 0x3f0d
+#define STM32F746_PD15_FUNC_EVENTOUT 0x3f10
+#define STM32F746_PD15_FUNC_ANALOG 0x3f11
+
+
+#define STM32F746_PE0_FUNC_GPIO 0x4000
+#define STM32F746_PE0_FUNC_TIM4_ETR 0x4003
+#define STM32F746_PE0_FUNC_LPTIM1_ETR 0x4004
+#define STM32F746_PE0_FUNC_UART8_RX 0x4009
+#define STM32F746_PE0_FUNC_SAI2_MCLK_A 0x400b
+#define STM32F746_PE0_FUNC_FMC_NBL0 0x400d
+#define STM32F746_PE0_FUNC_DCMI_D2 0x400e
+#define STM32F746_PE0_FUNC_EVENTOUT 0x4010
+#define STM32F746_PE0_FUNC_ANALOG 0x4011
+
+#define STM32F746_PE1_FUNC_GPIO 0x4100
+#define STM32F746_PE1_FUNC_LPTIM1_IN2 0x4104
+#define STM32F746_PE1_FUNC_UART8_TX 0x4109
+#define STM32F746_PE1_FUNC_FMC_NBL1 0x410d
+#define STM32F746_PE1_FUNC_DCMI_D3 0x410e
+#define STM32F746_PE1_FUNC_EVENTOUT 0x4110
+#define STM32F746_PE1_FUNC_ANALOG 0x4111
+
+#define STM32F746_PE2_FUNC_GPIO 0x4200
+#define STM32F746_PE2_FUNC_TRACECLK 0x4201
+#define STM32F746_PE2_FUNC_SPI4_SCK 0x4206
+#define STM32F746_PE2_FUNC_SAI1_MCLK_A 0x4207
+#define STM32F746_PE2_FUNC_QUADSPI_BK1_IO2 0x420a
+#define STM32F746_PE2_FUNC_ETH_MII_TXD3 0x420c
+#define STM32F746_PE2_FUNC_FMC_A23 0x420d
+#define STM32F746_PE2_FUNC_EVENTOUT 0x4210
+#define STM32F746_PE2_FUNC_ANALOG 0x4211
+
+#define STM32F746_PE3_FUNC_GPIO 0x4300
+#define STM32F746_PE3_FUNC_TRACED0 0x4301
+#define STM32F746_PE3_FUNC_SAI1_SD_B 0x4307
+#define STM32F746_PE3_FUNC_FMC_A19 0x430d
+#define STM32F746_PE3_FUNC_EVENTOUT 0x4310
+#define STM32F746_PE3_FUNC_ANALOG 0x4311
+
+#define STM32F746_PE4_FUNC_GPIO 0x4400
+#define STM32F746_PE4_FUNC_TRACED1 0x4401
+#define STM32F746_PE4_FUNC_SPI4_NSS 0x4406
+#define STM32F746_PE4_FUNC_SAI1_FS_A 0x4407
+#define STM32F746_PE4_FUNC_FMC_A20 0x440d
+#define STM32F746_PE4_FUNC_DCMI_D4 0x440e
+#define STM32F746_PE4_FUNC_LCD_B0 0x440f
+#define STM32F746_PE4_FUNC_EVENTOUT 0x4410
+#define STM32F746_PE4_FUNC_ANALOG 0x4411
+
+#define STM32F746_PE5_FUNC_GPIO 0x4500
+#define STM32F746_PE5_FUNC_TRACED2 0x4501
+#define STM32F746_PE5_FUNC_TIM9_CH1 0x4504
+#define STM32F746_PE5_FUNC_SPI4_MISO 0x4506
+#define STM32F746_PE5_FUNC_SAI1_SCK_A 0x4507
+#define STM32F746_PE5_FUNC_FMC_A21 0x450d
+#define STM32F746_PE5_FUNC_DCMI_D6 0x450e
+#define STM32F746_PE5_FUNC_LCD_G0 0x450f
+#define STM32F746_PE5_FUNC_EVENTOUT 0x4510
+#define STM32F746_PE5_FUNC_ANALOG 0x4511
+
+#define STM32F746_PE6_FUNC_GPIO 0x4600
+#define STM32F746_PE6_FUNC_TRACED3 0x4601
+#define STM32F746_PE6_FUNC_TIM1_BKIN2 0x4602
+#define STM32F746_PE6_FUNC_TIM9_CH2 0x4604
+#define STM32F746_PE6_FUNC_SPI4_MOSI 0x4606
+#define STM32F746_PE6_FUNC_SAI1_SD_A 0x4607
+#define STM32F746_PE6_FUNC_SAI2_MCLK_B 0x460b
+#define STM32F746_PE6_FUNC_FMC_A22 0x460d
+#define STM32F746_PE6_FUNC_DCMI_D7 0x460e
+#define STM32F746_PE6_FUNC_LCD_G1 0x460f
+#define STM32F746_PE6_FUNC_EVENTOUT 0x4610
+#define STM32F746_PE6_FUNC_ANALOG 0x4611
+
+#define STM32F746_PE7_FUNC_GPIO 0x4700
+#define STM32F746_PE7_FUNC_TIM1_ETR 0x4702
+#define STM32F746_PE7_FUNC_UART7_RX 0x4709
+#define STM32F746_PE7_FUNC_QUADSPI_BK2_IO0 0x470b
+#define STM32F746_PE7_FUNC_FMC_D4 0x470d
+#define STM32F746_PE7_FUNC_EVENTOUT 0x4710
+#define STM32F746_PE7_FUNC_ANALOG 0x4711
+
+#define STM32F746_PE8_FUNC_GPIO 0x4800
+#define STM32F746_PE8_FUNC_TIM1_CH1N 0x4802
+#define STM32F746_PE8_FUNC_UART7_TX 0x4809
+#define STM32F746_PE8_FUNC_QUADSPI_BK2_IO1 0x480b
+#define STM32F746_PE8_FUNC_FMC_D5 0x480d
+#define STM32F746_PE8_FUNC_EVENTOUT 0x4810
+#define STM32F746_PE8_FUNC_ANALOG 0x4811
+
+#define STM32F746_PE9_FUNC_GPIO 0x4900
+#define STM32F746_PE9_FUNC_TIM1_CH1 0x4902
+#define STM32F746_PE9_FUNC_UART7_RTS 0x4909
+#define STM32F746_PE9_FUNC_QUADSPI_BK2_IO2 0x490b
+#define STM32F746_PE9_FUNC_FMC_D6 0x490d
+#define STM32F746_PE9_FUNC_EVENTOUT 0x4910
+#define STM32F746_PE9_FUNC_ANALOG 0x4911
+
+#define STM32F746_PE10_FUNC_GPIO 0x4a00
+#define STM32F746_PE10_FUNC_TIM1_CH2N 0x4a02
+#define STM32F746_PE10_FUNC_UART7_CTS 0x4a09
+#define STM32F746_PE10_FUNC_QUADSPI_BK2_IO3 0x4a0b
+#define STM32F746_PE10_FUNC_FMC_D7 0x4a0d
+#define STM32F746_PE10_FUNC_EVENTOUT 0x4a10
+#define STM32F746_PE10_FUNC_ANALOG 0x4a11
+
+#define STM32F746_PE11_FUNC_GPIO 0x4b00
+#define STM32F746_PE11_FUNC_TIM1_CH2 0x4b02
+#define STM32F746_PE11_FUNC_SPI4_NSS 0x4b06
+#define STM32F746_PE11_FUNC_SAI2_SD_B 0x4b0b
+#define STM32F746_PE11_FUNC_FMC_D8 0x4b0d
+#define STM32F746_PE11_FUNC_LCD_G3 0x4b0f
+#define STM32F746_PE11_FUNC_EVENTOUT 0x4b10
+#define STM32F746_PE11_FUNC_ANALOG 0x4b11
+
+#define STM32F746_PE12_FUNC_GPIO 0x4c00
+#define STM32F746_PE12_FUNC_TIM1_CH3N 0x4c02
+#define STM32F746_PE12_FUNC_SPI4_SCK 0x4c06
+#define STM32F746_PE12_FUNC_SAI2_SCK_B 0x4c0b
+#define STM32F746_PE12_FUNC_FMC_D9 0x4c0d
+#define STM32F746_PE12_FUNC_LCD_B4 0x4c0f
+#define STM32F746_PE12_FUNC_EVENTOUT 0x4c10
+#define STM32F746_PE12_FUNC_ANALOG 0x4c11
+
+#define STM32F746_PE13_FUNC_GPIO 0x4d00
+#define STM32F746_PE13_FUNC_TIM1_CH3 0x4d02
+#define STM32F746_PE13_FUNC_SPI4_MISO 0x4d06
+#define STM32F746_PE13_FUNC_SAI2_FS_B 0x4d0b
+#define STM32F746_PE13_FUNC_FMC_D10 0x4d0d
+#define STM32F746_PE13_FUNC_LCD_DE 0x4d0f
+#define STM32F746_PE13_FUNC_EVENTOUT 0x4d10
+#define STM32F746_PE13_FUNC_ANALOG 0x4d11
+
+#define STM32F746_PE14_FUNC_GPIO 0x4e00
+#define STM32F746_PE14_FUNC_TIM1_CH4 0x4e02
+#define STM32F746_PE14_FUNC_SPI4_MOSI 0x4e06
+#define STM32F746_PE14_FUNC_SAI2_MCLK_B 0x4e0b
+#define STM32F746_PE14_FUNC_FMC_D11 0x4e0d
+#define STM32F746_PE14_FUNC_LCD_CLK 0x4e0f
+#define STM32F746_PE14_FUNC_EVENTOUT 0x4e10
+#define STM32F746_PE14_FUNC_ANALOG 0x4e11
+
+#define STM32F746_PE15_FUNC_GPIO 0x4f00
+#define STM32F746_PE15_FUNC_TIM1_BKIN 0x4f02
+#define STM32F746_PE15_FUNC_FMC_D12 0x4f0d
+#define STM32F746_PE15_FUNC_LCD_R7 0x4f0f
+#define STM32F746_PE15_FUNC_EVENTOUT 0x4f10
+#define STM32F746_PE15_FUNC_ANALOG 0x4f11
+
+
+#define STM32F746_PF0_FUNC_GPIO 0x5000
+#define STM32F746_PF0_FUNC_I2C2_SDA 0x5005
+#define STM32F746_PF0_FUNC_FMC_A0 0x500d
+#define STM32F746_PF0_FUNC_EVENTOUT 0x5010
+#define STM32F746_PF0_FUNC_ANALOG 0x5011
+
+#define STM32F746_PF1_FUNC_GPIO 0x5100
+#define STM32F746_PF1_FUNC_I2C2_SCL 0x5105
+#define STM32F746_PF1_FUNC_FMC_A1 0x510d
+#define STM32F746_PF1_FUNC_EVENTOUT 0x5110
+#define STM32F746_PF1_FUNC_ANALOG 0x5111
+
+#define STM32F746_PF2_FUNC_GPIO 0x5200
+#define STM32F746_PF2_FUNC_I2C2_SMBA 0x5205
+#define STM32F746_PF2_FUNC_FMC_A2 0x520d
+#define STM32F746_PF2_FUNC_EVENTOUT 0x5210
+#define STM32F746_PF2_FUNC_ANALOG 0x5211
+
+#define STM32F746_PF3_FUNC_GPIO 0x5300
+#define STM32F746_PF3_FUNC_FMC_A3 0x530d
+#define STM32F746_PF3_FUNC_EVENTOUT 0x5310
+#define STM32F746_PF3_FUNC_ANALOG 0x5311
+
+#define STM32F746_PF4_FUNC_GPIO 0x5400
+#define STM32F746_PF4_FUNC_FMC_A4 0x540d
+#define STM32F746_PF4_FUNC_EVENTOUT 0x5410
+#define STM32F746_PF4_FUNC_ANALOG 0x5411
+
+#define STM32F746_PF5_FUNC_GPIO 0x5500
+#define STM32F746_PF5_FUNC_FMC_A5 0x550d
+#define STM32F746_PF5_FUNC_EVENTOUT 0x5510
+#define STM32F746_PF5_FUNC_ANALOG 0x5511
+
+#define STM32F746_PF6_FUNC_GPIO 0x5600
+#define STM32F746_PF6_FUNC_TIM10_CH1 0x5604
+#define STM32F746_PF6_FUNC_SPI5_NSS 0x5606
+#define STM32F746_PF6_FUNC_SAI1_SD_B 0x5607
+#define STM32F746_PF6_FUNC_UART7_RX 0x5609
+#define STM32F746_PF6_FUNC_QUADSPI_BK1_IO3 0x560a
+#define STM32F746_PF6_FUNC_EVENTOUT 0x5610
+#define STM32F746_PF6_FUNC_ANALOG 0x5611
+
+#define STM32F746_PF7_FUNC_GPIO 0x5700
+#define STM32F746_PF7_FUNC_TIM11_CH1 0x5704
+#define STM32F746_PF7_FUNC_SPI5_SCK 0x5706
+#define STM32F746_PF7_FUNC_SAI1_MCLK_B 0x5707
+#define STM32F746_PF7_FUNC_UART7_TX 0x5709
+#define STM32F746_PF7_FUNC_QUADSPI_BK1_IO2 0x570a
+#define STM32F746_PF7_FUNC_EVENTOUT 0x5710
+#define STM32F746_PF7_FUNC_ANALOG 0x5711
+
+#define STM32F746_PF8_FUNC_GPIO 0x5800
+#define STM32F746_PF8_FUNC_SPI5_MISO 0x5806
+#define STM32F746_PF8_FUNC_SAI1_SCK_B 0x5807
+#define STM32F746_PF8_FUNC_UART7_RTS 0x5809
+#define STM32F746_PF8_FUNC_TIM13_CH1 0x580a
+#define STM32F746_PF8_FUNC_QUADSPI_BK1_IO0 0x580b
+#define STM32F746_PF8_FUNC_EVENTOUT 0x5810
+#define STM32F746_PF8_FUNC_ANALOG 0x5811
+
+#define STM32F746_PF9_FUNC_GPIO 0x5900
+#define STM32F746_PF9_FUNC_SPI5_MOSI 0x5906
+#define STM32F746_PF9_FUNC_SAI1_FS_B 0x5907
+#define STM32F746_PF9_FUNC_UART7_CTS 0x5909
+#define STM32F746_PF9_FUNC_TIM14_CH1 0x590a
+#define STM32F746_PF9_FUNC_QUADSPI_BK1_IO1 0x590b
+#define STM32F746_PF9_FUNC_EVENTOUT 0x5910
+#define STM32F746_PF9_FUNC_ANALOG 0x5911
+
+#define STM32F746_PF10_FUNC_GPIO 0x5a00
+#define STM32F746_PF10_FUNC_DCMI_D11 0x5a0e
+#define STM32F746_PF10_FUNC_LCD_DE 0x5a0f
+#define STM32F746_PF10_FUNC_EVENTOUT 0x5a10
+#define STM32F746_PF10_FUNC_ANALOG 0x5a11
+
+#define STM32F746_PF11_FUNC_GPIO 0x5b00
+#define STM32F746_PF11_FUNC_SPI5_MOSI 0x5b06
+#define STM32F746_PF11_FUNC_SAI2_SD_B 0x5b0b
+#define STM32F746_PF11_FUNC_FMC_SDNRAS 0x5b0d
+#define STM32F746_PF11_FUNC_DCMI_D12 0x5b0e
+#define STM32F746_PF11_FUNC_EVENTOUT 0x5b10
+#define STM32F746_PF11_FUNC_ANALOG 0x5b11
+
+#define STM32F746_PF12_FUNC_GPIO 0x5c00
+#define STM32F746_PF12_FUNC_FMC_A6 0x5c0d
+#define STM32F746_PF12_FUNC_EVENTOUT 0x5c10
+#define STM32F746_PF12_FUNC_ANALOG 0x5c11
+
+#define STM32F746_PF13_FUNC_GPIO 0x5d00
+#define STM32F746_PF13_FUNC_I2C4_SMBA 0x5d05
+#define STM32F746_PF13_FUNC_FMC_A7 0x5d0d
+#define STM32F746_PF13_FUNC_EVENTOUT 0x5d10
+#define STM32F746_PF13_FUNC_ANALOG 0x5d11
+
+#define STM32F746_PF14_FUNC_GPIO 0x5e00
+#define STM32F746_PF14_FUNC_I2C4_SCL 0x5e05
+#define STM32F746_PF14_FUNC_FMC_A8 0x5e0d
+#define STM32F746_PF14_FUNC_EVENTOUT 0x5e10
+#define STM32F746_PF14_FUNC_ANALOG 0x5e11
+
+#define STM32F746_PF15_FUNC_GPIO 0x5f00
+#define STM32F746_PF15_FUNC_I2C4_SDA 0x5f05
+#define STM32F746_PF15_FUNC_FMC_A9 0x5f0d
+#define STM32F746_PF15_FUNC_EVENTOUT 0x5f10
+#define STM32F746_PF15_FUNC_ANALOG 0x5f11
+
+
+#define STM32F746_PG0_FUNC_GPIO 0x6000
+#define STM32F746_PG0_FUNC_FMC_A10 0x600d
+#define STM32F746_PG0_FUNC_EVENTOUT 0x6010
+#define STM32F746_PG0_FUNC_ANALOG 0x6011
+
+#define STM32F746_PG1_FUNC_GPIO 0x6100
+#define STM32F746_PG1_FUNC_FMC_A11 0x610d
+#define STM32F746_PG1_FUNC_EVENTOUT 0x6110
+#define STM32F746_PG1_FUNC_ANALOG 0x6111
+
+#define STM32F746_PG2_FUNC_GPIO 0x6200
+#define STM32F746_PG2_FUNC_FMC_A12 0x620d
+#define STM32F746_PG2_FUNC_EVENTOUT 0x6210
+#define STM32F746_PG2_FUNC_ANALOG 0x6211
+
+#define STM32F746_PG3_FUNC_GPIO 0x6300
+#define STM32F746_PG3_FUNC_FMC_A13 0x630d
+#define STM32F746_PG3_FUNC_EVENTOUT 0x6310
+#define STM32F746_PG3_FUNC_ANALOG 0x6311
+
+#define STM32F746_PG4_FUNC_GPIO 0x6400
+#define STM32F746_PG4_FUNC_FMC_A14_FMC_BA0 0x640d
+#define STM32F746_PG4_FUNC_EVENTOUT 0x6410
+#define STM32F746_PG4_FUNC_ANALOG 0x6411
+
+#define STM32F746_PG5_FUNC_GPIO 0x6500
+#define STM32F746_PG5_FUNC_FMC_A15_FMC_BA1 0x650d
+#define STM32F746_PG5_FUNC_EVENTOUT 0x6510
+#define STM32F746_PG5_FUNC_ANALOG 0x6511
+
+#define STM32F746_PG6_FUNC_GPIO 0x6600
+#define STM32F746_PG6_FUNC_DCMI_D12 0x660e
+#define STM32F746_PG6_FUNC_LCD_R7 0x660f
+#define STM32F746_PG6_FUNC_EVENTOUT 0x6610
+#define STM32F746_PG6_FUNC_ANALOG 0x6611
+
+#define STM32F746_PG7_FUNC_GPIO 0x6700
+#define STM32F746_PG7_FUNC_USART6_CK 0x6709
+#define STM32F746_PG7_FUNC_FMC_INT 0x670d
+#define STM32F746_PG7_FUNC_DCMI_D13 0x670e
+#define STM32F746_PG7_FUNC_LCD_CLK 0x670f
+#define STM32F746_PG7_FUNC_EVENTOUT 0x6710
+#define STM32F746_PG7_FUNC_ANALOG 0x6711
+
+#define STM32F746_PG8_FUNC_GPIO 0x6800
+#define STM32F746_PG8_FUNC_SPI6_NSS 0x6806
+#define STM32F746_PG8_FUNC_SPDIFRX_IN2 0x6808
+#define STM32F746_PG8_FUNC_USART6_RTS 0x6809
+#define STM32F746_PG8_FUNC_ETH_PPS_OUT 0x680c
+#define STM32F746_PG8_FUNC_FMC_SDCLK 0x680d
+#define STM32F746_PG8_FUNC_EVENTOUT 0x6810
+#define STM32F746_PG8_FUNC_ANALOG 0x6811
+
+#define STM32F746_PG9_FUNC_GPIO 0x6900
+#define STM32F746_PG9_FUNC_SPDIFRX_IN3 0x6908
+#define STM32F746_PG9_FUNC_USART6_RX 0x6909
+#define STM32F746_PG9_FUNC_QUADSPI_BK2_IO2 0x690a
+#define STM32F746_PG9_FUNC_SAI2_FS_B 0x690b
+#define STM32F746_PG9_FUNC_FMC_NE2_FMC_NCE 0x690d
+#define STM32F746_PG9_FUNC_DCMI_VSYNC 0x690e
+#define STM32F746_PG9_FUNC_EVENTOUT 0x6910
+#define STM32F746_PG9_FUNC_ANALOG 0x6911
+
+#define STM32F746_PG10_FUNC_GPIO 0x6a00
+#define STM32F746_PG10_FUNC_LCD_G3 0x6a0a
+#define STM32F746_PG10_FUNC_SAI2_SD_B 0x6a0b
+#define STM32F746_PG10_FUNC_FMC_NE3 0x6a0d
+#define STM32F746_PG10_FUNC_DCMI_D2 0x6a0e
+#define STM32F746_PG10_FUNC_LCD_B2 0x6a0f
+#define STM32F746_PG10_FUNC_EVENTOUT 0x6a10
+#define STM32F746_PG10_FUNC_ANALOG 0x6a11
+
+#define STM32F746_PG11_FUNC_GPIO 0x6b00
+#define STM32F746_PG11_FUNC_SPDIFRX_IN0 0x6b08
+#define STM32F746_PG11_FUNC_ETH_MII_TX_EN_ETH_RMII_TX_EN 0x6b0c
+#define STM32F746_PG11_FUNC_DCMI_D3 0x6b0e
+#define STM32F746_PG11_FUNC_LCD_B3 0x6b0f
+#define STM32F746_PG11_FUNC_EVENTOUT 0x6b10
+#define STM32F746_PG11_FUNC_ANALOG 0x6b11
+
+#define STM32F746_PG12_FUNC_GPIO 0x6c00
+#define STM32F746_PG12_FUNC_LPTIM1_IN1 0x6c04
+#define STM32F746_PG12_FUNC_SPI6_MISO 0x6c06
+#define STM32F746_PG12_FUNC_SPDIFRX_IN1 0x6c08
+#define STM32F746_PG12_FUNC_USART6_RTS 0x6c09
+#define STM32F746_PG12_FUNC_LCD_B4 0x6c0a
+#define STM32F746_PG12_FUNC_FMC_NE4 0x6c0d
+#define STM32F746_PG12_FUNC_LCD_B1 0x6c0f
+#define STM32F746_PG12_FUNC_EVENTOUT 0x6c10
+#define STM32F746_PG12_FUNC_ANALOG 0x6c11
+
+#define STM32F746_PG13_FUNC_GPIO 0x6d00
+#define STM32F746_PG13_FUNC_TRACED0 0x6d01
+#define STM32F746_PG13_FUNC_LPTIM1_OUT 0x6d04
+#define STM32F746_PG13_FUNC_SPI6_SCK 0x6d06
+#define STM32F746_PG13_FUNC_USART6_CTS 0x6d09
+#define STM32F746_PG13_FUNC_ETH_MII_TXD0_ETH_RMII_TXD0 0x6d0c
+#define STM32F746_PG13_FUNC_FMC_A24 0x6d0d
+#define STM32F746_PG13_FUNC_LCD_R0 0x6d0f
+#define STM32F746_PG13_FUNC_EVENTOUT 0x6d10
+#define STM32F746_PG13_FUNC_ANALOG 0x6d11
+
+#define STM32F746_PG14_FUNC_GPIO 0x6e00
+#define STM32F746_PG14_FUNC_TRACED1 0x6e01
+#define STM32F746_PG14_FUNC_LPTIM1_ETR 0x6e04
+#define STM32F746_PG14_FUNC_SPI6_MOSI 0x6e06
+#define STM32F746_PG14_FUNC_USART6_TX 0x6e09
+#define STM32F746_PG14_FUNC_QUADSPI_BK2_IO3 0x6e0a
+#define STM32F746_PG14_FUNC_ETH_MII_TXD1_ETH_RMII_TXD1 0x6e0c
+#define STM32F746_PG14_FUNC_FMC_A25 0x6e0d
+#define STM32F746_PG14_FUNC_LCD_B0 0x6e0f
+#define STM32F746_PG14_FUNC_EVENTOUT 0x6e10
+#define STM32F746_PG14_FUNC_ANALOG 0x6e11
+
+#define STM32F746_PG15_FUNC_GPIO 0x6f00
+#define STM32F746_PG15_FUNC_USART6_CTS 0x6f09
+#define STM32F746_PG15_FUNC_FMC_SDNCAS 0x6f0d
+#define STM32F746_PG15_FUNC_DCMI_D13 0x6f0e
+#define STM32F746_PG15_FUNC_EVENTOUT 0x6f10
+#define STM32F746_PG15_FUNC_ANALOG 0x6f11
+
+
+#define STM32F746_PH0_FUNC_GPIO 0x7000
+#define STM32F746_PH0_FUNC_EVENTOUT 0x7010
+#define STM32F746_PH0_FUNC_ANALOG 0x7011
+
+#define STM32F746_PH1_FUNC_GPIO 0x7100
+#define STM32F746_PH1_FUNC_EVENTOUT 0x7110
+#define STM32F746_PH1_FUNC_ANALOG 0x7111
+
+#define STM32F746_PH2_FUNC_GPIO 0x7200
+#define STM32F746_PH2_FUNC_LPTIM1_IN2 0x7204
+#define STM32F746_PH2_FUNC_QUADSPI_BK2_IO0 0x720a
+#define STM32F746_PH2_FUNC_SAI2_SCK_B 0x720b
+#define STM32F746_PH2_FUNC_ETH_MII_CRS 0x720c
+#define STM32F746_PH2_FUNC_FMC_SDCKE0 0x720d
+#define STM32F746_PH2_FUNC_LCD_R0 0x720f
+#define STM32F746_PH2_FUNC_EVENTOUT 0x7210
+#define STM32F746_PH2_FUNC_ANALOG 0x7211
+
+#define STM32F746_PH3_FUNC_GPIO 0x7300
+#define STM32F746_PH3_FUNC_QUADSPI_BK2_IO1 0x730a
+#define STM32F746_PH3_FUNC_SAI2_MCLK_B 0x730b
+#define STM32F746_PH3_FUNC_ETH_MII_COL 0x730c
+#define STM32F746_PH3_FUNC_FMC_SDNE0 0x730d
+#define STM32F746_PH3_FUNC_LCD_R1 0x730f
+#define STM32F746_PH3_FUNC_EVENTOUT 0x7310
+#define STM32F746_PH3_FUNC_ANALOG 0x7311
+
+#define STM32F746_PH4_FUNC_GPIO 0x7400
+#define STM32F746_PH4_FUNC_I2C2_SCL 0x7405
+#define STM32F746_PH4_FUNC_OTG_HS_ULPI_NXT 0x740b
+#define STM32F746_PH4_FUNC_EVENTOUT 0x7410
+#define STM32F746_PH4_FUNC_ANALOG 0x7411
+
+#define STM32F746_PH5_FUNC_GPIO 0x7500
+#define STM32F746_PH5_FUNC_I2C2_SDA 0x7505
+#define STM32F746_PH5_FUNC_SPI5_NSS 0x7506
+#define STM32F746_PH5_FUNC_FMC_SDNWE 0x750d
+#define STM32F746_PH5_FUNC_EVENTOUT 0x7510
+#define STM32F746_PH5_FUNC_ANALOG 0x7511
+
+#define STM32F746_PH6_FUNC_GPIO 0x7600
+#define STM32F746_PH6_FUNC_I2C2_SMBA 0x7605
+#define STM32F746_PH6_FUNC_SPI5_SCK 0x7606
+#define STM32F746_PH6_FUNC_TIM12_CH1 0x760a
+#define STM32F746_PH6_FUNC_ETH_MII_RXD2 0x760c
+#define STM32F746_PH6_FUNC_FMC_SDNE1 0x760d
+#define STM32F746_PH6_FUNC_DCMI_D8 0x760e
+#define STM32F746_PH6_FUNC_EVENTOUT 0x7610
+#define STM32F746_PH6_FUNC_ANALOG 0x7611
+
+#define STM32F746_PH7_FUNC_GPIO 0x7700
+#define STM32F746_PH7_FUNC_I2C3_SCL 0x7705
+#define STM32F746_PH7_FUNC_SPI5_MISO 0x7706
+#define STM32F746_PH7_FUNC_ETH_MII_RXD3 0x770c
+#define STM32F746_PH7_FUNC_FMC_SDCKE1 0x770d
+#define STM32F746_PH7_FUNC_DCMI_D9 0x770e
+#define STM32F746_PH7_FUNC_EVENTOUT 0x7710
+#define STM32F746_PH7_FUNC_ANALOG 0x7711
+
+#define STM32F746_PH8_FUNC_GPIO 0x7800
+#define STM32F746_PH8_FUNC_I2C3_SDA 0x7805
+#define STM32F746_PH8_FUNC_FMC_D16 0x780d
+#define STM32F746_PH8_FUNC_DCMI_HSYNC 0x780e
+#define STM32F746_PH8_FUNC_LCD_R2 0x780f
+#define STM32F746_PH8_FUNC_EVENTOUT 0x7810
+#define STM32F746_PH8_FUNC_ANALOG 0x7811
+
+#define STM32F746_PH9_FUNC_GPIO 0x7900
+#define STM32F746_PH9_FUNC_I2C3_SMBA 0x7905
+#define STM32F746_PH9_FUNC_TIM12_CH2 0x790a
+#define STM32F746_PH9_FUNC_FMC_D17 0x790d
+#define STM32F746_PH9_FUNC_DCMI_D0 0x790e
+#define STM32F746_PH9_FUNC_LCD_R3 0x790f
+#define STM32F746_PH9_FUNC_EVENTOUT 0x7910
+#define STM32F746_PH9_FUNC_ANALOG 0x7911
+
+#define STM32F746_PH10_FUNC_GPIO 0x7a00
+#define STM32F746_PH10_FUNC_TIM5_CH1 0x7a03
+#define STM32F746_PH10_FUNC_I2C4_SMBA 0x7a05
+#define STM32F746_PH10_FUNC_FMC_D18 0x7a0d
+#define STM32F746_PH10_FUNC_DCMI_D1 0x7a0e
+#define STM32F746_PH10_FUNC_LCD_R4 0x7a0f
+#define STM32F746_PH10_FUNC_EVENTOUT 0x7a10
+#define STM32F746_PH10_FUNC_ANALOG 0x7a11
+
+#define STM32F746_PH11_FUNC_GPIO 0x7b00
+#define STM32F746_PH11_FUNC_TIM5_CH2 0x7b03
+#define STM32F746_PH11_FUNC_I2C4_SCL 0x7b05
+#define STM32F746_PH11_FUNC_FMC_D19 0x7b0d
+#define STM32F746_PH11_FUNC_DCMI_D2 0x7b0e
+#define STM32F746_PH11_FUNC_LCD_R5 0x7b0f
+#define STM32F746_PH11_FUNC_EVENTOUT 0x7b10
+#define STM32F746_PH11_FUNC_ANALOG 0x7b11
+
+#define STM32F746_PH12_FUNC_GPIO 0x7c00
+#define STM32F746_PH12_FUNC_TIM5_CH3 0x7c03
+#define STM32F746_PH12_FUNC_I2C4_SDA 0x7c05
+#define STM32F746_PH12_FUNC_FMC_D20 0x7c0d
+#define STM32F746_PH12_FUNC_DCMI_D3 0x7c0e
+#define STM32F746_PH12_FUNC_LCD_R6 0x7c0f
+#define STM32F746_PH12_FUNC_EVENTOUT 0x7c10
+#define STM32F746_PH12_FUNC_ANALOG 0x7c11
+
+#define STM32F746_PH13_FUNC_GPIO 0x7d00
+#define STM32F746_PH13_FUNC_TIM8_CH1N 0x7d04
+#define STM32F746_PH13_FUNC_CAN1_TX 0x7d0a
+#define STM32F746_PH13_FUNC_FMC_D21 0x7d0d
+#define STM32F746_PH13_FUNC_LCD_G2 0x7d0f
+#define STM32F746_PH13_FUNC_EVENTOUT 0x7d10
+#define STM32F746_PH13_FUNC_ANALOG 0x7d11
+
+#define STM32F746_PH14_FUNC_GPIO 0x7e00
+#define STM32F746_PH14_FUNC_TIM8_CH2N 0x7e04
+#define STM32F746_PH14_FUNC_FMC_D22 0x7e0d
+#define STM32F746_PH14_FUNC_DCMI_D4 0x7e0e
+#define STM32F746_PH14_FUNC_LCD_G3 0x7e0f
+#define STM32F746_PH14_FUNC_EVENTOUT 0x7e10
+#define STM32F746_PH14_FUNC_ANALOG 0x7e11
+
+#define STM32F746_PH15_FUNC_GPIO 0x7f00
+#define STM32F746_PH15_FUNC_TIM8_CH3N 0x7f04
+#define STM32F746_PH15_FUNC_FMC_D23 0x7f0d
+#define STM32F746_PH15_FUNC_DCMI_D11 0x7f0e
+#define STM32F746_PH15_FUNC_LCD_G4 0x7f0f
+#define STM32F746_PH15_FUNC_EVENTOUT 0x7f10
+#define STM32F746_PH15_FUNC_ANALOG 0x7f11
+
+
+#define STM32F746_PI0_FUNC_GPIO 0x8000
+#define STM32F746_PI0_FUNC_TIM5_CH4 0x8003
+#define STM32F746_PI0_FUNC_SPI2_NSS_I2S2_WS 0x8006
+#define STM32F746_PI0_FUNC_FMC_D24 0x800d
+#define STM32F746_PI0_FUNC_DCMI_D13 0x800e
+#define STM32F746_PI0_FUNC_LCD_G5 0x800f
+#define STM32F746_PI0_FUNC_EVENTOUT 0x8010
+#define STM32F746_PI0_FUNC_ANALOG 0x8011
+
+#define STM32F746_PI1_FUNC_GPIO 0x8100
+#define STM32F746_PI1_FUNC_TIM8_BKIN2 0x8104
+#define STM32F746_PI1_FUNC_SPI2_SCK_I2S2_CK 0x8106
+#define STM32F746_PI1_FUNC_FMC_D25 0x810d
+#define STM32F746_PI1_FUNC_DCMI_D8 0x810e
+#define STM32F746_PI1_FUNC_LCD_G6 0x810f
+#define STM32F746_PI1_FUNC_EVENTOUT 0x8110
+#define STM32F746_PI1_FUNC_ANALOG 0x8111
+
+#define STM32F746_PI2_FUNC_GPIO 0x8200
+#define STM32F746_PI2_FUNC_TIM8_CH4 0x8204
+#define STM32F746_PI2_FUNC_SPI2_MISO 0x8206
+#define STM32F746_PI2_FUNC_FMC_D26 0x820d
+#define STM32F746_PI2_FUNC_DCMI_D9 0x820e
+#define STM32F746_PI2_FUNC_LCD_G7 0x820f
+#define STM32F746_PI2_FUNC_EVENTOUT 0x8210
+#define STM32F746_PI2_FUNC_ANALOG 0x8211
+
+#define STM32F746_PI3_FUNC_GPIO 0x8300
+#define STM32F746_PI3_FUNC_TIM8_ETR 0x8304
+#define STM32F746_PI3_FUNC_SPI2_MOSI_I2S2_SD 0x8306
+#define STM32F746_PI3_FUNC_FMC_D27 0x830d
+#define STM32F746_PI3_FUNC_DCMI_D10 0x830e
+#define STM32F746_PI3_FUNC_EVENTOUT 0x8310
+#define STM32F746_PI3_FUNC_ANALOG 0x8311
+
+#define STM32F746_PI4_FUNC_GPIO 0x8400
+#define STM32F746_PI4_FUNC_TIM8_BKIN 0x8404
+#define STM32F746_PI4_FUNC_SAI2_MCLK_A 0x840b
+#define STM32F746_PI4_FUNC_FMC_NBL2 0x840d
+#define STM32F746_PI4_FUNC_DCMI_D5 0x840e
+#define STM32F746_PI4_FUNC_LCD_B4 0x840f
+#define STM32F746_PI4_FUNC_EVENTOUT 0x8410
+#define STM32F746_PI4_FUNC_ANALOG 0x8411
+
+#define STM32F746_PI5_FUNC_GPIO 0x8500
+#define STM32F746_PI5_FUNC_TIM8_CH1 0x8504
+#define STM32F746_PI5_FUNC_SAI2_SCK_A 0x850b
+#define STM32F746_PI5_FUNC_FMC_NBL3 0x850d
+#define STM32F746_PI5_FUNC_DCMI_VSYNC 0x850e
+#define STM32F746_PI5_FUNC_LCD_B5 0x850f
+#define STM32F746_PI5_FUNC_EVENTOUT 0x8510
+#define STM32F746_PI5_FUNC_ANALOG 0x8511
+
+#define STM32F746_PI6_FUNC_GPIO 0x8600
+#define STM32F746_PI6_FUNC_TIM8_CH2 0x8604
+#define STM32F746_PI6_FUNC_SAI2_SD_A 0x860b
+#define STM32F746_PI6_FUNC_FMC_D28 0x860d
+#define STM32F746_PI6_FUNC_DCMI_D6 0x860e
+#define STM32F746_PI6_FUNC_LCD_B6 0x860f
+#define STM32F746_PI6_FUNC_EVENTOUT 0x8610
+#define STM32F746_PI6_FUNC_ANALOG 0x8611
+
+#define STM32F746_PI7_FUNC_GPIO 0x8700
+#define STM32F746_PI7_FUNC_TIM8_CH3 0x8704
+#define STM32F746_PI7_FUNC_SAI2_FS_A 0x870b
+#define STM32F746_PI7_FUNC_FMC_D29 0x870d
+#define STM32F746_PI7_FUNC_DCMI_D7 0x870e
+#define STM32F746_PI7_FUNC_LCD_B7 0x870f
+#define STM32F746_PI7_FUNC_EVENTOUT 0x8710
+#define STM32F746_PI7_FUNC_ANALOG 0x8711
+
+#define STM32F746_PI8_FUNC_GPIO 0x8800
+#define STM32F746_PI8_FUNC_EVENTOUT 0x8810
+#define STM32F746_PI8_FUNC_ANALOG 0x8811
+
+#define STM32F746_PI9_FUNC_GPIO 0x8900
+#define STM32F746_PI9_FUNC_CAN1_RX 0x890a
+#define STM32F746_PI9_FUNC_FMC_D30 0x890d
+#define STM32F746_PI9_FUNC_LCD_VSYNC 0x890f
+#define STM32F746_PI9_FUNC_EVENTOUT 0x8910
+#define STM32F746_PI9_FUNC_ANALOG 0x8911
+
+#define STM32F746_PI10_FUNC_GPIO 0x8a00
+#define STM32F746_PI10_FUNC_ETH_MII_RX_ER 0x8a0c
+#define STM32F746_PI10_FUNC_FMC_D31 0x8a0d
+#define STM32F746_PI10_FUNC_LCD_HSYNC 0x8a0f
+#define STM32F746_PI10_FUNC_EVENTOUT 0x8a10
+#define STM32F746_PI10_FUNC_ANALOG 0x8a11
+
+#define STM32F746_PI11_FUNC_GPIO 0x8b00
+#define STM32F746_PI11_FUNC_OTG_HS_ULPI_DIR 0x8b0b
+#define STM32F746_PI11_FUNC_EVENTOUT 0x8b10
+#define STM32F746_PI11_FUNC_ANALOG 0x8b11
+
+#define STM32F746_PI12_FUNC_GPIO 0x8c00
+#define STM32F746_PI12_FUNC_LCD_HSYNC 0x8c0f
+#define STM32F746_PI12_FUNC_EVENTOUT 0x8c10
+#define STM32F746_PI12_FUNC_ANALOG 0x8c11
+
+#define STM32F746_PI13_FUNC_GPIO 0x8d00
+#define STM32F746_PI13_FUNC_LCD_VSYNC 0x8d0f
+#define STM32F746_PI13_FUNC_EVENTOUT 0x8d10
+#define STM32F746_PI13_FUNC_ANALOG 0x8d11
+
+#define STM32F746_PI14_FUNC_GPIO 0x8e00
+#define STM32F746_PI14_FUNC_LCD_CLK 0x8e0f
+#define STM32F746_PI14_FUNC_EVENTOUT 0x8e10
+#define STM32F746_PI14_FUNC_ANALOG 0x8e11
+
+#define STM32F746_PI15_FUNC_GPIO 0x8f00
+#define STM32F746_PI15_FUNC_LCD_R0 0x8f0f
+#define STM32F746_PI15_FUNC_EVENTOUT 0x8f10
+#define STM32F746_PI15_FUNC_ANALOG 0x8f11
+
+
+#define STM32F746_PJ0_FUNC_GPIO 0x9000
+#define STM32F746_PJ0_FUNC_LCD_R1 0x900f
+#define STM32F746_PJ0_FUNC_EVENTOUT 0x9010
+#define STM32F746_PJ0_FUNC_ANALOG 0x9011
+
+#define STM32F746_PJ1_FUNC_GPIO 0x9100
+#define STM32F746_PJ1_FUNC_LCD_R2 0x910f
+#define STM32F746_PJ1_FUNC_EVENTOUT 0x9110
+#define STM32F746_PJ1_FUNC_ANALOG 0x9111
+
+#define STM32F746_PJ2_FUNC_GPIO 0x9200
+#define STM32F746_PJ2_FUNC_LCD_R3 0x920f
+#define STM32F746_PJ2_FUNC_EVENTOUT 0x9210
+#define STM32F746_PJ2_FUNC_ANALOG 0x9211
+
+#define STM32F746_PJ3_FUNC_GPIO 0x9300
+#define STM32F746_PJ3_FUNC_LCD_R4 0x930f
+#define STM32F746_PJ3_FUNC_EVENTOUT 0x9310
+#define STM32F746_PJ3_FUNC_ANALOG 0x9311
+
+#define STM32F746_PJ4_FUNC_GPIO 0x9400
+#define STM32F746_PJ4_FUNC_LCD_R5 0x940f
+#define STM32F746_PJ4_FUNC_EVENTOUT 0x9410
+#define STM32F746_PJ4_FUNC_ANALOG 0x9411
+
+#define STM32F746_PJ5_FUNC_GPIO 0x9500
+#define STM32F746_PJ5_FUNC_LCD_R6 0x950f
+#define STM32F746_PJ5_FUNC_EVENTOUT 0x9510
+#define STM32F746_PJ5_FUNC_ANALOG 0x9511
+
+#define STM32F746_PJ6_FUNC_GPIO 0x9600
+#define STM32F746_PJ6_FUNC_LCD_R7 0x960f
+#define STM32F746_PJ6_FUNC_EVENTOUT 0x9610
+#define STM32F746_PJ6_FUNC_ANALOG 0x9611
+
+#define STM32F746_PJ7_FUNC_GPIO 0x9700
+#define STM32F746_PJ7_FUNC_LCD_G0 0x970f
+#define STM32F746_PJ7_FUNC_EVENTOUT 0x9710
+#define STM32F746_PJ7_FUNC_ANALOG 0x9711
+
+#define STM32F746_PJ8_FUNC_GPIO 0x9800
+#define STM32F746_PJ8_FUNC_LCD_G1 0x980f
+#define STM32F746_PJ8_FUNC_EVENTOUT 0x9810
+#define STM32F746_PJ8_FUNC_ANALOG 0x9811
+
+#define STM32F746_PJ9_FUNC_GPIO 0x9900
+#define STM32F746_PJ9_FUNC_LCD_G2 0x990f
+#define STM32F746_PJ9_FUNC_EVENTOUT 0x9910
+#define STM32F746_PJ9_FUNC_ANALOG 0x9911
+
+#define STM32F746_PJ10_FUNC_GPIO 0x9a00
+#define STM32F746_PJ10_FUNC_LCD_G3 0x9a0f
+#define STM32F746_PJ10_FUNC_EVENTOUT 0x9a10
+#define STM32F746_PJ10_FUNC_ANALOG 0x9a11
+
+#define STM32F746_PJ11_FUNC_GPIO 0x9b00
+#define STM32F746_PJ11_FUNC_LCD_G4 0x9b0f
+#define STM32F746_PJ11_FUNC_EVENTOUT 0x9b10
+#define STM32F746_PJ11_FUNC_ANALOG 0x9b11
+
+#define STM32F746_PJ12_FUNC_GPIO 0x9c00
+#define STM32F746_PJ12_FUNC_LCD_B0 0x9c0f
+#define STM32F746_PJ12_FUNC_EVENTOUT 0x9c10
+#define STM32F746_PJ12_FUNC_ANALOG 0x9c11
+
+#define STM32F746_PJ13_FUNC_GPIO 0x9d00
+#define STM32F746_PJ13_FUNC_LCD_B1 0x9d0f
+#define STM32F746_PJ13_FUNC_EVENTOUT 0x9d10
+#define STM32F746_PJ13_FUNC_ANALOG 0x9d11
+
+#define STM32F746_PJ14_FUNC_GPIO 0x9e00
+#define STM32F746_PJ14_FUNC_LCD_B2 0x9e0f
+#define STM32F746_PJ14_FUNC_EVENTOUT 0x9e10
+#define STM32F746_PJ14_FUNC_ANALOG 0x9e11
+
+#define STM32F746_PJ15_FUNC_GPIO 0x9f00
+#define STM32F746_PJ15_FUNC_LCD_B3 0x9f0f
+#define STM32F746_PJ15_FUNC_EVENTOUT 0x9f10
+#define STM32F746_PJ15_FUNC_ANALOG 0x9f11
+
+
+#define STM32F746_PK0_FUNC_GPIO 0xa000
+#define STM32F746_PK0_FUNC_LCD_G5 0xa00f
+#define STM32F746_PK0_FUNC_EVENTOUT 0xa010
+#define STM32F746_PK0_FUNC_ANALOG 0xa011
+
+#define STM32F746_PK1_FUNC_GPIO 0xa100
+#define STM32F746_PK1_FUNC_LCD_G6 0xa10f
+#define STM32F746_PK1_FUNC_EVENTOUT 0xa110
+#define STM32F746_PK1_FUNC_ANALOG 0xa111
+
+#define STM32F746_PK2_FUNC_GPIO 0xa200
+#define STM32F746_PK2_FUNC_LCD_G7 0xa20f
+#define STM32F746_PK2_FUNC_EVENTOUT 0xa210
+#define STM32F746_PK2_FUNC_ANALOG 0xa211
+
+#define STM32F746_PK3_FUNC_GPIO 0xa300
+#define STM32F746_PK3_FUNC_LCD_B4 0xa30f
+#define STM32F746_PK3_FUNC_EVENTOUT 0xa310
+#define STM32F746_PK3_FUNC_ANALOG 0xa311
+
+#define STM32F746_PK4_FUNC_GPIO 0xa400
+#define STM32F746_PK4_FUNC_LCD_B5 0xa40f
+#define STM32F746_PK4_FUNC_EVENTOUT 0xa410
+#define STM32F746_PK4_FUNC_ANALOG 0xa411
+
+#define STM32F746_PK5_FUNC_GPIO 0xa500
+#define STM32F746_PK5_FUNC_LCD_B6 0xa50f
+#define STM32F746_PK5_FUNC_EVENTOUT 0xa510
+#define STM32F746_PK5_FUNC_ANALOG 0xa511
+
+#define STM32F746_PK6_FUNC_GPIO 0xa600
+#define STM32F746_PK6_FUNC_LCD_B7 0xa60f
+#define STM32F746_PK6_FUNC_EVENTOUT 0xa610
+#define STM32F746_PK6_FUNC_ANALOG 0xa611
+
+#define STM32F746_PK7_FUNC_GPIO 0xa700
+#define STM32F746_PK7_FUNC_LCD_DE 0xa70f
+#define STM32F746_PK7_FUNC_EVENTOUT 0xa710
+#define STM32F746_PK7_FUNC_ANALOG 0xa711
+
+#endif /* _DT_BINDINGS_STM32F746_PINFUNC_H */
index c82794f20110420582d496ae478bc600f9400233..491a91717788591384230eb7d46a5332adf6298f 100644 (file)
@@ -197,7 +197,7 @@ static inline int wb_congested(struct bdi_writeback *wb, int cong_bits)
 }
 
 long congestion_wait(int sync, long timeout);
-long wait_iff_congested(struct zone *zone, int sync, long timeout);
+long wait_iff_congested(struct pglist_data *pgdat, int sync, long timeout);
 int pdflush_proc_obsolete(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp, loff_t *ppos);
 
index c96db9c22d1031496d01c0622a65ea0df8e2965a..adf33079771e740a93630305d229ef7d5578b814 100644 (file)
@@ -1665,7 +1665,7 @@ static inline bool integrity_req_gap_front_merge(struct request *req,
  */
 struct blk_dax_ctl {
        sector_t sector;
-       void __pmem *addr;
+       void *addr;
        long size;
        pfn_t pfn;
 };
@@ -1676,8 +1676,8 @@ struct block_device_operations {
        int (*rw_page)(struct block_device *, sector_t, struct page *, int rw);
        int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
-       long (*direct_access)(struct block_device *, sector_t, void __pmem **,
-                       pfn_t *, long);
+       long (*direct_access)(struct block_device *, sector_t, void **, pfn_t *,
+                       long);
        unsigned int (*check_events) (struct gendisk *disk,
                                      unsigned int clearing);
        /* ->media_changed() is DEPRECATED, use ->check_events() instead */
index 1a02dab16646ebc8917a71cc52b0a5491bd49b1c..d4e106b5dc277a387f159b40770b5f8f2c348038 100644 (file)
@@ -1,6 +1,18 @@
 #ifndef _LINUX_COMPACTION_H
 #define _LINUX_COMPACTION_H
 
+/*
+ * Determines how hard direct compaction should try to succeed.
+ * Lower value means higher priority, analogically to reclaim priority.
+ */
+enum compact_priority {
+       COMPACT_PRIO_SYNC_LIGHT,
+       MIN_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
+       DEF_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
+       COMPACT_PRIO_ASYNC,
+       INIT_COMPACT_PRIORITY = COMPACT_PRIO_ASYNC
+};
+
 /* Return values for compact_zone() and try_to_compact_pages() */
 /* When adding new states, please adjust include/trace/events/compaction.h */
 enum compact_result {
@@ -43,14 +55,6 @@ enum compact_result {
        COMPACT_PARTIAL,
 };
 
-/* Used to signal whether compaction detected need_sched() or lock contention */
-/* No contention detected */
-#define COMPACT_CONTENDED_NONE 0
-/* Either need_sched() was true or fatal signal pending */
-#define COMPACT_CONTENDED_SCHED        1
-/* Zone lock or lru_lock was contended in async compaction */
-#define COMPACT_CONTENDED_LOCK 2
-
 struct alloc_context; /* in mm/internal.h */
 
 #ifdef CONFIG_COMPACTION
@@ -64,9 +68,8 @@ extern int sysctl_compact_unevictable_allowed;
 
 extern int fragmentation_index(struct zone *zone, unsigned int order);
 extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
-                       unsigned int order,
-               unsigned int alloc_flags, const struct alloc_context *ac,
-               enum migrate_mode mode, int *contended);
+               unsigned int order, unsigned int alloc_flags,
+               const struct alloc_context *ac, enum compact_priority prio);
 extern void compact_pgdat(pg_data_t *pgdat, int order);
 extern void reset_isolation_suitable(pg_data_t *pgdat);
 extern enum compact_result compaction_suitable(struct zone *zone, int order,
@@ -151,14 +154,6 @@ extern void kcompactd_stop(int nid);
 extern void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx);
 
 #else
-static inline enum compact_result try_to_compact_pages(gfp_t gfp_mask,
-                       unsigned int order, int alloc_flags,
-                       const struct alloc_context *ac,
-                       enum migrate_mode mode, int *contended)
-{
-       return COMPACT_CONTINUE;
-}
-
 static inline void compact_pgdat(pg_data_t *pgdat, int order)
 {
 }
index 2e853b679a5da9c4061053b714801d7434728154..1bb95484272501bbc8d0603da489f56b4f87714a 100644 (file)
@@ -17,7 +17,6 @@
 # define __release(x)  __context__(x,-1)
 # define __cond_lock(x,c)      ((c) ? ({ __acquire(x); 1; }) : 0)
 # define __percpu      __attribute__((noderef, address_space(3)))
-# define __pmem                __attribute__((noderef, address_space(5)))
 #ifdef CONFIG_SPARSE_RCU_POINTER
 # define __rcu         __attribute__((noderef, address_space(4)))
 #else /* CONFIG_SPARSE_RCU_POINTER */
@@ -45,7 +44,6 @@ extern void __chk_io_ptr(const volatile void __iomem *);
 # define __cond_lock(x,c) (c)
 # define __percpu
 # define __rcu
-# define __pmem
 # define __private
 # define ACCESS_PRIVATE(p, member) ((p)->member)
 #endif /* __CHECKER__ */
index f53fa055021ab16bc182b739dcb665d1a70ce4a6..98044a8d1487d6c26e881071f3d83e0d730e6576 100644 (file)
@@ -133,14 +133,15 @@ struct dentry_operations {
        int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
+       int (*d_init)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_prune)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)(struct dentry *, char *, int);
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(struct dentry *, bool);
-       struct inode *(*d_select_inode)(struct dentry *, unsigned);
-       struct dentry *(*d_real)(struct dentry *, struct inode *);
+       struct dentry *(*d_real)(struct dentry *, const struct inode *,
+                                unsigned int);
 } ____cacheline_aligned;
 
 /*
@@ -206,10 +207,8 @@ struct dentry_operations {
 
 #define DCACHE_MAY_FREE                        0x00800000
 #define DCACHE_FALLTHRU                        0x01000000 /* Fall through to lower layer */
-#define DCACHE_OP_SELECT_INODE         0x02000000 /* Unioned entry: dcache op selects inode */
-
-#define DCACHE_ENCRYPTED_WITH_KEY      0x04000000 /* dir is encrypted with a valid key */
-#define DCACHE_OP_REAL                 0x08000000
+#define DCACHE_ENCRYPTED_WITH_KEY      0x02000000 /* dir is encrypted with a valid key */
+#define DCACHE_OP_REAL                 0x04000000
 
 #define DCACHE_PAR_LOOKUP              0x10000000 /* being looked up (with parent locked shared) */
 #define DCACHE_DENTRY_CURSOR           0x20000000
@@ -557,25 +556,27 @@ static inline struct dentry *d_backing_dentry(struct dentry *upper)
        return upper;
 }
 
-static inline struct dentry *d_real(struct dentry *dentry)
+/**
+ * d_real - Return the real dentry
+ * @dentry: the dentry to query
+ * @inode: inode to select the dentry from multiple layers (can be NULL)
+ * @flags: open flags to control copy-up behavior
+ *
+ * If dentry is on an union/overlay, then return the underlying, real dentry.
+ * Otherwise return the dentry itself.
+ *
+ * See also: Documentation/filesystems/vfs.txt
+ */
+static inline struct dentry *d_real(struct dentry *dentry,
+                                   const struct inode *inode,
+                                   unsigned int flags)
 {
        if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
-               return dentry->d_op->d_real(dentry, NULL);
+               return dentry->d_op->d_real(dentry, inode, flags);
        else
                return dentry;
 }
 
-static inline struct inode *vfs_select_inode(struct dentry *dentry,
-                                            unsigned open_flags)
-{
-       struct inode *inode = d_inode(dentry);
-
-       if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE))
-               inode = dentry->d_op->d_select_inode(dentry, open_flags);
-
-       return inode;
-}
-
 /**
  * d_real_inode - Return the real inode
  * @dentry: The dentry to query
@@ -585,7 +586,7 @@ static inline struct inode *vfs_select_inode(struct dentry *dentry,
  */
 static inline struct inode *d_real_inode(struct dentry *dentry)
 {
-       return d_backing_inode(d_real(dentry));
+       return d_backing_inode(d_real(dentry, NULL, 0));
 }
 
 
index b0db857f334b95630a4a05ff5b10a6c8383f0c6c..91acfce74a220010549536edde925ef9e3ec81c0 100644 (file)
@@ -131,7 +131,7 @@ typedef int (*dm_busy_fn) (struct dm_target *ti);
  * >= 0 : the number of bytes accessible at the address
  */
 typedef long (*dm_direct_access_fn) (struct dm_target *ti, sector_t sector,
-                                    void __pmem **kaddr, pfn_t *pfn, long size);
+                                    void **kaddr, pfn_t *pfn, long size);
 
 void dm_error(const char *message);
 
index f2a69f20926f442a8a0645f54f9e2d0c323881a1..f65a6801f60967346f7a47b4c49087966dcb2593 100644 (file)
@@ -457,7 +457,6 @@ struct block_device {
        struct inode *          bd_inode;       /* will die */
        struct super_block *    bd_super;
        struct mutex            bd_mutex;       /* open/close mutex */
-       struct list_head        bd_inodes;
        void *                  bd_claiming;
        void *                  bd_holder;
        int                     bd_holders;
@@ -1271,12 +1270,7 @@ static inline struct inode *file_inode(const struct file *f)
 
 static inline struct dentry *file_dentry(const struct file *file)
 {
-       struct dentry *dentry = file->f_path.dentry;
-
-       if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
-               return dentry->d_op->d_real(dentry, file_inode(file));
-       else
-               return dentry;
+       return d_real(file->f_path.dentry, file_inode(file), 0);
 }
 
 static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
@@ -2512,6 +2506,7 @@ extern int __filemap_fdatawrite_range(struct address_space *mapping,
                                loff_t start, loff_t end, int sync_mode);
 extern int filemap_fdatawrite_range(struct address_space *mapping,
                                loff_t start, loff_t end);
+extern int filemap_check_errors(struct address_space *mapping);
 
 extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end,
                           int datasync);
index 0141f257d67b6ae0f17890e11cef31f7ac6056f8..eed9e853a06f13c77506bc451262e83a99f1a332 100644 (file)
@@ -51,18 +51,6 @@ static inline int fsnotify_perm(struct file *file, int mask)
        return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
 }
 
-/*
- * fsnotify_d_move - dentry has been moved
- */
-static inline void fsnotify_d_move(struct dentry *dentry)
-{
-       /*
-        * On move we need to update dentry->d_flags to indicate if the new parent
-        * cares about events from this dentry.
-        */
-       __fsnotify_update_dcache_flags(dentry);
-}
-
 /*
  * fsnotify_link_count - inode's link count changed
  */
index 29f917517299fd0d4a61615d17a5045ce9826135..58205f33af023ee30cc9c18f52aa6f45fea08f59 100644 (file)
@@ -267,10 +267,8 @@ static inline int fsnotify_inode_watches_children(struct inode *inode)
  * Update the dentry with a flag indicating the interest of its parent to receive
  * filesystem events when those events happens to this dentry->d_inode.
  */
-static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
+static inline void fsnotify_update_flags(struct dentry *dentry)
 {
-       struct dentry *parent;
-
        assert_spin_locked(&dentry->d_lock);
 
        /*
@@ -280,21 +278,12 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
         * find our entry, so it will spin until we complete here, and update
         * us with the new state.
         */
-       parent = dentry->d_parent;
-       if (parent->d_inode && fsnotify_inode_watches_children(parent->d_inode))
+       if (fsnotify_inode_watches_children(dentry->d_parent->d_inode))
                dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED;
        else
                dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED;
 }
 
-/*
- * fsnotify_d_instantiate - instantiate a dentry for inode
- */
-static inline void __fsnotify_d_instantiate(struct dentry *dentry)
-{
-       __fsnotify_update_dcache_flags(dentry);
-}
-
 /* called from fsnotify listeners, such as fanotify or dnotify */
 
 /* create a new group */
@@ -386,10 +375,7 @@ static inline void __fsnotify_inode_delete(struct inode *inode)
 static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
 {}
 
-static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
-{}
-
-static inline void __fsnotify_d_instantiate(struct dentry *dentry)
+static inline void fsnotify_update_flags(struct dentry *dentry)
 {}
 
 static inline u32 fsnotify_get_cookie(void)
index 66a36a815f0a410f34c462fee1ec2a887a8a91ac..7d565afe35d2fa9ba25359c9bf879d8bde9893e7 100644 (file)
@@ -754,23 +754,27 @@ static inline void ftrace_init(void) { }
 
 /*
  * Structure that defines an entry function trace.
+ * It's already packed but the attribute "packed" is needed
+ * to remove extra padding at the end.
  */
 struct ftrace_graph_ent {
        unsigned long func; /* Current function */
        int depth;
-};
+} __packed;
 
 /*
  * Structure that defines a return function trace.
+ * It's already packed but the attribute "packed" is needed
+ * to remove extra padding at the end.
  */
 struct ftrace_graph_ret {
        unsigned long func; /* Current function */
-       unsigned long long calltime;
-       unsigned long long rettime;
        /* Number of functions that overran the depth limit for current task */
        unsigned long overrun;
+       unsigned long long calltime;
+       unsigned long long rettime;
        int depth;
-};
+} __packed;
 
 /* Type of the callback handlers for tracing function graph*/
 typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); /* return */
index c29e9d347bc697125e6eb02fe2ca0b033cbf83fa..f8041f9de31efc998916537889dd559b9fc375cb 100644 (file)
@@ -237,9 +237,11 @@ struct vm_area_struct;
  *   are expected to be movable via page reclaim or page migration. Typically,
  *   pages on the LRU would also be allocated with GFP_HIGHUSER_MOVABLE.
  *
- * GFP_TRANSHUGE is used for THP allocations. They are compound allocations
- *   that will fail quickly if memory is not available and will not wake
- *   kswapd on failure.
+ * GFP_TRANSHUGE and GFP_TRANSHUGE_LIGHT are used for THP allocations. They are
+ *   compound allocations that will generally fail quickly if memory is not
+ *   available and will not wake kswapd/kcompactd on failure. The _LIGHT
+ *   version does not attempt reclaim/compaction at all and is by default used
+ *   in page fault path, while the non-light is used by khugepaged.
  */
 #define GFP_ATOMIC     (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)
 #define GFP_KERNEL     (__GFP_RECLAIM | __GFP_IO | __GFP_FS)
@@ -254,9 +256,9 @@ struct vm_area_struct;
 #define GFP_DMA32      __GFP_DMA32
 #define GFP_HIGHUSER   (GFP_USER | __GFP_HIGHMEM)
 #define GFP_HIGHUSER_MOVABLE   (GFP_HIGHUSER | __GFP_MOVABLE)
-#define GFP_TRANSHUGE  ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
-                        __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN) & \
-                        ~__GFP_RECLAIM)
+#define GFP_TRANSHUGE_LIGHT    ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
+                        __GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM)
+#define GFP_TRANSHUGE  (GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)
 
 /* Convert GFP flags to their corresponding migrate type */
 #define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)
index 92ce91c03cd0e0165279c01e90e58f1f271f8a4b..6f14de45b5ce0807e01f7c5093d46ab5c9a546bb 100644 (file)
@@ -11,7 +11,7 @@ extern struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
                                          unsigned long addr,
                                          pmd_t *pmd,
                                          unsigned int flags);
-extern int madvise_free_huge_pmd(struct mmu_gather *tlb,
+extern bool madvise_free_huge_pmd(struct mmu_gather *tlb,
                        struct vm_area_struct *vma,
                        pmd_t *pmd, unsigned long addr, unsigned long next);
 extern int zap_huge_pmd(struct mmu_gather *tlb,
index ac4b3c46a84d1493d59e22e241c2cc7b9045ce27..c9cf374445d8ee748c1b2260a190b3998e9473a1 100644 (file)
@@ -77,6 +77,7 @@ void kasan_free_shadow(const struct vm_struct *vm);
 
 size_t ksize(const void *);
 static inline void kasan_unpoison_slab(const void *ptr) { ksize(ptr); }
+size_t kasan_metadata_size(struct kmem_cache *cache);
 
 #else /* CONFIG_KASAN */
 
@@ -121,6 +122,7 @@ static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
 static inline void kasan_free_shadow(const struct vm_struct *vm) {}
 
 static inline void kasan_unpoison_slab(const void *ptr) { }
+static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; }
 
 #endif /* CONFIG_KASAN */
 
index a19bcf9e762e1d4886e8bd5ed202e4485ba8cf3e..410decacff8fc7907622e99b9cbf7f3c32b1aefb 100644 (file)
@@ -177,7 +177,7 @@ extern int kdb_get_kbd_char(void);
 static inline
 int kdb_process_cpu(const struct task_struct *p)
 {
-       unsigned int cpu = task_thread_info(p)->cpu;
+       unsigned int cpu = task_cpu(p);
        if (cpu > num_possible_cpus())
                cpu = 0;
        return cpu;
index 0c3c30cbbea54431cff38dc01f21ba3d831674d4..b519e137b9b7d98ab44aa1409510ad35e841c10f 100644 (file)
@@ -52,6 +52,7 @@ typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
 
 struct nd_namespace_label;
 struct nvdimm_drvdata;
+
 struct nd_mapping {
        struct nvdimm *nvdimm;
        struct nd_namespace_label **labels;
@@ -69,6 +70,7 @@ struct nd_mapping {
 struct nvdimm_bus_descriptor {
        const struct attribute_group **attr_groups;
        unsigned long cmd_mask;
+       struct module *module;
        char *provider_name;
        ndctl_fn ndctl;
        int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc);
@@ -99,13 +101,21 @@ struct nd_region_desc {
        unsigned long flags;
 };
 
+struct device;
+void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset,
+               size_t size, unsigned long flags);
+static inline void __iomem *devm_nvdimm_ioremap(struct device *dev,
+               resource_size_t offset, size_t size)
+{
+       return (void __iomem *) devm_nvdimm_memremap(dev, offset, size, 0);
+}
+
 struct nvdimm_bus;
 struct module;
 struct device;
 struct nd_blk_region;
 struct nd_blk_region_desc {
        int (*enable)(struct nvdimm_bus *nvdimm_bus, struct device *dev);
-       void (*disable)(struct nvdimm_bus *nvdimm_bus, struct device *dev);
        int (*do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
                        void *iobuf, u64 len, int rw);
        struct nd_region_desc ndr_desc;
@@ -119,22 +129,22 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
 }
 
 int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length);
-struct nvdimm_bus *__nvdimm_bus_register(struct device *parent,
-               struct nvdimm_bus_descriptor *nfit_desc, struct module *module);
-#define nvdimm_bus_register(parent, desc) \
-       __nvdimm_bus_register(parent, desc, THIS_MODULE)
+struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
+               struct nvdimm_bus_descriptor *nfit_desc);
 void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus);
 struct nvdimm_bus *to_nvdimm_bus(struct device *dev);
 struct nvdimm *to_nvdimm(struct device *dev);
 struct nd_region *to_nd_region(struct device *dev);
 struct nd_blk_region *to_nd_blk_region(struct device *dev);
 struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus);
+struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus);
 const char *nvdimm_name(struct nvdimm *nvdimm);
 unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm);
 void *nvdimm_provider_data(struct nvdimm *nvdimm);
 struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
                const struct attribute_group **groups, unsigned long flags,
-               unsigned long cmd_mask);
+               unsigned long cmd_mask, int num_flush,
+               struct resource *flush_wpq);
 const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);
 const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
 u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
@@ -156,4 +166,6 @@ struct nvdimm *nd_blk_region_to_dimm(struct nd_blk_region *ndbr);
 unsigned int nd_region_acquire_lane(struct nd_region *nd_region);
 void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane);
 u64 nd_fletcher64(void *addr, size_t len, bool le);
+void nvdimm_flush(struct nd_region *nd_region);
+int nvdimm_has_flush(struct nd_region *nd_region);
 #endif /* __LIBNVDIMM_H__ */
index 6c14b6179727010f15c8ea3fcab036a32bfc84ad..2925da23505d1dd7939060b471e4efc266cacaef 100644 (file)
@@ -332,6 +332,7 @@ phys_addr_t memblock_mem_size(unsigned long limit_pfn);
 phys_addr_t memblock_start_of_DRAM(void);
 phys_addr_t memblock_end_of_DRAM(void);
 void memblock_enforce_memory_limit(phys_addr_t memory_limit);
+void memblock_mem_limit_remove_map(phys_addr_t limit);
 bool memblock_is_memory(phys_addr_t addr);
 int memblock_is_map_memory(phys_addr_t addr);
 int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
index 71aff733a4970879aee17c81b26444328e198dae..5d8ca6e02e396bd1eb5a00118ecf6141c43900ac 100644 (file)
@@ -52,7 +52,7 @@ enum mem_cgroup_stat_index {
        MEM_CGROUP_STAT_SWAP,           /* # of pages, swapped out */
        MEM_CGROUP_STAT_NSTATS,
        /* default hierarchy stats */
-       MEMCG_KERNEL_STACK = MEM_CGROUP_STAT_NSTATS,
+       MEMCG_KERNEL_STACK_KB = MEM_CGROUP_STAT_NSTATS,
        MEMCG_SLAB_RECLAIMABLE,
        MEMCG_SLAB_UNRECLAIMABLE,
        MEMCG_SOCK,
@@ -60,7 +60,7 @@ enum mem_cgroup_stat_index {
 };
 
 struct mem_cgroup_reclaim_cookie {
-       struct zone *zone;
+       pg_data_t *pgdat;
        int priority;
        unsigned int generation;
 };
@@ -118,7 +118,7 @@ struct mem_cgroup_reclaim_iter {
 /*
  * per-zone information in memory controller.
  */
-struct mem_cgroup_per_zone {
+struct mem_cgroup_per_node {
        struct lruvec           lruvec;
        unsigned long           lru_size[NR_LRU_LISTS];
 
@@ -132,10 +132,6 @@ struct mem_cgroup_per_zone {
                                                /* use container_of        */
 };
 
-struct mem_cgroup_per_node {
-       struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES];
-};
-
 struct mem_cgroup_threshold {
        struct eventfd_ctx *eventfd;
        unsigned long threshold;
@@ -314,8 +310,46 @@ void mem_cgroup_uncharge_list(struct list_head *page_list);
 
 void mem_cgroup_migrate(struct page *oldpage, struct page *newpage);
 
-struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *);
-struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *);
+static struct mem_cgroup_per_node *
+mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid)
+{
+       return memcg->nodeinfo[nid];
+}
+
+/**
+ * mem_cgroup_lruvec - get the lru list vector for a node or a memcg zone
+ * @node: node of the wanted lruvec
+ * @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.
+ */
+static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat,
+                               struct mem_cgroup *memcg)
+{
+       struct mem_cgroup_per_node *mz;
+       struct lruvec *lruvec;
+
+       if (mem_cgroup_disabled()) {
+               lruvec = node_lruvec(pgdat);
+               goto out;
+       }
+
+       mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id);
+       lruvec = &mz->lruvec;
+out:
+       /*
+        * Since a node can be onlined after the mem_cgroup was created,
+        * we have to be prepared to initialize lruvec->pgdat here;
+        * and if offlined then reonlined, we need to reinitialize it.
+        */
+       if (unlikely(lruvec->pgdat != pgdat))
+               lruvec->pgdat = pgdat;
+       return lruvec;
+}
+
+struct lruvec *mem_cgroup_page_lruvec(struct page *, struct pglist_data *);
 
 bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg);
 struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
@@ -404,9 +438,9 @@ unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
 static inline
 unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
 {
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
 
-       mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec);
+       mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
        return mz->lru_size[lru];
 }
 
@@ -477,7 +511,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
        mem_cgroup_update_page_stat(page, idx, -1);
 }
 
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
+unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                                gfp_t gfp_mask,
                                                unsigned long *total_scanned);
 
@@ -568,16 +602,16 @@ static inline void mem_cgroup_migrate(struct page *old, struct page *new)
 {
 }
 
-static inline struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
-                                                   struct mem_cgroup *memcg)
+static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat,
+                               struct mem_cgroup *memcg)
 {
-       return &zone->lruvec;
+       return node_lruvec(pgdat);
 }
 
 static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page,
-                                                   struct zone *zone)
+                                                   struct pglist_data *pgdat)
 {
-       return &zone->lruvec;
+       return &pgdat->lruvec;
 }
 
 static inline bool mm_match_cgroup(struct mm_struct *mm,
@@ -681,7 +715,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
 }
 
 static inline
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
+unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                            gfp_t gfp_mask,
                                            unsigned long *total_scanned)
 {
index bcaa634139a996160247738d94107ce08485e185..93416196ba64f6b4747ad9f37aaf5a913ff3ac29 100644 (file)
@@ -26,7 +26,7 @@ struct vmem_altmap {
 unsigned long vmem_altmap_offset(struct vmem_altmap *altmap);
 void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns);
 
-#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_ZONE_DEVICE)
+#ifdef CONFIG_ZONE_DEVICE
 struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start);
 #else
 static inline struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
index 192c1bbe5fcddac7d386b95cf7537843e6942cd5..08ed53eeedd5fd203a961310367ef8a206c76696 100644 (file)
@@ -933,6 +933,11 @@ static inline struct zone *page_zone(const struct page *page)
        return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)];
 }
 
+static inline pg_data_t *page_pgdat(const struct page *page)
+{
+       return NODE_DATA(page_to_nid(page));
+}
+
 #ifdef SECTION_IN_PAGE_FLAGS
 static inline void set_page_section(struct page *page, unsigned long section)
 {
@@ -973,11 +978,21 @@ static inline struct mem_cgroup *page_memcg(struct page *page)
 {
        return page->mem_cgroup;
 }
+static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
+{
+       WARN_ON_ONCE(!rcu_read_lock_held());
+       return READ_ONCE(page->mem_cgroup);
+}
 #else
 static inline struct mem_cgroup *page_memcg(struct page *page)
 {
        return NULL;
 }
+static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
+{
+       WARN_ON_ONCE(!rcu_read_lock_held());
+       return NULL;
+}
 #endif
 
 /*
@@ -2284,6 +2299,8 @@ static inline int in_gate_area(struct mm_struct *mm, unsigned long addr)
 }
 #endif /* __HAVE_ARCH_GATE_AREA */
 
+extern bool process_shares_mm(struct task_struct *p, struct mm_struct *mm);
+
 #ifdef CONFIG_SYSCTL
 extern int sysctl_drop_caches;
 int drop_caches_sysctl_handler(struct ctl_table *, int,
index 5bd29ba4f174f531d1921f8ea2616b7727b069aa..71613e8a720f99b6870f1e3f8957d2761a6ac1a0 100644 (file)
@@ -23,25 +23,30 @@ static inline int page_is_file_cache(struct page *page)
 }
 
 static __always_inline void __update_lru_size(struct lruvec *lruvec,
-                               enum lru_list lru, int nr_pages)
+                               enum lru_list lru, enum zone_type zid,
+                               int nr_pages)
 {
-       __mod_zone_page_state(lruvec_zone(lruvec), NR_LRU_BASE + lru, nr_pages);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
+
+       __mod_node_page_state(pgdat, NR_LRU_BASE + lru, nr_pages);
+       __mod_zone_page_state(&pgdat->node_zones[zid],
+                               NR_ZONE_LRU_BASE + lru, nr_pages);
 }
 
 static __always_inline void update_lru_size(struct lruvec *lruvec,
-                               enum lru_list lru, int nr_pages)
+                               enum lru_list lru, enum zone_type zid,
+                               int nr_pages)
 {
+       __update_lru_size(lruvec, lru, zid, nr_pages);
 #ifdef CONFIG_MEMCG
        mem_cgroup_update_lru_size(lruvec, lru, nr_pages);
-#else
-       __update_lru_size(lruvec, lru, nr_pages);
 #endif
 }
 
 static __always_inline void add_page_to_lru_list(struct page *page,
                                struct lruvec *lruvec, enum lru_list lru)
 {
-       update_lru_size(lruvec, lru, hpage_nr_pages(page));
+       update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page));
        list_add(&page->lru, &lruvec->lists[lru]);
 }
 
@@ -49,7 +54,7 @@ static __always_inline void del_page_from_lru_list(struct page *page,
                                struct lruvec *lruvec, enum lru_list lru)
 {
        list_del(&page->lru);
-       update_lru_size(lruvec, lru, -hpage_nr_pages(page));
+       update_lru_size(lruvec, lru, page_zonenum(page), -hpage_nr_pages(page));
 }
 
 /**
index 79472b22d23f0866cd251e3e5e47c902522994e0..903200f4ec41ce03c50c15bfa079d5a01f903afa 100644 (file)
@@ -118,7 +118,7 @@ struct page {
         */
        union {
                struct list_head lru;   /* Pageout list, eg. active_list
-                                        * protected by zone->lru_lock !
+                                        * protected by zone_lru_lock !
                                         * Can be used as a generic list
                                         * by the page owner.
                                         */
index 19425e988bdc1a6b2d9fc75a71064a9a57be68b7..f2e4e90621ec25c237703bc5b1ecba814d1afce9 100644 (file)
@@ -93,7 +93,7 @@ struct free_area {
 struct pglist_data;
 
 /*
- * zone->lock and zone->lru_lock are two of the hottest locks in the kernel.
+ * zone->lock and the zone lru_lock are two of the hottest locks in the kernel.
  * So add a wild amount of padding here to ensure that they fall into separate
  * cachelines.  There are very few zone structures in the machine, so space
  * consumption is not a concern here.
@@ -110,36 +110,20 @@ struct zone_padding {
 enum zone_stat_item {
        /* First 128 byte cacheline (assuming 64 bit words) */
        NR_FREE_PAGES,
-       NR_ALLOC_BATCH,
-       NR_LRU_BASE,
-       NR_INACTIVE_ANON = NR_LRU_BASE, /* must match order of LRU_[IN]ACTIVE */
-       NR_ACTIVE_ANON,         /*  "     "     "   "       "         */
-       NR_INACTIVE_FILE,       /*  "     "     "   "       "         */
-       NR_ACTIVE_FILE,         /*  "     "     "   "       "         */
-       NR_UNEVICTABLE,         /*  "     "     "   "       "         */
+       NR_ZONE_LRU_BASE, /* Used only for compaction and reclaim retry */
+       NR_ZONE_INACTIVE_ANON = NR_ZONE_LRU_BASE,
+       NR_ZONE_ACTIVE_ANON,
+       NR_ZONE_INACTIVE_FILE,
+       NR_ZONE_ACTIVE_FILE,
+       NR_ZONE_UNEVICTABLE,
+       NR_ZONE_WRITE_PENDING,  /* Count of dirty, writeback and unstable pages */
        NR_MLOCK,               /* mlock()ed pages found and moved off LRU */
-       NR_ANON_PAGES,  /* Mapped anonymous pages */
-       NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
-                          only modified from process context */
-       NR_FILE_PAGES,
-       NR_FILE_DIRTY,
-       NR_WRITEBACK,
        NR_SLAB_RECLAIMABLE,
        NR_SLAB_UNRECLAIMABLE,
        NR_PAGETABLE,           /* used for pagetables */
-       NR_KERNEL_STACK,
+       NR_KERNEL_STACK_KB,     /* measured in KiB */
        /* Second 128 byte cacheline */
-       NR_UNSTABLE_NFS,        /* NFS unstable pages */
        NR_BOUNCE,
-       NR_VMSCAN_WRITE,
-       NR_VMSCAN_IMMEDIATE,    /* Prioritise for reclaim when writeback ends */
-       NR_WRITEBACK_TEMP,      /* Writeback using temporary buffers */
-       NR_ISOLATED_ANON,       /* Temporary isolated pages from anon lru */
-       NR_ISOLATED_FILE,       /* Temporary isolated pages from file lru */
-       NR_SHMEM,               /* shmem pages (included tmpfs/GEM pages) */
-       NR_DIRTIED,             /* page dirtyings since bootup */
-       NR_WRITTEN,             /* page writings since bootup */
-       NR_PAGES_SCANNED,       /* pages scanned since last reclaim */
 #if IS_ENABLED(CONFIG_ZSMALLOC)
        NR_ZSPAGES,             /* allocated in zsmalloc */
 #endif
@@ -151,14 +135,40 @@ enum zone_stat_item {
        NUMA_LOCAL,             /* allocation from local node */
        NUMA_OTHER,             /* allocation from other node */
 #endif
+       NR_FREE_CMA_PAGES,
+       NR_VM_ZONE_STAT_ITEMS };
+
+enum node_stat_item {
+       NR_LRU_BASE,
+       NR_INACTIVE_ANON = NR_LRU_BASE, /* must match order of LRU_[IN]ACTIVE */
+       NR_ACTIVE_ANON,         /*  "     "     "   "       "         */
+       NR_INACTIVE_FILE,       /*  "     "     "   "       "         */
+       NR_ACTIVE_FILE,         /*  "     "     "   "       "         */
+       NR_UNEVICTABLE,         /*  "     "     "   "       "         */
+       NR_ISOLATED_ANON,       /* Temporary isolated pages from anon lru */
+       NR_ISOLATED_FILE,       /* Temporary isolated pages from file lru */
+       NR_PAGES_SCANNED,       /* pages scanned since last reclaim */
        WORKINGSET_REFAULT,
        WORKINGSET_ACTIVATE,
        WORKINGSET_NODERECLAIM,
-       NR_ANON_THPS,
+       NR_ANON_MAPPED, /* Mapped anonymous pages */
+       NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
+                          only modified from process context */
+       NR_FILE_PAGES,
+       NR_FILE_DIRTY,
+       NR_WRITEBACK,
+       NR_WRITEBACK_TEMP,      /* Writeback using temporary buffers */
+       NR_SHMEM,               /* shmem pages (included tmpfs/GEM pages) */
        NR_SHMEM_THPS,
        NR_SHMEM_PMDMAPPED,
-       NR_FREE_CMA_PAGES,
-       NR_VM_ZONE_STAT_ITEMS };
+       NR_ANON_THPS,
+       NR_UNSTABLE_NFS,        /* NFS unstable pages */
+       NR_VMSCAN_WRITE,
+       NR_VMSCAN_IMMEDIATE,    /* Prioritise for reclaim when writeback ends */
+       NR_DIRTIED,             /* page dirtyings since bootup */
+       NR_WRITTEN,             /* page writings since bootup */
+       NR_VM_NODE_STAT_ITEMS
+};
 
 /*
  * We do arithmetic on the LRU lists in various places in the code,
@@ -215,7 +225,7 @@ struct lruvec {
        /* Evictions & activations on the inactive file list */
        atomic_long_t                   inactive_age;
 #ifdef CONFIG_MEMCG
-       struct zone                     *zone;
+       struct pglist_data *pgdat;
 #endif
 };
 
@@ -267,6 +277,11 @@ struct per_cpu_pageset {
 #endif
 };
 
+struct per_cpu_nodestat {
+       s8 stat_threshold;
+       s8 vm_node_stat_diff[NR_VM_NODE_STAT_ITEMS];
+};
+
 #endif /* !__GENERATING_BOUNDS.H */
 
 enum zone_type {
@@ -348,22 +363,9 @@ struct zone {
 #ifdef CONFIG_NUMA
        int node;
 #endif
-
-       /*
-        * The target ratio of ACTIVE_ANON to INACTIVE_ANON pages on
-        * this zone's LRU.  Maintained by the pageout code.
-        */
-       unsigned int inactive_ratio;
-
        struct pglist_data      *zone_pgdat;
        struct per_cpu_pageset __percpu *pageset;
 
-       /*
-        * This is a per-zone reserve of pages that are not available
-        * to userspace allocations.
-        */
-       unsigned long           totalreserve_pages;
-
 #ifndef CONFIG_SPARSEMEM
        /*
         * Flags for a pageblock_nr_pages block. See pageblock-flags.h.
@@ -372,14 +374,6 @@ struct zone {
        unsigned long           *pageblock_flags;
 #endif /* CONFIG_SPARSEMEM */
 
-#ifdef CONFIG_NUMA
-       /*
-        * zone reclaim becomes active if more unmapped pages exist.
-        */
-       unsigned long           min_unmapped_pages;
-       unsigned long           min_slab_pages;
-#endif /* CONFIG_NUMA */
-
        /* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
        unsigned long           zone_start_pfn;
 
@@ -472,24 +466,21 @@ struct zone {
        unsigned long           wait_table_hash_nr_entries;
        unsigned long           wait_table_bits;
 
+       /* Write-intensive fields used from the page allocator */
        ZONE_PADDING(_pad1_)
+
        /* free areas of different sizes */
        struct free_area        free_area[MAX_ORDER];
 
        /* zone flags, see below */
        unsigned long           flags;
 
-       /* Write-intensive fields used from the page allocator */
+       /* Primarily protects free_area */
        spinlock_t              lock;
 
+       /* Write-intensive fields used by compaction and vmstats. */
        ZONE_PADDING(_pad2_)
 
-       /* Write-intensive fields used by page reclaim */
-
-       /* Fields commonly accessed by the page reclaim scanner */
-       spinlock_t              lru_lock;
-       struct lruvec           lruvec;
-
        /*
         * When free pages are below this point, additional steps are taken
         * when reading the number of free pages to avoid per-cpu counter
@@ -527,19 +518,18 @@ struct zone {
        atomic_long_t           vm_stat[NR_VM_ZONE_STAT_ITEMS];
 } ____cacheline_internodealigned_in_smp;
 
-enum zone_flags {
-       ZONE_RECLAIM_LOCKED,            /* prevents concurrent reclaim */
-       ZONE_CONGESTED,                 /* zone has many dirty pages backed by
+enum pgdat_flags {
+       PGDAT_CONGESTED,                /* pgdat has many dirty pages backed by
                                         * a congested BDI
                                         */
-       ZONE_DIRTY,                     /* reclaim scanning has recently found
+       PGDAT_DIRTY,                    /* reclaim scanning has recently found
                                         * many dirty file pages at the tail
                                         * of the LRU.
                                         */
-       ZONE_WRITEBACK,                 /* reclaim scanning has recently found
+       PGDAT_WRITEBACK,                /* reclaim scanning has recently found
                                         * many pages under writeback
                                         */
-       ZONE_FAIR_DEPLETED,             /* fair zone policy batch depleted */
+       PGDAT_RECLAIM_LOCKED,           /* prevents concurrent reclaim */
 };
 
 static inline unsigned long zone_end_pfn(const struct zone *zone)
@@ -663,8 +653,9 @@ typedef struct pglist_data {
        wait_queue_head_t pfmemalloc_wait;
        struct task_struct *kswapd;     /* Protected by
                                           mem_hotplug_begin/end() */
-       int kswapd_max_order;
-       enum zone_type classzone_idx;
+       int kswapd_order;
+       enum zone_type kswapd_classzone_idx;
+
 #ifdef CONFIG_COMPACTION
        int kcompactd_max_order;
        enum zone_type kcompactd_classzone_idx;
@@ -681,6 +672,23 @@ typedef struct pglist_data {
        /* Number of pages migrated during the rate limiting time interval */
        unsigned long numabalancing_migrate_nr_pages;
 #endif
+       /*
+        * This is a per-node reserve of pages that are not available
+        * to userspace allocations.
+        */
+       unsigned long           totalreserve_pages;
+
+#ifdef CONFIG_NUMA
+       /*
+        * zone reclaim becomes active if more unmapped pages exist.
+        */
+       unsigned long           min_unmapped_pages;
+       unsigned long           min_slab_pages;
+#endif /* CONFIG_NUMA */
+
+       /* Write-intensive fields used by page reclaim */
+       ZONE_PADDING(_pad1_)
+       spinlock_t              lru_lock;
 
 #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
        /*
@@ -695,6 +703,23 @@ typedef struct pglist_data {
        struct list_head split_queue;
        unsigned long split_queue_len;
 #endif
+
+       /* Fields commonly accessed by the page reclaim scanner */
+       struct lruvec           lruvec;
+
+       /*
+        * The target ratio of ACTIVE_ANON to INACTIVE_ANON pages on
+        * this node's LRU.  Maintained by the pageout code.
+        */
+       unsigned int inactive_ratio;
+
+       unsigned long           flags;
+
+       ZONE_PADDING(_pad2_)
+
+       /* Per-node vmstats */
+       struct per_cpu_nodestat __percpu *per_cpu_nodestats;
+       atomic_long_t           vm_stat[NR_VM_NODE_STAT_ITEMS];
 } pg_data_t;
 
 #define node_present_pages(nid)        (NODE_DATA(nid)->node_present_pages)
@@ -708,6 +733,15 @@ 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 spinlock_t *zone_lru_lock(struct zone *zone)
+{
+       return &zone->zone_pgdat->lru_lock;
+}
+
+static inline struct lruvec *node_lruvec(struct pglist_data *pgdat)
+{
+       return &pgdat->lruvec;
+}
 
 static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat)
 {
@@ -760,12 +794,12 @@ extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn,
 
 extern void lruvec_init(struct lruvec *lruvec);
 
-static inline struct zone *lruvec_zone(struct lruvec *lruvec)
+static inline struct pglist_data *lruvec_pgdat(struct lruvec *lruvec)
 {
 #ifdef CONFIG_MEMCG
-       return lruvec->zone;
+       return lruvec->pgdat;
 #else
-       return container_of(lruvec, struct zone, lruvec);
+       return container_of(lruvec, struct pglist_data, lruvec);
 #endif
 }
 
index d3d0398f2a1b4728f3db324eeeb86feab02a98a5..f29abda31e6dc8b32376a86c6c52e9e9ca6da0a0 100644 (file)
@@ -81,8 +81,6 @@ extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
 
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
 extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
-struct qstr;
-extern struct dentry *lookup_hash(const struct qstr *, struct dentry *);
 
 extern int follow_down_one(struct path *);
 extern int follow_down(struct path *);
index aee2761d294cbc6a06ae32de2c66dd4533cade3d..f1ea426d6a5e9ca742b7ae02ec03548ccaccd34e 100644 (file)
@@ -26,6 +26,7 @@ struct nd_device_driver {
        unsigned long type;
        int (*probe)(struct device *dev);
        int (*remove)(struct device *dev);
+       void (*shutdown)(struct device *dev);
        void (*notify)(struct device *dev, enum nvdimm_event event);
 };
 
@@ -67,7 +68,7 @@ struct nd_namespace_io {
        struct nd_namespace_common common;
        struct resource res;
        resource_size_t size;
-       void __pmem *addr;
+       void *addr;
        struct badblocks bb;
 };
 
index 606137b3b778e224291ba89e2df3d87277134aa8..5bc0457ee3a88955f64b750a06858d45cb74b5da 100644 (file)
@@ -73,9 +73,9 @@ static inline bool oom_task_origin(const struct task_struct *p)
 extern void mark_oom_victim(struct task_struct *tsk);
 
 #ifdef CONFIG_MMU
-extern void try_oom_reaper(struct task_struct *tsk);
+extern void wake_oom_reaper(struct task_struct *tsk);
 #else
-static inline void try_oom_reaper(struct task_struct *tsk)
+static inline void wake_oom_reaper(struct task_struct *tsk)
 {
 }
 #endif
@@ -107,27 +107,7 @@ extern void oom_killer_enable(void);
 
 extern struct task_struct *find_lock_task_mm(struct task_struct *p);
 
-static inline bool task_will_free_mem(struct task_struct *task)
-{
-       struct signal_struct *sig = task->signal;
-
-       /*
-        * A coredumping process may sleep for an extended period in exit_mm(),
-        * so the oom killer cannot assume that the process will promptly exit
-        * and release memory.
-        */
-       if (sig->flags & SIGNAL_GROUP_COREDUMP)
-               return false;
-
-       if (!(task->flags & PF_EXITING))
-               return false;
-
-       /* Make sure that the whole thread group is going down */
-       if (!thread_group_empty(task) && !(sig->flags & SIGNAL_GROUP_EXIT))
-               return false;
-
-       return true;
-}
+bool task_will_free_mem(struct task_struct *task);
 
 /* sysctls */
 extern int sysctl_oom_dump_tasks;
index 94994810c7c086e8410f3333d919ef5256595ad5..a3d90b9da18d444f0d53437d1dd5c4bd01c9e845 100644 (file)
@@ -28,7 +28,10 @@ static inline pfn_t pfn_to_pfn_t(unsigned long pfn)
        return __pfn_to_pfn_t(pfn, 0);
 }
 
-extern pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags);
+static inline pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags)
+{
+       return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags);
+}
 
 static inline bool pfn_t_has_page(pfn_t pfn)
 {
index d921afd5f10907c8d8058c0136463f6fcf54f345..12343caa114ef3ec27a5ab5a3caaf5320cbe6508 100644 (file)
@@ -175,6 +175,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
 int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
                struct device_node *np_config, struct pinctrl_map **map,
                unsigned *num_maps, enum pinctrl_map_type type);
+void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev,
+               struct pinctrl_map *map, unsigned num_maps);
 
 static inline int pinconf_generic_dt_node_to_map_group(
                struct pinctrl_dev *pctldev, struct device_node *np_config,
index 57d146fe44dd84e926199d81a8ca0a74a2d012fc..e856c2cb0fe86da91d55e2766b687b66ad02cc1e 100644 (file)
  * calling these symbols with arch_has_pmem_api() and redirect to the
  * implementation in asm/pmem.h.
  */
-static inline bool __arch_has_wmb_pmem(void)
-{
-       return false;
-}
-
-static inline void arch_wmb_pmem(void)
-{
-       BUG();
-}
-
-static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src,
-               size_t n)
+static inline void arch_memcpy_to_pmem(void *dst, const void *src, size_t n)
 {
        BUG();
 }
 
-static inline int arch_memcpy_from_pmem(void *dst, const void __pmem *src,
-               size_t n)
+static inline int arch_memcpy_from_pmem(void *dst, const void *src, size_t n)
 {
        BUG();
        return -EFAULT;
 }
 
-static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
+static inline size_t arch_copy_from_iter_pmem(void *addr, size_t bytes,
                struct iov_iter *i)
 {
        BUG();
        return 0;
 }
 
-static inline void arch_clear_pmem(void __pmem *addr, size_t size)
+static inline void arch_clear_pmem(void *addr, size_t size)
 {
        BUG();
 }
 
-static inline void arch_wb_cache_pmem(void __pmem *addr, size_t size)
+static inline void arch_wb_cache_pmem(void *addr, size_t size)
 {
        BUG();
 }
 
-static inline void arch_invalidate_pmem(void __pmem *addr, size_t size)
+static inline void arch_invalidate_pmem(void *addr, size_t size)
 {
        BUG();
 }
@@ -77,13 +65,6 @@ static inline bool arch_has_pmem_api(void)
        return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API);
 }
 
-static inline int default_memcpy_from_pmem(void *dst, void __pmem const *src,
-               size_t size)
-{
-       memcpy(dst, (void __force *) src, size);
-       return 0;
-}
-
 /*
  * memcpy_from_pmem - read from persistent memory with error handling
  * @dst: destination buffer
@@ -92,54 +73,13 @@ static inline int default_memcpy_from_pmem(void *dst, void __pmem const *src,
  *
  * Returns 0 on success negative error code on failure.
  */
-static inline int memcpy_from_pmem(void *dst, void __pmem const *src,
-               size_t size)
+static inline int memcpy_from_pmem(void *dst, void const *src, size_t size)
 {
        if (arch_has_pmem_api())
                return arch_memcpy_from_pmem(dst, src, size);
        else
-               return default_memcpy_from_pmem(dst, src, size);
-}
-
-/**
- * arch_has_wmb_pmem - true if wmb_pmem() ensures durability
- *
- * For a given cpu implementation within an architecture it is possible
- * that wmb_pmem() resolves to a nop.  In the case this returns
- * false, pmem api users are unable to ensure durability and may want to
- * fall back to a different data consistency model, or otherwise notify
- * the user.
- */
-static inline bool arch_has_wmb_pmem(void)
-{
-       return arch_has_pmem_api() && __arch_has_wmb_pmem();
-}
-
-/*
- * These defaults seek to offer decent performance and minimize the
- * window between i/o completion and writes being durable on media.
- * However, it is undefined / architecture specific whether
- * ARCH_MEMREMAP_PMEM + default_memcpy_to_pmem is sufficient for
- * making data durable relative to i/o completion.
- */
-static inline void default_memcpy_to_pmem(void __pmem *dst, const void *src,
-               size_t size)
-{
-       memcpy((void __force *) dst, src, size);
-}
-
-static inline size_t default_copy_from_iter_pmem(void __pmem *addr,
-               size_t bytes, struct iov_iter *i)
-{
-       return copy_from_iter_nocache((void __force *)addr, bytes, i);
-}
-
-static inline void default_clear_pmem(void __pmem *addr, size_t size)
-{
-       if (size == PAGE_SIZE && ((unsigned long)addr & ~PAGE_MASK) == 0)
-               clear_page((void __force *)addr);
-       else
-               memset((void __force *)addr, 0, size);
+               memcpy(dst, src, size);
+       return 0;
 }
 
 /**
@@ -152,29 +92,14 @@ static inline void default_clear_pmem(void __pmem *addr, size_t size)
  * being effectively evicted from, or never written to, the processor
  * cache hierarchy after the copy completes.  After memcpy_to_pmem()
  * data may still reside in cpu or platform buffers, so this operation
- * must be followed by a wmb_pmem().
+ * must be followed by a blkdev_issue_flush() on the pmem block device.
  */
-static inline void memcpy_to_pmem(void __pmem *dst, const void *src, size_t n)
+static inline void memcpy_to_pmem(void *dst, const void *src, size_t n)
 {
        if (arch_has_pmem_api())
                arch_memcpy_to_pmem(dst, src, n);
        else
-               default_memcpy_to_pmem(dst, src, n);
-}
-
-/**
- * wmb_pmem - synchronize writes to persistent memory
- *
- * After a series of memcpy_to_pmem() operations this drains data from
- * cpu write buffers and any platform (memory controller) buffers to
- * ensure that written data is durable on persistent memory media.
- */
-static inline void wmb_pmem(void)
-{
-       if (arch_has_wmb_pmem())
-               arch_wmb_pmem();
-       else
-               wmb();
+               memcpy(dst, src, n);
 }
 
 /**
@@ -184,14 +109,14 @@ static inline void wmb_pmem(void)
  * @i:         iterator with source data
  *
  * Copy data from the iterator 'i' to the PMEM buffer starting at 'addr'.
- * This function requires explicit ordering with a wmb_pmem() call.
+ * See blkdev_issue_flush() note for memcpy_to_pmem().
  */
-static inline size_t copy_from_iter_pmem(void __pmem *addr, size_t bytes,
+static inline size_t copy_from_iter_pmem(void *addr, size_t bytes,
                struct iov_iter *i)
 {
        if (arch_has_pmem_api())
                return arch_copy_from_iter_pmem(addr, bytes, i);
-       return default_copy_from_iter_pmem(addr, bytes, i);
+       return copy_from_iter_nocache(addr, bytes, i);
 }
 
 /**
@@ -200,14 +125,14 @@ static inline size_t copy_from_iter_pmem(void __pmem *addr, size_t bytes,
  * @size:      number of bytes to zero
  *
  * Write zeros into the memory range starting at 'addr' for 'size' bytes.
- * This function requires explicit ordering with a wmb_pmem() call.
+ * See blkdev_issue_flush() note for memcpy_to_pmem().
  */
-static inline void clear_pmem(void __pmem *addr, size_t size)
+static inline void clear_pmem(void *addr, size_t size)
 {
        if (arch_has_pmem_api())
                arch_clear_pmem(addr, size);
        else
-               default_clear_pmem(addr, size);
+               memset(addr, 0, size);
 }
 
 /**
@@ -218,7 +143,7 @@ static inline void clear_pmem(void __pmem *addr, size_t size)
  * For platforms that support clearing poison this flushes any poisoned
  * ranges out of the cache
  */
-static inline void invalidate_pmem(void __pmem *addr, size_t size)
+static inline void invalidate_pmem(void *addr, size_t size)
 {
        if (arch_has_pmem_api())
                arch_invalidate_pmem(addr, size);
@@ -230,9 +155,9 @@ static inline void invalidate_pmem(void __pmem *addr, size_t size)
  * @size:      number of bytes to write back
  *
  * Write back the processor cache range starting at 'addr' for 'size' bytes.
- * This function requires explicit ordering with a wmb_pmem() call.
+ * See blkdev_issue_flush() note for memcpy_to_pmem().
  */
-static inline void wb_cache_pmem(void __pmem *addr, size_t size)
+static inline void wb_cache_pmem(void *addr, size_t size)
 {
        if (arch_has_pmem_api())
                arch_wb_cache_pmem(addr, size);
index 9dfb6bce8c9eb08f0c45a8d1b76f86b0b489b30e..8486d27cf360bca4a33295cc0bfcbf49e0a84cd3 100644 (file)
@@ -200,8 +200,8 @@ struct mem_dqblk {
        qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
        qsize_t dqb_isoftlimit; /* preferred inode limit */
        qsize_t dqb_curinodes;  /* current # allocated inodes */
-       time_t dqb_btime;       /* time limit for excessive disk use */
-       time_t dqb_itime;       /* time limit for excessive inode use */
+       time64_t dqb_btime;     /* time limit for excessive disk use */
+       time64_t dqb_itime;     /* time limit for excessive inode use */
 };
 
 /*
index d99218a1e04370683dd239de59c38e48a04d2eb7..553af2923824e9611b015835a761436c2e422fe5 100644 (file)
@@ -523,6 +523,7 @@ static inline int get_dumpable(struct mm_struct *mm)
 #define MMF_HAS_UPROBES                19      /* has uprobes */
 #define MMF_RECALC_UPROBES     20      /* MMF_HAS_UPROBES can be wrong */
 #define MMF_OOM_REAPED         21      /* mm has been already reaped */
+#define MMF_OOM_NOT_REAPABLE   22      /* mm couldn't be reaped */
 
 #define MMF_INIT_MASK          (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)
 
@@ -1949,6 +1950,32 @@ static inline int tsk_nr_cpus_allowed(struct task_struct *p)
 #define TNF_FAULT_LOCAL        0x08
 #define TNF_MIGRATE_FAIL 0x10
 
+static inline bool in_vfork(struct task_struct *tsk)
+{
+       bool ret;
+
+       /*
+        * need RCU to access ->real_parent if CLONE_VM was used along with
+        * CLONE_PARENT.
+        *
+        * We check real_parent->mm == tsk->mm because CLONE_VFORK does not
+        * imply CLONE_VM
+        *
+        * CLONE_VFORK can be used with CLONE_PARENT/CLONE_THREAD and thus
+        * ->real_parent is not necessarily the task doing vfork(), so in
+        * theory we can't rely on task_lock() if we want to dereference it.
+        *
+        * And in this case we can't trust the real_parent->mm == tsk->mm
+        * check, it can be false negative. But we do not care, if init or
+        * another oom-unkillable task does this it should blame itself.
+        */
+       rcu_read_lock();
+       ret = tsk->vfork_done && tsk->real_parent->mm == tsk->mm;
+       rcu_read_unlock();
+
+       return ret;
+}
+
 #ifdef CONFIG_NUMA_BALANCING
 extern void task_numa_fault(int last_node, int node, int pages, int flags);
 extern pid_t task_numa_group_id(struct task_struct *p);
index 339ba027ade9873eebf91ea4180ee4a6527f4b92..4ad2c5a263999e24cf4d860f088bb4df07ba0e4c 100644 (file)
@@ -88,7 +88,8 @@ struct kmem_cache {
 };
 
 static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
-                               void *x) {
+                               void *x)
+{
        void *object = x - (x - page->s_mem) % cache->size;
        void *last_object = page->s_mem + (cache->num - 1) * cache->size;
 
index 5624c1f3eb0add4347768e1dada1581b794589d8..75f56c2ef2d471f1424b947632b984f431dd46e5 100644 (file)
@@ -104,6 +104,10 @@ struct kmem_cache {
        unsigned int *random_seq;
 #endif
 
+#ifdef CONFIG_KASAN
+       struct kasan_cache kasan_info;
+#endif
+
        struct kmem_cache_node *node[MAX_NUMNODES];
 };
 
@@ -119,15 +123,17 @@ static inline void sysfs_slab_remove(struct kmem_cache *s)
 void object_err(struct kmem_cache *s, struct page *page,
                u8 *object, char *reason);
 
+void *fixup_red_left(struct kmem_cache *s, void *p);
+
 static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
                                void *x) {
        void *object = x - (x - page_address(page)) % cache->size;
        void *last_object = page_address(page) +
                (page->objects - 1) * cache->size;
-       if (unlikely(object > last_object))
-               return last_object;
-       else
-               return object;
+       void *result = (unlikely(object > last_object)) ? last_object : object;
+
+       result = fixup_red_left(cache, result);
+       return result;
 }
 
 #endif /* _LINUX_SLUB_DEF_H */
index 451771d9b9c09e2ef8d8317dee9c10008772c7e6..7c2d95170d010254a09d2d06250cbd2f6cc5a65a 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/compiler.h>    /* For __pure */
 #include <linux/types.h>       /* For u32, u64 */
+#include <linux/hash.h>
 
 /*
  * Routines for hashing strings of bytes to a 32-bit hash value.
@@ -34,7 +35,7 @@
  */
 
 /* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
-#define init_name_hash()               0
+#define init_name_hash(salt)           (unsigned long)(salt)
 
 /* partial hash update function. Assume roughly 4 bits per character */
 static inline unsigned long
@@ -45,11 +46,12 @@ partial_name_hash(unsigned long c, unsigned long prevhash)
 
 /*
  * Finally: cut down the number of bits to a int value (and try to avoid
- * losing bits)
+ * losing bits).  This also has the property (wanted by the dcache)
+ * that the msbits make a good hash table index.
  */
 static inline unsigned long end_name_hash(unsigned long hash)
 {
-       return (unsigned int)hash;
+       return __hash_32((unsigned int)hash);
 }
 
 /*
@@ -60,7 +62,7 @@ static inline unsigned long end_name_hash(unsigned long hash)
  *
  * If not set, this falls back to a wrapper around the preceding.
  */
-extern unsigned int __pure full_name_hash(const char *, unsigned int);
+extern unsigned int __pure full_name_hash(const void *salt, const char *, unsigned int);
 
 /*
  * A hash_len is a u64 with the hash of a string in the low
@@ -71,6 +73,6 @@ extern unsigned int __pure full_name_hash(const char *, unsigned int);
 #define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash))
 
 /* Return the "hash_len" (hash and length) of a null-terminated string */
-extern u64 __pure hashlen_string(const char *name);
+extern u64 __pure hashlen_string(const void *salt, const char *name);
 
 #endif /* __LINUX_STRINGHASH_H */
index 91d5a5d6f52b0547b4652f4e3f6efbd7de1ff776..d03932055328ccef696dd3008dcddc2d5d1c5d70 100644 (file)
@@ -172,12 +172,12 @@ extern void unix_gid_cache_destroy(struct net *net);
  */
 static inline unsigned long hash_str(char const *name, int bits)
 {
-       return hashlen_hash(hashlen_string(name)) >> (32 - bits);
+       return hashlen_hash(hashlen_string(NULL, name)) >> (32 - bits);
 }
 
 static inline unsigned long hash_mem(char const *buf, int length, int bits)
 {
-       return full_name_hash(buf, length) >> (32 - bits);
+       return full_name_hash(NULL, buf, length) >> (32 - bits);
 }
 
 #endif /* __KERNEL__ */
index 0af2bb2028fd51c56b319b264e1d2f4991d7b073..b17cc4830fa670512abdc3987f58fc55e583f0bc 100644 (file)
@@ -157,15 +157,6 @@ enum {
 #define SWAP_CLUSTER_MAX 32UL
 #define COMPACT_CLUSTER_MAX SWAP_CLUSTER_MAX
 
-/*
- * Ratio between zone->managed_pages and the "gap" that above the per-zone
- * "high_wmark". While balancing nodes, We allow kswapd to shrink zones that
- * do not meet the (high_wmark + gap) watermark, even which already met the
- * high_wmark, in order to provide better per-zone lru behavior. We are ok to
- * spend not more than 1% of the memory for this zone balancing "gap".
- */
-#define KSWAPD_ZONE_BALANCE_GAP_RATIO 100
-
 #define SWAP_MAP_MAX   0x3e    /* Max duplication count, in first swap_map */
 #define SWAP_MAP_BAD   0x3f    /* Note pageblock is bad, in first swap_map */
 #define SWAP_HAS_CACHE 0x40    /* Flag page is cached, in first swap_map */
@@ -317,6 +308,7 @@ extern void lru_cache_add_active_or_unevictable(struct page *page,
 
 /* linux/mm/vmscan.c */
 extern unsigned long zone_reclaimable_pages(struct zone *zone);
+extern unsigned long pgdat_reclaimable_pages(struct pglist_data *pgdat);
 extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                                        gfp_t gfp_mask, nodemask_t *mask);
 extern int __isolate_lru_page(struct page *page, isolate_mode_t mode);
@@ -324,9 +316,9 @@ extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                                  unsigned long nr_pages,
                                                  gfp_t gfp_mask,
                                                  bool may_swap);
-extern unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
+extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem,
                                                gfp_t gfp_mask, bool noswap,
-                                               struct zone *zone,
+                                               pg_data_t *pgdat,
                                                unsigned long *nr_scanned);
 extern unsigned long shrink_all_memory(unsigned long nr_pages);
 extern int vm_swappiness;
@@ -334,13 +326,14 @@ extern int remove_mapping(struct address_space *mapping, struct page *page);
 extern unsigned long vm_total_pages;
 
 #ifdef CONFIG_NUMA
-extern int zone_reclaim_mode;
+extern int node_reclaim_mode;
 extern int sysctl_min_unmapped_ratio;
 extern int sysctl_min_slab_ratio;
-extern int zone_reclaim(struct zone *, gfp_t, unsigned int);
+extern int node_reclaim(struct pglist_data *, gfp_t, unsigned int);
 #else
-#define zone_reclaim_mode 0
-static inline int zone_reclaim(struct zone *z, gfp_t mask, unsigned int order)
+#define node_reclaim_mode 0
+static inline int node_reclaim(struct pglist_data *pgdat, gfp_t mask,
+                               unsigned int order)
 {
        return 0;
 }
index afce69296ac05699880b80c6ae42c1a46b409b8c..cb0775e1ee4bd5f2dfc6d004a5f3fb4438390893 100644 (file)
@@ -54,7 +54,7 @@ int arch_update_cpu_topology(void);
 /*
  * If the distance between nodes in a system is larger than RECLAIM_DISTANCE
  * (in whatever arch specific measurement units returned by node_distance())
- * and zone_reclaim_mode is enabled then the VM will only call zone_reclaim()
+ * and node_reclaim_mode is enabled then the VM will only call node_reclaim()
  * on nodes within this distance.
  */
 #define RECLAIM_DISTANCE 30
index 42604173f122423303d06371e7e8bfb45774df6d..4d6ec58a8d45b04aa6bae51585e49d44319dd155 100644 (file)
 
 enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                FOR_ALL_ZONES(PGALLOC),
+               FOR_ALL_ZONES(ALLOCSTALL),
+               FOR_ALL_ZONES(PGSCAN_SKIP),
                PGFREE, PGACTIVATE, PGDEACTIVATE,
                PGFAULT, PGMAJFAULT,
                PGLAZYFREED,
-               FOR_ALL_ZONES(PGREFILL),
-               FOR_ALL_ZONES(PGSTEAL_KSWAPD),
-               FOR_ALL_ZONES(PGSTEAL_DIRECT),
-               FOR_ALL_ZONES(PGSCAN_KSWAPD),
-               FOR_ALL_ZONES(PGSCAN_DIRECT),
+               PGREFILL,
+               PGSTEAL_KSWAPD,
+               PGSTEAL_DIRECT,
+               PGSCAN_KSWAPD,
+               PGSCAN_DIRECT,
                PGSCAN_DIRECT_THROTTLE,
 #ifdef CONFIG_NUMA
                PGSCAN_ZONE_RECLAIM_FAILED,
 #endif
                PGINODESTEAL, SLABS_SCANNED, KSWAPD_INODESTEAL,
                KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY,
-               PAGEOUTRUN, ALLOCSTALL, PGROTATED,
+               PAGEOUTRUN, PGROTATED,
                DROP_PAGECACHE, DROP_SLAB,
 #ifdef CONFIG_NUMA_BALANCING
                NUMA_PTE_UPDATES,
index d2da8e053210041bfcefb9e04b59d195880d2d0e..613771909b6ee1f284806c49b444b8779926a373 100644 (file)
@@ -101,25 +101,42 @@ static inline void vm_events_fold_cpu(int cpu)
 #define count_vm_vmacache_event(x) do {} while (0)
 #endif
 
-#define __count_zone_vm_events(item, zone, delta) \
-               __count_vm_events(item##_NORMAL - ZONE_NORMAL + \
-               zone_idx(zone), delta)
+#define __count_zid_vm_events(item, zid, delta) \
+       __count_vm_events(item##_NORMAL - ZONE_NORMAL + zid, delta)
 
 /*
- * Zone based page accounting with per cpu differentials.
+ * Zone and node-based page accounting with per cpu differentials.
  */
-extern atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
+extern atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS];
+extern atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS];
 
 static inline void zone_page_state_add(long x, struct zone *zone,
                                 enum zone_stat_item item)
 {
        atomic_long_add(x, &zone->vm_stat[item]);
-       atomic_long_add(x, &vm_stat[item]);
+       atomic_long_add(x, &vm_zone_stat[item]);
+}
+
+static inline void node_page_state_add(long x, struct pglist_data *pgdat,
+                                enum node_stat_item item)
+{
+       atomic_long_add(x, &pgdat->vm_stat[item]);
+       atomic_long_add(x, &vm_node_stat[item]);
 }
 
 static inline unsigned long global_page_state(enum zone_stat_item item)
 {
-       long x = atomic_long_read(&vm_stat[item]);
+       long x = atomic_long_read(&vm_zone_stat[item]);
+#ifdef CONFIG_SMP
+       if (x < 0)
+               x = 0;
+#endif
+       return x;
+}
+
+static inline unsigned long global_node_page_state(enum node_stat_item item)
+{
+       long x = atomic_long_read(&vm_node_stat[item]);
 #ifdef CONFIG_SMP
        if (x < 0)
                x = 0;
@@ -160,32 +177,61 @@ static inline unsigned long zone_page_state_snapshot(struct zone *zone,
        return x;
 }
 
-#ifdef CONFIG_NUMA
+static inline unsigned long node_page_state_snapshot(pg_data_t *pgdat,
+                                       enum node_stat_item item)
+{
+       long x = atomic_long_read(&pgdat->vm_stat[item]);
 
-extern unsigned long node_page_state(int node, enum zone_stat_item item);
+#ifdef CONFIG_SMP
+       int cpu;
+       for_each_online_cpu(cpu)
+               x += per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->vm_node_stat_diff[item];
 
-#else
+       if (x < 0)
+               x = 0;
+#endif
+       return x;
+}
 
-#define node_page_state(node, item) global_page_state(item)
 
+#ifdef CONFIG_NUMA
+extern unsigned long sum_zone_node_page_state(int node,
+                                               enum zone_stat_item item);
+extern unsigned long node_page_state(struct pglist_data *pgdat,
+                                               enum node_stat_item item);
+#else
+#define sum_zone_node_page_state(node, item) global_page_state(item)
+#define node_page_state(node, item) global_node_page_state(item)
 #endif /* CONFIG_NUMA */
 
 #define add_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, __d)
 #define sub_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, -(__d))
+#define add_node_page_state(__p, __i, __d) mod_node_page_state(__p, __i, __d)
+#define sub_node_page_state(__p, __i, __d) mod_node_page_state(__p, __i, -(__d))
 
 #ifdef CONFIG_SMP
 void __mod_zone_page_state(struct zone *, enum zone_stat_item item, long);
 void __inc_zone_page_state(struct page *, enum zone_stat_item);
 void __dec_zone_page_state(struct page *, enum zone_stat_item);
 
+void __mod_node_page_state(struct pglist_data *, enum node_stat_item item, long);
+void __inc_node_page_state(struct page *, enum node_stat_item);
+void __dec_node_page_state(struct page *, enum node_stat_item);
+
 void mod_zone_page_state(struct zone *, enum zone_stat_item, long);
 void inc_zone_page_state(struct page *, enum zone_stat_item);
 void dec_zone_page_state(struct page *, enum zone_stat_item);
 
-extern void inc_zone_state(struct zone *, enum zone_stat_item);
+void mod_node_page_state(struct pglist_data *, enum node_stat_item, long);
+void inc_node_page_state(struct page *, enum node_stat_item);
+void dec_node_page_state(struct page *, enum node_stat_item);
+
+extern void inc_node_state(struct pglist_data *, enum node_stat_item);
 extern void __inc_zone_state(struct zone *, enum zone_stat_item);
+extern void __inc_node_state(struct pglist_data *, enum node_stat_item);
 extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
+extern void __dec_node_state(struct pglist_data *, enum node_stat_item);
 
 void quiet_vmstat(void);
 void cpu_vm_stats_fold(int cpu);
@@ -213,16 +259,34 @@ static inline void __mod_zone_page_state(struct zone *zone,
        zone_page_state_add(delta, zone, item);
 }
 
+static inline void __mod_node_page_state(struct pglist_data *pgdat,
+                       enum node_stat_item item, int delta)
+{
+       node_page_state_add(delta, pgdat, item);
+}
+
 static inline void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
 {
        atomic_long_inc(&zone->vm_stat[item]);
-       atomic_long_inc(&vm_stat[item]);
+       atomic_long_inc(&vm_zone_stat[item]);
+}
+
+static inline void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       atomic_long_inc(&pgdat->vm_stat[item]);
+       atomic_long_inc(&vm_node_stat[item]);
 }
 
 static inline void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
 {
        atomic_long_dec(&zone->vm_stat[item]);
-       atomic_long_dec(&vm_stat[item]);
+       atomic_long_dec(&vm_zone_stat[item]);
+}
+
+static inline void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       atomic_long_dec(&pgdat->vm_stat[item]);
+       atomic_long_dec(&vm_node_stat[item]);
 }
 
 static inline void __inc_zone_page_state(struct page *page,
@@ -231,12 +295,26 @@ static inline void __inc_zone_page_state(struct page *page,
        __inc_zone_state(page_zone(page), item);
 }
 
+static inline void __inc_node_page_state(struct page *page,
+                       enum node_stat_item item)
+{
+       __inc_node_state(page_pgdat(page), item);
+}
+
+
 static inline void __dec_zone_page_state(struct page *page,
                        enum zone_stat_item item)
 {
        __dec_zone_state(page_zone(page), item);
 }
 
+static inline void __dec_node_page_state(struct page *page,
+                       enum node_stat_item item)
+{
+       __dec_node_state(page_pgdat(page), item);
+}
+
+
 /*
  * We only use atomic operations to update counters. So there is no need to
  * disable interrupts.
@@ -245,7 +323,12 @@ static inline void __dec_zone_page_state(struct page *page,
 #define dec_zone_page_state __dec_zone_page_state
 #define mod_zone_page_state __mod_zone_page_state
 
+#define inc_node_page_state __inc_node_page_state
+#define dec_node_page_state __dec_node_page_state
+#define mod_node_page_state __mod_node_page_state
+
 #define inc_zone_state __inc_zone_state
+#define inc_node_state __inc_node_state
 #define dec_zone_state __dec_zone_state
 
 #define set_pgdat_percpu_threshold(pgdat, callback) { }
index 27d7a0ab5da3edf217e60d767c10c65d3e3c52a0..c3ff74d764faad094e7f00dcd025ddb568a6382d 100644 (file)
@@ -600,6 +600,19 @@ do {                                                                       \
        __ret;                                                          \
 })
 
+#define __wait_event_killable_exclusive(wq, condition)                 \
+       ___wait_event(wq, condition, TASK_KILLABLE, 1, 0,               \
+                     schedule())
+
+#define wait_event_killable_exclusive(wq, condition)                   \
+({                                                                     \
+       int __ret = 0;                                                  \
+       might_sleep();                                                  \
+       if (!(condition))                                               \
+               __ret = __wait_event_killable_exclusive(wq, condition); \
+       __ret;                                                          \
+})
+
 
 #define __wait_event_freezable_exclusive(wq, condition)                        \
        ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 1, 0,          \
index 717e6149e753364084698d3b32b1004d4087a281..fc1e16c25a296877e85d37d267bd953929ee93cd 100644 (file)
@@ -320,7 +320,7 @@ void laptop_mode_timer_fn(unsigned long data);
 static inline void laptop_sync_completion(void) { }
 #endif
 void throttle_vm_writeout(gfp_t gfp_mask);
-bool zone_dirty_ok(struct zone *zone);
+bool node_dirty_ok(struct pglist_data *pgdat);
 int wb_domain_init(struct wb_domain *dom, gfp_t gfp);
 #ifdef CONFIG_CGROUP_WRITEBACK
 void wb_domain_exit(struct wb_domain *dom);
index 1443d79e4fe66bb6456840d0597fadeed5b90bf9..1791a12cfa85e9875a8972826c01085d916a751e 100644 (file)
@@ -147,7 +147,7 @@ TRACE_EVENT(mc_event,
                  __entry->error_count,
                  mc_event_error_type(__entry->error_type),
                  __entry->error_count > 1 ? "s" : "",
-                 ((char *)__get_str(msg))[0] ? " " : "",
+                 __get_str(msg)[0] ? " " : "",
                  __get_str(msg),
                  __get_str(label),
                  __entry->mc_index,
@@ -157,7 +157,7 @@ TRACE_EVENT(mc_event,
                  __entry->address,
                  1 << __entry->grain_bits,
                  __entry->syndrome,
-                 ((char *)__get_str(driver_detail))[0] ? " " : "",
+                 __get_str(driver_detail)[0] ? " " : "",
                  __get_str(driver_detail))
 );
 
index 36e2d6fb1360a722183e9cabd47b8583b557b13f..c2ba402ab25651009c5b67e90145b81124fd110e 100644 (file)
@@ -226,26 +226,26 @@ TRACE_EVENT(mm_compaction_try_to_compact_pages,
        TP_PROTO(
                int order,
                gfp_t gfp_mask,
-               enum migrate_mode mode),
+               int prio),
 
-       TP_ARGS(order, gfp_mask, mode),
+       TP_ARGS(order, gfp_mask, prio),
 
        TP_STRUCT__entry(
                __field(int, order)
                __field(gfp_t, gfp_mask)
-               __field(enum migrate_mode, mode)
+               __field(int, prio)
        ),
 
        TP_fast_assign(
                __entry->order = order;
                __entry->gfp_mask = gfp_mask;
-               __entry->mode = mode;
+               __entry->prio = prio;
        ),
 
-       TP_printk("order=%d gfp_mask=0x%x mode=%d",
+       TP_printk("order=%d gfp_mask=0x%x priority=%d",
                __entry->order,
                __entry->gfp_mask,
-               (int)__entry->mode)
+               __entry->prio)
 );
 
 DECLARE_EVENT_CLASS(mm_compaction_suitable_template,
index 43cedbf0c759e5074871baf4d600ab5f3e2bb3e8..5a81ab48a2fb2921328e098c388e77d58a765147 100644 (file)
@@ -11,6 +11,7 @@
 
 #define __def_gfpflag_names                                            \
        {(unsigned long)GFP_TRANSHUGE,          "GFP_TRANSHUGE"},       \
+       {(unsigned long)GFP_TRANSHUGE_LIGHT,    "GFP_TRANSHUGE_LIGHT"}, \
        {(unsigned long)GFP_HIGHUSER_MOVABLE,   "GFP_HIGHUSER_MOVABLE"},\
        {(unsigned long)GFP_HIGHUSER,           "GFP_HIGHUSER"},        \
        {(unsigned long)GFP_USER,               "GFP_USER"},            \
index c008bc99f9fa9093beb2668f2ebb33a72b825715..f350170059c6c274dc951fb7b550272c8bff4df9 100644 (file)
@@ -16,8 +16,16 @@ TRACE_EVENT(console,
        ),
 
        TP_fast_assign(
-               memcpy(__get_dynamic_array(msg), text, len);
-               ((char *)__get_dynamic_array(msg))[len] = 0;
+               /*
+                * Each trace entry is printed in a new line.
+                * If the msg finishes with '\n', cut it off
+                * to avoid blank lines in the trace.
+                */
+               if ((len > 0) && (text[len-1] == '\n'))
+                       len -= 1;
+
+               memcpy(__get_str(msg), text, len);
+               __get_str(msg)[len] = 0;
        ),
 
        TP_printk("%s", __get_str(msg))
index 0101ef37f1eed78a39ef095f3ced183cb4e3f7c8..c88fd0934e7ead911941d13272bb89215584ba67 100644 (file)
@@ -55,21 +55,23 @@ TRACE_EVENT(mm_vmscan_kswapd_sleep,
 
 TRACE_EVENT(mm_vmscan_kswapd_wake,
 
-       TP_PROTO(int nid, int order),
+       TP_PROTO(int nid, int zid, int order),
 
-       TP_ARGS(nid, order),
+       TP_ARGS(nid, zid, order),
 
        TP_STRUCT__entry(
                __field(        int,    nid     )
+               __field(        int,    zid     )
                __field(        int,    order   )
        ),
 
        TP_fast_assign(
                __entry->nid    = nid;
+               __entry->zid    = zid;
                __entry->order  = order;
        ),
 
-       TP_printk("nid=%d order=%d", __entry->nid, __entry->order)
+       TP_printk("nid=%d zid=%d order=%d", __entry->nid, __entry->zid, __entry->order)
 );
 
 TRACE_EVENT(mm_vmscan_wakeup_kswapd,
@@ -98,47 +100,50 @@ TRACE_EVENT(mm_vmscan_wakeup_kswapd,
 
 DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags),
+       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
 
-       TP_ARGS(order, may_writepage, gfp_flags),
+       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx),
 
        TP_STRUCT__entry(
                __field(        int,    order           )
                __field(        int,    may_writepage   )
                __field(        gfp_t,  gfp_flags       )
+               __field(        int,    classzone_idx   )
        ),
 
        TP_fast_assign(
                __entry->order          = order;
                __entry->may_writepage  = may_writepage;
                __entry->gfp_flags      = gfp_flags;
+               __entry->classzone_idx  = classzone_idx;
        ),
 
-       TP_printk("order=%d may_writepage=%d gfp_flags=%s",
+       TP_printk("order=%d may_writepage=%d gfp_flags=%s classzone_idx=%d",
                __entry->order,
                __entry->may_writepage,
-               show_gfp_flags(__entry->gfp_flags))
+               show_gfp_flags(__entry->gfp_flags),
+               __entry->classzone_idx)
 );
 
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_direct_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags),
+       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
 
-       TP_ARGS(order, may_writepage, gfp_flags)
+       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
 );
 
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags),
+       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
 
-       TP_ARGS(order, may_writepage, gfp_flags)
+       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
 );
 
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_softlimit_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags),
+       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
 
-       TP_ARGS(order, may_writepage, gfp_flags)
+       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
 );
 
 DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template,
@@ -266,16 +271,18 @@ TRACE_EVENT(mm_shrink_slab_end,
 
 DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
 
-       TP_PROTO(int order,
+       TP_PROTO(int classzone_idx,
+               int order,
                unsigned long nr_requested,
                unsigned long nr_scanned,
                unsigned long nr_taken,
                isolate_mode_t isolate_mode,
                int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file),
+       TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file),
 
        TP_STRUCT__entry(
+               __field(int, classzone_idx)
                __field(int, order)
                __field(unsigned long, nr_requested)
                __field(unsigned long, nr_scanned)
@@ -285,6 +292,7 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
        ),
 
        TP_fast_assign(
+               __entry->classzone_idx = classzone_idx;
                __entry->order = order;
                __entry->nr_requested = nr_requested;
                __entry->nr_scanned = nr_scanned;
@@ -293,8 +301,9 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __entry->file = file;
        ),
 
-       TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d",
+       TP_printk("isolate_mode=%d classzone=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d",
                __entry->isolate_mode,
+               __entry->classzone_idx,
                __entry->order,
                __entry->nr_requested,
                __entry->nr_scanned,
@@ -304,27 +313,29 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
 
 DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
 
-       TP_PROTO(int order,
+       TP_PROTO(int classzone_idx,
+               int order,
                unsigned long nr_requested,
                unsigned long nr_scanned,
                unsigned long nr_taken,
                isolate_mode_t isolate_mode,
                int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
+       TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
 
 );
 
 DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate,
 
-       TP_PROTO(int order,
+       TP_PROTO(int classzone_idx,
+               int order,
                unsigned long nr_requested,
                unsigned long nr_scanned,
                unsigned long nr_taken,
                isolate_mode_t isolate_mode,
                int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
+       TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
 
 );
 
@@ -352,15 +363,14 @@ TRACE_EVENT(mm_vmscan_writepage,
 
 TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
 
-       TP_PROTO(struct zone *zone,
+       TP_PROTO(int nid,
                unsigned long nr_scanned, unsigned long nr_reclaimed,
                int priority, int file),
 
-       TP_ARGS(zone, nr_scanned, nr_reclaimed, priority, file),
+       TP_ARGS(nid, nr_scanned, nr_reclaimed, priority, file),
 
        TP_STRUCT__entry(
                __field(int, nid)
-               __field(int, zid)
                __field(unsigned long, nr_scanned)
                __field(unsigned long, nr_reclaimed)
                __field(int, priority)
@@ -368,16 +378,15 @@ TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
        ),
 
        TP_fast_assign(
-               __entry->nid = zone_to_nid(zone);
-               __entry->zid = zone_idx(zone);
+               __entry->nid = nid;
                __entry->nr_scanned = nr_scanned;
                __entry->nr_reclaimed = nr_reclaimed;
                __entry->priority = priority;
                __entry->reclaim_flags = trace_shrink_flags(file);
        ),
 
-       TP_printk("nid=%d zid=%d nr_scanned=%ld nr_reclaimed=%ld priority=%d flags=%s",
-               __entry->nid, __entry->zid,
+       TP_printk("nid=%d nr_scanned=%ld nr_reclaimed=%ld priority=%d flags=%s",
+               __entry->nid,
                __entry->nr_scanned, __entry->nr_reclaimed,
                __entry->priority,
                show_reclaim_flags(__entry->reclaim_flags))
index 531f5811ff6be07dd264d7cacd11507de9083fab..2ccd9ccbf9efeaa7794eda0ca20589d42cf67784 100644 (file)
@@ -412,11 +412,11 @@ TRACE_EVENT(global_dirty_state,
        ),
 
        TP_fast_assign(
-               __entry->nr_dirty       = global_page_state(NR_FILE_DIRTY);
-               __entry->nr_writeback   = global_page_state(NR_WRITEBACK);
-               __entry->nr_unstable    = global_page_state(NR_UNSTABLE_NFS);
-               __entry->nr_dirtied     = global_page_state(NR_DIRTIED);
-               __entry->nr_written     = global_page_state(NR_WRITTEN);
+               __entry->nr_dirty       = global_node_page_state(NR_FILE_DIRTY);
+               __entry->nr_writeback   = global_node_page_state(NR_WRITEBACK);
+               __entry->nr_unstable    = global_node_page_state(NR_UNSTABLE_NFS);
+               __entry->nr_dirtied     = global_node_page_state(NR_DIRTIED);
+               __entry->nr_written     = global_node_page_state(NR_WRITTEN);
                __entry->background_thresh = background_thresh;
                __entry->dirty_thresh   = dirty_thresh;
                __entry->dirty_limit    = global_wb_domain.dirty_limit;
index 88de5c205e86f7040854221baa2fe04c737daa3a..04fe68bbe7679f48ef5e58b883b7780a5b6fbbfd 100644 (file)
@@ -15,7 +15,7 @@
                ((__entry->__data_loc_##field >> 16) & 0xffff)
 
 #undef __get_str
-#define __get_str(field) (char *)__get_dynamic_array(field)
+#define __get_str(field) ((char *)__get_dynamic_array(field))
 
 #undef __get_bitmask
 #define __get_bitmask(field) (char *)__get_dynamic_array(field)
index 80679a9fae65e3d5a00be4235d7153d7aad34177..467e12f780d863956b1b1b650c406d9d4cb5c0c2 100644 (file)
@@ -256,7 +256,7 @@ TRACE_MAKE_SYSTEM_STR();
                ((__entry->__data_loc_##field >> 16) & 0xffff)
 
 #undef __get_str
-#define __get_str(field) (char *)__get_dynamic_array(field)
+#define __get_str(field) ((char *)__get_dynamic_array(field))
 
 #undef __get_bitmask
 #define __get_bitmask(field)                                           \
index 309915f74492406595782af8e8c4e20a5a7ef934..ba5a8c79652a469f048d1507bea9e489ed698bef 100644 (file)
@@ -298,6 +298,7 @@ struct nd_cmd_pkg {
 #define NVDIMM_FAMILY_INTEL 0
 #define NVDIMM_FAMILY_HPE1 1
 #define NVDIMM_FAMILY_HPE2 2
+#define NVDIMM_FAMILY_MSFT 3
 
 #define ND_IOCTL_CALL                  _IOWR(ND_IOCTL, ND_CMD_CALL,\
                                        struct nd_cmd_pkg)
index 504057925ee9df37a9cfa9cfc200cb1071f1b23d..46f817abff0e60902e3e1b6c1c71b1a8355dc572 100644 (file)
@@ -852,8 +852,8 @@ config LOG_CPU_MAX_BUF_SHIFT
          used as it forces an exact (power of two) size of the ring buffer.
 
          The number of possible CPUs is used for this computation ignoring
-         hotplugging making the compuation optimal for the the worst case
-         scenerio while allowing a simple algorithm to be used from bootup.
+         hotplugging making the computation optimal for the worst case
+         scenario while allowing a simple algorithm to be used from bootup.
 
          Examples shift values and their meaning:
                     17 => 128 KB for each CPU
index 73e93e53884d1098ceec4b3c8d31049c8d9fc70b..c7fd2778ed50edc52b7c0e5f1f651dcb141c9495 100644 (file)
@@ -1034,15 +1034,6 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
 {
        bool need_loop;
 
-       /*
-        * Allow tasks that have access to memory reserves because they have
-        * been OOM killed to get memory anywhere.
-        */
-       if (unlikely(test_thread_flag(TIF_MEMDIE)))
-               return;
-       if (current->flags & PF_EXITING) /* Let dying task have memory */
-               return;
-
        task_lock(tsk);
        /*
         * Determine if a loop is necessary if another thread is doing
index de21f25e0d2ce9755b80ecc653269b8b5f8e5415..52e725d4a866b4ac30f16b4db075b9b197e4e53d 100644 (file)
@@ -165,20 +165,12 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk,
        struct page *page = alloc_pages_node(node, THREADINFO_GFP,
                                             THREAD_SIZE_ORDER);
 
-       if (page)
-               memcg_kmem_update_page_stat(page, MEMCG_KERNEL_STACK,
-                                           1 << THREAD_SIZE_ORDER);
-
        return page ? page_address(page) : NULL;
 }
 
 static inline void free_thread_stack(unsigned long *stack)
 {
-       struct page *page = virt_to_page(stack);
-
-       memcg_kmem_update_page_stat(page, MEMCG_KERNEL_STACK,
-                                   -(1 << THREAD_SIZE_ORDER));
-       __free_pages(page, THREAD_SIZE_ORDER);
+       __free_pages(virt_to_page(stack), THREAD_SIZE_ORDER);
 }
 # else
 static struct kmem_cache *thread_stack_cache;
@@ -223,9 +215,15 @@ static struct kmem_cache *mm_cachep;
 
 static void account_kernel_stack(unsigned long *stack, int account)
 {
-       struct zone *zone = page_zone(virt_to_page(stack));
+       /* All stack pages are in the same zone and belong to the same memcg. */
+       struct page *first_page = virt_to_page(stack);
+
+       mod_zone_page_state(page_zone(first_page), NR_KERNEL_STACK_KB,
+                           THREAD_SIZE / 1024 * account);
 
-       mod_zone_page_state(zone, NR_KERNEL_STACK, account);
+       memcg_kmem_update_page_stat(
+               first_page, MEMCG_KERNEL_STACK_KB,
+               account * (THREAD_SIZE / 1024));
 }
 
 void free_task(struct task_struct *tsk)
index a8900a3bc27a895b65580a23a144e581bfe0149d..6f56a9e219facf003d802bd1e9c0cd2dea9824d3 100644 (file)
@@ -42,7 +42,7 @@ bool freezing_slow_path(struct task_struct *p)
        if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
                return false;
 
-       if (test_thread_flag(TIF_MEMDIE))
+       if (test_tsk_thread_flag(p, TIF_MEMDIE))
                return false;
 
        if (pm_nosig_freezing || cgroup_freezing(p))
index 017532193fb1c009b83801b27172f8210988f074..251d16b4cb41e67111ff2f1f783bf39cdea13822 100644 (file)
@@ -169,12 +169,6 @@ void devm_memunmap(struct device *dev, void *addr)
 }
 EXPORT_SYMBOL(devm_memunmap);
 
-pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags)
-{
-       return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags);
-}
-EXPORT_SYMBOL(phys_to_pfn_t);
-
 #ifdef CONFIG_ZONE_DEVICE
 static DEFINE_MUTEX(pgmap_lock);
 static RADIX_TREE(pgmap_radix, GFP_KERNEL);
@@ -308,12 +302,6 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
        if (is_ram == REGION_INTERSECTS)
                return __va(res->start);
 
-       if (altmap && !IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP)) {
-               dev_err(dev, "%s: altmap requires CONFIG_SPARSEMEM_VMEMMAP=y\n",
-                               __func__);
-               return ERR_PTR(-ENXIO);
-       }
-
        if (!ref)
                return ERR_PTR(-EINVAL);
 
@@ -401,7 +389,6 @@ void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns)
        altmap->alloc -= nr_pfns;
 }
 
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
 struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
 {
        /*
@@ -427,5 +414,4 @@ struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
 
        return pgmap ? pgmap->altmap : NULL;
 }
-#endif /* CONFIG_SPARSEMEM_VMEMMAP */
 #endif /* CONFIG_ZONE_DEVICE */
index d90df926b59fbdf8e76d057d85b55b31ef615f1d..9a0178c2ac1df6b68f52a31e96beda95a1517781 100644 (file)
@@ -1627,11 +1627,11 @@ static unsigned long minimum_image_size(unsigned long saveable)
        unsigned long size;
 
        size = global_page_state(NR_SLAB_RECLAIMABLE)
-               + global_page_state(NR_ACTIVE_ANON)
-               + global_page_state(NR_INACTIVE_ANON)
-               + global_page_state(NR_ACTIVE_FILE)
-               + global_page_state(NR_INACTIVE_FILE)
-               - global_page_state(NR_FILE_MAPPED);
+               + global_node_page_state(NR_ACTIVE_ANON)
+               + global_node_page_state(NR_INACTIVE_ANON)
+               + global_node_page_state(NR_ACTIVE_FILE)
+               + global_node_page_state(NR_INACTIVE_FILE)
+               - global_node_page_state(NR_FILE_MAPPED);
 
        return saveable <= size ? 0 : saveable - size;
 }
index 60cdf63867632bdca556d7ab32a2824138a48f4c..d4de33934dacc41d481269bd7fe7e7b2660e1efd 100644 (file)
@@ -3177,9 +3177,8 @@ void show_regs_print_info(const char *log_lvl)
 {
        dump_stack_print_info(log_lvl);
 
-       printk("%stask: %p ti: %p task.ti: %p\n",
-              log_lvl, current, current_thread_info(),
-              task_thread_info(current));
+       printk("%stask: %p task.stack: %p\n",
+              log_lvl, current, task_stack_page(current));
 }
 
 #endif
index 35f0dcb1cb4f6db187679edc586b5df543e85046..53954631a4e192e9c8a35d806b31345b5ece2423 100644 (file)
@@ -1508,8 +1508,8 @@ static struct ctl_table vm_table[] = {
 #ifdef CONFIG_NUMA
        {
                .procname       = "zone_reclaim_mode",
-               .data           = &zone_reclaim_mode,
-               .maxlen         = sizeof(zone_reclaim_mode),
+               .data           = &node_reclaim_mode,
+               .maxlen         = sizeof(node_reclaim_mode),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
                .extra1         = &zero,
index fafeaf803bd04f605dddd103f8bfc7de3ee0651e..f4b86e8ca1e77dba8d969aa009491876186f457f 100644 (file)
@@ -542,6 +542,7 @@ config HIST_TRIGGERS
        bool "Histogram triggers"
        depends on ARCH_HAVE_NMI_SAFE_CMPXCHG
        select TRACING_MAP
+       select TRACING
        default n
        help
          Hist triggers allow one or more arbitrary trace event fields
index 900dbb1efff2bb8554e3fa6edeb4172af3594d55..84752c8e28b5286b03d9422a79a92429427681cb 100644 (file)
@@ -89,16 +89,16 @@ struct ftrace_ops *function_trace_op __read_mostly = &ftrace_list_end;
 /* What to set function_trace_op to */
 static struct ftrace_ops *set_function_trace_op;
 
-/* List for set_ftrace_pid's pids. */
-LIST_HEAD(ftrace_pids);
-struct ftrace_pid {
-       struct list_head list;
-       struct pid *pid;
-};
-
-static bool ftrace_pids_enabled(void)
+static bool ftrace_pids_enabled(struct ftrace_ops *ops)
 {
-       return !list_empty(&ftrace_pids);
+       struct trace_array *tr;
+
+       if (!(ops->flags & FTRACE_OPS_FL_PID) || !ops->private)
+               return false;
+
+       tr = ops->private;
+
+       return tr->function_pids != NULL;
 }
 
 static void ftrace_update_trampoline(struct ftrace_ops *ops);
@@ -179,7 +179,9 @@ int ftrace_nr_registered_ops(void)
 static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip,
                            struct ftrace_ops *op, struct pt_regs *regs)
 {
-       if (!test_tsk_trace_trace(current))
+       struct trace_array *tr = op->private;
+
+       if (tr && this_cpu_read(tr->trace_buffer.data->ftrace_ignore_pid))
                return;
 
        op->saved_func(ip, parent_ip, op, regs);
@@ -417,7 +419,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
        /* Always save the function, and reset at unregistering */
        ops->saved_func = ops->func;
 
-       if (ops->flags & FTRACE_OPS_FL_PID && ftrace_pids_enabled())
+       if (ftrace_pids_enabled(ops))
                ops->func = ftrace_pid_func;
 
        ftrace_update_trampoline(ops);
@@ -450,7 +452,6 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
 
 static void ftrace_update_pid_func(void)
 {
-       bool enabled = ftrace_pids_enabled();
        struct ftrace_ops *op;
 
        /* Only do something if we are tracing something */
@@ -459,8 +460,8 @@ static void ftrace_update_pid_func(void)
 
        do_for_each_ftrace_op(op, ftrace_ops_list) {
                if (op->flags & FTRACE_OPS_FL_PID) {
-                       op->func = enabled ? ftrace_pid_func :
-                               op->saved_func;
+                       op->func = ftrace_pids_enabled(op) ?
+                               ftrace_pid_func : op->saved_func;
                        ftrace_update_trampoline(op);
                }
        } while_for_each_ftrace_op(op);
@@ -5324,179 +5325,99 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops)
        return ops->func;
 }
 
-static void clear_ftrace_swapper(void)
+static void
+ftrace_filter_pid_sched_switch_probe(void *data, bool preempt,
+                   struct task_struct *prev, struct task_struct *next)
 {
-       struct task_struct *p;
-       int cpu;
+       struct trace_array *tr = data;
+       struct trace_pid_list *pid_list;
 
-       get_online_cpus();
-       for_each_online_cpu(cpu) {
-               p = idle_task(cpu);
-               clear_tsk_trace_trace(p);
-       }
-       put_online_cpus();
-}
-
-static void set_ftrace_swapper(void)
-{
-       struct task_struct *p;
-       int cpu;
+       pid_list = rcu_dereference_sched(tr->function_pids);
 
-       get_online_cpus();
-       for_each_online_cpu(cpu) {
-               p = idle_task(cpu);
-               set_tsk_trace_trace(p);
-       }
-       put_online_cpus();
+       this_cpu_write(tr->trace_buffer.data->ftrace_ignore_pid,
+                      trace_ignore_this_task(pid_list, next));
 }
 
-static void clear_ftrace_pid(struct pid *pid)
+static void clear_ftrace_pids(struct trace_array *tr)
 {
-       struct task_struct *p;
+       struct trace_pid_list *pid_list;
+       int cpu;
 
-       rcu_read_lock();
-       do_each_pid_task(pid, PIDTYPE_PID, p) {
-               clear_tsk_trace_trace(p);
-       } while_each_pid_task(pid, PIDTYPE_PID, p);
-       rcu_read_unlock();
+       pid_list = rcu_dereference_protected(tr->function_pids,
+                                            lockdep_is_held(&ftrace_lock));
+       if (!pid_list)
+               return;
 
-       put_pid(pid);
-}
+       unregister_trace_sched_switch(ftrace_filter_pid_sched_switch_probe, tr);
 
-static void set_ftrace_pid(struct pid *pid)
-{
-       struct task_struct *p;
+       for_each_possible_cpu(cpu)
+               per_cpu_ptr(tr->trace_buffer.data, cpu)->ftrace_ignore_pid = false;
 
-       rcu_read_lock();
-       do_each_pid_task(pid, PIDTYPE_PID, p) {
-               set_tsk_trace_trace(p);
-       } while_each_pid_task(pid, PIDTYPE_PID, p);
-       rcu_read_unlock();
-}
+       rcu_assign_pointer(tr->function_pids, NULL);
 
-static void clear_ftrace_pid_task(struct pid *pid)
-{
-       if (pid == ftrace_swapper_pid)
-               clear_ftrace_swapper();
-       else
-               clear_ftrace_pid(pid);
-}
+       /* Wait till all users are no longer using pid filtering */
+       synchronize_sched();
 
-static void set_ftrace_pid_task(struct pid *pid)
-{
-       if (pid == ftrace_swapper_pid)
-               set_ftrace_swapper();
-       else
-               set_ftrace_pid(pid);
+       trace_free_pid_list(pid_list);
 }
 
-static int ftrace_pid_add(int p)
+static void ftrace_pid_reset(struct trace_array *tr)
 {
-       struct pid *pid;
-       struct ftrace_pid *fpid;
-       int ret = -EINVAL;
-
        mutex_lock(&ftrace_lock);
-
-       if (!p)
-               pid = ftrace_swapper_pid;
-       else
-               pid = find_get_pid(p);
-
-       if (!pid)
-               goto out;
-
-       ret = 0;
-
-       list_for_each_entry(fpid, &ftrace_pids, list)
-               if (fpid->pid == pid)
-                       goto out_put;
-
-       ret = -ENOMEM;
-
-       fpid = kmalloc(sizeof(*fpid), GFP_KERNEL);
-       if (!fpid)
-               goto out_put;
-
-       list_add(&fpid->list, &ftrace_pids);
-       fpid->pid = pid;
-
-       set_ftrace_pid_task(pid);
+       clear_ftrace_pids(tr);
 
        ftrace_update_pid_func();
-
        ftrace_startup_all(0);
 
        mutex_unlock(&ftrace_lock);
-       return 0;
-
-out_put:
-       if (pid != ftrace_swapper_pid)
-               put_pid(pid);
-
-out:
-       mutex_unlock(&ftrace_lock);
-       return ret;
 }
 
-static void ftrace_pid_reset(void)
-{
-       struct ftrace_pid *fpid, *safe;
-
-       mutex_lock(&ftrace_lock);
-       list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) {
-               struct pid *pid = fpid->pid;
-
-               clear_ftrace_pid_task(pid);
-
-               list_del(&fpid->list);
-               kfree(fpid);
-       }
-
-       ftrace_update_pid_func();
-       ftrace_startup_all(0);
-
-       mutex_unlock(&ftrace_lock);
-}
+/* Greater than any max PID */
+#define FTRACE_NO_PIDS         (void *)(PID_MAX_LIMIT + 1)
 
 static void *fpid_start(struct seq_file *m, loff_t *pos)
+       __acquires(RCU)
 {
+       struct trace_pid_list *pid_list;
+       struct trace_array *tr = m->private;
+
        mutex_lock(&ftrace_lock);
+       rcu_read_lock_sched();
 
-       if (!ftrace_pids_enabled() && (!*pos))
-               return (void *) 1;
+       pid_list = rcu_dereference_sched(tr->function_pids);
 
-       return seq_list_start(&ftrace_pids, *pos);
+       if (!pid_list)
+               return !(*pos) ? FTRACE_NO_PIDS : NULL;
+
+       return trace_pid_start(pid_list, pos);
 }
 
 static void *fpid_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       if (v == (void *)1)
+       struct trace_array *tr = m->private;
+       struct trace_pid_list *pid_list = rcu_dereference_sched(tr->function_pids);
+
+       if (v == FTRACE_NO_PIDS)
                return NULL;
 
-       return seq_list_next(v, &ftrace_pids, pos);
+       return trace_pid_next(pid_list, v, pos);
 }
 
 static void fpid_stop(struct seq_file *m, void *p)
+       __releases(RCU)
 {
+       rcu_read_unlock_sched();
        mutex_unlock(&ftrace_lock);
 }
 
 static int fpid_show(struct seq_file *m, void *v)
 {
-       const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list);
-
-       if (v == (void *)1) {
+       if (v == FTRACE_NO_PIDS) {
                seq_puts(m, "no pid\n");
                return 0;
        }
 
-       if (fpid->pid == ftrace_swapper_pid)
-               seq_puts(m, "swapper tasks\n");
-       else
-               seq_printf(m, "%u\n", pid_vnr(fpid->pid));
-
-       return 0;
+       return trace_pid_show(m, v);
 }
 
 static const struct seq_operations ftrace_pid_sops = {
@@ -5509,58 +5430,103 @@ static const struct seq_operations ftrace_pid_sops = {
 static int
 ftrace_pid_open(struct inode *inode, struct file *file)
 {
+       struct trace_array *tr = inode->i_private;
+       struct seq_file *m;
        int ret = 0;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        if ((file->f_mode & FMODE_WRITE) &&
            (file->f_flags & O_TRUNC))
-               ftrace_pid_reset();
+               ftrace_pid_reset(tr);
 
-       if (file->f_mode & FMODE_READ)
-               ret = seq_open(file, &ftrace_pid_sops);
+       ret = seq_open(file, &ftrace_pid_sops);
+       if (ret < 0) {
+               trace_array_put(tr);
+       } else {
+               m = file->private_data;
+               /* copy tr over to seq ops */
+               m->private = tr;
+       }
 
        return ret;
 }
 
+static void ignore_task_cpu(void *data)
+{
+       struct trace_array *tr = data;
+       struct trace_pid_list *pid_list;
+
+       /*
+        * This function is called by on_each_cpu() while the
+        * event_mutex is held.
+        */
+       pid_list = rcu_dereference_protected(tr->function_pids,
+                                            mutex_is_locked(&ftrace_lock));
+
+       this_cpu_write(tr->trace_buffer.data->ftrace_ignore_pid,
+                      trace_ignore_this_task(pid_list, current));
+}
+
 static ssize_t
 ftrace_pid_write(struct file *filp, const char __user *ubuf,
                   size_t cnt, loff_t *ppos)
 {
-       char buf[64], *tmp;
-       long val;
-       int ret;
+       struct seq_file *m = filp->private_data;
+       struct trace_array *tr = m->private;
+       struct trace_pid_list *filtered_pids = NULL;
+       struct trace_pid_list *pid_list;
+       ssize_t ret;
 
-       if (cnt >= sizeof(buf))
-               return -EINVAL;
+       if (!cnt)
+               return 0;
+
+       mutex_lock(&ftrace_lock);
+
+       filtered_pids = rcu_dereference_protected(tr->function_pids,
+                                            lockdep_is_held(&ftrace_lock));
+
+       ret = trace_pid_write(filtered_pids, &pid_list, ubuf, cnt);
+       if (ret < 0)
+               goto out;
 
-       if (copy_from_user(&buf, ubuf, cnt))
-               return -EFAULT;
+       rcu_assign_pointer(tr->function_pids, pid_list);
 
-       buf[cnt] = 0;
+       if (filtered_pids) {
+               synchronize_sched();
+               trace_free_pid_list(filtered_pids);
+       } else if (pid_list) {
+               /* Register a probe to set whether to ignore the tracing of a task */
+               register_trace_sched_switch(ftrace_filter_pid_sched_switch_probe, tr);
+       }
 
        /*
-        * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid"
-        * to clean the filter quietly.
+        * Ignoring of pids is done at task switch. But we have to
+        * check for those tasks that are currently running.
+        * Always do this in case a pid was appended or removed.
         */
-       tmp = strstrip(buf);
-       if (strlen(tmp) == 0)
-               return 1;
+       on_each_cpu(ignore_task_cpu, tr, 1);
 
-       ret = kstrtol(tmp, 10, &val);
-       if (ret < 0)
-               return ret;
+       ftrace_update_pid_func();
+       ftrace_startup_all(0);
+ out:
+       mutex_unlock(&ftrace_lock);
 
-       ret = ftrace_pid_add(val);
+       if (ret > 0)
+               *ppos += ret;
 
-       return ret ? ret : cnt;
+       return ret;
 }
 
 static int
 ftrace_pid_release(struct inode *inode, struct file *file)
 {
-       if (file->f_mode & FMODE_READ)
-               seq_release(inode, file);
+       struct trace_array *tr = inode->i_private;
 
-       return 0;
+       trace_array_put(tr);
+
+       return seq_release(inode, file);
 }
 
 static const struct file_operations ftrace_pid_fops = {
@@ -5571,24 +5537,21 @@ static const struct file_operations ftrace_pid_fops = {
        .release        = ftrace_pid_release,
 };
 
-static __init int ftrace_init_tracefs(void)
+void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer)
 {
-       struct dentry *d_tracer;
+       trace_create_file("set_ftrace_pid", 0644, d_tracer,
+                           tr, &ftrace_pid_fops);
+}
 
-       d_tracer = tracing_init_dentry();
-       if (IS_ERR(d_tracer))
-               return 0;
+void __init ftrace_init_tracefs_toplevel(struct trace_array *tr,
+                                        struct dentry *d_tracer)
+{
+       /* Only the top level directory has the dyn_tracefs and profile */
+       WARN_ON(!(tr->flags & TRACE_ARRAY_FL_GLOBAL));
 
        ftrace_init_dyn_tracefs(d_tracer);
-
-       trace_create_file("set_ftrace_pid", 0644, d_tracer,
-                           NULL, &ftrace_pid_fops);
-
        ftrace_profile_tracefs(d_tracer);
-
-       return 0;
 }
-fs_initcall(ftrace_init_tracefs);
 
 /**
  * ftrace_kill - kill ftrace
index 8a4bd6b68a0b6ee4c6c315b9d891806482e14b3c..dade4c9559cc036c1b6aa8567abf0b0887847923 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/hardirq.h>
 #include <linux/linkage.h>
 #include <linux/uaccess.h>
-#include <linux/kprobes.h>
+#include <linux/vmalloc.h>
 #include <linux/ftrace.h>
 #include <linux/module.h>
 #include <linux/percpu.h>
@@ -319,6 +319,258 @@ int call_filter_check_discard(struct trace_event_call *call, void *rec,
        return 0;
 }
 
+void trace_free_pid_list(struct trace_pid_list *pid_list)
+{
+       vfree(pid_list->pids);
+       kfree(pid_list);
+}
+
+/**
+ * trace_find_filtered_pid - check if a pid exists in a filtered_pid list
+ * @filtered_pids: The list of pids to check
+ * @search_pid: The PID to find in @filtered_pids
+ *
+ * Returns true if @search_pid is fonud in @filtered_pids, and false otherwis.
+ */
+bool
+trace_find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid)
+{
+       /*
+        * If pid_max changed after filtered_pids was created, we
+        * by default ignore all pids greater than the previous pid_max.
+        */
+       if (search_pid >= filtered_pids->pid_max)
+               return false;
+
+       return test_bit(search_pid, filtered_pids->pids);
+}
+
+/**
+ * trace_ignore_this_task - should a task be ignored for tracing
+ * @filtered_pids: The list of pids to check
+ * @task: The task that should be ignored if not filtered
+ *
+ * Checks if @task should be traced or not from @filtered_pids.
+ * Returns true if @task should *NOT* be traced.
+ * Returns false if @task should be traced.
+ */
+bool
+trace_ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task)
+{
+       /*
+        * Return false, because if filtered_pids does not exist,
+        * all pids are good to trace.
+        */
+       if (!filtered_pids)
+               return false;
+
+       return !trace_find_filtered_pid(filtered_pids, task->pid);
+}
+
+/**
+ * trace_pid_filter_add_remove - Add or remove a task from a pid_list
+ * @pid_list: The list to modify
+ * @self: The current task for fork or NULL for exit
+ * @task: The task to add or remove
+ *
+ * If adding a task, if @self is defined, the task is only added if @self
+ * is also included in @pid_list. This happens on fork and tasks should
+ * only be added when the parent is listed. If @self is NULL, then the
+ * @task pid will be removed from the list, which would happen on exit
+ * of a task.
+ */
+void trace_filter_add_remove_task(struct trace_pid_list *pid_list,
+                                 struct task_struct *self,
+                                 struct task_struct *task)
+{
+       if (!pid_list)
+               return;
+
+       /* For forks, we only add if the forking task is listed */
+       if (self) {
+               if (!trace_find_filtered_pid(pid_list, self->pid))
+                       return;
+       }
+
+       /* Sorry, but we don't support pid_max changing after setting */
+       if (task->pid >= pid_list->pid_max)
+               return;
+
+       /* "self" is set for forks, and NULL for exits */
+       if (self)
+               set_bit(task->pid, pid_list->pids);
+       else
+               clear_bit(task->pid, pid_list->pids);
+}
+
+/**
+ * trace_pid_next - Used for seq_file to get to the next pid of a pid_list
+ * @pid_list: The pid list to show
+ * @v: The last pid that was shown (+1 the actual pid to let zero be displayed)
+ * @pos: The position of the file
+ *
+ * This is used by the seq_file "next" operation to iterate the pids
+ * listed in a trace_pid_list structure.
+ *
+ * Returns the pid+1 as we want to display pid of zero, but NULL would
+ * stop the iteration.
+ */
+void *trace_pid_next(struct trace_pid_list *pid_list, void *v, loff_t *pos)
+{
+       unsigned long pid = (unsigned long)v;
+
+       (*pos)++;
+
+       /* pid already is +1 of the actual prevous bit */
+       pid = find_next_bit(pid_list->pids, pid_list->pid_max, pid);
+
+       /* Return pid + 1 to allow zero to be represented */
+       if (pid < pid_list->pid_max)
+               return (void *)(pid + 1);
+
+       return NULL;
+}
+
+/**
+ * trace_pid_start - Used for seq_file to start reading pid lists
+ * @pid_list: The pid list to show
+ * @pos: The position of the file
+ *
+ * This is used by seq_file "start" operation to start the iteration
+ * of listing pids.
+ *
+ * Returns the pid+1 as we want to display pid of zero, but NULL would
+ * stop the iteration.
+ */
+void *trace_pid_start(struct trace_pid_list *pid_list, loff_t *pos)
+{
+       unsigned long pid;
+       loff_t l = 0;
+
+       pid = find_first_bit(pid_list->pids, pid_list->pid_max);
+       if (pid >= pid_list->pid_max)
+               return NULL;
+
+       /* Return pid + 1 so that zero can be the exit value */
+       for (pid++; pid && l < *pos;
+            pid = (unsigned long)trace_pid_next(pid_list, (void *)pid, &l))
+               ;
+       return (void *)pid;
+}
+
+/**
+ * trace_pid_show - show the current pid in seq_file processing
+ * @m: The seq_file structure to write into
+ * @v: A void pointer of the pid (+1) value to display
+ *
+ * Can be directly used by seq_file operations to display the current
+ * pid value.
+ */
+int trace_pid_show(struct seq_file *m, void *v)
+{
+       unsigned long pid = (unsigned long)v - 1;
+
+       seq_printf(m, "%lu\n", pid);
+       return 0;
+}
+
+/* 128 should be much more than enough */
+#define PID_BUF_SIZE           127
+
+int trace_pid_write(struct trace_pid_list *filtered_pids,
+                   struct trace_pid_list **new_pid_list,
+                   const char __user *ubuf, size_t cnt)
+{
+       struct trace_pid_list *pid_list;
+       struct trace_parser parser;
+       unsigned long val;
+       int nr_pids = 0;
+       ssize_t read = 0;
+       ssize_t ret = 0;
+       loff_t pos;
+       pid_t pid;
+
+       if (trace_parser_get_init(&parser, PID_BUF_SIZE + 1))
+               return -ENOMEM;
+
+       /*
+        * Always recreate a new array. The write is an all or nothing
+        * operation. Always create a new array when adding new pids by
+        * the user. If the operation fails, then the current list is
+        * not modified.
+        */
+       pid_list = kmalloc(sizeof(*pid_list), GFP_KERNEL);
+       if (!pid_list)
+               return -ENOMEM;
+
+       pid_list->pid_max = READ_ONCE(pid_max);
+
+       /* Only truncating will shrink pid_max */
+       if (filtered_pids && filtered_pids->pid_max > pid_list->pid_max)
+               pid_list->pid_max = filtered_pids->pid_max;
+
+       pid_list->pids = vzalloc((pid_list->pid_max + 7) >> 3);
+       if (!pid_list->pids) {
+               kfree(pid_list);
+               return -ENOMEM;
+       }
+
+       if (filtered_pids) {
+               /* copy the current bits to the new max */
+               for_each_set_bit(pid, filtered_pids->pids,
+                                filtered_pids->pid_max) {
+                       set_bit(pid, pid_list->pids);
+                       nr_pids++;
+               }
+       }
+
+       while (cnt > 0) {
+
+               pos = 0;
+
+               ret = trace_get_user(&parser, ubuf, cnt, &pos);
+               if (ret < 0 || !trace_parser_loaded(&parser))
+                       break;
+
+               read += ret;
+               ubuf += ret;
+               cnt -= ret;
+
+               parser.buffer[parser.idx] = 0;
+
+               ret = -EINVAL;
+               if (kstrtoul(parser.buffer, 0, &val))
+                       break;
+               if (val >= pid_list->pid_max)
+                       break;
+
+               pid = (pid_t)val;
+
+               set_bit(pid, pid_list->pids);
+               nr_pids++;
+
+               trace_parser_clear(&parser);
+               ret = 0;
+       }
+       trace_parser_put(&parser);
+
+       if (ret < 0) {
+               trace_free_pid_list(pid_list);
+               return ret;
+       }
+
+       if (!nr_pids) {
+               /* Cleared the list of pids */
+               trace_free_pid_list(pid_list);
+               read = ret;
+               pid_list = NULL;
+       }
+
+       *new_pid_list = pid_list;
+
+       return read;
+}
+
 static cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu)
 {
        u64 ts;
@@ -1862,7 +2114,17 @@ void trace_buffer_unlock_commit_regs(struct trace_array *tr,
 {
        __buffer_unlock_commit(buffer, event);
 
-       ftrace_trace_stack(tr, buffer, flags, 0, pc, regs);
+       /*
+        * If regs is not set, then skip the following callers:
+        *   trace_buffer_unlock_commit_regs
+        *   event_trigger_unlock_commit
+        *   trace_event_buffer_commit
+        *   trace_event_raw_event_sched_switch
+        * Note, we can still get here via blktrace, wakeup tracer
+        * and mmiotrace, but that's ok if they lose a function or
+        * two. They are that meaningful.
+        */
+       ftrace_trace_stack(tr, buffer, flags, regs ? 0 : 4, pc, regs);
        ftrace_trace_userstack(buffer, flags, pc);
 }
 
@@ -1912,6 +2174,13 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,
        trace.nr_entries        = 0;
        trace.skip              = skip;
 
+       /*
+        * Add two, for this function and the call to save_stack_trace()
+        * If regs is set, then these functions will not be in the way.
+        */
+       if (!regs)
+               trace.skip += 2;
+
        /*
         * Since events can happen in NMIs there's no safe way to
         * use the per cpu ftrace_stacks. We reserve it and if an interrupt
@@ -2083,83 +2352,41 @@ static void __trace_userstack(struct trace_array *tr, unsigned long flags)
 
 /* created for use with alloc_percpu */
 struct trace_buffer_struct {
-       char buffer[TRACE_BUF_SIZE];
+       int nesting;
+       char buffer[4][TRACE_BUF_SIZE];
 };
 
 static struct trace_buffer_struct *trace_percpu_buffer;
-static struct trace_buffer_struct *trace_percpu_sirq_buffer;
-static struct trace_buffer_struct *trace_percpu_irq_buffer;
-static struct trace_buffer_struct *trace_percpu_nmi_buffer;
 
 /*
- * The buffer used is dependent on the context. There is a per cpu
- * buffer for normal context, softirq contex, hard irq context and
- * for NMI context. Thise allows for lockless recording.
- *
- * Note, if the buffers failed to be allocated, then this returns NULL
+ * Thise allows for lockless recording.  If we're nested too deeply, then
+ * this returns NULL.
  */
 static char *get_trace_buf(void)
 {
-       struct trace_buffer_struct *percpu_buffer;
-
-       /*
-        * If we have allocated per cpu buffers, then we do not
-        * need to do any locking.
-        */
-       if (in_nmi())
-               percpu_buffer = trace_percpu_nmi_buffer;
-       else if (in_irq())
-               percpu_buffer = trace_percpu_irq_buffer;
-       else if (in_softirq())
-               percpu_buffer = trace_percpu_sirq_buffer;
-       else
-               percpu_buffer = trace_percpu_buffer;
+       struct trace_buffer_struct *buffer = this_cpu_ptr(trace_percpu_buffer);
 
-       if (!percpu_buffer)
+       if (!buffer || buffer->nesting >= 4)
                return NULL;
 
-       return this_cpu_ptr(&percpu_buffer->buffer[0]);
+       return &buffer->buffer[buffer->nesting++][0];
+}
+
+static void put_trace_buf(void)
+{
+       this_cpu_dec(trace_percpu_buffer->nesting);
 }
 
 static int alloc_percpu_trace_buffer(void)
 {
        struct trace_buffer_struct *buffers;
-       struct trace_buffer_struct *sirq_buffers;
-       struct trace_buffer_struct *irq_buffers;
-       struct trace_buffer_struct *nmi_buffers;
 
        buffers = alloc_percpu(struct trace_buffer_struct);
-       if (!buffers)
-               goto err_warn;
-
-       sirq_buffers = alloc_percpu(struct trace_buffer_struct);
-       if (!sirq_buffers)
-               goto err_sirq;
-
-       irq_buffers = alloc_percpu(struct trace_buffer_struct);
-       if (!irq_buffers)
-               goto err_irq;
-
-       nmi_buffers = alloc_percpu(struct trace_buffer_struct);
-       if (!nmi_buffers)
-               goto err_nmi;
+       if (WARN(!buffers, "Could not allocate percpu trace_printk buffer"))
+               return -ENOMEM;
 
        trace_percpu_buffer = buffers;
-       trace_percpu_sirq_buffer = sirq_buffers;
-       trace_percpu_irq_buffer = irq_buffers;
-       trace_percpu_nmi_buffer = nmi_buffers;
-
        return 0;
-
- err_nmi:
-       free_percpu(irq_buffers);
- err_irq:
-       free_percpu(sirq_buffers);
- err_sirq:
-       free_percpu(buffers);
- err_warn:
-       WARN(1, "Could not allocate percpu trace_printk buffer");
-       return -ENOMEM;
 }
 
 static int buffers_allocated;
@@ -2250,7 +2477,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
        tbuffer = get_trace_buf();
        if (!tbuffer) {
                len = 0;
-               goto out;
+               goto out_nobuffer;
        }
 
        len = vbin_printf((u32 *)tbuffer, TRACE_BUF_SIZE/sizeof(int), fmt, args);
@@ -2276,6 +2503,9 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
        }
 
 out:
+       put_trace_buf();
+
+out_nobuffer:
        preempt_enable_notrace();
        unpause_graph_tracing();
 
@@ -2307,7 +2537,7 @@ __trace_array_vprintk(struct ring_buffer *buffer,
        tbuffer = get_trace_buf();
        if (!tbuffer) {
                len = 0;
-               goto out;
+               goto out_nobuffer;
        }
 
        len = vscnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args);
@@ -2326,7 +2556,11 @@ __trace_array_vprintk(struct ring_buffer *buffer,
                __buffer_unlock_commit(buffer, event);
                ftrace_trace_stack(&global_trace, buffer, flags, 6, pc, NULL);
        }
- out:
+
+out:
+       put_trace_buf();
+
+out_nobuffer:
        preempt_enable_notrace();
        unpause_graph_tracing();
 
@@ -6977,6 +7211,7 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
        for_each_tracing_cpu(cpu)
                tracing_init_tracefs_percpu(tr, cpu);
 
+       ftrace_init_tracefs(tr, d_tracer);
 }
 
 static struct vfsmount *trace_automount(void *ingore)
@@ -7130,6 +7365,7 @@ static __init int tracer_init_tracefs(void)
                return 0;
 
        init_tracer_tracefs(&global_trace, d_tracer);
+       ftrace_init_tracefs_toplevel(&global_trace, d_tracer);
 
        trace_create_file("tracing_thresh", 0644, d_tracer,
                        &global_trace, &tracing_thresh_fops);
index 5167c366d6b787a8b2a24ac7380e82d5495b4638..f783df416726497b0e43fe6666fdc01a7432b644 100644 (file)
@@ -80,6 +80,12 @@ enum trace_type {
        FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
                     filter)
 
+#undef FTRACE_ENTRY_PACKED
+#define FTRACE_ENTRY_PACKED(name, struct_name, id, tstruct, print,     \
+                           filter)                                     \
+       FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
+                    filter) __packed
+
 #include "trace_entries.h"
 
 /*
@@ -156,6 +162,9 @@ struct trace_array_cpu {
        char                    comm[TASK_COMM_LEN];
 
        bool                    ignore_pid;
+#ifdef CONFIG_FUNCTION_TRACER
+       bool                    ftrace_ignore_pid;
+#endif
 };
 
 struct tracer;
@@ -247,6 +256,7 @@ struct trace_array {
        int                     ref;
 #ifdef CONFIG_FUNCTION_TRACER
        struct ftrace_ops       *ops;
+       struct trace_pid_list   __rcu *function_pids;
        /* function tracing enabled */
        int                     function_enabled;
 #endif
@@ -628,6 +638,25 @@ extern unsigned long nsecs_to_usecs(unsigned long nsecs);
 
 extern unsigned long tracing_thresh;
 
+/* PID filtering */
+
+extern int pid_max;
+
+bool trace_find_filtered_pid(struct trace_pid_list *filtered_pids,
+                            pid_t search_pid);
+bool trace_ignore_this_task(struct trace_pid_list *filtered_pids,
+                           struct task_struct *task);
+void trace_filter_add_remove_task(struct trace_pid_list *pid_list,
+                                 struct task_struct *self,
+                                 struct task_struct *task);
+void *trace_pid_next(struct trace_pid_list *pid_list, void *v, loff_t *pos);
+void *trace_pid_start(struct trace_pid_list *pid_list, loff_t *pos);
+int trace_pid_show(struct seq_file *m, void *v);
+void trace_free_pid_list(struct trace_pid_list *pid_list);
+int trace_pid_write(struct trace_pid_list *filtered_pids,
+                   struct trace_pid_list **new_pid_list,
+                   const char __user *ubuf, size_t cnt);
+
 #ifdef CONFIG_TRACER_MAX_TRACE
 void update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu);
 void update_max_tr_single(struct trace_array *tr,
@@ -821,12 +850,9 @@ extern struct list_head ftrace_pids;
 
 #ifdef CONFIG_FUNCTION_TRACER
 extern bool ftrace_filter_param __initdata;
-static inline int ftrace_trace_task(struct task_struct *task)
+static inline int ftrace_trace_task(struct trace_array *tr)
 {
-       if (list_empty(&ftrace_pids))
-               return 1;
-
-       return test_tsk_trace_trace(task);
+       return !this_cpu_read(tr->trace_buffer.data->ftrace_ignore_pid);
 }
 extern int ftrace_is_dead(void);
 int ftrace_create_function_files(struct trace_array *tr,
@@ -836,8 +862,11 @@ void ftrace_init_global_array_ops(struct trace_array *tr);
 void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func);
 void ftrace_reset_array_ops(struct trace_array *tr);
 int using_ftrace_ops_list_func(void);
+void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer);
+void ftrace_init_tracefs_toplevel(struct trace_array *tr,
+                                 struct dentry *d_tracer);
 #else
-static inline int ftrace_trace_task(struct task_struct *task)
+static inline int ftrace_trace_task(struct trace_array *tr)
 {
        return 1;
 }
@@ -852,6 +881,8 @@ static inline void ftrace_destroy_function_files(struct trace_array *tr) { }
 static inline __init void
 ftrace_init_global_array_ops(struct trace_array *tr) { }
 static inline void ftrace_reset_array_ops(struct trace_array *tr) { }
+static inline void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d) { }
+static inline void ftrace_init_tracefs_toplevel(struct trace_array *tr, struct dentry *d) { }
 /* ftace_func_t type is not defined, use macro instead of static inline */
 #define ftrace_init_array_ops(tr, func) do { } while (0)
 #endif /* CONFIG_FUNCTION_TRACER */
@@ -1600,6 +1631,11 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled);
 #define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print, filter)        \
        FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \
                     filter)
+#undef FTRACE_ENTRY_PACKED
+#define FTRACE_ENTRY_PACKED(call, struct_name, id, tstruct, print, filter) \
+       FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \
+                    filter)
+
 #include "trace_entries.h"
 
 #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_FUNCTION_TRACER)
index ee7b94a4810af8c85aa4baa246203dc52f588eb6..5c30efcda5e696ce53b51d00bffd38f9fdf5d000 100644 (file)
@@ -72,7 +72,7 @@ FTRACE_ENTRY_REG(function, ftrace_entry,
 );
 
 /* Function call entry */
-FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry,
+FTRACE_ENTRY_PACKED(funcgraph_entry, ftrace_graph_ent_entry,
 
        TRACE_GRAPH_ENT,
 
@@ -88,7 +88,7 @@ FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry,
 );
 
 /* Function return entry */
-FTRACE_ENTRY(funcgraph_exit, ftrace_graph_ret_entry,
+FTRACE_ENTRY_PACKED(funcgraph_exit, ftrace_graph_ret_entry,
 
        TRACE_GRAPH_RET,
 
index 3d4155892a1e78cf6b8b7850e9a64c460fe825b5..03c0a48c3ac4f3daca47a46e401a75f02a826316 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kthread.h>
 #include <linux/tracefs.h>
 #include <linux/uaccess.h>
-#include <linux/vmalloc.h>
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/sort.h>
@@ -262,6 +261,14 @@ void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer,
 
        local_save_flags(fbuffer->flags);
        fbuffer->pc = preempt_count();
+       /*
+        * If CONFIG_PREEMPT is enabled, then the tracepoint itself disables
+        * preemption (adding one to the preempt_count). Since we are
+        * interested in the preempt_count at the time the tracepoint was
+        * hit, we need to subtract one to offset the increment.
+        */
+       if (IS_ENABLED(CONFIG_PREEMPT))
+               fbuffer->pc--;
        fbuffer->trace_file = trace_file;
 
        fbuffer->event =
@@ -499,60 +506,6 @@ static void ftrace_clear_events(struct trace_array *tr)
        mutex_unlock(&event_mutex);
 }
 
-/* Shouldn't this be in a header? */
-extern int pid_max;
-
-/* Returns true if found in filter */
-static bool
-find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid)
-{
-       /*
-        * If pid_max changed after filtered_pids was created, we
-        * by default ignore all pids greater than the previous pid_max.
-        */
-       if (search_pid >= filtered_pids->pid_max)
-               return false;
-
-       return test_bit(search_pid, filtered_pids->pids);
-}
-
-static bool
-ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task)
-{
-       /*
-        * Return false, because if filtered_pids does not exist,
-        * all pids are good to trace.
-        */
-       if (!filtered_pids)
-               return false;
-
-       return !find_filtered_pid(filtered_pids, task->pid);
-}
-
-static void filter_add_remove_task(struct trace_pid_list *pid_list,
-                                  struct task_struct *self,
-                                  struct task_struct *task)
-{
-       if (!pid_list)
-               return;
-
-       /* For forks, we only add if the forking task is listed */
-       if (self) {
-               if (!find_filtered_pid(pid_list, self->pid))
-                       return;
-       }
-
-       /* Sorry, but we don't support pid_max changing after setting */
-       if (task->pid >= pid_list->pid_max)
-               return;
-
-       /* "self" is set for forks, and NULL for exits */
-       if (self)
-               set_bit(task->pid, pid_list->pids);
-       else
-               clear_bit(task->pid, pid_list->pids);
-}
-
 static void
 event_filter_pid_sched_process_exit(void *data, struct task_struct *task)
 {
@@ -560,7 +513,7 @@ event_filter_pid_sched_process_exit(void *data, struct task_struct *task)
        struct trace_array *tr = data;
 
        pid_list = rcu_dereference_sched(tr->filtered_pids);
-       filter_add_remove_task(pid_list, NULL, task);
+       trace_filter_add_remove_task(pid_list, NULL, task);
 }
 
 static void
@@ -572,7 +525,7 @@ event_filter_pid_sched_process_fork(void *data,
        struct trace_array *tr = data;
 
        pid_list = rcu_dereference_sched(tr->filtered_pids);
-       filter_add_remove_task(pid_list, self, task);
+       trace_filter_add_remove_task(pid_list, self, task);
 }
 
 void trace_event_follow_fork(struct trace_array *tr, bool enable)
@@ -600,8 +553,8 @@ event_filter_pid_sched_switch_probe_pre(void *data, bool preempt,
        pid_list = rcu_dereference_sched(tr->filtered_pids);
 
        this_cpu_write(tr->trace_buffer.data->ignore_pid,
-                      ignore_this_task(pid_list, prev) &&
-                      ignore_this_task(pid_list, next));
+                      trace_ignore_this_task(pid_list, prev) &&
+                      trace_ignore_this_task(pid_list, next));
 }
 
 static void
@@ -614,7 +567,7 @@ event_filter_pid_sched_switch_probe_post(void *data, bool preempt,
        pid_list = rcu_dereference_sched(tr->filtered_pids);
 
        this_cpu_write(tr->trace_buffer.data->ignore_pid,
-                      ignore_this_task(pid_list, next));
+                      trace_ignore_this_task(pid_list, next));
 }
 
 static void
@@ -630,7 +583,7 @@ event_filter_pid_sched_wakeup_probe_pre(void *data, struct task_struct *task)
        pid_list = rcu_dereference_sched(tr->filtered_pids);
 
        this_cpu_write(tr->trace_buffer.data->ignore_pid,
-                      ignore_this_task(pid_list, task));
+                      trace_ignore_this_task(pid_list, task));
 }
 
 static void
@@ -647,7 +600,7 @@ event_filter_pid_sched_wakeup_probe_post(void *data, struct task_struct *task)
 
        /* Set tracing if current is enabled */
        this_cpu_write(tr->trace_buffer.data->ignore_pid,
-                      ignore_this_task(pid_list, current));
+                      trace_ignore_this_task(pid_list, current));
 }
 
 static void __ftrace_clear_event_pids(struct trace_array *tr)
@@ -685,8 +638,7 @@ static void __ftrace_clear_event_pids(struct trace_array *tr)
        /* Wait till all users are no longer using pid filtering */
        synchronize_sched();
 
-       vfree(pid_list->pids);
-       kfree(pid_list);
+       trace_free_pid_list(pid_list);
 }
 
 static void ftrace_clear_event_pids(struct trace_array *tr)
@@ -1034,18 +986,8 @@ p_next(struct seq_file *m, void *v, loff_t *pos)
 {
        struct trace_array *tr = m->private;
        struct trace_pid_list *pid_list = rcu_dereference_sched(tr->filtered_pids);
-       unsigned long pid = (unsigned long)v;
-
-       (*pos)++;
-
-       /* pid already is +1 of the actual prevous bit */
-       pid = find_next_bit(pid_list->pids, pid_list->pid_max, pid);
 
-       /* Return pid + 1 to allow zero to be represented */
-       if (pid < pid_list->pid_max)
-               return (void *)(pid + 1);
-
-       return NULL;
+       return trace_pid_next(pid_list, v, pos);
 }
 
 static void *p_start(struct seq_file *m, loff_t *pos)
@@ -1053,8 +995,6 @@ static void *p_start(struct seq_file *m, loff_t *pos)
 {
        struct trace_pid_list *pid_list;
        struct trace_array *tr = m->private;
-       unsigned long pid;
-       loff_t l = 0;
 
        /*
         * Grab the mutex, to keep calls to p_next() having the same
@@ -1070,15 +1010,7 @@ static void *p_start(struct seq_file *m, loff_t *pos)
        if (!pid_list)
                return NULL;
 
-       pid = find_first_bit(pid_list->pids, pid_list->pid_max);
-       if (pid >= pid_list->pid_max)
-               return NULL;
-
-       /* Return pid + 1 so that zero can be the exit value */
-       for (pid++; pid && l < *pos;
-            pid = (unsigned long)p_next(m, (void *)pid, &l))
-               ;
-       return (void *)pid;
+       return trace_pid_start(pid_list, pos);
 }
 
 static void p_stop(struct seq_file *m, void *p)
@@ -1088,14 +1020,6 @@ static void p_stop(struct seq_file *m, void *p)
        mutex_unlock(&event_mutex);
 }
 
-static int p_show(struct seq_file *m, void *v)
-{
-       unsigned long pid = (unsigned long)v - 1;
-
-       seq_printf(m, "%lu\n", pid);
-       return 0;
-}
-
 static ssize_t
 event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
@@ -1654,7 +1578,7 @@ static void ignore_task_cpu(void *data)
                                             mutex_is_locked(&event_mutex));
 
        this_cpu_write(tr->trace_buffer.data->ignore_pid,
-                      ignore_this_task(pid_list, current));
+                      trace_ignore_this_task(pid_list, current));
 }
 
 static ssize_t
@@ -1666,13 +1590,7 @@ ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
        struct trace_pid_list *filtered_pids = NULL;
        struct trace_pid_list *pid_list;
        struct trace_event_file *file;
-       struct trace_parser parser;
-       unsigned long val;
-       loff_t this_pos;
-       ssize_t read = 0;
-       ssize_t ret = 0;
-       pid_t pid;
-       int nr_pids = 0;
+       ssize_t ret;
 
        if (!cnt)
                return 0;
@@ -1681,93 +1599,15 @@ ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
        if (ret < 0)
                return ret;
 
-       if (trace_parser_get_init(&parser, EVENT_BUF_SIZE + 1))
-               return -ENOMEM;
-
        mutex_lock(&event_mutex);
+
        filtered_pids = rcu_dereference_protected(tr->filtered_pids,
                                             lockdep_is_held(&event_mutex));
 
-       /*
-        * Always recreate a new array. The write is an all or nothing
-        * operation. Always create a new array when adding new pids by
-        * the user. If the operation fails, then the current list is
-        * not modified.
-        */
-       pid_list = kmalloc(sizeof(*pid_list), GFP_KERNEL);
-       if (!pid_list) {
-               read = -ENOMEM;
-               goto out;
-       }
-       pid_list->pid_max = READ_ONCE(pid_max);
-       /* Only truncating will shrink pid_max */
-       if (filtered_pids && filtered_pids->pid_max > pid_list->pid_max)
-               pid_list->pid_max = filtered_pids->pid_max;
-       pid_list->pids = vzalloc((pid_list->pid_max + 7) >> 3);
-       if (!pid_list->pids) {
-               kfree(pid_list);
-               read = -ENOMEM;
-               goto out;
-       }
-       if (filtered_pids) {
-               /* copy the current bits to the new max */
-               pid = find_first_bit(filtered_pids->pids,
-                                    filtered_pids->pid_max);
-               while (pid < filtered_pids->pid_max) {
-                       set_bit(pid, pid_list->pids);
-                       pid = find_next_bit(filtered_pids->pids,
-                                           filtered_pids->pid_max,
-                                           pid + 1);
-                       nr_pids++;
-               }
-       }
-
-       while (cnt > 0) {
-
-               this_pos = 0;
-
-               ret = trace_get_user(&parser, ubuf, cnt, &this_pos);
-               if (ret < 0 || !trace_parser_loaded(&parser))
-                       break;
-
-               read += ret;
-               ubuf += ret;
-               cnt -= ret;
-
-               parser.buffer[parser.idx] = 0;
-
-               ret = -EINVAL;
-               if (kstrtoul(parser.buffer, 0, &val))
-                       break;
-               if (val >= pid_list->pid_max)
-                       break;
-
-               pid = (pid_t)val;
-
-               set_bit(pid, pid_list->pids);
-               nr_pids++;
-
-               trace_parser_clear(&parser);
-               ret = 0;
-       }
-       trace_parser_put(&parser);
-
-       if (ret < 0) {
-               vfree(pid_list->pids);
-               kfree(pid_list);
-               read = ret;
+       ret = trace_pid_write(filtered_pids, &pid_list, ubuf, cnt);
+       if (ret < 0)
                goto out;
-       }
 
-       if (!nr_pids) {
-               /* Cleared the list of pids */
-               vfree(pid_list->pids);
-               kfree(pid_list);
-               read = ret;
-               if (!filtered_pids)
-                       goto out;
-               pid_list = NULL;
-       }
        rcu_assign_pointer(tr->filtered_pids, pid_list);
 
        list_for_each_entry(file, &tr->events, list) {
@@ -1776,10 +1616,8 @@ ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
 
        if (filtered_pids) {
                synchronize_sched();
-
-               vfree(filtered_pids->pids);
-               kfree(filtered_pids);
-       } else {
+               trace_free_pid_list(filtered_pids);
+       } else if (pid_list) {
                /*
                 * Register a probe that is called before all other probes
                 * to set ignore_pid if next or prev do not match.
@@ -1817,9 +1655,8 @@ ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
  out:
        mutex_unlock(&event_mutex);
 
-       ret = read;
-       if (read > 0)
-               *ppos += read;
+       if (ret > 0)
+               *ppos += ret;
 
        return ret;
 }
@@ -1846,7 +1683,7 @@ static const struct seq_operations show_set_event_seq_ops = {
 static const struct seq_operations show_set_pid_seq_ops = {
        .start = p_start,
        .next = p_next,
-       .show = p_show,
+       .show = trace_pid_show,
        .stop = p_stop,
 };
 
index 5a095c2e4b6988c8685db80871a847c8c84da781..0efa00d80623db3de438a5233a8ee6f84fae65ed 100644 (file)
@@ -43,7 +43,7 @@ static int allocate_ftrace_ops(struct trace_array *tr)
 
        /* Currently only the non stack verision is supported */
        ops->func = function_trace_call;
-       ops->flags = FTRACE_OPS_FL_RECURSION_SAFE;
+       ops->flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_PID;
 
        tr->ops = ops;
        ops->private = tr;
index 3a0244ff7ea8df27680c1eeca9caf177d8e083bd..7363ccf795125ce14d89a3303300e47a096c877e 100644 (file)
@@ -319,7 +319,7 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)
        int cpu;
        int pc;
 
-       if (!ftrace_trace_task(current))
+       if (!ftrace_trace_task(tr))
                return 0;
 
        /* trace it when it is-nested-in or is a function enabled. */
@@ -338,6 +338,13 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)
        if (ftrace_graph_notrace_addr(trace->func))
                return 1;
 
+       /*
+        * Stop here if tracing_threshold is set. We only write function return
+        * events to the ring buffer.
+        */
+       if (tracing_thresh)
+               return 1;
+
        local_irq_save(flags);
        cpu = raw_smp_processor_id();
        data = per_cpu_ptr(tr->trace_buffer.data, cpu);
@@ -355,14 +362,6 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)
        return ret;
 }
 
-static int trace_graph_thresh_entry(struct ftrace_graph_ent *trace)
-{
-       if (tracing_thresh)
-               return 1;
-       else
-               return trace_graph_entry(trace);
-}
-
 static void
 __trace_graph_function(struct trace_array *tr,
                unsigned long ip, unsigned long flags, int pc)
@@ -457,7 +456,7 @@ static int graph_trace_init(struct trace_array *tr)
        set_graph_array(tr);
        if (tracing_thresh)
                ret = register_ftrace_graph(&trace_graph_thresh_return,
-                                           &trace_graph_thresh_entry);
+                                           &trace_graph_entry);
        else
                ret = register_ftrace_graph(&trace_graph_return,
                                            &trace_graph_entry);
index 5546eec0505f7e111fa5b64d88dcc7806588dace..9aedb0b06683765f4293eb750465ed5849c2902f 100644 (file)
@@ -587,6 +587,7 @@ static int create_trace_kprobe(int argc, char **argv)
         *  $retval     : fetch return value
         *  $stack      : fetch stack address
         *  $stackN     : fetch Nth of stack (N:0-)
+        *  $comm       : fetch current task comm
         *  @ADDR       : fetch memory at ADDR (ADDR should be in kernel)
         *  @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol)
         *  %REG        : fetch register REG
index 68f376ca6d3fa5b23fc5658dbd5ad5ee5d56d208..cd7480d0a201e335cd7adc20c9cb0a8dba16f189 100644 (file)
@@ -68,19 +68,15 @@ static void mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
        trace_seq_printf(s, "PCIDEV %02x%02x %04x%04x %x",
                         dev->bus->number, dev->devfn,
                         dev->vendor, dev->device, dev->irq);
-       /*
-        * XXX: is pci_resource_to_user() appropriate, since we are
-        * supposed to interpret the __ioremap() phys_addr argument based on
-        * these printed values?
-        */
        for (i = 0; i < 7; i++) {
-               pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
+               start = dev->resource[i].start;
                trace_seq_printf(s, " %llx",
                        (unsigned long long)(start |
                        (dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
        }
        for (i = 0; i < 7; i++) {
-               pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
+               start = dev->resource[i].start;
+               end = dev->resource[i].end;
                trace_seq_printf(s, " %llx",
                        dev->resource[i].start < dev->resource[i].end ?
                        (unsigned long long)(end - start) + 1 : 0);
index 1d372fa6fefb7b44b8c3c38f4436621070ba0da7..74e80a582c28988fbc0227453378d36bf4346999 100644 (file)
@@ -218,6 +218,28 @@ free_bitfield_fetch_param(struct bitfield_fetch_param *data)
        kfree(data);
 }
 
+void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs,
+                                         void *data, void *dest)
+{
+       int maxlen = get_rloc_len(*(u32 *)dest);
+       u8 *dst = get_rloc_data(dest);
+       long ret;
+
+       if (!maxlen)
+               return;
+
+       ret = strlcpy(dst, current->comm, maxlen);
+       *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
+}
+NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string));
+
+void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs,
+                                              void *data, void *dest)
+{
+       *(u32 *)dest = strlen(current->comm) + 1;
+}
+NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size));
+
 static const struct fetch_type *find_fetch_type(const char *type,
                                                const struct fetch_type *ftbl)
 {
@@ -348,6 +370,11 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
                        }
                } else
                        ret = -EINVAL;
+       } else if (strcmp(arg, "comm") == 0) {
+               if (strcmp(t->name, "string") != 0 &&
+                   strcmp(t->name, "string_size") != 0)
+                       return -EINVAL;
+               f->fn = t->fetch[FETCH_MTD_comm];
        } else
                ret = -EINVAL;
 
@@ -522,6 +549,12 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
                arg[t - parg->comm] = '\0';
                t++;
        }
+       /*
+        * The default type of $comm should be "string", and it can't be
+        * dereferenced.
+        */
+       if (!t && strcmp(arg, "$comm") == 0)
+               t = "string";
        parg->type = find_fetch_type(t, ftbl);
        if (!parg->type) {
                pr_info("Unsupported type: %s\n", t);
index f6398db0911424cca72031a7a5831d505fae71b7..45400ca5ded1acf673d713851f930425b1d20849 100644 (file)
@@ -102,6 +102,7 @@ enum {
        FETCH_MTD_reg = 0,
        FETCH_MTD_stack,
        FETCH_MTD_retval,
+       FETCH_MTD_comm,
        FETCH_MTD_memory,
        FETCH_MTD_symbol,
        FETCH_MTD_deref,
@@ -183,6 +184,14 @@ DECLARE_BASIC_FETCH_FUNCS(bitfield);
 #define fetch_bitfield_string                  NULL
 #define fetch_bitfield_string_size             NULL
 
+/* comm only makes sense as a string */
+#define fetch_comm_u8          NULL
+#define fetch_comm_u16         NULL
+#define fetch_comm_u32         NULL
+#define fetch_comm_u64         NULL
+DECLARE_FETCH_FUNC(comm, string);
+DECLARE_FETCH_FUNC(comm, string_size);
+
 /*
  * Define macro for basic types - we don't need to define s* types, because
  * we have to care only about bitwidth at recording time.
@@ -213,6 +222,7 @@ DEFINE_FETCH_##method(u64)
 ASSIGN_FETCH_FUNC(reg, ftype),                         \
 ASSIGN_FETCH_FUNC(stack, ftype),                       \
 ASSIGN_FETCH_FUNC(retval, ftype),                      \
+ASSIGN_FETCH_FUNC(comm, ftype),                                \
 ASSIGN_FETCH_FUNC(memory, ftype),                      \
 ASSIGN_FETCH_FUNC(symbol, ftype),                      \
 ASSIGN_FETCH_FUNC(deref, ftype),                       \
index 67d8c6838ba95fe244060e1d67362220e646514f..bd38aab05929813acae4db2cd09f609a83d2025c 100644 (file)
@@ -5,9 +5,9 @@ if HAVE_ARCH_KASAN
 
 config KASAN
        bool "KASan: runtime memory debugger"
-       depends on SLUB_DEBUG || (SLAB && !DEBUG_SLAB)
+       depends on SLUB || (SLAB && !DEBUG_SLAB)
        select CONSTRUCTORS
-       select STACKDEPOT if SLAB
+       select STACKDEPOT
        help
          Enables kernel address sanitizer - runtime memory debugger,
          designed to find out-of-bounds accesses and use-after-free bugs.
index d67c8288d95dba435bf608b6258c3168c8206d7a..9e8c7386b3a03e8d418dd09847c9c7f295e06e77 100644 (file)
@@ -144,7 +144,7 @@ static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t b
        buf = iov->iov_base + skip;
        copy = min(bytes, iov->iov_len - skip);
 
-       if (!fault_in_pages_writeable(buf, copy)) {
+       if (IS_ENABLED(CONFIG_HIGHMEM) && !fault_in_pages_writeable(buf, copy)) {
                kaddr = kmap_atomic(page);
                from = kaddr + offset;
 
@@ -175,6 +175,7 @@ static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t b
                copy = min(bytes, iov->iov_len - skip);
        }
        /* Too bad - revert to non-atomic kmap */
+
        kaddr = kmap(page);
        from = kaddr + offset;
        left = __copy_to_user(buf, from, copy);
@@ -193,6 +194,7 @@ static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t b
                bytes -= copy;
        }
        kunmap(page);
+
 done:
        if (skip == iov->iov_len) {
                iov++;
@@ -225,7 +227,7 @@ static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t
        buf = iov->iov_base + skip;
        copy = min(bytes, iov->iov_len - skip);
 
-       if (!fault_in_pages_readable(buf, copy)) {
+       if (IS_ENABLED(CONFIG_HIGHMEM) && !fault_in_pages_readable(buf, copy)) {
                kaddr = kmap_atomic(page);
                to = kaddr + offset;
 
@@ -256,6 +258,7 @@ static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t
                copy = min(bytes, iov->iov_len - skip);
        }
        /* Too bad - revert to non-atomic kmap */
+
        kaddr = kmap(page);
        to = kaddr + offset;
        left = __copy_from_user(to, buf, copy);
@@ -274,6 +277,7 @@ static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t
                bytes -= copy;
        }
        kunmap(page);
+
 done:
        if (skip == iov->iov_len) {
                iov++;
index 53ad6c0831aebe6d3c9ec7cfc1387fa34ca7ea72..60f77f1d470a0589ccdeacbb52a9eb45a8a1cec1 100644 (file)
@@ -242,6 +242,7 @@ depot_stack_handle_t depot_save_stack(struct stack_trace *trace,
                 */
                alloc_flags &= ~GFP_ZONEMASK;
                alloc_flags &= (GFP_ATOMIC | GFP_KERNEL);
+               alloc_flags |= __GFP_NOWARN;
                page = alloc_pages(alloc_flags, STACK_ALLOC_ORDER);
                if (page)
                        prealloc = page_address(page);
index c9549c8b49090d7e3bd7ee1484f31ae313334511..66c5fc8351e84d703373a3572d6afaea84c410da 100644 (file)
@@ -155,8 +155,8 @@ test_hash_init(void)
                buf[j] = '\0';
 
                for (i = 0; i <= j; i++) {
-                       u64 hashlen = hashlen_string(buf+i);
-                       u32 h0 = full_name_hash(buf+i, j-i);
+                       u64 hashlen = hashlen_string(buf+i, buf+i);
+                       u32 h0 = full_name_hash(buf+i, buf+i, j-i);
 
                        /* Check that hashlen_string gets the length right */
                        if (hashlen_len(hashlen) != j-i) {
index 3c81803b00a32c44690893758cf0bb35d6f4db95..c0837845c17c408a123d5864c1bec354ee074723 100644 (file)
@@ -681,7 +681,7 @@ config IDLE_PAGE_TRACKING
          See Documentation/vm/idle_page_tracking.txt for more details.
 
 config ZONE_DEVICE
-       bool "Device memory (pmem, etc...) hotplug support" if EXPERT
+       bool "Device memory (pmem, etc...) hotplug support"
        depends on MEMORY_HOTPLUG
        depends on MEMORY_HOTREMOVE
        depends on SPARSEMEM_VMEMMAP
index ed173b8ae8f24a317e11da29735f0a5faa9e361e..efe2377420744d4d557b801ce4a265d3815cfb8f 100644 (file)
@@ -947,24 +947,24 @@ long congestion_wait(int sync, long timeout)
 EXPORT_SYMBOL(congestion_wait);
 
 /**
- * wait_iff_congested - Conditionally wait for a backing_dev to become uncongested or a zone to complete writes
- * @zone: A zone to check if it is heavily congested
+ * wait_iff_congested - Conditionally wait for a backing_dev to become uncongested or a pgdat to complete writes
+ * @pgdat: A pgdat to check if it is heavily congested
  * @sync: SYNC or ASYNC IO
  * @timeout: timeout in jiffies
  *
  * In the event of a congested backing_dev (any backing_dev) and the given
- * @zone has experienced recent congestion, this waits for up to @timeout
+ * @pgdat has experienced recent congestion, this waits for up to @timeout
  * jiffies for either a BDI to exit congestion of the given @sync queue
  * or a write to complete.
  *
- * In the absence of zone congestion, cond_resched() is called to yield
+ * In the absence of pgdat congestion, cond_resched() is called to yield
  * the processor if necessary but otherwise does not sleep.
  *
  * The return value is 0 if the sleep is for the full timeout. Otherwise,
  * it is the number of jiffies that were still remaining when the function
  * returned. return_value == timeout implies the function did not sleep.
  */
-long wait_iff_congested(struct zone *zone, int sync, long timeout)
+long wait_iff_congested(struct pglist_data *pgdat, int sync, long timeout)
 {
        long ret;
        unsigned long start = jiffies;
@@ -973,12 +973,13 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout)
 
        /*
         * If there is no congestion, or heavy congestion is not being
-        * encountered in the current zone, yield if necessary instead
+        * encountered in the current pgdat, yield if necessary instead
         * of sleeping on the congestion queue
         */
        if (atomic_read(&nr_wb_congested[sync]) == 0 ||
-           !test_bit(ZONE_CONGESTED, &zone->flags)) {
+           !test_bit(PGDAT_CONGESTED, &pgdat->flags)) {
                cond_resched();
+
                /* In case we scheduled, work out time remaining */
                ret = timeout - (jiffies - start);
                if (ret < 0)
index 64df5fe052db656dcfd38999abdf561942dfd4c5..9affb290830421de71f82eac65d7e4f7ce78cb9d 100644 (file)
@@ -331,7 +331,7 @@ static bool compact_trylock_irqsave(spinlock_t *lock, unsigned long *flags,
 {
        if (cc->mode == MIGRATE_ASYNC) {
                if (!spin_trylock_irqsave(lock, *flags)) {
-                       cc->contended = COMPACT_CONTENDED_LOCK;
+                       cc->contended = true;
                        return false;
                }
        } else {
@@ -365,13 +365,13 @@ static bool compact_unlock_should_abort(spinlock_t *lock,
        }
 
        if (fatal_signal_pending(current)) {
-               cc->contended = COMPACT_CONTENDED_SCHED;
+               cc->contended = true;
                return true;
        }
 
        if (need_resched()) {
                if (cc->mode == MIGRATE_ASYNC) {
-                       cc->contended = COMPACT_CONTENDED_SCHED;
+                       cc->contended = true;
                        return true;
                }
                cond_resched();
@@ -394,7 +394,7 @@ static inline bool compact_should_abort(struct compact_control *cc)
        /* async compaction aborts if contended */
        if (need_resched()) {
                if (cc->mode == MIGRATE_ASYNC) {
-                       cc->contended = COMPACT_CONTENDED_SCHED;
+                       cc->contended = true;
                        return true;
                }
 
@@ -646,8 +646,8 @@ static void acct_isolated(struct zone *zone, struct compact_control *cc)
        list_for_each_entry(page, &cc->migratepages, lru)
                count[!!page_is_file_cache(page)]++;
 
-       mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
-       mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+       mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON, count[0]);
+       mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE, count[1]);
 }
 
 /* Similar to reclaim, but different enough that they don't share logic */
@@ -655,12 +655,12 @@ static bool too_many_isolated(struct zone *zone)
 {
        unsigned long active, inactive, isolated;
 
-       inactive = zone_page_state(zone, NR_INACTIVE_FILE) +
-                                       zone_page_state(zone, NR_INACTIVE_ANON);
-       active = zone_page_state(zone, NR_ACTIVE_FILE) +
-                                       zone_page_state(zone, NR_ACTIVE_ANON);
-       isolated = zone_page_state(zone, NR_ISOLATED_FILE) +
-                                       zone_page_state(zone, NR_ISOLATED_ANON);
+       inactive = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE) +
+                       node_page_state(zone->zone_pgdat, NR_INACTIVE_ANON);
+       active = node_page_state(zone->zone_pgdat, NR_ACTIVE_FILE) +
+                       node_page_state(zone->zone_pgdat, NR_ACTIVE_ANON);
+       isolated = node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE) +
+                       node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON);
 
        return isolated > (inactive + active) / 2;
 }
@@ -752,7 +752,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                 * if contended.
                 */
                if (!(low_pfn % SWAP_CLUSTER_MAX)
-                   && compact_unlock_should_abort(&zone->lru_lock, flags,
+                   && compact_unlock_should_abort(zone_lru_lock(zone), flags,
                                                                &locked, cc))
                        break;
 
@@ -813,7 +813,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        if (unlikely(__PageMovable(page)) &&
                                        !PageIsolated(page)) {
                                if (locked) {
-                                       spin_unlock_irqrestore(&zone->lru_lock,
+                                       spin_unlock_irqrestore(zone_lru_lock(zone),
                                                                        flags);
                                        locked = false;
                                }
@@ -836,7 +836,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
 
                /* If we already hold the lock, we can skip some rechecking */
                if (!locked) {
-                       locked = compact_trylock_irqsave(&zone->lru_lock,
+                       locked = compact_trylock_irqsave(zone_lru_lock(zone),
                                                                &flags, cc);
                        if (!locked)
                                break;
@@ -856,7 +856,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        }
                }
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
 
                /* Try isolate the page */
                if (__isolate_lru_page(page, isolate_mode) != 0)
@@ -899,7 +899,7 @@ isolate_fail:
                 */
                if (nr_isolated) {
                        if (locked) {
-                               spin_unlock_irqrestore(&zone->lru_lock, flags);
+                               spin_unlock_irqrestore(zone_lru_lock(zone), flags);
                                locked = false;
                        }
                        acct_isolated(zone, cc);
@@ -927,7 +927,7 @@ isolate_fail:
                low_pfn = end_pfn;
 
        if (locked)
-               spin_unlock_irqrestore(&zone->lru_lock, flags);
+               spin_unlock_irqrestore(zone_lru_lock(zone), flags);
 
        /*
         * Update the pageblock-skip information and cached scanner pfn,
@@ -1200,7 +1200,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
        struct page *page;
        const isolate_mode_t isolate_mode =
                (sysctl_compact_unevictable_allowed ? ISOLATE_UNEVICTABLE : 0) |
-               (cc->mode == MIGRATE_ASYNC ? ISOLATE_ASYNC_MIGRATE : 0);
+               (cc->mode != MIGRATE_SYNC ? ISOLATE_ASYNC_MIGRATE : 0);
 
        /*
         * Start at where we last stopped, or beginning of the zone as
@@ -1619,14 +1619,11 @@ out:
        trace_mm_compaction_end(start_pfn, cc->migrate_pfn,
                                cc->free_pfn, end_pfn, sync, ret);
 
-       if (ret == COMPACT_CONTENDED)
-               ret = COMPACT_PARTIAL;
-
        return ret;
 }
 
 static enum compact_result compact_zone_order(struct zone *zone, int order,
-               gfp_t gfp_mask, enum migrate_mode mode, int *contended,
+               gfp_t gfp_mask, enum compact_priority prio,
                unsigned int alloc_flags, int classzone_idx)
 {
        enum compact_result ret;
@@ -1636,7 +1633,8 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
                .order = order,
                .gfp_mask = gfp_mask,
                .zone = zone,
-               .mode = mode,
+               .mode = (prio == COMPACT_PRIO_ASYNC) ?
+                                       MIGRATE_ASYNC : MIGRATE_SYNC_LIGHT,
                .alloc_flags = alloc_flags,
                .classzone_idx = classzone_idx,
                .direct_compaction = true,
@@ -1649,7 +1647,6 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
        VM_BUG_ON(!list_empty(&cc.freepages));
        VM_BUG_ON(!list_empty(&cc.migratepages));
 
-       *contended = cc.contended;
        return ret;
 }
 
@@ -1662,50 +1659,38 @@ int sysctl_extfrag_threshold = 500;
  * @alloc_flags: The allocation flags of the current allocation
  * @ac: The context of current allocation
  * @mode: The migration mode for async, sync light, or sync migration
- * @contended: Return value that determines if compaction was aborted due to
- *            need_resched() or lock contention
  *
  * This is the main entry point for direct page compaction.
  */
 enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
                unsigned int alloc_flags, const struct alloc_context *ac,
-               enum migrate_mode mode, int *contended)
+               enum compact_priority prio)
 {
        int may_enter_fs = gfp_mask & __GFP_FS;
        int may_perform_io = gfp_mask & __GFP_IO;
        struct zoneref *z;
        struct zone *zone;
        enum compact_result rc = COMPACT_SKIPPED;
-       int all_zones_contended = COMPACT_CONTENDED_LOCK; /* init for &= op */
-
-       *contended = COMPACT_CONTENDED_NONE;
 
        /* Check if the GFP flags allow compaction */
-       if (!order || !may_enter_fs || !may_perform_io)
+       if (!may_enter_fs || !may_perform_io)
                return COMPACT_SKIPPED;
 
-       trace_mm_compaction_try_to_compact_pages(order, gfp_mask, mode);
+       trace_mm_compaction_try_to_compact_pages(order, gfp_mask, prio);
 
        /* Compact each zone in the list */
        for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
                                                                ac->nodemask) {
                enum compact_result status;
-               int zone_contended;
 
                if (compaction_deferred(zone, order)) {
                        rc = max_t(enum compact_result, COMPACT_DEFERRED, rc);
                        continue;
                }
 
-               status = compact_zone_order(zone, order, gfp_mask, mode,
-                               &zone_contended, alloc_flags,
-                               ac_classzone_idx(ac));
+               status = compact_zone_order(zone, order, gfp_mask, prio,
+                                       alloc_flags, ac_classzone_idx(ac));
                rc = max(status, rc);
-               /*
-                * It takes at least one zone that wasn't lock contended
-                * to clear all_zones_contended.
-                */
-               all_zones_contended &= zone_contended;
 
                /* If a normal allocation would succeed, stop compacting */
                if (zone_watermark_ok(zone, order, low_wmark_pages(zone),
@@ -1717,59 +1702,29 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
                         * succeeds in this zone.
                         */
                        compaction_defer_reset(zone, order, false);
-                       /*
-                        * It is possible that async compaction aborted due to
-                        * need_resched() and the watermarks were ok thanks to
-                        * somebody else freeing memory. The allocation can
-                        * however still fail so we better signal the
-                        * need_resched() contention anyway (this will not
-                        * prevent the allocation attempt).
-                        */
-                       if (zone_contended == COMPACT_CONTENDED_SCHED)
-                               *contended = COMPACT_CONTENDED_SCHED;
 
-                       goto break_loop;
+                       break;
                }
 
-               if (mode != MIGRATE_ASYNC && (status == COMPACT_COMPLETE ||
-                                       status == COMPACT_PARTIAL_SKIPPED)) {
+               if (prio != COMPACT_PRIO_ASYNC && (status == COMPACT_COMPLETE ||
+                                       status == COMPACT_PARTIAL_SKIPPED))
                        /*
                         * We think that allocation won't succeed in this zone
                         * so we defer compaction there. If it ends up
                         * succeeding after all, it will be reset.
                         */
                        defer_compaction(zone, order);
-               }
 
                /*
                 * We might have stopped compacting due to need_resched() in
                 * async compaction, or due to a fatal signal detected. In that
-                * case do not try further zones and signal need_resched()
-                * contention.
-                */
-               if ((zone_contended == COMPACT_CONTENDED_SCHED)
-                                       || fatal_signal_pending(current)) {
-                       *contended = COMPACT_CONTENDED_SCHED;
-                       goto break_loop;
-               }
-
-               continue;
-break_loop:
-               /*
-                * We might not have tried all the zones, so  be conservative
-                * and assume they are not all lock contended.
+                * case do not try further zones
                 */
-               all_zones_contended = 0;
-               break;
+               if ((prio == COMPACT_PRIO_ASYNC && need_resched())
+                                       || fatal_signal_pending(current))
+                       break;
        }
 
-       /*
-        * If at least one zone wasn't deferred or skipped, we report if all
-        * zones that were tried were lock contended.
-        */
-       if (rc > COMPACT_INACTIVE && all_zones_contended)
-               *contended = COMPACT_CONTENDED_LOCK;
-
        return rc;
 }
 
index e90c1543ec2dc0fa577bf07c5a6eea824c0eecf6..3083ded98b15f32b68c58d744a5c3abb07d94c96 100644 (file)
@@ -95,8 +95,8 @@
  *    ->swap_lock              (try_to_unmap_one)
  *    ->private_lock           (try_to_unmap_one)
  *    ->tree_lock              (try_to_unmap_one)
- *    ->zone.lru_lock          (follow_page->mark_page_accessed)
- *    ->zone.lru_lock          (check_pte_range->isolate_lru_page)
+ *    ->zone_lru_lock(zone)    (follow_page->mark_page_accessed)
+ *    ->zone_lru_lock(zone)    (check_pte_range->isolate_lru_page)
  *    ->private_lock           (page_remove_rmap->set_page_dirty)
  *    ->tree_lock              (page_remove_rmap->set_page_dirty)
  *    bdi.wb->list_lock                (page_remove_rmap->set_page_dirty)
@@ -218,11 +218,11 @@ void __delete_from_page_cache(struct page *page, void *shadow)
 
        /* hugetlb pages do not participate in page cache accounting. */
        if (!PageHuge(page))
-               __mod_zone_page_state(page_zone(page), NR_FILE_PAGES, -nr);
+               __mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, -nr);
        if (PageSwapBacked(page)) {
-               __mod_zone_page_state(page_zone(page), NR_SHMEM, -nr);
+               __mod_node_page_state(page_pgdat(page), NR_SHMEM, -nr);
                if (PageTransHuge(page))
-                       __dec_zone_page_state(page, NR_SHMEM_THPS);
+                       __dec_node_page_state(page, NR_SHMEM_THPS);
        } else {
                VM_BUG_ON_PAGE(PageTransHuge(page) && !PageHuge(page), page);
        }
@@ -273,7 +273,7 @@ void delete_from_page_cache(struct page *page)
 }
 EXPORT_SYMBOL(delete_from_page_cache);
 
-static int filemap_check_errors(struct address_space *mapping)
+int filemap_check_errors(struct address_space *mapping)
 {
        int ret = 0;
        /* Check for outstanding write errors */
@@ -285,6 +285,7 @@ static int filemap_check_errors(struct address_space *mapping)
                ret = -EIO;
        return ret;
 }
+EXPORT_SYMBOL(filemap_check_errors);
 
 /**
  * __filemap_fdatawrite_range - start writeback on mapping dirty pages in range
@@ -568,9 +569,9 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
                 * hugetlb pages do not participate in page cache accounting.
                 */
                if (!PageHuge(new))
-                       __inc_zone_page_state(new, NR_FILE_PAGES);
+                       __inc_node_page_state(new, NR_FILE_PAGES);
                if (PageSwapBacked(new))
-                       __inc_zone_page_state(new, NR_SHMEM);
+                       __inc_node_page_state(new, NR_SHMEM);
                spin_unlock_irqrestore(&mapping->tree_lock, flags);
                mem_cgroup_migrate(old, new);
                radix_tree_preload_end();
@@ -677,7 +678,7 @@ static int __add_to_page_cache_locked(struct page *page,
 
        /* hugetlb pages do not participate in page cache accounting. */
        if (!huge)
-               __inc_zone_page_state(page, NR_FILE_PAGES);
+               __inc_node_page_state(page, NR_FILE_PAGES);
        spin_unlock_irq(&mapping->tree_lock);
        if (!huge)
                mem_cgroup_commit_charge(page, memcg, false, false);
index 3647334c2ef916ce9824153a359cb13cff3d9aba..2373f0a7d3405bb869ac4a3a4be175289af38114 100644 (file)
@@ -539,23 +539,26 @@ static int __do_huge_pmd_anonymous_page(struct fault_env *fe, struct page *page,
 }
 
 /*
- * If THP is set to always then directly reclaim/compact as necessary
- * If set to defer then do no reclaim and defer to khugepaged
+ * If THP defrag is set to always then directly reclaim/compact as necessary
+ * If set to defer then do only background reclaim/compact and defer to khugepaged
  * If set to madvise and the VMA is flagged then directly reclaim/compact
+ * When direct reclaim/compact is allowed, don't retry except for flagged VMA's
  */
 static inline gfp_t alloc_hugepage_direct_gfpmask(struct vm_area_struct *vma)
 {
-       gfp_t reclaim_flags = 0;
-
-       if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags) &&
-           (vma->vm_flags & VM_HUGEPAGE))
-               reclaim_flags = __GFP_DIRECT_RECLAIM;
-       else if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags))
-               reclaim_flags = __GFP_KSWAPD_RECLAIM;
-       else if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags))
-               reclaim_flags = __GFP_DIRECT_RECLAIM;
-
-       return GFP_TRANSHUGE | reclaim_flags;
+       bool vma_madvised = !!(vma->vm_flags & VM_HUGEPAGE);
+
+       if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG,
+                               &transparent_hugepage_flags) && vma_madvised)
+               return GFP_TRANSHUGE;
+       else if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG,
+                                               &transparent_hugepage_flags))
+               return GFP_TRANSHUGE_LIGHT | __GFP_KSWAPD_RECLAIM;
+       else if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG,
+                                               &transparent_hugepage_flags))
+               return GFP_TRANSHUGE | (vma_madvised ? 0 : __GFP_NORETRY);
+
+       return GFP_TRANSHUGE_LIGHT;
 }
 
 /* Caller must hold page table lock. */
@@ -1249,25 +1252,26 @@ out:
        return 0;
 }
 
-int madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
+/*
+ * Return true if we do MADV_FREE successfully on entire pmd page.
+ * Otherwise, return false.
+ */
+bool madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
                pmd_t *pmd, unsigned long addr, unsigned long next)
-
 {
        spinlock_t *ptl;
        pmd_t orig_pmd;
        struct page *page;
        struct mm_struct *mm = tlb->mm;
-       int ret = 0;
+       bool ret = false;
 
        ptl = pmd_trans_huge_lock(pmd, vma);
        if (!ptl)
                goto out_unlocked;
 
        orig_pmd = *pmd;
-       if (is_huge_zero_pmd(orig_pmd)) {
-               ret = 1;
+       if (is_huge_zero_pmd(orig_pmd))
                goto out;
-       }
 
        page = pmd_page(orig_pmd);
        /*
@@ -1309,7 +1313,7 @@ int madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
                set_pmd_at(mm, addr, pmd, orig_pmd);
                tlb_remove_pmd_tlb_entry(tlb, pmd, addr);
        }
-       ret = 1;
+       ret = true;
 out:
        spin_unlock(ptl);
 out_unlocked:
@@ -1586,7 +1590,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
 
        if (atomic_add_negative(-1, compound_mapcount_ptr(page))) {
                /* Last compound_mapcount is gone. */
-               __dec_zone_page_state(page, NR_ANON_THPS);
+               __dec_node_page_state(page, NR_ANON_THPS);
                if (TestClearPageDoubleMap(page)) {
                        /* No need in mapcount reference anymore */
                        for (i = 0; i < HPAGE_PMD_NR; i++)
@@ -1818,7 +1822,7 @@ static void __split_huge_page(struct page *page, struct list_head *list,
        pgoff_t end = -1;
        int i;
 
-       lruvec = mem_cgroup_page_lruvec(head, zone);
+       lruvec = mem_cgroup_page_lruvec(head, zone->zone_pgdat);
 
        /* complete memcg works before add pages to LRU */
        mem_cgroup_split_huge_fixup(head);
@@ -1848,7 +1852,7 @@ static void __split_huge_page(struct page *page, struct list_head *list,
                spin_unlock(&head->mapping->tree_lock);
        }
 
-       spin_unlock_irqrestore(&page_zone(head)->lru_lock, flags);
+       spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags);
 
        unfreeze_page(head);
 
@@ -2034,7 +2038,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                lru_add_drain();
 
        /* prevent PageLRU to go away from under us, and freeze lru stats */
-       spin_lock_irqsave(&page_zone(head)->lru_lock, flags);
+       spin_lock_irqsave(zone_lru_lock(page_zone(head)), flags);
 
        if (mapping) {
                void **pslot;
@@ -2061,7 +2065,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                        list_del(page_deferred_list(head));
                }
                if (mapping)
-                       __dec_zone_page_state(page, NR_SHMEM_THPS);
+                       __dec_node_page_state(page, NR_SHMEM_THPS);
                spin_unlock(&pgdata->split_queue_lock);
                __split_huge_page(page, list, flags);
                ret = 0;
@@ -2077,7 +2081,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                spin_unlock(&pgdata->split_queue_lock);
 fail:          if (mapping)
                        spin_unlock(&mapping->tree_lock);
-               spin_unlock_irqrestore(&page_zone(head)->lru_lock, flags);
+               spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags);
                unfreeze_page(head);
                ret = -EBUSY;
        }
index abc1c5fb722243769ee345ccee68ab9ea4ad9445..f904246a8fd5ae29d0d727f9eb1ccad6b9272cca 100644 (file)
@@ -3316,7 +3316,7 @@ static void unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
        address = address & huge_page_mask(h);
        pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) +
                        vma->vm_pgoff;
-       mapping = file_inode(vma->vm_file)->i_mapping;
+       mapping = vma->vm_file->f_mapping;
 
        /*
         * Take the mapping lock for the duration of the table walk. As
@@ -4391,7 +4391,6 @@ follow_huge_pud(struct mm_struct *mm, unsigned long address,
 
 /*
  * This function is called from memory failure code.
- * Assume the caller holds page lock of the head page.
  */
 int dequeue_hwpoisoned_huge_page(struct page *hpage)
 {
index 9b6a6c43ac391d5548d7a6e62eca30f4aadca875..1501304f87a41aaa48b0b32d16917a51ba73a1b7 100644 (file)
@@ -78,7 +78,7 @@ extern unsigned long highest_memmap_pfn;
  */
 extern int isolate_lru_page(struct page *page);
 extern void putback_lru_page(struct page *page);
-extern bool zone_reclaimable(struct zone *zone);
+extern bool pgdat_reclaimable(struct pglist_data *pgdat);
 
 /*
  * in mm/rmap.c:
@@ -185,10 +185,7 @@ struct compact_control {
        const unsigned int alloc_flags; /* alloc flags of a direct compactor */
        const int classzone_idx;        /* zone index of a direct compactor */
        struct zone *zone;
-       int contended;                  /* Signal need_sched() or lock
-                                        * contention detected during
-                                        * compaction
-                                        */
+       bool contended;                 /* Signal lock or sched contention */
 };
 
 unsigned long
@@ -433,10 +430,10 @@ static inline void mminit_validate_memmodel_limits(unsigned long *start_pfn,
 }
 #endif /* CONFIG_SPARSEMEM */
 
-#define ZONE_RECLAIM_NOSCAN    -2
-#define ZONE_RECLAIM_FULL      -1
-#define ZONE_RECLAIM_SOME      0
-#define ZONE_RECLAIM_SUCCESS   1
+#define NODE_RECLAIM_NOSCAN    -2
+#define NODE_RECLAIM_FULL      -1
+#define NODE_RECLAIM_SOME      0
+#define NODE_RECLAIM_SUCCESS   1
 
 extern int hwpoison_filter(struct page *p);
 
@@ -467,7 +464,6 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
 #define ALLOC_HIGH             0x20 /* __GFP_HIGH set */
 #define ALLOC_CPUSET           0x40 /* check for correct cpuset */
 #define ALLOC_CMA              0x80 /* allow allocations from CMA areas */
-#define ALLOC_FAIR             0x100 /* fair zone allocation */
 
 enum ttu_flags;
 struct tlbflush_unmap_batch;
index 1548749a3d452735c78028f4fb30ec3ac6bb10e8..2976a9ee104f9248731dc07c3619e34b79998041 100644 (file)
@@ -7,5 +7,4 @@ CFLAGS_REMOVE_kasan.o = -pg
 # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533
 CFLAGS_kasan.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector)
 
-obj-y := kasan.o report.o kasan_init.o
-obj-$(CONFIG_SLAB) += quarantine.o
+obj-y := kasan.o report.o kasan_init.o quarantine.o
index 6845f9294696cedb9d6567bd09a7a86862bd5c3b..b6f99e81bfebdce9cc13ee7fb72e665d117b1ce8 100644 (file)
@@ -351,7 +351,6 @@ void kasan_free_pages(struct page *page, unsigned int order)
                                KASAN_FREE_PAGE);
 }
 
-#ifdef CONFIG_SLAB
 /*
  * Adaptive redzone policy taken from the userspace AddressSanitizer runtime.
  * For larger allocations larger redzones are used.
@@ -373,16 +372,8 @@ void kasan_cache_create(struct kmem_cache *cache, size_t *size,
                        unsigned long *flags)
 {
        int redzone_adjust;
-       /* Make sure the adjusted size is still less than
-        * KMALLOC_MAX_CACHE_SIZE.
-        * TODO: this check is only useful for SLAB, but not SLUB. We'll need
-        * to skip it for SLUB when it starts using kasan_cache_create().
-        */
-       if (*size > KMALLOC_MAX_CACHE_SIZE -
-           sizeof(struct kasan_alloc_meta) -
-           sizeof(struct kasan_free_meta))
-               return;
-       *flags |= SLAB_KASAN;
+       int orig_size = *size;
+
        /* Add alloc meta. */
        cache->kasan_info.alloc_meta_offset = *size;
        *size += sizeof(struct kasan_alloc_meta);
@@ -395,14 +386,26 @@ void kasan_cache_create(struct kmem_cache *cache, size_t *size,
        }
        redzone_adjust = optimal_redzone(cache->object_size) -
                (*size - cache->object_size);
+
        if (redzone_adjust > 0)
                *size += redzone_adjust;
-       *size = min(KMALLOC_MAX_CACHE_SIZE,
-                   max(*size,
-                       cache->object_size +
-                       optimal_redzone(cache->object_size)));
+
+       *size = min(KMALLOC_MAX_SIZE, max(*size, cache->object_size +
+                                       optimal_redzone(cache->object_size)));
+
+       /*
+        * If the metadata doesn't fit, don't enable KASAN at all.
+        */
+       if (*size <= cache->kasan_info.alloc_meta_offset ||
+                       *size <= cache->kasan_info.free_meta_offset) {
+               cache->kasan_info.alloc_meta_offset = 0;
+               cache->kasan_info.free_meta_offset = 0;
+               *size = orig_size;
+               return;
+       }
+
+       *flags |= SLAB_KASAN;
 }
-#endif
 
 void kasan_cache_shrink(struct kmem_cache *cache)
 {
@@ -414,6 +417,14 @@ void kasan_cache_destroy(struct kmem_cache *cache)
        quarantine_remove_cache(cache);
 }
 
+size_t kasan_metadata_size(struct kmem_cache *cache)
+{
+       return (cache->kasan_info.alloc_meta_offset ?
+               sizeof(struct kasan_alloc_meta) : 0) +
+               (cache->kasan_info.free_meta_offset ?
+               sizeof(struct kasan_free_meta) : 0);
+}
+
 void kasan_poison_slab(struct page *page)
 {
        kasan_poison_shadow(page_address(page),
@@ -431,16 +442,13 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object)
        kasan_poison_shadow(object,
                        round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE),
                        KASAN_KMALLOC_REDZONE);
-#ifdef CONFIG_SLAB
        if (cache->flags & SLAB_KASAN) {
                struct kasan_alloc_meta *alloc_info =
                        get_alloc_info(cache, object);
                alloc_info->state = KASAN_STATE_INIT;
        }
-#endif
 }
 
-#ifdef CONFIG_SLAB
 static inline int in_irqentry_text(unsigned long ptr)
 {
        return (ptr >= (unsigned long)&__irqentry_text_start &&
@@ -501,7 +509,6 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache,
        BUILD_BUG_ON(sizeof(struct kasan_free_meta) > 32);
        return (void *)object + cache->kasan_info.free_meta_offset;
 }
-#endif
 
 void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags)
 {
@@ -522,16 +529,16 @@ static void kasan_poison_slab_free(struct kmem_cache *cache, void *object)
 
 bool kasan_slab_free(struct kmem_cache *cache, void *object)
 {
-#ifdef CONFIG_SLAB
        /* RCU slabs could be legally used after free within the RCU period */
        if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU))
                return false;
 
        if (likely(cache->flags & SLAB_KASAN)) {
-               struct kasan_alloc_meta *alloc_info =
-                       get_alloc_info(cache, object);
-               struct kasan_free_meta *free_info =
-                       get_free_info(cache, object);
+               struct kasan_alloc_meta *alloc_info;
+               struct kasan_free_meta *free_info;
+
+               alloc_info = get_alloc_info(cache, object);
+               free_info = get_free_info(cache, object);
 
                switch (alloc_info->state) {
                case KASAN_STATE_ALLOC:
@@ -550,10 +557,6 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object)
                }
        }
        return false;
-#else
-       kasan_poison_slab_free(cache, object);
-       return false;
-#endif
 }
 
 void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
@@ -576,7 +579,6 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
        kasan_unpoison_shadow(object, size);
        kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start,
                KASAN_KMALLOC_REDZONE);
-#ifdef CONFIG_SLAB
        if (cache->flags & SLAB_KASAN) {
                struct kasan_alloc_meta *alloc_info =
                        get_alloc_info(cache, object);
@@ -585,7 +587,6 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
                alloc_info->alloc_size = size;
                set_track(&alloc_info->track, flags);
        }
-#endif
 }
 EXPORT_SYMBOL(kasan_kmalloc);
 
index fb87923552ef2b90c65847fdb5c56644560ca7ec..31972cdba433a97f114147ecf2a823ac91cdc5bc 100644 (file)
@@ -95,7 +95,6 @@ struct kasan_alloc_meta *get_alloc_info(struct kmem_cache *cache,
 struct kasan_free_meta *get_free_info(struct kmem_cache *cache,
                                        const void *object);
 
-
 static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
 {
        return (void *)(((unsigned long)shadow_addr - KASAN_SHADOW_OFFSET)
@@ -110,7 +109,7 @@ static inline bool kasan_report_enabled(void)
 void kasan_report(unsigned long addr, size_t size,
                bool is_write, unsigned long ip);
 
-#ifdef CONFIG_SLAB
+#if defined(CONFIG_SLAB) || defined(CONFIG_SLUB)
 void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache);
 void quarantine_reduce(void);
 void quarantine_remove_cache(struct kmem_cache *cache);
index b3c122ddd45483566de8311ab1e1cf814ff18176..861b9776841a94ee69f485fa91e13cdeebc0d8be 100644 (file)
@@ -116,7 +116,6 @@ static inline bool init_task_stack_addr(const void *addr)
                        sizeof(init_thread_union.stack));
 }
 
-#ifdef CONFIG_SLAB
 static void print_track(struct kasan_track *track)
 {
        pr_err("PID = %u\n", track->pid);
@@ -130,8 +129,8 @@ static void print_track(struct kasan_track *track)
        }
 }
 
-static void object_err(struct kmem_cache *cache, struct page *page,
-                       void *object, char *unused_reason)
+static void kasan_object_err(struct kmem_cache *cache, struct page *page,
+                               void *object, char *unused_reason)
 {
        struct kasan_alloc_meta *alloc_info = get_alloc_info(cache, object);
        struct kasan_free_meta *free_info;
@@ -162,7 +161,6 @@ static void object_err(struct kmem_cache *cache, struct page *page,
                break;
        }
 }
-#endif
 
 static void print_address_description(struct kasan_access_info *info)
 {
@@ -177,7 +175,7 @@ static void print_address_description(struct kasan_access_info *info)
                        struct kmem_cache *cache = page->slab_cache;
                        object = nearest_obj(cache, page,
                                                (void *)info->access_addr);
-                       object_err(cache, page, object,
+                       kasan_object_err(cache, page, object,
                                        "kasan: bad access detected");
                        return;
                }
index 7dbee698d6aa8594c7a65fded02a5b48265f348d..79c52d0061af591b0417e5d67462f49fda8ac632 100644 (file)
@@ -480,7 +480,7 @@ void __khugepaged_exit(struct mm_struct *mm)
 static void release_pte_page(struct page *page)
 {
        /* 0 stands for page_is_file_cache(page) == false */
-       dec_zone_page_state(page, NR_ISOLATED_ANON + 0);
+       dec_node_page_state(page, NR_ISOLATED_ANON + 0);
        unlock_page(page);
        putback_lru_page(page);
 }
@@ -576,7 +576,7 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
                        goto out;
                }
                /* 0 stands for page_is_file_cache(page) == false */
-               inc_zone_page_state(page, NR_ISOLATED_ANON + 0);
+               inc_node_page_state(page, NR_ISOLATED_ANON + 0);
                VM_BUG_ON_PAGE(!PageLocked(page), page);
                VM_BUG_ON_PAGE(PageLRU(page), page);
 
@@ -672,10 +672,10 @@ static bool khugepaged_scan_abort(int nid)
        int i;
 
        /*
-        * If zone_reclaim_mode is disabled, then no extra effort is made to
+        * If node_reclaim_mode is disabled, then no extra effort is made to
         * allocate memory locally.
         */
-       if (!zone_reclaim_mode)
+       if (!node_reclaim_mode)
                return false;
 
        /* If there is a count for this node already, it must be acceptable */
@@ -694,7 +694,7 @@ static bool khugepaged_scan_abort(int nid)
 /* Defrag for khugepaged will enter direct reclaim/compaction if necessary */
 static inline gfp_t alloc_hugepage_khugepaged_gfpmask(void)
 {
-       return GFP_TRANSHUGE | (khugepaged_defrag() ? __GFP_DIRECT_RECLAIM : 0);
+       return khugepaged_defrag() ? GFP_TRANSHUGE : GFP_TRANSHUGE_LIGHT;
 }
 
 #ifdef CONFIG_NUMA
@@ -1483,10 +1483,10 @@ tree_unlocked:
                }
 
                local_irq_save(flags);
-               __inc_zone_page_state(new_page, NR_SHMEM_THPS);
+               __inc_node_page_state(new_page, NR_SHMEM_THPS);
                if (nr_none) {
-                       __mod_zone_page_state(zone, NR_FILE_PAGES, nr_none);
-                       __mod_zone_page_state(zone, NR_SHMEM, nr_none);
+                       __mod_node_page_state(zone->zone_pgdat, NR_FILE_PAGES, nr_none);
+                       __mod_node_page_state(zone->zone_pgdat, NR_SHMEM, nr_none);
                }
                local_irq_restore(flags);
 
index 04320d3adbef9922edda52e43cc516463e9e33c6..086292f7c59d1a69881068758150c2140feb8253 100644 (file)
@@ -1485,8 +1485,10 @@ static int kmemleak_scan_thread(void *arg)
         * Wait before the first scan to allow the system to fully initialize.
         */
        if (first_run) {
+               signed long timeout = msecs_to_jiffies(SECS_FIRST_SCAN * 1000);
                first_run = 0;
-               ssleep(SECS_FIRST_SCAN);
+               while (timeout && !kthread_should_stop())
+                       timeout = schedule_timeout_interruptible(timeout);
        }
 
        while (!kthread_should_stop()) {
index ca099159b45a82c2f1fcfbad28fc14221953a8ee..ff5ff3b5f1ea774403b2231aa3053865a52ee31d 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/seq_file.h>
 #include <linux/memblock.h>
 
-#include <asm-generic/sections.h>
+#include <asm/sections.h>
 #include <linux/io.h>
 
 #include "internal.h"
@@ -1027,7 +1027,7 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags,
                                *out_end = m_end;
                        if (out_nid)
                                *out_nid = m_nid;
-                       idx_a++;
+                       idx_a--;
                        *idx = (u32)idx_a | (u64)idx_b << 32;
                        return;
                }
@@ -1465,15 +1465,16 @@ phys_addr_t __init_memblock memblock_end_of_DRAM(void)
        return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
 }
 
-void __init memblock_enforce_memory_limit(phys_addr_t limit)
+static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit)
 {
        phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
        struct memblock_region *r;
 
-       if (!limit)
-               return;
-
-       /* find out max address */
+       /*
+        * translate the memory @limit size into the max address within one of
+        * the memory memblock regions, if the @limit exceeds the total size
+        * of those regions, max_addr will keep original value ULLONG_MAX
+        */
        for_each_memblock(memory, r) {
                if (limit <= r->size) {
                        max_addr = r->base + limit;
@@ -1482,6 +1483,22 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
                limit -= r->size;
        }
 
+       return max_addr;
+}
+
+void __init memblock_enforce_memory_limit(phys_addr_t limit)
+{
+       phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
+
+       if (!limit)
+               return;
+
+       max_addr = __find_max_addr(limit);
+
+       /* @limit exceeds the total size of the memory, do nothing */
+       if (max_addr == (phys_addr_t)ULLONG_MAX)
+               return;
+
        /* truncate both memory and reserved regions */
        memblock_remove_range(&memblock.memory, max_addr,
                              (phys_addr_t)ULLONG_MAX);
@@ -1489,6 +1506,36 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
                              (phys_addr_t)ULLONG_MAX);
 }
 
+void __init memblock_mem_limit_remove_map(phys_addr_t limit)
+{
+       struct memblock_type *type = &memblock.memory;
+       phys_addr_t max_addr;
+       int i, ret, start_rgn, end_rgn;
+
+       if (!limit)
+               return;
+
+       max_addr = __find_max_addr(limit);
+
+       /* @limit exceeds the total size of the memory, do nothing */
+       if (max_addr == (phys_addr_t)ULLONG_MAX)
+               return;
+
+       ret = memblock_isolate_range(type, max_addr, (phys_addr_t)ULLONG_MAX,
+                               &start_rgn, &end_rgn);
+       if (ret)
+               return;
+
+       /* remove all the MAP regions above the limit */
+       for (i = end_rgn - 1; i >= start_rgn; i--) {
+               if (!memblock_is_nomap(&type->regions[i]))
+                       memblock_remove_region(type, i);
+       }
+       /* truncate the reserved regions */
+       memblock_remove_range(&memblock.reserved, max_addr,
+                             (phys_addr_t)ULLONG_MAX);
+}
+
 static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
 {
        unsigned int left = 0, right = type->cnt;
index f3a84c64f35cf807c5e6d6ddbf6c601d5ff334a3..c265212bec8c0f412e9f23e260a5ff0d490ea046 100644 (file)
@@ -132,15 +132,11 @@ static const char * const mem_cgroup_lru_names[] = {
  * their hierarchy representation
  */
 
-struct mem_cgroup_tree_per_zone {
+struct mem_cgroup_tree_per_node {
        struct rb_root rb_root;
        spinlock_t lock;
 };
 
-struct mem_cgroup_tree_per_node {
-       struct mem_cgroup_tree_per_zone rb_tree_per_zone[MAX_NR_ZONES];
-};
-
 struct mem_cgroup_tree {
        struct mem_cgroup_tree_per_node *rb_tree_per_node[MAX_NUMNODES];
 };
@@ -323,15 +319,6 @@ EXPORT_SYMBOL(memcg_kmem_enabled_key);
 
 #endif /* !CONFIG_SLOB */
 
-static struct mem_cgroup_per_zone *
-mem_cgroup_zone_zoneinfo(struct mem_cgroup *memcg, struct zone *zone)
-{
-       int nid = zone_to_nid(zone);
-       int zid = zone_idx(zone);
-
-       return &memcg->nodeinfo[nid]->zoneinfo[zid];
-}
-
 /**
  * mem_cgroup_css_from_page - css of the memcg associated with a page
  * @page: page of interest
@@ -383,37 +370,35 @@ ino_t page_cgroup_ino(struct page *page)
        return ino;
 }
 
-static struct mem_cgroup_per_zone *
-mem_cgroup_page_zoneinfo(struct mem_cgroup *memcg, struct page *page)
+static struct mem_cgroup_per_node *
+mem_cgroup_page_nodeinfo(struct mem_cgroup *memcg, struct page *page)
 {
        int nid = page_to_nid(page);
-       int zid = page_zonenum(page);
 
-       return &memcg->nodeinfo[nid]->zoneinfo[zid];
+       return memcg->nodeinfo[nid];
 }
 
-static struct mem_cgroup_tree_per_zone *
-soft_limit_tree_node_zone(int nid, int zid)
+static struct mem_cgroup_tree_per_node *
+soft_limit_tree_node(int nid)
 {
-       return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid];
+       return soft_limit_tree.rb_tree_per_node[nid];
 }
 
-static struct mem_cgroup_tree_per_zone *
+static struct mem_cgroup_tree_per_node *
 soft_limit_tree_from_page(struct page *page)
 {
        int nid = page_to_nid(page);
-       int zid = page_zonenum(page);
 
-       return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid];
+       return soft_limit_tree.rb_tree_per_node[nid];
 }
 
-static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz,
-                                        struct mem_cgroup_tree_per_zone *mctz,
+static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_node *mz,
+                                        struct mem_cgroup_tree_per_node *mctz,
                                         unsigned long new_usage_in_excess)
 {
        struct rb_node **p = &mctz->rb_root.rb_node;
        struct rb_node *parent = NULL;
-       struct mem_cgroup_per_zone *mz_node;
+       struct mem_cgroup_per_node *mz_node;
 
        if (mz->on_tree)
                return;
@@ -423,7 +408,7 @@ static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz,
                return;
        while (*p) {
                parent = *p;
-               mz_node = rb_entry(parent, struct mem_cgroup_per_zone,
+               mz_node = rb_entry(parent, struct mem_cgroup_per_node,
                                        tree_node);
                if (mz->usage_in_excess < mz_node->usage_in_excess)
                        p = &(*p)->rb_left;
@@ -439,8 +424,8 @@ static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz,
        mz->on_tree = true;
 }
 
-static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz,
-                                        struct mem_cgroup_tree_per_zone *mctz)
+static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_node *mz,
+                                        struct mem_cgroup_tree_per_node *mctz)
 {
        if (!mz->on_tree)
                return;
@@ -448,8 +433,8 @@ static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz,
        mz->on_tree = false;
 }
 
-static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz,
-                                      struct mem_cgroup_tree_per_zone *mctz)
+static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_node *mz,
+                                      struct mem_cgroup_tree_per_node *mctz)
 {
        unsigned long flags;
 
@@ -473,8 +458,8 @@ static unsigned long soft_limit_excess(struct mem_cgroup *memcg)
 static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
 {
        unsigned long excess;
-       struct mem_cgroup_per_zone *mz;
-       struct mem_cgroup_tree_per_zone *mctz;
+       struct mem_cgroup_per_node *mz;
+       struct mem_cgroup_tree_per_node *mctz;
 
        mctz = soft_limit_tree_from_page(page);
        /*
@@ -482,7 +467,7 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
         * because their event counter is not touched.
         */
        for (; memcg; memcg = parent_mem_cgroup(memcg)) {
-               mz = mem_cgroup_page_zoneinfo(memcg, page);
+               mz = mem_cgroup_page_nodeinfo(memcg, page);
                excess = soft_limit_excess(memcg);
                /*
                 * We have to update the tree if mz is on RB-tree or
@@ -507,24 +492,22 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
 
 static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg)
 {
-       struct mem_cgroup_tree_per_zone *mctz;
-       struct mem_cgroup_per_zone *mz;
-       int nid, zid;
+       struct mem_cgroup_tree_per_node *mctz;
+       struct mem_cgroup_per_node *mz;
+       int nid;
 
        for_each_node(nid) {
-               for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-                       mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-                       mctz = soft_limit_tree_node_zone(nid, zid);
-                       mem_cgroup_remove_exceeded(mz, mctz);
-               }
+               mz = mem_cgroup_nodeinfo(memcg, nid);
+               mctz = soft_limit_tree_node(nid);
+               mem_cgroup_remove_exceeded(mz, mctz);
        }
 }
 
-static struct mem_cgroup_per_zone *
-__mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
+static struct mem_cgroup_per_node *
+__mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz)
 {
        struct rb_node *rightmost = NULL;
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
 
 retry:
        mz = NULL;
@@ -532,7 +515,7 @@ retry:
        if (!rightmost)
                goto done;              /* Nothing to reclaim from */
 
-       mz = rb_entry(rightmost, struct mem_cgroup_per_zone, tree_node);
+       mz = rb_entry(rightmost, struct mem_cgroup_per_node, tree_node);
        /*
         * Remove the node now but someone else can add it back,
         * we will to add it back at the end of reclaim to its correct
@@ -546,10 +529,10 @@ done:
        return mz;
 }
 
-static struct mem_cgroup_per_zone *
-mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
+static struct mem_cgroup_per_node *
+mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz)
 {
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
 
        spin_lock_irq(&mctz->lock);
        mz = __mem_cgroup_largest_soft_limit_node(mctz);
@@ -643,20 +626,16 @@ unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
                                           int nid, unsigned int lru_mask)
 {
        unsigned long nr = 0;
-       int zid;
+       struct mem_cgroup_per_node *mz;
+       enum lru_list lru;
 
        VM_BUG_ON((unsigned)nid >= nr_node_ids);
 
-       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-               struct mem_cgroup_per_zone *mz;
-               enum lru_list lru;
-
-               for_each_lru(lru) {
-                       if (!(BIT(lru) & lru_mask))
-                               continue;
-                       mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-                       nr += mz->lru_size[lru];
-               }
+       for_each_lru(lru) {
+               if (!(BIT(lru) & lru_mask))
+                       continue;
+               mz = mem_cgroup_nodeinfo(memcg, nid);
+               nr += mz->lru_size[lru];
        }
        return nr;
 }
@@ -809,9 +788,9 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
        rcu_read_lock();
 
        if (reclaim) {
-               struct mem_cgroup_per_zone *mz;
+               struct mem_cgroup_per_node *mz;
 
-               mz = mem_cgroup_zone_zoneinfo(root, reclaim->zone);
+               mz = mem_cgroup_nodeinfo(root, reclaim->pgdat->node_id);
                iter = &mz->iter[reclaim->priority];
 
                if (prev && reclaim->generation != iter->generation)
@@ -910,19 +889,17 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
 {
        struct mem_cgroup *memcg = dead_memcg;
        struct mem_cgroup_reclaim_iter *iter;
-       struct mem_cgroup_per_zone *mz;
-       int nid, zid;
+       struct mem_cgroup_per_node *mz;
+       int nid;
        int i;
 
        while ((memcg = parent_mem_cgroup(memcg))) {
                for_each_node(nid) {
-                       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-                               mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-                               for (i = 0; i <= DEF_PRIORITY; i++) {
-                                       iter = &mz->iter[i];
-                                       cmpxchg(&iter->position,
-                                               dead_memcg, NULL);
-                               }
+                       mz = mem_cgroup_nodeinfo(memcg, nid);
+                       for (i = 0; i <= DEF_PRIORITY; i++) {
+                               iter = &mz->iter[i];
+                               cmpxchg(&iter->position,
+                                       dead_memcg, NULL);
                        }
                }
        }
@@ -943,39 +920,6 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
             iter != NULL;                              \
             iter = mem_cgroup_iter(NULL, iter, NULL))
 
-/**
- * mem_cgroup_zone_lruvec - get the lru list vector for a zone and memcg
- * @zone: zone of the wanted lruvec
- * @memcg: memcg of the wanted lruvec
- *
- * Returns the lru list vector holding pages for the given @zone and
- * @mem.  This can be the global zone lruvec, if the memory controller
- * is disabled.
- */
-struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
-                                     struct mem_cgroup *memcg)
-{
-       struct mem_cgroup_per_zone *mz;
-       struct lruvec *lruvec;
-
-       if (mem_cgroup_disabled()) {
-               lruvec = &zone->lruvec;
-               goto out;
-       }
-
-       mz = mem_cgroup_zone_zoneinfo(memcg, zone);
-       lruvec = &mz->lruvec;
-out:
-       /*
-        * Since a node can be onlined after the mem_cgroup was created,
-        * we have to be prepared to initialize lruvec->zone here;
-        * and if offlined then reonlined, we need to reinitialize it.
-        */
-       if (unlikely(lruvec->zone != zone))
-               lruvec->zone = zone;
-       return lruvec;
-}
-
 /**
  * mem_cgroup_page_lruvec - return lruvec for isolating/putting an LRU page
  * @page: the page
@@ -985,14 +929,14 @@ out:
  * and putback protocol: the LRU lock must be held, and the page must
  * either be PageLRU() or the caller must have isolated/allocated it.
  */
-struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone)
+struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgdat)
 {
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
        struct mem_cgroup *memcg;
        struct lruvec *lruvec;
 
        if (mem_cgroup_disabled()) {
-               lruvec = &zone->lruvec;
+               lruvec = &pgdat->lruvec;
                goto out;
        }
 
@@ -1004,7 +948,7 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone)
        if (!memcg)
                memcg = root_mem_cgroup;
 
-       mz = mem_cgroup_page_zoneinfo(memcg, page);
+       mz = mem_cgroup_page_nodeinfo(memcg, page);
        lruvec = &mz->lruvec;
 out:
        /*
@@ -1012,8 +956,8 @@ out:
         * we have to be prepared to initialize lruvec->zone here;
         * and if offlined then reonlined, we need to reinitialize it.
         */
-       if (unlikely(lruvec->zone != zone))
-               lruvec->zone = zone;
+       if (unlikely(lruvec->pgdat != pgdat))
+               lruvec->pgdat = pgdat;
        return lruvec;
 }
 
@@ -1030,17 +974,15 @@ out:
 void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
                                int nr_pages)
 {
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
        unsigned long *lru_size;
        long size;
        bool empty;
 
-       __update_lru_size(lruvec, lru, nr_pages);
-
        if (mem_cgroup_disabled())
                return;
 
-       mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec);
+       mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
        lru_size = mz->lru_size + lru;
        empty = list_empty(lruvec->lists + lru);
 
@@ -1276,9 +1218,9 @@ static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
         * select it.  The goal is to allow it to allocate so that it may
         * quickly exit and free its memory.
         */
-       if (fatal_signal_pending(current) || task_will_free_mem(current)) {
+       if (task_will_free_mem(current)) {
                mark_oom_victim(current);
-               try_oom_reaper(current);
+               wake_oom_reaper(current);
                goto unlock;
        }
 
@@ -1433,7 +1375,7 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
 #endif
 
 static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
-                                  struct zone *zone,
+                                  pg_data_t *pgdat,
                                   gfp_t gfp_mask,
                                   unsigned long *total_scanned)
 {
@@ -1443,7 +1385,7 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
        unsigned long excess;
        unsigned long nr_scanned;
        struct mem_cgroup_reclaim_cookie reclaim = {
-               .zone = zone,
+               .pgdat = pgdat,
                .priority = 0,
        };
 
@@ -1473,8 +1415,8 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
                        }
                        continue;
                }
-               total += mem_cgroup_shrink_node_zone(victim, gfp_mask, false,
-                                                    zone, &nr_scanned);
+               total += mem_cgroup_shrink_node(victim, gfp_mask, false,
+                                       pgdat, &nr_scanned);
                *total_scanned += nr_scanned;
                if (!soft_limit_excess(root_memcg))
                        break;
@@ -2107,11 +2049,11 @@ static void lock_page_lru(struct page *page, int *isolated)
 {
        struct zone *zone = page_zone(page);
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
        if (PageLRU(page)) {
                struct lruvec *lruvec;
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
                ClearPageLRU(page);
                del_page_from_lru_list(page, lruvec, page_lru(page));
                *isolated = 1;
@@ -2126,12 +2068,12 @@ static void unlock_page_lru(struct page *page, int isolated)
        if (isolated) {
                struct lruvec *lruvec;
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
                VM_BUG_ON_PAGE(PageLRU(page), page);
                SetPageLRU(page);
                add_page_to_lru_list(page, lruvec, page_lru(page));
        }
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(zone_lru_lock(zone));
 }
 
 static void commit_charge(struct page *page, struct mem_cgroup *memcg,
@@ -2431,7 +2373,7 @@ void memcg_kmem_uncharge(struct page *page, int order)
 
 /*
  * Because tail pages are not marked as "used", set it. We're under
- * zone->lru_lock and migration entries setup in all page mappings.
+ * zone_lru_lock and migration entries setup in all page mappings.
  */
 void mem_cgroup_split_huge_fixup(struct page *head)
 {
@@ -2601,22 +2543,22 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
        return ret;
 }
 
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
+unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                            gfp_t gfp_mask,
                                            unsigned long *total_scanned)
 {
        unsigned long nr_reclaimed = 0;
-       struct mem_cgroup_per_zone *mz, *next_mz = NULL;
+       struct mem_cgroup_per_node *mz, *next_mz = NULL;
        unsigned long reclaimed;
        int loop = 0;
-       struct mem_cgroup_tree_per_zone *mctz;
+       struct mem_cgroup_tree_per_node *mctz;
        unsigned long excess;
        unsigned long nr_scanned;
 
        if (order > 0)
                return 0;
 
-       mctz = soft_limit_tree_node_zone(zone_to_nid(zone), zone_idx(zone));
+       mctz = soft_limit_tree_node(pgdat->node_id);
        /*
         * This loop can run a while, specially if mem_cgroup's continuously
         * keep exceeding their soft limit and putting the system under
@@ -2631,7 +2573,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
                        break;
 
                nr_scanned = 0;
-               reclaimed = mem_cgroup_soft_reclaim(mz->memcg, zone,
+               reclaimed = mem_cgroup_soft_reclaim(mz->memcg, pgdat,
                                                    gfp_mask, &nr_scanned);
                nr_reclaimed += reclaimed;
                *total_scanned += nr_scanned;
@@ -3252,22 +3194,21 @@ static int memcg_stat_show(struct seq_file *m, void *v)
 
 #ifdef CONFIG_DEBUG_VM
        {
-               int nid, zid;
-               struct mem_cgroup_per_zone *mz;
+               pg_data_t *pgdat;
+               struct mem_cgroup_per_node *mz;
                struct zone_reclaim_stat *rstat;
                unsigned long recent_rotated[2] = {0, 0};
                unsigned long recent_scanned[2] = {0, 0};
 
-               for_each_online_node(nid)
-                       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-                               mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-                               rstat = &mz->lruvec.reclaim_stat;
+               for_each_online_pgdat(pgdat) {
+                       mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id);
+                       rstat = &mz->lruvec.reclaim_stat;
 
-                               recent_rotated[0] += rstat->recent_rotated[0];
-                               recent_rotated[1] += rstat->recent_rotated[1];
-                               recent_scanned[0] += rstat->recent_scanned[0];
-                               recent_scanned[1] += rstat->recent_scanned[1];
-                       }
+                       recent_rotated[0] += rstat->recent_rotated[0];
+                       recent_rotated[1] += rstat->recent_rotated[1];
+                       recent_scanned[0] += rstat->recent_scanned[0];
+                       recent_scanned[1] += rstat->recent_scanned[1];
+               }
                seq_printf(m, "recent_rotated_anon %lu\n", recent_rotated[0]);
                seq_printf(m, "recent_rotated_file %lu\n", recent_rotated[1]);
                seq_printf(m, "recent_scanned_anon %lu\n", recent_scanned[0]);
@@ -4147,11 +4088,10 @@ struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
        return idr_find(&mem_cgroup_idr, id);
 }
 
-static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
+static int alloc_mem_cgroup_per_node_info(struct mem_cgroup *memcg, int node)
 {
        struct mem_cgroup_per_node *pn;
-       struct mem_cgroup_per_zone *mz;
-       int zone, tmp = node;
+       int tmp = node;
        /*
         * This routine is called against possible nodes.
         * But it's BUG to call kmalloc() against offline node.
@@ -4166,18 +4106,16 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
        if (!pn)
                return 1;
 
-       for (zone = 0; zone < MAX_NR_ZONES; zone++) {
-               mz = &pn->zoneinfo[zone];
-               lruvec_init(&mz->lruvec);
-               mz->usage_in_excess = 0;
-               mz->on_tree = false;
-               mz->memcg = memcg;
-       }
+       lruvec_init(&pn->lruvec);
+       pn->usage_in_excess = 0;
+       pn->on_tree = false;
+       pn->memcg = memcg;
+
        memcg->nodeinfo[node] = pn;
        return 0;
 }
 
-static void free_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
+static void free_mem_cgroup_per_node_info(struct mem_cgroup *memcg, int node)
 {
        kfree(memcg->nodeinfo[node]);
 }
@@ -4188,7 +4126,7 @@ static void mem_cgroup_free(struct mem_cgroup *memcg)
 
        memcg_wb_domain_exit(memcg);
        for_each_node(node)
-               free_mem_cgroup_per_zone_info(memcg, node);
+               free_mem_cgroup_per_node_info(memcg, node);
        free_percpu(memcg->stat);
        kfree(memcg);
 }
@@ -4217,7 +4155,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
                goto fail;
 
        for_each_node(node)
-               if (alloc_mem_cgroup_per_zone_info(memcg, node))
+               if (alloc_mem_cgroup_per_node_info(memcg, node))
                        goto fail;
 
        if (memcg_wb_domain_init(memcg, GFP_KERNEL))
@@ -5233,7 +5171,7 @@ static int memory_stat_show(struct seq_file *m, void *v)
        seq_printf(m, "file %llu\n",
                   (u64)stat[MEM_CGROUP_STAT_CACHE] * PAGE_SIZE);
        seq_printf(m, "kernel_stack %llu\n",
-                  (u64)stat[MEMCG_KERNEL_STACK] * PAGE_SIZE);
+                  (u64)stat[MEMCG_KERNEL_STACK_KB] * 1024);
        seq_printf(m, "slab %llu\n",
                   (u64)(stat[MEMCG_SLAB_RECLAIMABLE] +
                         stat[MEMCG_SLAB_UNRECLAIMABLE]) * PAGE_SIZE);
@@ -5820,18 +5758,12 @@ static int __init mem_cgroup_init(void)
 
        for_each_node(node) {
                struct mem_cgroup_tree_per_node *rtpn;
-               int zone;
 
                rtpn = kzalloc_node(sizeof(*rtpn), GFP_KERNEL,
                                    node_online(node) ? node : NUMA_NO_NODE);
 
-               for (zone = 0; zone < MAX_NR_ZONES; zone++) {
-                       struct mem_cgroup_tree_per_zone *rtpz;
-
-                       rtpz = &rtpn->rb_tree_per_zone[zone];
-                       rtpz->rb_root = RB_ROOT;
-                       spin_lock_init(&rtpz->lock);
-               }
+               rtpn->rb_root = RB_ROOT;
+               spin_lock_init(&rtpn->lock);
                soft_limit_tree.rb_tree_per_node[node] = rtpn;
        }
 
index 2fcca6b0e005f0b973af6f13a91ee3a0659267fc..de88f33519c0d6398de8fcc06bfa82f2a477dd95 100644 (file)
@@ -741,8 +741,6 @@ static int me_huge_page(struct page *p, unsigned long pfn)
         * page->lru because it can be used in other hugepage operations,
         * such as __unmap_hugepage_range() and gather_surplus_pages().
         * So instead we use page_mapping() and PageAnon().
-        * We assume that this function is called with page lock held,
-        * so there is no race between isolation and mapping/unmapping.
         */
        if (!(page_mapping(hpage) || PageAnon(hpage))) {
                res = dequeue_hwpoisoned_huge_page(hpage);
@@ -1663,7 +1661,7 @@ static int __soft_offline_page(struct page *page, int flags)
        put_hwpoison_page(page);
        if (!ret) {
                LIST_HEAD(pagelist);
-               inc_zone_page_state(page, NR_ISOLATED_ANON +
+               inc_node_page_state(page, NR_ISOLATED_ANON +
                                        page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
                ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL,
@@ -1671,7 +1669,7 @@ static int __soft_offline_page(struct page *page, int flags)
                if (ret) {
                        if (!list_empty(&pagelist)) {
                                list_del(&page->lru);
-                               dec_zone_page_state(page, NR_ISOLATED_ANON +
+                               dec_node_page_state(page, NR_ISOLATED_ANON +
                                                page_is_file_cache(page));
                                putback_lru_page(page);
                        }
index 82d0b98d27f878015153dd4d360ad7825bab9c48..3894b65b155555f11076f0cae90f71e2475b6929 100644 (file)
@@ -1209,9 +1209,10 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
 
                arch_refresh_nodedata(nid, pgdat);
        } else {
-               /* Reset the nr_zones and classzone_idx to 0 before reuse */
+               /* Reset the nr_zones, order and classzone_idx before reuse */
                pgdat->nr_zones = 0;
-               pgdat->classzone_idx = 0;
+               pgdat->kswapd_order = 0;
+               pgdat->kswapd_classzone_idx = 0;
        }
 
        /* we can use NODE_DATA(nid) from here */
@@ -1547,6 +1548,37 @@ static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
        return 0;
 }
 
+static struct page *new_node_page(struct page *page, unsigned long private,
+               int **result)
+{
+       gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
+       int nid = page_to_nid(page);
+       nodemask_t nmask = node_online_map;
+       struct page *new_page;
+
+       /*
+        * TODO: allocate a destination hugepage from a nearest neighbor node,
+        * accordance with memory policy of the user process if possible. For
+        * now as a simple work-around, we use the next node for destination.
+        */
+       if (PageHuge(page))
+               return alloc_huge_page_node(page_hstate(compound_head(page)),
+                                       next_node_in(nid, nmask));
+
+       node_clear(nid, nmask);
+       if (PageHighMem(page)
+           || (zone_idx(page_zone(page)) == ZONE_MOVABLE))
+               gfp_mask |= __GFP_HIGHMEM;
+
+       new_page = __alloc_pages_nodemask(gfp_mask, 0,
+                                       node_zonelist(nid, gfp_mask), &nmask);
+       if (!new_page)
+               new_page = __alloc_pages(gfp_mask, 0,
+                                       node_zonelist(nid, gfp_mask));
+
+       return new_page;
+}
+
 #define NR_OFFLINE_AT_ONCE_PAGES       (256)
 static int
 do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
@@ -1586,7 +1618,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                        put_page(page);
                        list_add_tail(&page->lru, &source);
                        move_pages--;
-                       inc_zone_page_state(page, NR_ISOLATED_ANON +
+                       inc_node_page_state(page, NR_ISOLATED_ANON +
                                            page_is_file_cache(page));
 
                } else {
@@ -1610,11 +1642,8 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                        goto out;
                }
 
-               /*
-                * alloc_migrate_target should be improooooved!!
-                * migrate_pages returns # of failed pages.
-                */
-               ret = migrate_pages(&source, alloc_migrate_target, NULL, 0,
+               /* Allocate a new page from the nearest neighbor node */
+               ret = migrate_pages(&source, new_node_page, NULL, 0,
                                        MIGRATE_SYNC, MR_MEMORY_HOTPLUG);
                if (ret)
                        putback_movable_pages(&source);
index 53e40d3f39335d2602c94517c5f4e150538067bc..d8c4e38fb5f4be1d9748dc77f214c8a285374f8d 100644 (file)
@@ -962,7 +962,7 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
        if ((flags & MPOL_MF_MOVE_ALL) || page_mapcount(page) == 1) {
                if (!isolate_lru_page(page)) {
                        list_add_tail(&page->lru, pagelist);
-                       inc_zone_page_state(page, NR_ISOLATED_ANON +
+                       inc_node_page_state(page, NR_ISOLATED_ANON +
                                            page_is_file_cache(page));
                }
        }
index 8f65464da5de84d8bca0a8d97352f3c800f90614..47a659dedd44405a277190d3bf9b1655636573d5 100644 (file)
@@ -306,7 +306,7 @@ EXPORT_SYMBOL(mempool_resize);
  * returns NULL. Note that due to preallocation, this function
  * *never* fails when called from process contexts. (it might
  * fail if called from an IRQ context.)
- * Note: neither __GFP_NOMEMALLOC nor __GFP_ZERO are supported.
+ * Note: using __GFP_ZERO is not supported.
  */
 void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask)
 {
@@ -315,27 +315,16 @@ void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask)
        wait_queue_t wait;
        gfp_t gfp_temp;
 
-       /* If oom killed, memory reserves are essential to prevent livelock */
-       VM_WARN_ON_ONCE(gfp_mask & __GFP_NOMEMALLOC);
-       /* No element size to zero on allocation */
        VM_WARN_ON_ONCE(gfp_mask & __GFP_ZERO);
-
        might_sleep_if(gfp_mask & __GFP_DIRECT_RECLAIM);
 
+       gfp_mask |= __GFP_NOMEMALLOC;   /* don't allocate emergency reserves */
        gfp_mask |= __GFP_NORETRY;      /* don't loop in __alloc_pages */
        gfp_mask |= __GFP_NOWARN;       /* failures are OK */
 
        gfp_temp = gfp_mask & ~(__GFP_DIRECT_RECLAIM|__GFP_IO);
 
 repeat_alloc:
-       if (likely(pool->curr_nr)) {
-               /*
-                * Don't allocate from emergency reserves if there are
-                * elements available.  This check is racy, but it will
-                * be rechecked each loop.
-                */
-               gfp_temp |= __GFP_NOMEMALLOC;
-       }
 
        element = pool->alloc(gfp_temp, pool->pool_data);
        if (likely(element != NULL))
@@ -359,12 +348,11 @@ repeat_alloc:
         * We use gfp mask w/o direct reclaim or IO for the first round.  If
         * alloc failed with that and @pool was empty, retry immediately.
         */
-       if ((gfp_temp & ~__GFP_NOMEMALLOC) != gfp_mask) {
+       if (gfp_temp != gfp_mask) {
                spin_unlock_irqrestore(&pool->lock, flags);
                gfp_temp = gfp_mask;
                goto repeat_alloc;
        }
-       gfp_temp = gfp_mask;
 
        /* We must not sleep if !__GFP_DIRECT_RECLAIM */
        if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) {
index 2232f6923cc720963d4cd4a2ac105d3b984e9a7a..f7ee04a5ae27a2934de9fab746667597bffafef3 100644 (file)
@@ -168,7 +168,7 @@ void putback_movable_pages(struct list_head *l)
                        continue;
                }
                list_del(&page->lru);
-               dec_zone_page_state(page, NR_ISOLATED_ANON +
+               dec_node_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
                /*
                 * We isolated non-lru movable page so here we can use
@@ -501,19 +501,21 @@ int migrate_page_move_mapping(struct address_space *mapping,
         * new page and drop references to the old page.
         *
         * Note that anonymous pages are accounted for
-        * via NR_FILE_PAGES and NR_ANON_PAGES if they
+        * via NR_FILE_PAGES and NR_ANON_MAPPED if they
         * are mapped to swap space.
         */
        if (newzone != oldzone) {
-               __dec_zone_state(oldzone, NR_FILE_PAGES);
-               __inc_zone_state(newzone, NR_FILE_PAGES);
+               __dec_node_state(oldzone->zone_pgdat, NR_FILE_PAGES);
+               __inc_node_state(newzone->zone_pgdat, NR_FILE_PAGES);
                if (PageSwapBacked(page) && !PageSwapCache(page)) {
-                       __dec_zone_state(oldzone, NR_SHMEM);
-                       __inc_zone_state(newzone, NR_SHMEM);
+                       __dec_node_state(oldzone->zone_pgdat, NR_SHMEM);
+                       __inc_node_state(newzone->zone_pgdat, NR_SHMEM);
                }
                if (dirty && mapping_cap_account_dirty(mapping)) {
-                       __dec_zone_state(oldzone, NR_FILE_DIRTY);
-                       __inc_zone_state(newzone, NR_FILE_DIRTY);
+                       __dec_node_state(oldzone->zone_pgdat, NR_FILE_DIRTY);
+                       __dec_zone_state(oldzone, NR_ZONE_WRITE_PENDING);
+                       __inc_node_state(newzone->zone_pgdat, NR_FILE_DIRTY);
+                       __inc_zone_state(newzone, NR_ZONE_WRITE_PENDING);
                }
        }
        local_irq_enable();
@@ -1119,7 +1121,7 @@ out:
                 * restored.
                 */
                list_del(&page->lru);
-               dec_zone_page_state(page, NR_ISOLATED_ANON +
+               dec_node_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
        }
 
@@ -1460,7 +1462,7 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
                err = isolate_lru_page(page);
                if (!err) {
                        list_add_tail(&page->lru, &pagelist);
-                       inc_zone_page_state(page, NR_ISOLATED_ANON +
+                       inc_node_page_state(page, NR_ISOLATED_ANON +
                                            page_is_file_cache(page));
                }
 put_and_set:
@@ -1726,15 +1728,16 @@ static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
                                   unsigned long nr_migrate_pages)
 {
        int z;
+
+       if (!pgdat_reclaimable(pgdat))
+               return false;
+
        for (z = pgdat->nr_zones - 1; z >= 0; z--) {
                struct zone *zone = pgdat->node_zones + z;
 
                if (!populated_zone(zone))
                        continue;
 
-               if (!zone_reclaimable(zone))
-                       continue;
-
                /* Avoid waking kswapd by allocating pages_to_migrate pages. */
                if (!zone_watermark_ok(zone, 0,
                                       high_wmark_pages(zone) +
@@ -1828,7 +1831,7 @@ static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
        }
 
        page_lru = page_is_file_cache(page);
-       mod_zone_page_state(page_zone(page), NR_ISOLATED_ANON + page_lru,
+       mod_node_page_state(page_pgdat(page), NR_ISOLATED_ANON + page_lru,
                                hpage_nr_pages(page));
 
        /*
@@ -1886,7 +1889,7 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
        if (nr_remaining) {
                if (!list_empty(&migratepages)) {
                        list_del(&page->lru);
-                       dec_zone_page_state(page, NR_ISOLATED_ANON +
+                       dec_node_page_state(page, NR_ISOLATED_ANON +
                                        page_is_file_cache(page));
                        putback_lru_page(page);
                }
@@ -1931,7 +1934,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
                goto out_dropref;
 
        new_page = alloc_pages_node(node,
-               (GFP_TRANSHUGE | __GFP_THISNODE) & ~__GFP_RECLAIM,
+               (GFP_TRANSHUGE_LIGHT | __GFP_THISNODE),
                HPAGE_PMD_ORDER);
        if (!new_page)
                goto out_fail;
@@ -1979,7 +1982,7 @@ fail_putback:
                /* Retake the callers reference and putback on LRU */
                get_page(page);
                putback_lru_page(page);
-               mod_zone_page_state(page_zone(page),
+               mod_node_page_state(page_pgdat(page),
                         NR_ISOLATED_ANON + page_lru, -HPAGE_PMD_NR);
 
                goto out_unlock;
@@ -2030,7 +2033,7 @@ fail_putback:
        count_vm_events(PGMIGRATE_SUCCESS, HPAGE_PMD_NR);
        count_vm_numa_events(NUMA_PAGE_MIGRATE, HPAGE_PMD_NR);
 
-       mod_zone_page_state(page_zone(page),
+       mod_node_page_state(page_pgdat(page),
                        NR_ISOLATED_ANON + page_lru,
                        -HPAGE_PMD_NR);
        return isolated;
index ef8dc9f395c4cb52e5e80c73f31654dc6936223b..14645be06e301cfc4a62301e25818365e766874e 100644 (file)
@@ -103,7 +103,7 @@ static bool __munlock_isolate_lru_page(struct page *page, bool getpage)
        if (PageLRU(page)) {
                struct lruvec *lruvec;
 
-               lruvec = mem_cgroup_page_lruvec(page, page_zone(page));
+               lruvec = mem_cgroup_page_lruvec(page, page_pgdat(page));
                if (getpage)
                        get_page(page);
                ClearPageLRU(page);
@@ -188,7 +188,7 @@ unsigned int munlock_vma_page(struct page *page)
         * might otherwise copy PageMlocked to part of the tail pages before
         * we clear it in the head page. It also stabilizes hpage_nr_pages().
         */
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
 
        nr_pages = hpage_nr_pages(page);
        if (!TestClearPageMlocked(page))
@@ -197,14 +197,14 @@ unsigned int munlock_vma_page(struct page *page)
        __mod_zone_page_state(zone, NR_MLOCK, -nr_pages);
 
        if (__munlock_isolate_lru_page(page, true)) {
-               spin_unlock_irq(&zone->lru_lock);
+               spin_unlock_irq(zone_lru_lock(zone));
                __munlock_isolated_page(page);
                goto out;
        }
        __munlock_isolation_failed(page);
 
 unlock_out:
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(zone_lru_lock(zone));
 
 out:
        return nr_pages - 1;
@@ -289,7 +289,7 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
        pagevec_init(&pvec_putback, 0);
 
        /* Phase 1: page isolation */
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
        for (i = 0; i < nr; i++) {
                struct page *page = pvec->pages[i];
 
@@ -315,7 +315,7 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
        }
        delta_munlocked = -nr + pagevec_count(&pvec_putback);
        __mod_zone_page_state(zone, NR_MLOCK, delta_munlocked);
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(zone_lru_lock(zone));
 
        /* Now we can release pins of pages that we are not munlocking */
        pagevec_release(&pvec_putback);
index 86b18f334f4f759d8342a5220f8ac850c770ab03..d44bee96a5fe4f5141d56916591889424a195684 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -621,7 +621,6 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
 {
        struct mm_struct *mm = vma->vm_mm;
        struct vm_area_struct *next = vma->vm_next;
-       struct vm_area_struct *importer = NULL;
        struct address_space *mapping = NULL;
        struct rb_root *root = NULL;
        struct anon_vma *anon_vma = NULL;
@@ -631,17 +630,25 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
        int remove_next = 0;
 
        if (next && !insert) {
-               struct vm_area_struct *exporter = NULL;
+               struct vm_area_struct *exporter = NULL, *importer = NULL;
 
                if (end >= next->vm_end) {
                        /*
                         * vma expands, overlapping all the next, and
                         * perhaps the one after too (mprotect case 6).
                         */
-again:                 remove_next = 1 + (end > next->vm_end);
+                       remove_next = 1 + (end > next->vm_end);
                        end = next->vm_end;
                        exporter = next;
                        importer = vma;
+
+                       /*
+                        * If next doesn't have anon_vma, import from vma after
+                        * next, if the vma overlaps with it.
+                        */
+                       if (remove_next == 2 && next && !next->anon_vma)
+                               exporter = next->vm_next;
+
                } else if (end > next->vm_start) {
                        /*
                         * vma expands, overlapping part of the next:
@@ -675,7 +682,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
                                return error;
                }
        }
-
+again:
        vma_adjust_trans_huge(vma, start, end, adjust_next);
 
        if (file) {
@@ -796,8 +803,11 @@ again:                     remove_next = 1 + (end > next->vm_end);
                 * up the code too much to do both in one go.
                 */
                next = vma->vm_next;
-               if (remove_next == 2)
+               if (remove_next == 2) {
+                       remove_next = 1;
+                       end = next->vm_end;
                        goto again;
+               }
                else if (next)
                        vma_gap_update(next);
                else
index d4a929d79470aa0c9edc6131854dbf309ca39d47..7d0a275df822e9e14c55e5d472cfc473ac3ae173 100644 (file)
@@ -176,11 +176,13 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
 
        /*
         * Do not even consider tasks which are explicitly marked oom
-        * unkillable or have been already oom reaped.
+        * unkillable or have been already oom reaped or the are in
+        * the middle of vfork
         */
        adj = (long)p->signal->oom_score_adj;
        if (adj == OOM_SCORE_ADJ_MIN ||
-                       test_bit(MMF_OOM_REAPED, &p->mm->flags)) {
+                       test_bit(MMF_OOM_REAPED, &p->mm->flags) ||
+                       in_vfork(p)) {
                task_unlock(p);
                return 0;
        }
@@ -281,10 +283,22 @@ enum oom_scan_t oom_scan_process_thread(struct oom_control *oc,
 
        /*
         * This task already has access to memory reserves and is being killed.
-        * Don't allow any other task to have access to the reserves.
+        * Don't allow any other task to have access to the reserves unless
+        * the task has MMF_OOM_REAPED because chances that it would release
+        * any memory is quite low.
         */
-       if (!is_sysrq_oom(oc) && atomic_read(&task->signal->oom_victims))
-               return OOM_SCAN_ABORT;
+       if (!is_sysrq_oom(oc) && atomic_read(&task->signal->oom_victims)) {
+               struct task_struct *p = find_lock_task_mm(task);
+               enum oom_scan_t ret = OOM_SCAN_ABORT;
+
+               if (p) {
+                       if (test_bit(MMF_OOM_REAPED, &p->mm->flags))
+                               ret = OOM_SCAN_CONTINUE;
+                       task_unlock(p);
+               }
+
+               return ret;
+       }
 
        /*
         * If task is allocating a lot of memory and has been marked to be
@@ -415,7 +429,7 @@ bool oom_killer_disabled __read_mostly;
  * task's threads: if one of those is using this mm then this task was also
  * using it.
  */
-static bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
+bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
 {
        struct task_struct *t;
 
@@ -554,8 +568,27 @@ static void oom_reap_task(struct task_struct *tsk)
                schedule_timeout_idle(HZ/10);
 
        if (attempts > MAX_OOM_REAP_RETRIES) {
+               struct task_struct *p;
+
                pr_info("oom_reaper: unable to reap pid:%d (%s)\n",
                                task_pid_nr(tsk), tsk->comm);
+
+               /*
+                * If we've already tried to reap this task in the past and
+                * failed it probably doesn't make much sense to try yet again
+                * so hide the mm from the oom killer so that it can move on
+                * to another task with a different mm struct.
+                */
+               p = find_lock_task_mm(tsk);
+               if (p) {
+                       if (test_and_set_bit(MMF_OOM_NOT_REAPABLE, &p->mm->flags)) {
+                               pr_info("oom_reaper: giving up pid:%d (%s)\n",
+                                               task_pid_nr(tsk), tsk->comm);
+                               set_bit(MMF_OOM_REAPED, &p->mm->flags);
+                       }
+                       task_unlock(p);
+               }
+
                debug_show_all_locks();
        }
 
@@ -594,7 +627,7 @@ static int oom_reaper(void *unused)
        return 0;
 }
 
-static void wake_oom_reaper(struct task_struct *tsk)
+void wake_oom_reaper(struct task_struct *tsk)
 {
        if (!oom_reaper_th)
                return;
@@ -612,46 +645,6 @@ static void wake_oom_reaper(struct task_struct *tsk)
        wake_up(&oom_reaper_wait);
 }
 
-/* Check if we can reap the given task. This has to be called with stable
- * tsk->mm
- */
-void try_oom_reaper(struct task_struct *tsk)
-{
-       struct mm_struct *mm = tsk->mm;
-       struct task_struct *p;
-
-       if (!mm)
-               return;
-
-       /*
-        * There might be other threads/processes which are either not
-        * dying or even not killable.
-        */
-       if (atomic_read(&mm->mm_users) > 1) {
-               rcu_read_lock();
-               for_each_process(p) {
-                       if (!process_shares_mm(p, mm))
-                               continue;
-                       if (fatal_signal_pending(p))
-                               continue;
-
-                       /*
-                        * If the task is exiting make sure the whole thread group
-                        * is exiting and cannot acces mm anymore.
-                        */
-                       if (signal_group_exit(p->signal))
-                               continue;
-
-                       /* Give up */
-                       rcu_read_unlock();
-                       return;
-               }
-               rcu_read_unlock();
-       }
-
-       wake_oom_reaper(tsk);
-}
-
 static int __init oom_init(void)
 {
        oom_reaper_th = kthread_run(oom_reaper, NULL, "oom_reaper");
@@ -663,10 +656,6 @@ static int __init oom_init(void)
        return 0;
 }
 subsys_initcall(oom_init)
-#else
-static void wake_oom_reaper(struct task_struct *tsk)
-{
-}
 #endif
 
 /**
@@ -743,6 +732,80 @@ void oom_killer_enable(void)
        oom_killer_disabled = false;
 }
 
+static inline bool __task_will_free_mem(struct task_struct *task)
+{
+       struct signal_struct *sig = task->signal;
+
+       /*
+        * A coredumping process may sleep for an extended period in exit_mm(),
+        * so the oom killer cannot assume that the process will promptly exit
+        * and release memory.
+        */
+       if (sig->flags & SIGNAL_GROUP_COREDUMP)
+               return false;
+
+       if (sig->flags & SIGNAL_GROUP_EXIT)
+               return true;
+
+       if (thread_group_empty(task) && (task->flags & PF_EXITING))
+               return true;
+
+       return false;
+}
+
+/*
+ * Checks whether the given task is dying or exiting and likely to
+ * release its address space. This means that all threads and processes
+ * sharing the same mm have to be killed or exiting.
+ * Caller has to make sure that task->mm is stable (hold task_lock or
+ * it operates on the current).
+ */
+bool task_will_free_mem(struct task_struct *task)
+{
+       struct mm_struct *mm = task->mm;
+       struct task_struct *p;
+       bool ret;
+
+       /*
+        * Skip tasks without mm because it might have passed its exit_mm and
+        * exit_oom_victim. oom_reaper could have rescued that but do not rely
+        * on that for now. We can consider find_lock_task_mm in future.
+        */
+       if (!mm)
+               return false;
+
+       if (!__task_will_free_mem(task))
+               return false;
+
+       /*
+        * This task has already been drained by the oom reaper so there are
+        * only small chances it will free some more
+        */
+       if (test_bit(MMF_OOM_REAPED, &mm->flags))
+               return false;
+
+       if (atomic_read(&mm->mm_users) <= 1)
+               return true;
+
+       /*
+        * This is really pessimistic but we do not have any reliable way
+        * to check that external processes share with our mm
+        */
+       rcu_read_lock();
+       for_each_process(p) {
+               if (!process_shares_mm(p, mm))
+                       continue;
+               if (same_thread_group(task, p))
+                       continue;
+               ret = __task_will_free_mem(p);
+               if (!ret)
+                       break;
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
 /*
  * Must be called while holding a reference to p, which will be released upon
  * returning.
@@ -765,9 +828,9 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
         * its children or threads, just set TIF_MEMDIE so it can die quickly
         */
        task_lock(p);
-       if (p->mm && task_will_free_mem(p)) {
+       if (task_will_free_mem(p)) {
                mark_oom_victim(p);
-               try_oom_reaper(p);
+               wake_oom_reaper(p);
                task_unlock(p);
                put_task_struct(p);
                return;
@@ -850,14 +913,18 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
                        continue;
                if (same_thread_group(p, victim))
                        continue;
-               if (unlikely(p->flags & PF_KTHREAD) || is_global_init(p) ||
-                   p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+               if (unlikely(p->flags & PF_KTHREAD) || is_global_init(p)) {
                        /*
                         * We cannot use oom_reaper for the mm shared by this
                         * process because it wouldn't get killed and so the
-                        * memory might be still used.
+                        * memory might be still used. Hide the mm from the oom
+                        * killer to guarantee OOM forward progress.
                         */
                        can_oom_reap = false;
+                       set_bit(MMF_OOM_REAPED, &mm->flags);
+                       pr_info("oom killer %d (%s) has mm pinned by %d (%s)\n",
+                                       task_pid_nr(victim), victim->comm,
+                                       task_pid_nr(p), p->comm);
                        continue;
                }
                do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);
@@ -939,14 +1006,10 @@ bool out_of_memory(struct oom_control *oc)
         * If current has a pending SIGKILL or is exiting, then automatically
         * select it.  The goal is to allow it to allocate so that it may
         * quickly exit and free its memory.
-        *
-        * But don't select if current has already released its mm and cleared
-        * TIF_MEMDIE flag at exit_mm(), otherwise an OOM livelock may occur.
         */
-       if (current->mm &&
-           (fatal_signal_pending(current) || task_will_free_mem(current))) {
+       if (task_will_free_mem(current)) {
                mark_oom_victim(current);
-               try_oom_reaper(current);
+               wake_oom_reaper(current);
                return true;
        }
 
index d578d2a56b192d5cc566fea4b88ecae81a431818..f4cd7d8005c9071dc1caf77a155eb3f2dc611b61 100644 (file)
@@ -267,26 +267,35 @@ static void wb_min_max_ratio(struct bdi_writeback *wb,
  */
 
 /**
- * zone_dirtyable_memory - number of dirtyable pages in a zone
- * @zone: the zone
+ * node_dirtyable_memory - number of dirtyable pages in a node
+ * @pgdat: the node
  *
- * Returns the zone's number of pages potentially available for dirty
- * page cache.  This is the base value for the per-zone dirty limits.
+ * Returns the node's number of pages potentially available for dirty
+ * page cache.  This is the base value for the per-node dirty limits.
  */
-static unsigned long zone_dirtyable_memory(struct zone *zone)
+static unsigned long node_dirtyable_memory(struct pglist_data *pgdat)
 {
-       unsigned long nr_pages;
+       unsigned long nr_pages = 0;
+       int z;
+
+       for (z = 0; z < MAX_NR_ZONES; z++) {
+               struct zone *zone = pgdat->node_zones + z;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               nr_pages += zone_page_state(zone, NR_FREE_PAGES);
+       }
 
-       nr_pages = zone_page_state(zone, NR_FREE_PAGES);
        /*
         * Pages reserved for the kernel should not be considered
         * dirtyable, to prevent a situation where reclaim has to
         * clean pages in order to balance the zones.
         */
-       nr_pages -= min(nr_pages, zone->totalreserve_pages);
+       nr_pages -= min(nr_pages, pgdat->totalreserve_pages);
 
-       nr_pages += zone_page_state(zone, NR_INACTIVE_FILE);
-       nr_pages += zone_page_state(zone, NR_ACTIVE_FILE);
+       nr_pages += node_page_state(pgdat, NR_INACTIVE_FILE);
+       nr_pages += node_page_state(pgdat, NR_ACTIVE_FILE);
 
        return nr_pages;
 }
@@ -299,13 +308,26 @@ static unsigned long highmem_dirtyable_memory(unsigned long total)
        int i;
 
        for_each_node_state(node, N_HIGH_MEMORY) {
-               for (i = 0; i < MAX_NR_ZONES; i++) {
-                       struct zone *z = &NODE_DATA(node)->node_zones[i];
+               for (i = ZONE_NORMAL + 1; i < MAX_NR_ZONES; i++) {
+                       struct zone *z;
+                       unsigned long nr_pages;
+
+                       if (!is_highmem_idx(i))
+                               continue;
+
+                       z = &NODE_DATA(node)->node_zones[i];
+                       if (!populated_zone(z))
+                               continue;
 
-                       if (is_highmem(z))
-                               x += zone_dirtyable_memory(z);
+                       nr_pages = zone_page_state(z, NR_FREE_PAGES);
+                       /* watch for underflows */
+                       nr_pages -= min(nr_pages, high_wmark_pages(z));
+                       nr_pages += zone_page_state(z, NR_ZONE_INACTIVE_FILE);
+                       nr_pages += zone_page_state(z, NR_ZONE_ACTIVE_FILE);
+                       x += nr_pages;
                }
        }
+
        /*
         * Unreclaimable memory (kernel memory or anonymous memory
         * without swap) can bring down the dirtyable pages below
@@ -348,8 +370,8 @@ static unsigned long global_dirtyable_memory(void)
         */
        x -= min(x, totalreserve_pages);
 
-       x += global_page_state(NR_INACTIVE_FILE);
-       x += global_page_state(NR_ACTIVE_FILE);
+       x += global_node_page_state(NR_INACTIVE_FILE);
+       x += global_node_page_state(NR_ACTIVE_FILE);
 
        if (!vm_highmem_is_dirtyable)
                x -= highmem_dirtyable_memory(x);
@@ -445,23 +467,23 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
 }
 
 /**
- * zone_dirty_limit - maximum number of dirty pages allowed in a zone
- * @zone: the zone
+ * node_dirty_limit - maximum number of dirty pages allowed in a node
+ * @pgdat: the node
  *
- * Returns the maximum number of dirty pages allowed in a zone, based
- * on the zone's dirtyable memory.
+ * Returns the maximum number of dirty pages allowed in a node, based
+ * on the node's dirtyable memory.
  */
-static unsigned long zone_dirty_limit(struct zone *zone)
+static unsigned long node_dirty_limit(struct pglist_data *pgdat)
 {
-       unsigned long zone_memory = zone_dirtyable_memory(zone);
+       unsigned long node_memory = node_dirtyable_memory(pgdat);
        struct task_struct *tsk = current;
        unsigned long dirty;
 
        if (vm_dirty_bytes)
                dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE) *
-                       zone_memory / global_dirtyable_memory();
+                       node_memory / global_dirtyable_memory();
        else
-               dirty = vm_dirty_ratio * zone_memory / 100;
+               dirty = vm_dirty_ratio * node_memory / 100;
 
        if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk))
                dirty += dirty / 4;
@@ -470,19 +492,22 @@ static unsigned long zone_dirty_limit(struct zone *zone)
 }
 
 /**
- * zone_dirty_ok - tells whether a zone is within its dirty limits
- * @zone: the zone to check
+ * node_dirty_ok - tells whether a node is within its dirty limits
+ * @pgdat: the node to check
  *
- * Returns %true when the dirty pages in @zone are within the zone's
+ * Returns %true when the dirty pages in @pgdat are within the node's
  * dirty limit, %false if the limit is exceeded.
  */
-bool zone_dirty_ok(struct zone *zone)
+bool node_dirty_ok(struct pglist_data *pgdat)
 {
-       unsigned long limit = zone_dirty_limit(zone);
+       unsigned long limit = node_dirty_limit(pgdat);
+       unsigned long nr_pages = 0;
+
+       nr_pages += node_page_state(pgdat, NR_FILE_DIRTY);
+       nr_pages += node_page_state(pgdat, NR_UNSTABLE_NFS);
+       nr_pages += node_page_state(pgdat, NR_WRITEBACK);
 
-       return zone_page_state(zone, NR_FILE_DIRTY) +
-              zone_page_state(zone, NR_UNSTABLE_NFS) +
-              zone_page_state(zone, NR_WRITEBACK) <= limit;
+       return nr_pages <= limit;
 }
 
 int dirty_background_ratio_handler(struct ctl_table *table, int write,
@@ -1570,10 +1595,10 @@ static void balance_dirty_pages(struct address_space *mapping,
                 * written to the server's write cache, but has not yet
                 * been flushed to permanent storage.
                 */
-               nr_reclaimable = global_page_state(NR_FILE_DIRTY) +
-                                       global_page_state(NR_UNSTABLE_NFS);
+               nr_reclaimable = global_node_page_state(NR_FILE_DIRTY) +
+                                       global_node_page_state(NR_UNSTABLE_NFS);
                gdtc->avail = global_dirtyable_memory();
-               gdtc->dirty = nr_reclaimable + global_page_state(NR_WRITEBACK);
+               gdtc->dirty = nr_reclaimable + global_node_page_state(NR_WRITEBACK);
 
                domain_dirty_limits(gdtc);
 
@@ -1910,8 +1935,8 @@ bool wb_over_bg_thresh(struct bdi_writeback *wb)
         * as we're trying to decide whether to put more under writeback.
         */
        gdtc->avail = global_dirtyable_memory();
-       gdtc->dirty = global_page_state(NR_FILE_DIRTY) +
-                     global_page_state(NR_UNSTABLE_NFS);
+       gdtc->dirty = global_node_page_state(NR_FILE_DIRTY) +
+                     global_node_page_state(NR_UNSTABLE_NFS);
        domain_dirty_limits(gdtc);
 
        if (gdtc->dirty > gdtc->bg_thresh)
@@ -1955,8 +1980,8 @@ void throttle_vm_writeout(gfp_t gfp_mask)
                  */
                 dirty_thresh += dirty_thresh / 10;      /* wheeee... */
 
-                if (global_page_state(NR_UNSTABLE_NFS) +
-                       global_page_state(NR_WRITEBACK) <= dirty_thresh)
+                if (global_node_page_state(NR_UNSTABLE_NFS) +
+                       global_node_page_state(NR_WRITEBACK) <= dirty_thresh)
                                break;
                 congestion_wait(BLK_RW_ASYNC, HZ/10);
 
@@ -1984,8 +2009,8 @@ int dirty_writeback_centisecs_handler(struct ctl_table *table, int write,
 void laptop_mode_timer_fn(unsigned long data)
 {
        struct request_queue *q = (struct request_queue *)data;
-       int nr_pages = global_page_state(NR_FILE_DIRTY) +
-               global_page_state(NR_UNSTABLE_NFS);
+       int nr_pages = global_node_page_state(NR_FILE_DIRTY) +
+               global_node_page_state(NR_UNSTABLE_NFS);
        struct bdi_writeback *wb;
 
        /*
@@ -2436,8 +2461,9 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
                wb = inode_to_wb(inode);
 
                mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_DIRTY);
-               __inc_zone_page_state(page, NR_FILE_DIRTY);
-               __inc_zone_page_state(page, NR_DIRTIED);
+               __inc_node_page_state(page, NR_FILE_DIRTY);
+               __inc_zone_page_state(page, NR_ZONE_WRITE_PENDING);
+               __inc_node_page_state(page, NR_DIRTIED);
                __inc_wb_stat(wb, WB_RECLAIMABLE);
                __inc_wb_stat(wb, WB_DIRTIED);
                task_io_account_write(PAGE_SIZE);
@@ -2457,7 +2483,8 @@ void account_page_cleaned(struct page *page, struct address_space *mapping,
 {
        if (mapping_cap_account_dirty(mapping)) {
                mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY);
-               dec_zone_page_state(page, NR_FILE_DIRTY);
+               dec_node_page_state(page, NR_FILE_DIRTY);
+               dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                dec_wb_stat(wb, WB_RECLAIMABLE);
                task_io_account_cancelled_write(PAGE_SIZE);
        }
@@ -2525,7 +2552,7 @@ void account_page_redirty(struct page *page)
 
                wb = unlocked_inode_to_wb_begin(inode, &locked);
                current->nr_dirtied--;
-               dec_zone_page_state(page, NR_DIRTIED);
+               dec_node_page_state(page, NR_DIRTIED);
                dec_wb_stat(wb, WB_DIRTIED);
                unlocked_inode_to_wb_end(inode, locked);
        }
@@ -2713,7 +2740,8 @@ int clear_page_dirty_for_io(struct page *page)
                wb = unlocked_inode_to_wb_begin(inode, &locked);
                if (TestClearPageDirty(page)) {
                        mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY);
-                       dec_zone_page_state(page, NR_FILE_DIRTY);
+                       dec_node_page_state(page, NR_FILE_DIRTY);
+                       dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                        dec_wb_stat(wb, WB_RECLAIMABLE);
                        ret = 1;
                }
@@ -2759,8 +2787,9 @@ int test_clear_page_writeback(struct page *page)
        }
        if (ret) {
                mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
-               dec_zone_page_state(page, NR_WRITEBACK);
-               inc_zone_page_state(page, NR_WRITTEN);
+               dec_node_page_state(page, NR_WRITEBACK);
+               dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
+               inc_node_page_state(page, NR_WRITTEN);
        }
        unlock_page_memcg(page);
        return ret;
@@ -2813,7 +2842,8 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
        }
        if (!ret) {
                mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
-               inc_zone_page_state(page, NR_WRITEBACK);
+               inc_node_page_state(page, NR_WRITEBACK);
+               inc_zone_page_state(page, NR_ZONE_WRITE_PENDING);
        }
        unlock_page_memcg(page);
        return ret;
index 452513bf02ceca4d331a2bd1781d0e1f9ec47b79..ea759b9353603bcea22bf77fb5fef633877c4a22 100644 (file)
@@ -295,14 +295,6 @@ static inline bool __meminit early_page_uninitialised(unsigned long pfn)
        return false;
 }
 
-static inline bool early_page_nid_uninitialised(unsigned long pfn, int nid)
-{
-       if (pfn >= NODE_DATA(nid)->first_deferred_pfn)
-               return true;
-
-       return false;
-}
-
 /*
  * Returns false when the remaining initialisation should be deferred until
  * later in the boot cycle when it can be parallelised.
@@ -342,11 +334,6 @@ static inline bool early_page_uninitialised(unsigned long pfn)
        return false;
 }
 
-static inline bool early_page_nid_uninitialised(unsigned long pfn, int nid)
-{
-       return false;
-}
-
 static inline bool update_defer_init(pg_data_t *pgdat,
                                unsigned long pfn, unsigned long zone_end,
                                unsigned long *nr_initialised)
@@ -1091,9 +1078,9 @@ static void free_pcppages_bulk(struct zone *zone, int count,
 
        spin_lock(&zone->lock);
        isolated_pageblocks = has_isolate_pageblock(zone);
-       nr_scanned = zone_page_state(zone, NR_PAGES_SCANNED);
+       nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
        if (nr_scanned)
-               __mod_zone_page_state(zone, NR_PAGES_SCANNED, -nr_scanned);
+               __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
 
        while (count) {
                struct page *page;
@@ -1148,9 +1135,9 @@ static void free_one_page(struct zone *zone,
 {
        unsigned long nr_scanned;
        spin_lock(&zone->lock);
-       nr_scanned = zone_page_state(zone, NR_PAGES_SCANNED);
+       nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
        if (nr_scanned)
-               __mod_zone_page_state(zone, NR_PAGES_SCANNED, -nr_scanned);
+               __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
 
        if (unlikely(has_isolate_pageblock(zone) ||
                is_migrate_isolate(migratetype))) {
@@ -2517,7 +2504,10 @@ int __isolate_free_page(struct page *page, unsigned int order)
        zone->free_area[order].nr_free--;
        rmv_page_order(page);
 
-       /* Set the pageblock if the isolated page is at least a pageblock */
+       /*
+        * Set the pageblock if the isolated page is at least half of a
+        * pageblock
+        */
        if (order >= pageblock_order - 1) {
                struct page *endpage = page + (1 << order) - 1;
                for (; page < endpage; page += pageblock_nr_pages) {
@@ -2597,7 +2587,6 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
                        else
                                page = list_first_entry(list, struct page, lru);
 
-                       __dec_zone_state(zone, NR_ALLOC_BATCH);
                        list_del(&page->lru);
                        pcp->count--;
 
@@ -2623,16 +2612,11 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
                spin_unlock(&zone->lock);
                if (!page)
                        goto failed;
-               __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
                __mod_zone_freepage_state(zone, -(1 << order),
                                          get_pcppage_migratetype(page));
        }
 
-       if (atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]) <= 0 &&
-           !test_bit(ZONE_FAIR_DEPLETED, &zone->flags))
-               set_bit(ZONE_FAIR_DEPLETED, &zone->flags);
-
-       __count_zone_vm_events(PGALLOC, zone, 1 << order);
+       __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
        zone_statistics(preferred_zone, zone, gfp_flags);
        local_irq_restore(flags);
 
@@ -2842,40 +2826,18 @@ bool zone_watermark_ok_safe(struct zone *z, unsigned int order,
 }
 
 #ifdef CONFIG_NUMA
-static bool zone_local(struct zone *local_zone, struct zone *zone)
-{
-       return local_zone->node == zone->node;
-}
-
 static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
 {
        return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <
                                RECLAIM_DISTANCE;
 }
 #else  /* CONFIG_NUMA */
-static bool zone_local(struct zone *local_zone, struct zone *zone)
-{
-       return true;
-}
-
 static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
 {
        return true;
 }
 #endif /* CONFIG_NUMA */
 
-static void reset_alloc_batches(struct zone *preferred_zone)
-{
-       struct zone *zone = preferred_zone->zone_pgdat->node_zones;
-
-       do {
-               mod_zone_page_state(zone, NR_ALLOC_BATCH,
-                       high_wmark_pages(zone) - low_wmark_pages(zone) -
-                       atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]));
-               clear_bit(ZONE_FAIR_DEPLETED, &zone->flags);
-       } while (zone++ != preferred_zone);
-}
-
 /*
  * get_page_from_freelist goes through the zonelist trying to allocate
  * a page.
@@ -2886,10 +2848,8 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
 {
        struct zoneref *z = ac->preferred_zoneref;
        struct zone *zone;
-       bool fair_skipped = false;
-       bool apply_fair = (alloc_flags & ALLOC_FAIR);
+       struct pglist_data *last_pgdat_dirty_limit = NULL;
 
-zonelist_scan:
        /*
         * Scan zonelist, looking for a zone with enough free.
         * See also __cpuset_node_allowed() comment in kernel/cpuset.c.
@@ -2903,51 +2863,34 @@ zonelist_scan:
                        (alloc_flags & ALLOC_CPUSET) &&
                        !__cpuset_zone_allowed(zone, gfp_mask))
                                continue;
-               /*
-                * Distribute pages in proportion to the individual
-                * zone size to ensure fair page aging.  The zone a
-                * page was allocated in should have no effect on the
-                * time the page has in memory before being reclaimed.
-                */
-               if (apply_fair) {
-                       if (test_bit(ZONE_FAIR_DEPLETED, &zone->flags)) {
-                               fair_skipped = true;
-                               continue;
-                       }
-                       if (!zone_local(ac->preferred_zoneref->zone, zone)) {
-                               if (fair_skipped)
-                                       goto reset_fair;
-                               apply_fair = false;
-                       }
-               }
                /*
                 * When allocating a page cache page for writing, we
-                * want to get it from a zone that is within its dirty
-                * limit, such that no single zone holds more than its
+                * want to get it from a node that is within its dirty
+                * limit, such that no single node holds more than its
                 * proportional share of globally allowed dirty pages.
-                * The dirty limits take into account the zone's
+                * The dirty limits take into account the node's
                 * lowmem reserves and high watermark so that kswapd
                 * should be able to balance it without having to
                 * write pages from its LRU list.
                 *
-                * This may look like it could increase pressure on
-                * lower zones by failing allocations in higher zones
-                * before they are full.  But the pages that do spill
-                * over are limited as the lower zones are protected
-                * by this very same mechanism.  It should not become
-                * a practical burden to them.
-                *
                 * XXX: For now, allow allocations to potentially
-                * exceed the per-zone dirty limit in the slowpath
+                * exceed the per-node dirty limit in the slowpath
                 * (spread_dirty_pages unset) before going into reclaim,
                 * which is important when on a NUMA setup the allowed
-                * zones are together not big enough to reach the
+                * nodes are together not big enough to reach the
                 * global limit.  The proper fix for these situations
-                * will require awareness of zones in the
+                * will require awareness of nodes in the
                 * dirty-throttling and the flusher threads.
                 */
-               if (ac->spread_dirty_pages && !zone_dirty_ok(zone))
-                       continue;
+               if (ac->spread_dirty_pages) {
+                       if (last_pgdat_dirty_limit == zone->zone_pgdat)
+                               continue;
+
+                       if (!node_dirty_ok(zone->zone_pgdat)) {
+                               last_pgdat_dirty_limit = zone->zone_pgdat;
+                               continue;
+                       }
+               }
 
                mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
                if (!zone_watermark_fast(zone, order, mark,
@@ -2959,16 +2902,16 @@ zonelist_scan:
                        if (alloc_flags & ALLOC_NO_WATERMARKS)
                                goto try_this_zone;
 
-                       if (zone_reclaim_mode == 0 ||
+                       if (node_reclaim_mode == 0 ||
                            !zone_allows_reclaim(ac->preferred_zoneref->zone, zone))
                                continue;
 
-                       ret = zone_reclaim(zone, gfp_mask, order);
+                       ret = node_reclaim(zone->zone_pgdat, gfp_mask, order);
                        switch (ret) {
-                       case ZONE_RECLAIM_NOSCAN:
+                       case NODE_RECLAIM_NOSCAN:
                                /* did not scan */
                                continue;
-                       case ZONE_RECLAIM_FULL:
+                       case NODE_RECLAIM_FULL:
                                /* scanned but unreclaimable */
                                continue;
                        default:
@@ -2998,23 +2941,6 @@ try_this_zone:
                }
        }
 
-       /*
-        * The first pass makes sure allocations are spread fairly within the
-        * local node.  However, the local node might have free pages left
-        * after the fairness batches are exhausted, and remote zones haven't
-        * even been considered yet.  Try once more without fairness, and
-        * include remote zones now, before entering the slowpath and waking
-        * kswapd: prefer spilling to a remote zone over swapping locally.
-        */
-       if (fair_skipped) {
-reset_fair:
-               apply_fair = false;
-               fair_skipped = false;
-               reset_alloc_batches(ac->preferred_zoneref->zone);
-               z = ac->preferred_zoneref;
-               goto zonelist_scan;
-       }
-
        return NULL;
 }
 
@@ -3159,7 +3085,6 @@ out:
        return page;
 }
 
-
 /*
  * Maximum number of compaction retries wit a progress before OOM
  * killer is consider as the only way to move forward.
@@ -3171,17 +3096,16 @@ out:
 static struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
                unsigned int alloc_flags, const struct alloc_context *ac,
-               enum migrate_mode mode, enum compact_result *compact_result)
+               enum compact_priority prio, enum compact_result *compact_result)
 {
        struct page *page;
-       int contended_compaction;
 
        if (!order)
                return NULL;
 
        current->flags |= PF_MEMALLOC;
        *compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac,
-                                               mode, &contended_compaction);
+                                                                       prio);
        current->flags &= ~PF_MEMALLOC;
 
        if (*compact_result <= COMPACT_INACTIVE)
@@ -3193,8 +3117,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
         */
        count_vm_event(COMPACTSTALL);
 
-       page = get_page_from_freelist(gfp_mask, order,
-                                       alloc_flags & ~ALLOC_NO_WATERMARKS, ac);
+       page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
 
        if (page) {
                struct zone *zone = page_zone(page);
@@ -3211,24 +3134,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
         */
        count_vm_event(COMPACTFAIL);
 
-       /*
-        * In all zones where compaction was attempted (and not
-        * deferred or skipped), lock contention has been detected.
-        * For THP allocation we do not want to disrupt the others
-        * so we fallback to base pages instead.
-        */
-       if (contended_compaction == COMPACT_CONTENDED_LOCK)
-               *compact_result = COMPACT_CONTENDED;
-
-       /*
-        * If compaction was aborted due to need_resched(), we do not
-        * want to further increase allocation latency, unless it is
-        * khugepaged trying to collapse.
-        */
-       if (contended_compaction == COMPACT_CONTENDED_SCHED
-               && !(current->flags & PF_KTHREAD))
-               *compact_result = COMPACT_CONTENDED;
-
        cond_resched();
 
        return NULL;
@@ -3236,7 +3141,8 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
 
 static inline bool
 should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
-                    enum compact_result compact_result, enum migrate_mode *migrate_mode,
+                    enum compact_result compact_result,
+                    enum compact_priority *compact_priority,
                     int compaction_retries)
 {
        int max_retries = MAX_COMPACT_RETRIES;
@@ -3247,11 +3153,11 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
        /*
         * compaction considers all the zone as desperately out of memory
         * so it doesn't really make much sense to retry except when the
-        * failure could be caused by weak migration mode.
+        * failure could be caused by insufficient priority
         */
        if (compaction_failed(compact_result)) {
-               if (*migrate_mode == MIGRATE_ASYNC) {
-                       *migrate_mode = MIGRATE_SYNC_LIGHT;
+               if (*compact_priority > MIN_COMPACT_PRIORITY) {
+                       (*compact_priority)--;
                        return true;
                }
                return false;
@@ -3285,7 +3191,7 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
 static inline struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
                unsigned int alloc_flags, const struct alloc_context *ac,
-               enum migrate_mode mode, enum compact_result *compact_result)
+               enum compact_priority prio, enum compact_result *compact_result)
 {
        *compact_result = COMPACT_SKIPPED;
        return NULL;
@@ -3294,7 +3200,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
 static inline bool
 should_compact_retry(struct alloc_context *ac, unsigned int order, int alloc_flags,
                     enum compact_result compact_result,
-                    enum migrate_mode *migrate_mode,
+                    enum compact_priority *compact_priority,
                     int compaction_retries)
 {
        struct zone *zone;
@@ -3362,8 +3268,7 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,
                return NULL;
 
 retry:
-       page = get_page_from_freelist(gfp_mask, order,
-                                       alloc_flags & ~ALLOC_NO_WATERMARKS, ac);
+       page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
 
        /*
         * If an allocation failed after direct reclaim, it could be because
@@ -3384,10 +3289,14 @@ static void wake_all_kswapds(unsigned int order, const struct alloc_context *ac)
 {
        struct zoneref *z;
        struct zone *zone;
+       pg_data_t *last_pgdat = NULL;
 
        for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
-                                               ac->high_zoneidx, ac->nodemask)
-               wakeup_kswapd(zone, order, ac_classzone_idx(ac));
+                                       ac->high_zoneidx, ac->nodemask) {
+               if (last_pgdat != zone->zone_pgdat)
+                       wakeup_kswapd(zone, order, ac->high_zoneidx);
+               last_pgdat = zone->zone_pgdat;
+       }
 }
 
 static inline unsigned int
@@ -3421,16 +3330,6 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
        } else if (unlikely(rt_task(current)) && !in_interrupt())
                alloc_flags |= ALLOC_HARDER;
 
-       if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) {
-               if (gfp_mask & __GFP_MEMALLOC)
-                       alloc_flags |= ALLOC_NO_WATERMARKS;
-               else if (in_serving_softirq() && (current->flags & PF_MEMALLOC))
-                       alloc_flags |= ALLOC_NO_WATERMARKS;
-               else if (!in_interrupt() &&
-                               ((current->flags & PF_MEMALLOC) ||
-                                unlikely(test_thread_flag(TIF_MEMDIE))))
-                       alloc_flags |= ALLOC_NO_WATERMARKS;
-       }
 #ifdef CONFIG_CMA
        if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
                alloc_flags |= ALLOC_CMA;
@@ -3440,12 +3339,19 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
 
 bool gfp_pfmemalloc_allowed(gfp_t gfp_mask)
 {
-       return !!(gfp_to_alloc_flags(gfp_mask) & ALLOC_NO_WATERMARKS);
-}
+       if (unlikely(gfp_mask & __GFP_NOMEMALLOC))
+               return false;
 
-static inline bool is_thp_gfp_mask(gfp_t gfp_mask)
-{
-       return (gfp_mask & (GFP_TRANSHUGE | __GFP_KSWAPD_RECLAIM)) == GFP_TRANSHUGE;
+       if (gfp_mask & __GFP_MEMALLOC)
+               return true;
+       if (in_serving_softirq() && (current->flags & PF_MEMALLOC))
+               return true;
+       if (!in_interrupt() &&
+                       ((current->flags & PF_MEMALLOC) ||
+                        unlikely(test_thread_flag(TIF_MEMDIE))))
+               return true;
+
+       return false;
 }
 
 /*
@@ -3481,10 +3387,10 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
                return false;
 
        /*
-        * Keep reclaiming pages while there is a chance this will lead somewhere.
-        * If none of the target zones can satisfy our allocation request even
-        * if all reclaimable pages are considered then we are screwed and have
-        * to go OOM.
+        * Keep reclaiming pages while there is a chance this will lead
+        * somewhere.  If none of the target zones can satisfy our allocation
+        * request even if all reclaimable pages are considered then we are
+        * screwed and have to go OOM.
         */
        for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
                                        ac->nodemask) {
@@ -3509,14 +3415,12 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
                         * prevent from pre mature OOM
                         */
                        if (!did_some_progress) {
-                               unsigned long writeback;
-                               unsigned long dirty;
+                               unsigned long write_pending;
 
-                               writeback = zone_page_state_snapshot(zone,
-                                                                    NR_WRITEBACK);
-                               dirty = zone_page_state_snapshot(zone, NR_FILE_DIRTY);
+                               write_pending = zone_page_state_snapshot(zone,
+                                                       NR_ZONE_WRITE_PENDING);
 
-                               if (2*(writeback + dirty) > reclaimable) {
+                               if (2 * write_pending > reclaimable) {
                                        congestion_wait(BLK_RW_ASYNC, HZ/10);
                                        return true;
                                }
@@ -3551,7 +3455,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
        struct page *page = NULL;
        unsigned int alloc_flags;
        unsigned long did_some_progress;
-       enum migrate_mode migration_mode = MIGRATE_ASYNC;
+       enum compact_priority compact_priority = DEF_COMPACT_PRIORITY;
        enum compact_result compact_result;
        int compaction_retries = 0;
        int no_progress_loops = 0;
@@ -3575,42 +3479,88 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
                                (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)))
                gfp_mask &= ~__GFP_ATOMIC;
 
-retry:
+       /*
+        * The fast path uses conservative alloc_flags to succeed only until
+        * kswapd needs to be woken up, and to avoid the cost of setting up
+        * alloc_flags precisely. So we do that now.
+        */
+       alloc_flags = gfp_to_alloc_flags(gfp_mask);
+
        if (gfp_mask & __GFP_KSWAPD_RECLAIM)
                wake_all_kswapds(order, ac);
 
        /*
-        * OK, we're below the kswapd watermark and have kicked background
-        * reclaim. Now things get more complex, so set up alloc_flags according
-        * to how we want to proceed.
+        * The adjusted alloc_flags might result in immediate success, so try
+        * that first
         */
-       alloc_flags = gfp_to_alloc_flags(gfp_mask);
+       page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
+       if (page)
+               goto got_pg;
+
+       /*
+        * For costly allocations, try direct compaction first, as it's likely
+        * that we have enough base pages and don't need to reclaim. Don't try
+        * that for allocations that are allowed to ignore watermarks, as the
+        * ALLOC_NO_WATERMARKS attempt didn't yet happen.
+        */
+       if (can_direct_reclaim && order > PAGE_ALLOC_COSTLY_ORDER &&
+               !gfp_pfmemalloc_allowed(gfp_mask)) {
+               page = __alloc_pages_direct_compact(gfp_mask, order,
+                                               alloc_flags, ac,
+                                               INIT_COMPACT_PRIORITY,
+                                               &compact_result);
+               if (page)
+                       goto got_pg;
+
+               /*
+                * Checks for costly allocations with __GFP_NORETRY, which
+                * includes THP page fault allocations
+                */
+               if (gfp_mask & __GFP_NORETRY) {
+                       /*
+                        * If compaction is deferred for high-order allocations,
+                        * it is because sync compaction recently failed. If
+                        * this is the case and the caller requested a THP
+                        * allocation, we do not want to heavily disrupt the
+                        * system, so we fail the allocation instead of entering
+                        * direct reclaim.
+                        */
+                       if (compact_result == COMPACT_DEFERRED)
+                               goto nopage;
+
+                       /*
+                        * Looks like reclaim/compaction is worth trying, but
+                        * sync compaction could be very expensive, so keep
+                        * using async compaction.
+                        */
+                       compact_priority = INIT_COMPACT_PRIORITY;
+               }
+       }
+
+retry:
+       /* Ensure kswapd doesn't accidentally go to sleep as long as we loop */
+       if (gfp_mask & __GFP_KSWAPD_RECLAIM)
+               wake_all_kswapds(order, ac);
+
+       if (gfp_pfmemalloc_allowed(gfp_mask))
+               alloc_flags = ALLOC_NO_WATERMARKS;
 
        /*
         * Reset the zonelist iterators if memory policies can be ignored.
         * These allocations are high priority and system rather than user
         * orientated.
         */
-       if ((alloc_flags & ALLOC_NO_WATERMARKS) || !(alloc_flags & ALLOC_CPUSET)) {
+       if (!(alloc_flags & ALLOC_CPUSET) || (alloc_flags & ALLOC_NO_WATERMARKS)) {
                ac->zonelist = node_zonelist(numa_node_id(), gfp_mask);
                ac->preferred_zoneref = first_zones_zonelist(ac->zonelist,
                                        ac->high_zoneidx, ac->nodemask);
        }
 
-       /* This is the last chance, in general, before the goto nopage. */
-       page = get_page_from_freelist(gfp_mask, order,
-                               alloc_flags & ~ALLOC_NO_WATERMARKS, ac);
+       /* Attempt with potentially adjusted zonelist and alloc_flags */
+       page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
        if (page)
                goto got_pg;
 
-       /* Allocate without watermarks if the context allows */
-       if (alloc_flags & ALLOC_NO_WATERMARKS) {
-               page = get_page_from_freelist(gfp_mask, order,
-                                               ALLOC_NO_WATERMARKS, ac);
-               if (page)
-                       goto got_pg;
-       }
-
        /* Caller is not willing to reclaim, we can't balance anything */
        if (!can_direct_reclaim) {
                /*
@@ -3640,38 +3590,6 @@ retry:
        if (test_thread_flag(TIF_MEMDIE) && !(gfp_mask & __GFP_NOFAIL))
                goto nopage;
 
-       /*
-        * Try direct compaction. The first pass is asynchronous. Subsequent
-        * attempts after direct reclaim are synchronous
-        */
-       page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,
-                                       migration_mode,
-                                       &compact_result);
-       if (page)
-               goto got_pg;
-
-       /* Checks for THP-specific high-order allocations */
-       if (is_thp_gfp_mask(gfp_mask)) {
-               /*
-                * If compaction is deferred for high-order allocations, it is
-                * because sync compaction recently failed. If this is the case
-                * and the caller requested a THP allocation, we do not want
-                * to heavily disrupt the system, so we fail the allocation
-                * instead of entering direct reclaim.
-                */
-               if (compact_result == COMPACT_DEFERRED)
-                       goto nopage;
-
-               /*
-                * Compaction is contended so rather back off than cause
-                * excessive stalls.
-                */
-               if(compact_result == COMPACT_CONTENDED)
-                       goto nopage;
-       }
-
-       if (order && compaction_made_progress(compact_result))
-               compaction_retries++;
 
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac,
@@ -3679,16 +3597,25 @@ retry:
        if (page)
                goto got_pg;
 
+       /* Try direct compaction and then allocating */
+       page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,
+                                       compact_priority, &compact_result);
+       if (page)
+               goto got_pg;
+
+       if (order && compaction_made_progress(compact_result))
+               compaction_retries++;
+
        /* Do not loop if specifically requested */
        if (gfp_mask & __GFP_NORETRY)
-               goto noretry;
+               goto nopage;
 
        /*
         * Do not retry costly high order allocations unless they are
         * __GFP_REPEAT
         */
        if (order > PAGE_ALLOC_COSTLY_ORDER && !(gfp_mask & __GFP_REPEAT))
-               goto noretry;
+               goto nopage;
 
        /*
         * Costly allocations might have made a progress but this doesn't mean
@@ -3712,7 +3639,7 @@ retry:
         */
        if (did_some_progress > 0 &&
                        should_compact_retry(ac, order, alloc_flags,
-                               compact_result, &migration_mode,
+                               compact_result, &compact_priority,
                                compaction_retries))
                goto retry;
 
@@ -3727,25 +3654,6 @@ retry:
                goto retry;
        }
 
-noretry:
-       /*
-        * High-order allocations do not necessarily loop after direct reclaim
-        * and reclaim/compaction depends on compaction being called after
-        * reclaim so call directly if necessary.
-        * It can become very expensive to allocate transparent hugepages at
-        * fault, so use asynchronous memory compaction for THP unless it is
-        * khugepaged trying to collapse. All other requests should tolerate
-        * at least light sync migration.
-        */
-       if (is_thp_gfp_mask(gfp_mask) && !(current->flags & PF_KTHREAD))
-               migration_mode = MIGRATE_ASYNC;
-       else
-               migration_mode = MIGRATE_SYNC_LIGHT;
-       page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags,
-                                           ac, migration_mode,
-                                           &compact_result);
-       if (page)
-               goto got_pg;
 nopage:
        warn_alloc_failed(gfp_mask, order, NULL);
 got_pg:
@@ -3761,7 +3669,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
 {
        struct page *page;
        unsigned int cpuset_mems_cookie;
-       unsigned int alloc_flags = ALLOC_WMARK_LOW|ALLOC_FAIR;
+       unsigned int alloc_flags = ALLOC_WMARK_LOW;
        gfp_t alloc_mask = gfp_mask; /* The gfp_t that was actually used for allocation */
        struct alloc_context ac = {
                .high_zoneidx = gfp_zone(gfp_mask),
@@ -4192,7 +4100,7 @@ EXPORT_SYMBOL_GPL(si_mem_available);
 void si_meminfo(struct sysinfo *val)
 {
        val->totalram = totalram_pages;
-       val->sharedram = global_page_state(NR_SHMEM);
+       val->sharedram = global_node_page_state(NR_SHMEM);
        val->freeram = global_page_state(NR_FREE_PAGES);
        val->bufferram = nr_blockdev_pages();
        val->totalhigh = totalhigh_pages;
@@ -4214,8 +4122,8 @@ void si_meminfo_node(struct sysinfo *val, int nid)
        for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++)
                managed_pages += pgdat->node_zones[zone_type].managed_pages;
        val->totalram = managed_pages;
-       val->sharedram = node_page_state(nid, NR_SHMEM);
-       val->freeram = node_page_state(nid, NR_FREE_PAGES);
+       val->sharedram = node_page_state(pgdat, NR_SHMEM);
+       val->freeram = sum_zone_node_page_state(nid, NR_FREE_PAGES);
 #ifdef CONFIG_HIGHMEM
        for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) {
                struct zone *zone = &pgdat->node_zones[zone_type];
@@ -4298,6 +4206,7 @@ void show_free_areas(unsigned int filter)
        unsigned long free_pcp = 0;
        int cpu;
        struct zone *zone;
+       pg_data_t *pgdat;
 
        for_each_populated_zone(zone) {
                if (skip_free_areas_node(filter, zone_to_nid(zone)))
@@ -4312,35 +4221,74 @@ void show_free_areas(unsigned int filter)
                " unevictable:%lu dirty:%lu writeback:%lu unstable:%lu\n"
                " slab_reclaimable:%lu slab_unreclaimable:%lu\n"
                " mapped:%lu shmem:%lu pagetables:%lu bounce:%lu\n"
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               " anon_thp: %lu shmem_thp: %lu shmem_pmdmapped: %lu\n"
-#endif
                " free:%lu free_pcp:%lu free_cma:%lu\n",
-               global_page_state(NR_ACTIVE_ANON),
-               global_page_state(NR_INACTIVE_ANON),
-               global_page_state(NR_ISOLATED_ANON),
-               global_page_state(NR_ACTIVE_FILE),
-               global_page_state(NR_INACTIVE_FILE),
-               global_page_state(NR_ISOLATED_FILE),
-               global_page_state(NR_UNEVICTABLE),
-               global_page_state(NR_FILE_DIRTY),
-               global_page_state(NR_WRITEBACK),
-               global_page_state(NR_UNSTABLE_NFS),
+               global_node_page_state(NR_ACTIVE_ANON),
+               global_node_page_state(NR_INACTIVE_ANON),
+               global_node_page_state(NR_ISOLATED_ANON),
+               global_node_page_state(NR_ACTIVE_FILE),
+               global_node_page_state(NR_INACTIVE_FILE),
+               global_node_page_state(NR_ISOLATED_FILE),
+               global_node_page_state(NR_UNEVICTABLE),
+               global_node_page_state(NR_FILE_DIRTY),
+               global_node_page_state(NR_WRITEBACK),
+               global_node_page_state(NR_UNSTABLE_NFS),
                global_page_state(NR_SLAB_RECLAIMABLE),
                global_page_state(NR_SLAB_UNRECLAIMABLE),
-               global_page_state(NR_FILE_MAPPED),
-               global_page_state(NR_SHMEM),
+               global_node_page_state(NR_FILE_MAPPED),
+               global_node_page_state(NR_SHMEM),
                global_page_state(NR_PAGETABLE),
                global_page_state(NR_BOUNCE),
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               global_page_state(NR_ANON_THPS) * HPAGE_PMD_NR,
-               global_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR,
-               global_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR,
-#endif
                global_page_state(NR_FREE_PAGES),
                free_pcp,
                global_page_state(NR_FREE_CMA_PAGES));
 
+       for_each_online_pgdat(pgdat) {
+               printk("Node %d"
+                       " active_anon:%lukB"
+                       " inactive_anon:%lukB"
+                       " active_file:%lukB"
+                       " inactive_file:%lukB"
+                       " unevictable:%lukB"
+                       " isolated(anon):%lukB"
+                       " isolated(file):%lukB"
+                       " mapped:%lukB"
+                       " dirty:%lukB"
+                       " writeback:%lukB"
+                       " shmem:%lukB"
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+                       " shmem_thp: %lukB"
+                       " shmem_pmdmapped: %lukB"
+                       " anon_thp: %lukB"
+#endif
+                       " writeback_tmp:%lukB"
+                       " unstable:%lukB"
+                       " pages_scanned:%lu"
+                       " all_unreclaimable? %s"
+                       "\n",
+                       pgdat->node_id,
+                       K(node_page_state(pgdat, NR_ACTIVE_ANON)),
+                       K(node_page_state(pgdat, NR_INACTIVE_ANON)),
+                       K(node_page_state(pgdat, NR_ACTIVE_FILE)),
+                       K(node_page_state(pgdat, NR_INACTIVE_FILE)),
+                       K(node_page_state(pgdat, NR_UNEVICTABLE)),
+                       K(node_page_state(pgdat, NR_ISOLATED_ANON)),
+                       K(node_page_state(pgdat, NR_ISOLATED_FILE)),
+                       K(node_page_state(pgdat, NR_FILE_MAPPED)),
+                       K(node_page_state(pgdat, NR_FILE_DIRTY)),
+                       K(node_page_state(pgdat, NR_WRITEBACK)),
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+                       K(node_page_state(pgdat, NR_SHMEM_THPS) * HPAGE_PMD_NR),
+                       K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED)
+                                       * HPAGE_PMD_NR),
+                       K(node_page_state(pgdat, NR_ANON_THPS) * HPAGE_PMD_NR),
+#endif
+                       K(node_page_state(pgdat, NR_SHMEM)),
+                       K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
+                       K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
+                       node_page_state(pgdat, NR_PAGES_SCANNED),
+                       !pgdat_reclaimable(pgdat) ? "yes" : "no");
+       }
+
        for_each_populated_zone(zone) {
                int i;
 
@@ -4362,72 +4310,41 @@ void show_free_areas(unsigned int filter)
                        " active_file:%lukB"
                        " inactive_file:%lukB"
                        " unevictable:%lukB"
-                       " isolated(anon):%lukB"
-                       " isolated(file):%lukB"
+                       " writepending:%lukB"
                        " present:%lukB"
                        " managed:%lukB"
                        " mlocked:%lukB"
-                       " dirty:%lukB"
-                       " writeback:%lukB"
-                       " mapped:%lukB"
-                       " shmem:%lukB"
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-                       " shmem_thp: %lukB"
-                       " shmem_pmdmapped: %lukB"
-                       " anon_thp: %lukB"
-#endif
                        " slab_reclaimable:%lukB"
                        " slab_unreclaimable:%lukB"
                        " kernel_stack:%lukB"
                        " pagetables:%lukB"
-                       " unstable:%lukB"
                        " bounce:%lukB"
                        " free_pcp:%lukB"
                        " local_pcp:%ukB"
                        " free_cma:%lukB"
-                       " writeback_tmp:%lukB"
-                       " pages_scanned:%lu"
-                       " all_unreclaimable? %s"
                        "\n",
                        zone->name,
                        K(zone_page_state(zone, NR_FREE_PAGES)),
                        K(min_wmark_pages(zone)),
                        K(low_wmark_pages(zone)),
                        K(high_wmark_pages(zone)),
-                       K(zone_page_state(zone, NR_ACTIVE_ANON)),
-                       K(zone_page_state(zone, NR_INACTIVE_ANON)),
-                       K(zone_page_state(zone, NR_ACTIVE_FILE)),
-                       K(zone_page_state(zone, NR_INACTIVE_FILE)),
-                       K(zone_page_state(zone, NR_UNEVICTABLE)),
-                       K(zone_page_state(zone, NR_ISOLATED_ANON)),
-                       K(zone_page_state(zone, NR_ISOLATED_FILE)),
+                       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)),
+                       K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)),
+                       K(zone_page_state(zone, NR_ZONE_UNEVICTABLE)),
+                       K(zone_page_state(zone, NR_ZONE_WRITE_PENDING)),
                        K(zone->present_pages),
                        K(zone->managed_pages),
                        K(zone_page_state(zone, NR_MLOCK)),
-                       K(zone_page_state(zone, NR_FILE_DIRTY)),
-                       K(zone_page_state(zone, NR_WRITEBACK)),
-                       K(zone_page_state(zone, NR_FILE_MAPPED)),
-                       K(zone_page_state(zone, NR_SHMEM)),
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-                       K(zone_page_state(zone, NR_SHMEM_THPS) * HPAGE_PMD_NR),
-                       K(zone_page_state(zone, NR_SHMEM_PMDMAPPED)
-                                       * HPAGE_PMD_NR),
-                       K(zone_page_state(zone, NR_ANON_THPS) * HPAGE_PMD_NR),
-#endif
                        K(zone_page_state(zone, NR_SLAB_RECLAIMABLE)),
                        K(zone_page_state(zone, NR_SLAB_UNRECLAIMABLE)),
-                       zone_page_state(zone, NR_KERNEL_STACK) *
-                               THREAD_SIZE / 1024,
+                       zone_page_state(zone, NR_KERNEL_STACK_KB),
                        K(zone_page_state(zone, NR_PAGETABLE)),
-                       K(zone_page_state(zone, NR_UNSTABLE_NFS)),
                        K(zone_page_state(zone, NR_BOUNCE)),
                        K(free_pcp),
                        K(this_cpu_read(zone->pageset->pcp.count)),
-                       K(zone_page_state(zone, NR_FREE_CMA_PAGES)),
-                       K(zone_page_state(zone, NR_WRITEBACK_TEMP)),
-                       K(zone_page_state(zone, NR_PAGES_SCANNED)),
-                       (!zone_reclaimable(zone) ? "yes" : "no")
-                       );
+                       K(zone_page_state(zone, NR_FREE_CMA_PAGES)));
                printk("lowmem_reserve[]:");
                for (i = 0; i < MAX_NR_ZONES; i++)
                        printk(" %ld", zone->lowmem_reserve[i]);
@@ -4469,7 +4386,7 @@ void show_free_areas(unsigned int filter)
 
        hugetlb_show_meminfo();
 
-       printk("%ld total pagecache pages\n", global_page_state(NR_FILE_PAGES));
+       printk("%ld total pagecache pages\n", global_node_page_state(NR_FILE_PAGES));
 
        show_swap_cache_info();
 }
@@ -5340,6 +5257,11 @@ static void __meminit setup_zone_pageset(struct zone *zone)
        zone->pageset = alloc_percpu(struct per_cpu_pageset);
        for_each_possible_cpu(cpu)
                zone_pageset_init(zone, cpu);
+
+       if (!zone->zone_pgdat->per_cpu_nodestats) {
+               zone->zone_pgdat->per_cpu_nodestats =
+                       alloc_percpu(struct per_cpu_nodestat);
+       }
 }
 
 /*
@@ -5909,6 +5831,8 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
        init_waitqueue_head(&pgdat->kcompactd_wait);
 #endif
        pgdat_page_ext_init(pgdat);
+       spin_lock_init(&pgdat->lru_lock);
+       lruvec_init(node_lruvec(pgdat));
 
        for (j = 0; j < MAX_NR_ZONES; j++) {
                struct zone *zone = pgdat->node_zones + j;
@@ -5958,21 +5882,16 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
                zone->managed_pages = is_highmem_idx(j) ? realsize : freesize;
 #ifdef CONFIG_NUMA
                zone->node = nid;
-               zone->min_unmapped_pages = (freesize*sysctl_min_unmapped_ratio)
+               pgdat->min_unmapped_pages += (freesize*sysctl_min_unmapped_ratio)
                                                / 100;
-               zone->min_slab_pages = (freesize * sysctl_min_slab_ratio) / 100;
+               pgdat->min_slab_pages += (freesize * sysctl_min_slab_ratio) / 100;
 #endif
                zone->name = zone_names[j];
+               zone->zone_pgdat = pgdat;
                spin_lock_init(&zone->lock);
-               spin_lock_init(&zone->lru_lock);
                zone_seqlock_init(zone);
-               zone->zone_pgdat = pgdat;
                zone_pcp_init(zone);
 
-               /* For bootup, initialized properly in watermark setup */
-               mod_zone_page_state(zone, NR_ALLOC_BATCH, zone->managed_pages);
-
-               lruvec_init(&zone->lruvec);
                if (!size)
                        continue;
 
@@ -6038,11 +5957,12 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
        unsigned long end_pfn = 0;
 
        /* pg_data_t should be reset to zero when it's allocated */
-       WARN_ON(pgdat->nr_zones || pgdat->classzone_idx);
+       WARN_ON(pgdat->nr_zones || pgdat->kswapd_classzone_idx);
 
        reset_deferred_meminit(pgdat);
        pgdat->node_id = nid;
        pgdat->node_start_pfn = node_start_pfn;
+       pgdat->per_cpu_nodestats = NULL;
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
        get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
        pr_info("Initmem setup node %d [mem %#018Lx-%#018Lx]\n", nid,
@@ -6699,6 +6619,9 @@ static void calculate_totalreserve_pages(void)
        enum zone_type i, j;
 
        for_each_online_pgdat(pgdat) {
+
+               pgdat->totalreserve_pages = 0;
+
                for (i = 0; i < MAX_NR_ZONES; i++) {
                        struct zone *zone = pgdat->node_zones + i;
                        long max = 0;
@@ -6715,7 +6638,7 @@ static void calculate_totalreserve_pages(void)
                        if (max > zone->managed_pages)
                                max = zone->managed_pages;
 
-                       zone->totalreserve_pages = max;
+                       pgdat->totalreserve_pages += max;
 
                        reserve_pages += max;
                }
@@ -6816,10 +6739,6 @@ static void __setup_per_zone_wmarks(void)
                zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + tmp;
                zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + tmp * 2;
 
-               __mod_zone_page_state(zone, NR_ALLOC_BATCH,
-                       high_wmark_pages(zone) - low_wmark_pages(zone) -
-                       atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]));
-
                spin_unlock_irqrestore(&zone->lock, flags);
        }
 
@@ -6930,6 +6849,7 @@ int watermark_scale_factor_sysctl_handler(struct ctl_table *table, int write,
 int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int rc;
 
@@ -6937,8 +6857,11 @@ int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
        if (rc)
                return rc;
 
+       for_each_online_pgdat(pgdat)
+               pgdat->min_slab_pages = 0;
+
        for_each_zone(zone)
-               zone->min_unmapped_pages = (zone->managed_pages *
+               zone->zone_pgdat->min_unmapped_pages += (zone->managed_pages *
                                sysctl_min_unmapped_ratio) / 100;
        return 0;
 }
@@ -6946,6 +6869,7 @@ int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
 int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int rc;
 
@@ -6953,8 +6877,11 @@ int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *table, int write,
        if (rc)
                return rc;
 
+       for_each_online_pgdat(pgdat)
+               pgdat->min_slab_pages = 0;
+
        for_each_zone(zone)
-               zone->min_slab_pages = (zone->managed_pages *
+               zone->zone_pgdat->min_slab_pages += (zone->managed_pages *
                                sysctl_min_slab_ratio) / 100;
        return 0;
 }
index 4ea9c4ef5146b8b784848a6710b70e5fc0dfcd41..ae11aa914e5569afbd5ee67f5349b81912121d02 100644 (file)
@@ -41,12 +41,12 @@ static struct page *page_idle_get_page(unsigned long pfn)
                return NULL;
 
        zone = page_zone(page);
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
        if (unlikely(!PageLRU(page))) {
                put_page(page);
                page = NULL;
        }
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(zone_lru_lock(zone));
        return page;
 }
 
index dcc5d3769608088a8c100f04f4e01dcccf5b74da..fb1fa269d3a06416151a2b3ef9e57a1e99ae4db5 100644 (file)
@@ -166,6 +166,8 @@ int generic_swapfile_activate(struct swap_info_struct *sis,
                unsigned block_in_page;
                sector_t first_block;
 
+               cond_resched();
+
                first_block = bmap(inode, probe_block);
                if (first_block == 0)
                        goto bad_bmap;
index 8a13d9f7b5666b153d64788576f46029bdc1d99f..709bc83703b1bfef419fa674ef5b5e28f5d70f05 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -27,7 +27,7 @@
  *         mapping->i_mmap_rwsem
  *           anon_vma->rwsem
  *             mm->page_table_lock or pte_lock
- *               zone->lru_lock (in mark_page_accessed, isolate_lru_page)
+ *               zone_lru_lock (in mark_page_accessed, isolate_lru_page)
  *               swap_lock (in swap_duplicate, swap_info_get)
  *                 mmlist_lock (in mmput, drain_mmlist and others)
  *                 mapping->private_lock (in __set_page_dirty_buffers)
@@ -1213,8 +1213,8 @@ void do_page_add_anon_rmap(struct page *page,
                 * disabled.
                 */
                if (compound)
-                       __inc_zone_page_state(page, NR_ANON_THPS);
-               __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, nr);
+                       __inc_node_page_state(page, NR_ANON_THPS);
+               __mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, nr);
        }
        if (unlikely(PageKsm(page)))
                return;
@@ -1251,14 +1251,14 @@ void page_add_new_anon_rmap(struct page *page,
                VM_BUG_ON_PAGE(!PageTransHuge(page), page);
                /* increment count (starts at -1) */
                atomic_set(compound_mapcount_ptr(page), 0);
-               __inc_zone_page_state(page, NR_ANON_THPS);
+               __inc_node_page_state(page, NR_ANON_THPS);
        } else {
                /* Anon THP always mapped first with PMD */
                VM_BUG_ON_PAGE(PageTransCompound(page), page);
                /* increment count (starts at -1) */
                atomic_set(&page->_mapcount, 0);
        }
-       __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, nr);
+       __mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, nr);
        __page_set_anon_rmap(page, vma, address, 1);
 }
 
@@ -1282,7 +1282,7 @@ void page_add_file_rmap(struct page *page, bool compound)
                if (!atomic_inc_and_test(compound_mapcount_ptr(page)))
                        goto out;
                VM_BUG_ON_PAGE(!PageSwapBacked(page), page);
-               __inc_zone_page_state(page, NR_SHMEM_PMDMAPPED);
+               __inc_node_page_state(page, NR_SHMEM_PMDMAPPED);
        } else {
                if (PageTransCompound(page)) {
                        VM_BUG_ON_PAGE(!PageLocked(page), page);
@@ -1293,7 +1293,7 @@ void page_add_file_rmap(struct page *page, bool compound)
                if (!atomic_inc_and_test(&page->_mapcount))
                        goto out;
        }
-       __mod_zone_page_state(page_zone(page), NR_FILE_MAPPED, nr);
+       __mod_node_page_state(page_pgdat(page), NR_FILE_MAPPED, nr);
        mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
 out:
        unlock_page_memcg(page);
@@ -1322,18 +1322,18 @@ static void page_remove_file_rmap(struct page *page, bool compound)
                if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
                        goto out;
                VM_BUG_ON_PAGE(!PageSwapBacked(page), page);
-               __dec_zone_page_state(page, NR_SHMEM_PMDMAPPED);
+               __dec_node_page_state(page, NR_SHMEM_PMDMAPPED);
        } else {
                if (!atomic_add_negative(-1, &page->_mapcount))
                        goto out;
        }
 
        /*
-        * We use the irq-unsafe __{inc|mod}_zone_page_stat because
+        * We use the irq-unsafe __{inc|mod}_zone_page_state because
         * these counters are not modified in interrupt context, and
         * pte lock(a spinlock) is held, which implies preemption disabled.
         */
-       __mod_zone_page_state(page_zone(page), NR_FILE_MAPPED, -nr);
+       __mod_node_page_state(page_pgdat(page), NR_FILE_MAPPED, -nr);
        mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
 
        if (unlikely(PageMlocked(page)))
@@ -1356,7 +1356,7 @@ static void page_remove_anon_compound_rmap(struct page *page)
        if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
                return;
 
-       __dec_zone_page_state(page, NR_ANON_THPS);
+       __dec_node_page_state(page, NR_ANON_THPS);
 
        if (TestClearPageDoubleMap(page)) {
                /*
@@ -1375,7 +1375,7 @@ static void page_remove_anon_compound_rmap(struct page *page)
                clear_page_mlock(page);
 
        if (nr) {
-               __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, -nr);
+               __mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, -nr);
                deferred_split_huge_page(page);
        }
 }
@@ -1404,7 +1404,7 @@ void page_remove_rmap(struct page *page, bool compound)
         * these counters are not modified in interrupt context, and
         * pte lock(a spinlock) is held, which implies preemption disabled.
         */
-       __dec_zone_page_state(page, NR_ANON_PAGES);
+       __dec_node_page_state(page, NR_ANON_MAPPED);
 
        if (unlikely(PageMlocked(page)))
                clear_page_mlock(page);
index 62e42c7d544c148cd7f1fc10839e6e7a2205884e..2ac19a61d5655b82d6aa6b01a37eb6d05ea3a72a 100644 (file)
@@ -575,9 +575,9 @@ static int shmem_add_to_page_cache(struct page *page,
        if (!error) {
                mapping->nrpages += nr;
                if (PageTransHuge(page))
-                       __inc_zone_page_state(page, NR_SHMEM_THPS);
-               __mod_zone_page_state(page_zone(page), NR_FILE_PAGES, nr);
-               __mod_zone_page_state(page_zone(page), NR_SHMEM, nr);
+                       __inc_node_page_state(page, NR_SHMEM_THPS);
+               __mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, nr);
+               __mod_node_page_state(page_pgdat(page), NR_SHMEM, nr);
                spin_unlock_irq(&mapping->tree_lock);
        } else {
                page->mapping = NULL;
@@ -601,8 +601,8 @@ static void shmem_delete_from_page_cache(struct page *page, void *radswap)
        error = shmem_radix_tree_replace(mapping, page->index, page, radswap);
        page->mapping = NULL;
        mapping->nrpages--;
-       __dec_zone_page_state(page, NR_FILE_PAGES);
-       __dec_zone_page_state(page, NR_SHMEM);
+       __dec_node_page_state(page, NR_FILE_PAGES);
+       __dec_node_page_state(page, NR_SHMEM);
        spin_unlock_irq(&mapping->tree_lock);
        put_page(page);
        BUG_ON(error);
@@ -1493,8 +1493,8 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp,
        error = shmem_radix_tree_replace(swap_mapping, swap_index, oldpage,
                                                                   newpage);
        if (!error) {
-               __inc_zone_page_state(newpage, NR_FILE_PAGES);
-               __dec_zone_page_state(oldpage, NR_FILE_PAGES);
+               __inc_node_page_state(newpage, NR_FILE_PAGES);
+               __dec_node_page_state(oldpage, NR_FILE_PAGES);
        }
        spin_unlock_irq(&swap_mapping->tree_lock);
 
index f33980ab0406980edc03bb4a54f6f08c5e9aaa4b..9653f2e2591ad0982d2dc74c668323a43e5b026d 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -369,6 +369,8 @@ static inline size_t slab_ksize(const struct kmem_cache *s)
        if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
                return s->object_size;
 # endif
+       if (s->flags & SLAB_KASAN)
+               return s->object_size;
        /*
         * If we have the need to store the freelist pointer
         * back there or track user information then we can
index f9da8716b8b358fb6a0d7184a5c2ccb95d7369a5..74e7c8c30db8e15ef3455b7bbdd0b2ab9412d452 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -124,7 +124,7 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 #endif
 }
 
-static inline void *fixup_red_left(struct kmem_cache *s, void *p)
+inline void *fixup_red_left(struct kmem_cache *s, void *p)
 {
        if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE)
                p += s->red_left_pad;
@@ -454,8 +454,6 @@ static inline void *restore_red_left(struct kmem_cache *s, void *p)
  */
 #if defined(CONFIG_SLUB_DEBUG_ON)
 static int slub_debug = DEBUG_DEFAULT_FLAGS;
-#elif defined(CONFIG_KASAN)
-static int slub_debug = SLAB_STORE_USER;
 #else
 static int slub_debug;
 #endif
@@ -660,6 +658,8 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
        if (s->flags & SLAB_STORE_USER)
                off += 2 * sizeof(struct track);
 
+       off += kasan_metadata_size(s);
+
        if (off != size_from_object(s))
                /* Beginning of the filler is the free pointer */
                print_section("Padding ", p + off, size_from_object(s) - off);
@@ -787,6 +787,8 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
                /* We also have user information there */
                off += 2 * sizeof(struct track);
 
+       off += kasan_metadata_size(s);
+
        if (size_from_object(s) == off)
                return 1;
 
@@ -1322,8 +1324,10 @@ static inline void kfree_hook(const void *x)
        kasan_kfree_large(x);
 }
 
-static inline void slab_free_hook(struct kmem_cache *s, void *x)
+static inline void *slab_free_hook(struct kmem_cache *s, void *x)
 {
+       void *freeptr;
+
        kmemleak_free_recursive(x, s->flags);
 
        /*
@@ -1344,7 +1348,13 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
        if (!(s->flags & SLAB_DEBUG_OBJECTS))
                debug_check_no_obj_freed(x, s->object_size);
 
+       freeptr = get_freepointer(s, x);
+       /*
+        * kasan_slab_free() may put x into memory quarantine, delaying its
+        * reuse. In this case the object's freelist pointer is changed.
+        */
        kasan_slab_free(s, x);
+       return freeptr;
 }
 
 static inline void slab_free_freelist_hook(struct kmem_cache *s,
@@ -1362,11 +1372,11 @@ static inline void slab_free_freelist_hook(struct kmem_cache *s,
 
        void *object = head;
        void *tail_obj = tail ? : head;
+       void *freeptr;
 
        do {
-               slab_free_hook(s, object);
-       } while ((object != tail_obj) &&
-                (object = get_freepointer(s, object)));
+               freeptr = slab_free_hook(s, object);
+       } while ((object != tail_obj) && (object = freeptr));
 #endif
 }
 
@@ -2878,16 +2888,13 @@ slab_empty:
  * same page) possible by specifying head and tail ptr, plus objects
  * count (cnt). Bulk free indicated by tail pointer being set.
  */
-static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
-                                     void *head, void *tail, int cnt,
-                                     unsigned long addr)
+static __always_inline void do_slab_free(struct kmem_cache *s,
+                               struct page *page, void *head, void *tail,
+                               int cnt, unsigned long addr)
 {
        void *tail_obj = tail ? : head;
        struct kmem_cache_cpu *c;
        unsigned long tid;
-
-       slab_free_freelist_hook(s, head, tail);
-
 redo:
        /*
         * Determine the currently cpus per cpu slab.
@@ -2921,6 +2928,27 @@ redo:
 
 }
 
+static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
+                                     void *head, void *tail, int cnt,
+                                     unsigned long addr)
+{
+       slab_free_freelist_hook(s, head, tail);
+       /*
+        * slab_free_freelist_hook() could have put the items into quarantine.
+        * If so, no need to free them.
+        */
+       if (s->flags & SLAB_KASAN && !(s->flags & SLAB_DESTROY_BY_RCU))
+               return;
+       do_slab_free(s, page, head, tail, cnt, addr);
+}
+
+#ifdef CONFIG_KASAN
+void ___cache_free(struct kmem_cache *cache, void *x, unsigned long addr)
+{
+       do_slab_free(cache, virt_to_head_page(x), x, NULL, 1, addr);
+}
+#endif
+
 void kmem_cache_free(struct kmem_cache *s, void *x)
 {
        s = cache_from_obj(s, x);
@@ -3363,7 +3391,7 @@ static void set_min_partial(struct kmem_cache *s, unsigned long min)
 static int calculate_sizes(struct kmem_cache *s, int forced_order)
 {
        unsigned long flags = s->flags;
-       unsigned long size = s->object_size;
+       size_t size = s->object_size;
        int order;
 
        /*
@@ -3422,7 +3450,10 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
                 * the object.
                 */
                size += 2 * sizeof(struct track);
+#endif
 
+       kasan_cache_create(s, &size, &s->flags);
+#ifdef CONFIG_SLUB_DEBUG
        if (flags & SLAB_RED_ZONE) {
                /*
                 * Add some empty padding so that we can catch
index 5d0cf45403646e54b0e92673f8855e693ad1cf84..36d7bbb80e4932ceed6887f27f9e5d15d0311b39 100644 (file)
@@ -100,11 +100,7 @@ static inline int sparse_index_init(unsigned long section_nr, int nid)
 }
 #endif
 
-/*
- * Although written for the SPARSEMEM_EXTREME case, this happens
- * to also work for the flat array case because
- * NR_SECTION_ROOTS==NR_MEM_SECTIONS.
- */
+#ifdef CONFIG_SPARSEMEM_EXTREME
 int __section_nr(struct mem_section* ms)
 {
        unsigned long root_nr;
@@ -123,6 +119,12 @@ int __section_nr(struct mem_section* ms)
 
        return (root_nr * SECTIONS_PER_ROOT) + (ms - root);
 }
+#else
+int __section_nr(struct mem_section* ms)
+{
+       return (int)(ms - mem_section[0]);
+}
+#endif
 
 /*
  * During early boot, before section_mem_map is used for an actual
index 616df4ddd8708ee7dc4a16fcd6f4814256a86d82..75c63bb2a1da1dc0c3e55600e9db1618949df87a 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -62,12 +62,12 @@ static void __page_cache_release(struct page *page)
                struct lruvec *lruvec;
                unsigned long flags;
 
-               spin_lock_irqsave(&zone->lru_lock, flags);
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               spin_lock_irqsave(zone_lru_lock(zone), flags);
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
                VM_BUG_ON_PAGE(!PageLRU(page), page);
                __ClearPageLRU(page);
                del_page_from_lru_list(page, lruvec, page_off_lru(page));
-               spin_unlock_irqrestore(&zone->lru_lock, flags);
+               spin_unlock_irqrestore(zone_lru_lock(zone), flags);
        }
        mem_cgroup_uncharge(page);
 }
@@ -179,26 +179,26 @@ static void pagevec_lru_move_fn(struct pagevec *pvec,
        void *arg)
 {
        int i;
-       struct zone *zone = NULL;
+       struct pglist_data *pgdat = NULL;
        struct lruvec *lruvec;
        unsigned long flags = 0;
 
        for (i = 0; i < pagevec_count(pvec); i++) {
                struct page *page = pvec->pages[i];
-               struct zone *pagezone = page_zone(page);
+               struct pglist_data *pagepgdat = page_pgdat(page);
 
-               if (pagezone != zone) {
-                       if (zone)
-                               spin_unlock_irqrestore(&zone->lru_lock, flags);
-                       zone = pagezone;
-                       spin_lock_irqsave(&zone->lru_lock, flags);
+               if (pagepgdat != pgdat) {
+                       if (pgdat)
+                               spin_unlock_irqrestore(&pgdat->lru_lock, flags);
+                       pgdat = pagepgdat;
+                       spin_lock_irqsave(&pgdat->lru_lock, flags);
                }
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
                (*move_fn)(page, lruvec, arg);
        }
-       if (zone)
-               spin_unlock_irqrestore(&zone->lru_lock, flags);
+       if (pgdat)
+               spin_unlock_irqrestore(&pgdat->lru_lock, flags);
        release_pages(pvec->pages, pvec->nr, pvec->cold);
        pagevec_reinit(pvec);
 }
@@ -318,9 +318,9 @@ void activate_page(struct page *page)
        struct zone *zone = page_zone(page);
 
        page = compound_head(page);
-       spin_lock_irq(&zone->lru_lock);
-       __activate_page(page, mem_cgroup_page_lruvec(page, zone), NULL);
-       spin_unlock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
+       __activate_page(page, mem_cgroup_page_lruvec(page, zone->zone_pgdat), NULL);
+       spin_unlock_irq(zone_lru_lock(zone));
 }
 #endif
 
@@ -445,16 +445,16 @@ void lru_cache_add(struct page *page)
  */
 void add_page_to_unevictable_list(struct page *page)
 {
-       struct zone *zone = page_zone(page);
+       struct pglist_data *pgdat = page_pgdat(page);
        struct lruvec *lruvec;
 
-       spin_lock_irq(&zone->lru_lock);
-       lruvec = mem_cgroup_page_lruvec(page, zone);
+       spin_lock_irq(&pgdat->lru_lock);
+       lruvec = mem_cgroup_page_lruvec(page, pgdat);
        ClearPageActive(page);
        SetPageUnevictable(page);
        SetPageLRU(page);
        add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE);
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 }
 
 /**
@@ -730,7 +730,7 @@ void release_pages(struct page **pages, int nr, bool cold)
 {
        int i;
        LIST_HEAD(pages_to_free);
-       struct zone *zone = NULL;
+       struct pglist_data *locked_pgdat = NULL;
        struct lruvec *lruvec;
        unsigned long uninitialized_var(flags);
        unsigned int uninitialized_var(lock_batch);
@@ -741,11 +741,11 @@ void release_pages(struct page **pages, int nr, bool cold)
                /*
                 * Make sure the IRQ-safe lock-holding time does not get
                 * excessive with a continuous string of pages from the
-                * same zone. The lock is held only if zone != NULL.
+                * same pgdat. The lock is held only if pgdat != NULL.
                 */
-               if (zone && ++lock_batch == SWAP_CLUSTER_MAX) {
-                       spin_unlock_irqrestore(&zone->lru_lock, flags);
-                       zone = NULL;
+               if (locked_pgdat && ++lock_batch == SWAP_CLUSTER_MAX) {
+                       spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
+                       locked_pgdat = NULL;
                }
 
                if (is_huge_zero_page(page)) {
@@ -758,27 +758,27 @@ void release_pages(struct page **pages, int nr, bool cold)
                        continue;
 
                if (PageCompound(page)) {
-                       if (zone) {
-                               spin_unlock_irqrestore(&zone->lru_lock, flags);
-                               zone = NULL;
+                       if (locked_pgdat) {
+                               spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
+                               locked_pgdat = NULL;
                        }
                        __put_compound_page(page);
                        continue;
                }
 
                if (PageLRU(page)) {
-                       struct zone *pagezone = page_zone(page);
+                       struct pglist_data *pgdat = page_pgdat(page);
 
-                       if (pagezone != zone) {
-                               if (zone)
-                                       spin_unlock_irqrestore(&zone->lru_lock,
+                       if (pgdat != locked_pgdat) {
+                               if (locked_pgdat)
+                                       spin_unlock_irqrestore(&locked_pgdat->lru_lock,
                                                                        flags);
                                lock_batch = 0;
-                               zone = pagezone;
-                               spin_lock_irqsave(&zone->lru_lock, flags);
+                               locked_pgdat = pgdat;
+                               spin_lock_irqsave(&locked_pgdat->lru_lock, flags);
                        }
 
-                       lruvec = mem_cgroup_page_lruvec(page, zone);
+                       lruvec = mem_cgroup_page_lruvec(page, locked_pgdat);
                        VM_BUG_ON_PAGE(!PageLRU(page), page);
                        __ClearPageLRU(page);
                        del_page_from_lru_list(page, lruvec, page_off_lru(page));
@@ -789,8 +789,8 @@ void release_pages(struct page **pages, int nr, bool cold)
 
                list_add(&page->lru, &pages_to_free);
        }
-       if (zone)
-               spin_unlock_irqrestore(&zone->lru_lock, flags);
+       if (locked_pgdat)
+               spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
 
        mem_cgroup_uncharge_list(&pages_to_free);
        free_hot_cold_page_list(&pages_to_free, cold);
@@ -826,7 +826,7 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
        VM_BUG_ON_PAGE(PageCompound(page_tail), page);
        VM_BUG_ON_PAGE(PageLRU(page_tail), page);
        VM_BUG_ON(NR_CPUS != 1 &&
-                 !spin_is_locked(&lruvec_zone(lruvec)->lru_lock));
+                 !spin_is_locked(&lruvec_pgdat(lruvec)->lru_lock));
 
        if (!list)
                SetPageLRU(page_tail);
index c99463ac02fb56d270fdc4ea7ab749e1f58fe666..c8310a37be3abbcf267472f30bd0e3677c1336d4 100644 (file)
@@ -95,7 +95,7 @@ int __add_to_swap_cache(struct page *page, swp_entry_t entry)
                                        entry.val, page);
        if (likely(!error)) {
                address_space->nrpages++;
-               __inc_zone_page_state(page, NR_FILE_PAGES);
+               __inc_node_page_state(page, NR_FILE_PAGES);
                INC_CACHE_INFO(add_total);
        }
        spin_unlock_irq(&address_space->tree_lock);
@@ -147,7 +147,7 @@ void __delete_from_swap_cache(struct page *page)
        set_page_private(page, 0);
        ClearPageSwapCache(page);
        address_space->nrpages--;
-       __dec_zone_page_state(page, NR_FILE_PAGES);
+       __dec_node_page_state(page, NR_FILE_PAGES);
        INC_CACHE_INFO(del_total);
 }
 
index 8d010ef2ce1c8e094919b85e95130fe82474bd5b..662cddf914af2048ab6c9c674f59d37a7aceba69 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -528,7 +528,7 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
 
        if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
                free = global_page_state(NR_FREE_PAGES);
-               free += global_page_state(NR_FILE_PAGES);
+               free += global_node_page_state(NR_FILE_PAGES);
 
                /*
                 * shmem pages shouldn't be counted as free in this
@@ -536,7 +536,7 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
                 * that won't affect the overall amount of available
                 * memory in the system.
                 */
-               free -= global_page_state(NR_SHMEM);
+               free -= global_node_page_state(NR_SHMEM);
 
                free += get_nr_swap_pages();
 
index 21d417ccff69d4efb8154d78c976b97e353a3609..650d26832569a9c41399f3a5da49c6eb56015d46 100644 (file)
@@ -84,6 +84,9 @@ struct scan_control {
        /* Scan (total_size >> priority) pages at once */
        int priority;
 
+       /* The highest zone to isolate pages for reclaim from */
+       enum zone_type reclaim_idx;
+
        unsigned int may_writepage:1;
 
        /* Can mapped pages be reclaimed? */
@@ -191,26 +194,44 @@ static bool sane_reclaim(struct scan_control *sc)
 }
 #endif
 
+/*
+ * This misses isolated pages which are not accounted for to save counters.
+ * As the data only determines if reclaim or compaction continues, it is
+ * not expected that isolated pages will be a dominating factor.
+ */
 unsigned long zone_reclaimable_pages(struct zone *zone)
 {
        unsigned long nr;
 
-       nr = zone_page_state_snapshot(zone, NR_ACTIVE_FILE) +
-            zone_page_state_snapshot(zone, NR_INACTIVE_FILE) +
-            zone_page_state_snapshot(zone, NR_ISOLATED_FILE);
+       nr = zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_FILE) +
+               zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_FILE);
+       if (get_nr_swap_pages() > 0)
+               nr += zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_ANON) +
+                       zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_ANON);
+
+       return nr;
+}
+
+unsigned long pgdat_reclaimable_pages(struct pglist_data *pgdat)
+{
+       unsigned long nr;
+
+       nr = node_page_state_snapshot(pgdat, NR_ACTIVE_FILE) +
+            node_page_state_snapshot(pgdat, NR_INACTIVE_FILE) +
+            node_page_state_snapshot(pgdat, NR_ISOLATED_FILE);
 
        if (get_nr_swap_pages() > 0)
-               nr += zone_page_state_snapshot(zone, NR_ACTIVE_ANON) +
-                     zone_page_state_snapshot(zone, NR_INACTIVE_ANON) +
-                     zone_page_state_snapshot(zone, NR_ISOLATED_ANON);
+               nr += node_page_state_snapshot(pgdat, NR_ACTIVE_ANON) +
+                     node_page_state_snapshot(pgdat, NR_INACTIVE_ANON) +
+                     node_page_state_snapshot(pgdat, NR_ISOLATED_ANON);
 
        return nr;
 }
 
-bool zone_reclaimable(struct zone *zone)
+bool pgdat_reclaimable(struct pglist_data *pgdat)
 {
-       return zone_page_state_snapshot(zone, NR_PAGES_SCANNED) <
-               zone_reclaimable_pages(zone) * 6;
+       return node_page_state_snapshot(pgdat, NR_PAGES_SCANNED) <
+               pgdat_reclaimable_pages(pgdat) * 6;
 }
 
 unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru)
@@ -218,7 +239,7 @@ unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru)
        if (!mem_cgroup_disabled())
                return mem_cgroup_get_lru_size(lruvec, lru);
 
-       return zone_page_state(lruvec_zone(lruvec), NR_LRU_BASE + lru);
+       return node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
 }
 
 /*
@@ -593,7 +614,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
                        ClearPageReclaim(page);
                }
                trace_mm_vmscan_writepage(page);
-               inc_zone_page_state(page, NR_VMSCAN_WRITE);
+               inc_node_page_state(page, NR_VMSCAN_WRITE);
                return PAGE_SUCCESS;
        }
 
@@ -877,7 +898,7 @@ static void page_check_dirty_writeback(struct page *page,
  * shrink_page_list() returns the number of reclaimed pages
  */
 static unsigned long shrink_page_list(struct list_head *page_list,
-                                     struct zone *zone,
+                                     struct pglist_data *pgdat,
                                      struct scan_control *sc,
                                      enum ttu_flags ttu_flags,
                                      unsigned long *ret_nr_dirty,
@@ -917,7 +938,6 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        goto keep;
 
                VM_BUG_ON_PAGE(PageActive(page), page);
-               VM_BUG_ON_PAGE(page_zone(page) != zone, page);
 
                sc->nr_scanned++;
 
@@ -996,7 +1016,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        /* Case 1 above */
                        if (current_is_kswapd() &&
                            PageReclaim(page) &&
-                           test_bit(ZONE_WRITEBACK, &zone->flags)) {
+                           test_bit(PGDAT_WRITEBACK, &pgdat->flags)) {
                                nr_immediate++;
                                goto keep_locked;
 
@@ -1092,14 +1112,14 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                         */
                        if (page_is_file_cache(page) &&
                                        (!current_is_kswapd() ||
-                                        !test_bit(ZONE_DIRTY, &zone->flags))) {
+                                        !test_bit(PGDAT_DIRTY, &pgdat->flags))) {
                                /*
                                 * Immediately reclaim when written back.
                                 * Similar in principal to deactivate_page()
                                 * except we already have the page isolated
                                 * and know it's dirty
                                 */
-                               inc_zone_page_state(page, NR_VMSCAN_IMMEDIATE);
+                               inc_node_page_state(page, NR_VMSCAN_IMMEDIATE);
                                SetPageReclaim(page);
 
                                goto keep_locked;
@@ -1266,11 +1286,11 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
                }
        }
 
-       ret = shrink_page_list(&clean_pages, zone, &sc,
+       ret = shrink_page_list(&clean_pages, zone->zone_pgdat, &sc,
                        TTU_UNMAP|TTU_IGNORE_ACCESS,
                        &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, true);
        list_splice(&clean_pages, page_list);
-       mod_zone_page_state(zone, NR_ISOLATED_FILE, -ret);
+       mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE, -ret);
        return ret;
 }
 
@@ -1348,8 +1368,31 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode)
        return ret;
 }
 
+
 /*
- * zone->lru_lock is heavily contended.  Some of the functions that
+ * Update LRU sizes after isolating pages. The LRU size updates must
+ * be complete before mem_cgroup_update_lru_size due to a santity check.
+ */
+static __always_inline void update_lru_sizes(struct lruvec *lruvec,
+                       enum lru_list lru, unsigned long *nr_zone_taken,
+                       unsigned long nr_taken)
+{
+       int zid;
+
+       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+               if (!nr_zone_taken[zid])
+                       continue;
+
+               __update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]);
+       }
+
+#ifdef CONFIG_MEMCG
+       mem_cgroup_update_lru_size(lruvec, lru, -nr_taken);
+#endif
+}
+
+/*
+ * zone_lru_lock is heavily contended.  Some of the functions that
  * shrink the lists perform better by taking out a batch of pages
  * and working on them outside the LRU lock.
  *
@@ -1375,10 +1418,13 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 {
        struct list_head *src = &lruvec->lists[lru];
        unsigned long nr_taken = 0;
-       unsigned long scan;
+       unsigned long nr_zone_taken[MAX_NR_ZONES] = { 0 };
+       unsigned long nr_skipped[MAX_NR_ZONES] = { 0, };
+       unsigned long scan, nr_pages;
+       LIST_HEAD(pages_skipped);
 
        for (scan = 0; scan < nr_to_scan && nr_taken < nr_to_scan &&
-                                       !list_empty(src); scan++) {
+                                       !list_empty(src);) {
                struct page *page;
 
                page = lru_to_page(src);
@@ -1386,9 +1432,23 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 
                VM_BUG_ON_PAGE(!PageLRU(page), page);
 
+               if (page_zonenum(page) > sc->reclaim_idx) {
+                       list_move(&page->lru, &pages_skipped);
+                       nr_skipped[page_zonenum(page)]++;
+                       continue;
+               }
+
+               /*
+                * Account for scanned and skipped separetly to avoid the pgdat
+                * being prematurely marked unreclaimable by pgdat_reclaimable.
+                */
+               scan++;
+
                switch (__isolate_lru_page(page, mode)) {
                case 0:
-                       nr_taken += hpage_nr_pages(page);
+                       nr_pages = hpage_nr_pages(page);
+                       nr_taken += nr_pages;
+                       nr_zone_taken[page_zonenum(page)] += nr_pages;
                        list_move(&page->lru, dst);
                        break;
 
@@ -1402,9 +1462,38 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                }
        }
 
+       /*
+        * Splice any skipped pages to the start of the LRU list. Note that
+        * this disrupts the LRU order when reclaiming for lower zones but
+        * we cannot splice to the tail. If we did then the SWAP_CLUSTER_MAX
+        * scanning would soon rescan the same pages to skip and put the
+        * system at risk of premature OOM.
+        */
+       if (!list_empty(&pages_skipped)) {
+               int zid;
+               unsigned long total_skipped = 0;
+
+               for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+                       if (!nr_skipped[zid])
+                               continue;
+
+                       __count_zid_vm_events(PGSCAN_SKIP, zid, nr_skipped[zid]);
+                       total_skipped += nr_skipped[zid];
+               }
+
+               /*
+                * Account skipped pages as a partial scan as the pgdat may be
+                * close to unreclaimable. If the LRU list is empty, account
+                * skipped pages as a full scan.
+                */
+               scan += list_empty(src) ? total_skipped : total_skipped >> 2;
+
+               list_splice(&pages_skipped, src);
+       }
        *nr_scanned = scan;
-       trace_mm_vmscan_lru_isolate(sc->order, nr_to_scan, scan,
+       trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scan,
                                    nr_taken, mode, is_file_lru(lru));
+       update_lru_sizes(lruvec, lru, nr_zone_taken, nr_taken);
        return nr_taken;
 }
 
@@ -1444,8 +1533,8 @@ int isolate_lru_page(struct page *page)
                struct zone *zone = page_zone(page);
                struct lruvec *lruvec;
 
-               spin_lock_irq(&zone->lru_lock);
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               spin_lock_irq(zone_lru_lock(zone));
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
                if (PageLRU(page)) {
                        int lru = page_lru(page);
                        get_page(page);
@@ -1453,7 +1542,7 @@ int isolate_lru_page(struct page *page)
                        del_page_from_lru_list(page, lruvec, lru);
                        ret = 0;
                }
-               spin_unlock_irq(&zone->lru_lock);
+               spin_unlock_irq(zone_lru_lock(zone));
        }
        return ret;
 }
@@ -1465,7 +1554,7 @@ int isolate_lru_page(struct page *page)
  * the LRU list will go small and be scanned faster than necessary, leading to
  * unnecessary swapping, thrashing and OOM.
  */
-static int too_many_isolated(struct zone *zone, int file,
+static int too_many_isolated(struct pglist_data *pgdat, int file,
                struct scan_control *sc)
 {
        unsigned long inactive, isolated;
@@ -1477,11 +1566,11 @@ static int too_many_isolated(struct zone *zone, int file,
                return 0;
 
        if (file) {
-               inactive = zone_page_state(zone, NR_INACTIVE_FILE);
-               isolated = zone_page_state(zone, NR_ISOLATED_FILE);
+               inactive = node_page_state(pgdat, NR_INACTIVE_FILE);
+               isolated = node_page_state(pgdat, NR_ISOLATED_FILE);
        } else {
-               inactive = zone_page_state(zone, NR_INACTIVE_ANON);
-               isolated = zone_page_state(zone, NR_ISOLATED_ANON);
+               inactive = node_page_state(pgdat, NR_INACTIVE_ANON);
+               isolated = node_page_state(pgdat, NR_ISOLATED_ANON);
        }
 
        /*
@@ -1499,7 +1588,7 @@ static noinline_for_stack void
 putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
 {
        struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        LIST_HEAD(pages_to_free);
 
        /*
@@ -1512,13 +1601,13 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
                VM_BUG_ON_PAGE(PageLRU(page), page);
                list_del(&page->lru);
                if (unlikely(!page_evictable(page))) {
-                       spin_unlock_irq(&zone->lru_lock);
+                       spin_unlock_irq(&pgdat->lru_lock);
                        putback_lru_page(page);
-                       spin_lock_irq(&zone->lru_lock);
+                       spin_lock_irq(&pgdat->lru_lock);
                        continue;
                }
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
 
                SetPageLRU(page);
                lru = page_lru(page);
@@ -1535,10 +1624,10 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
                        del_page_from_lru_list(page, lruvec, lru);
 
                        if (unlikely(PageCompound(page))) {
-                               spin_unlock_irq(&zone->lru_lock);
+                               spin_unlock_irq(&pgdat->lru_lock);
                                mem_cgroup_uncharge(page);
                                (*get_compound_page_dtor(page))(page);
-                               spin_lock_irq(&zone->lru_lock);
+                               spin_lock_irq(&pgdat->lru_lock);
                        } else
                                list_add(&page->lru, &pages_to_free);
                }
@@ -1563,8 +1652,32 @@ static int current_may_throttle(void)
                bdi_write_congested(current->backing_dev_info);
 }
 
+static bool inactive_reclaimable_pages(struct lruvec *lruvec,
+                               struct scan_control *sc, enum lru_list lru)
+{
+       int zid;
+       struct zone *zone;
+       int file = is_file_lru(lru);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
+
+       if (!global_reclaim(sc))
+               return true;
+
+       for (zid = sc->reclaim_idx; zid >= 0; zid--) {
+               zone = &pgdat->node_zones[zid];
+               if (!populated_zone(zone))
+                       continue;
+
+               if (zone_page_state_snapshot(zone, NR_ZONE_LRU_BASE +
+                               LRU_FILE * file) >= SWAP_CLUSTER_MAX)
+                       return true;
+       }
+
+       return false;
+}
+
 /*
- * shrink_inactive_list() is a helper for shrink_zone().  It returns the number
+ * shrink_inactive_list() is a helper for shrink_node().  It returns the number
  * of reclaimed pages
  */
 static noinline_for_stack unsigned long
@@ -1582,10 +1695,13 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        unsigned long nr_immediate = 0;
        isolate_mode_t isolate_mode = 0;
        int file = is_file_lru(lru);
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
 
-       while (unlikely(too_many_isolated(zone, file, sc))) {
+       if (!inactive_reclaimable_pages(lruvec, sc, lru))
+               return 0;
+
+       while (unlikely(too_many_isolated(pgdat, file, sc))) {
                congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                /* We are about to die and free our memory. Return now. */
@@ -1600,48 +1716,45 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        if (!sc->may_writepage)
                isolate_mode |= ISOLATE_CLEAN;
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
 
        nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &page_list,
                                     &nr_scanned, sc, isolate_mode, lru);
 
-       update_lru_size(lruvec, lru, -nr_taken);
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, nr_taken);
+       __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
        reclaim_stat->recent_scanned[file] += nr_taken;
 
        if (global_reclaim(sc)) {
-               __mod_zone_page_state(zone, NR_PAGES_SCANNED, nr_scanned);
+               __mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned);
                if (current_is_kswapd())
-                       __count_zone_vm_events(PGSCAN_KSWAPD, zone, nr_scanned);
+                       __count_vm_events(PGSCAN_KSWAPD, nr_scanned);
                else
-                       __count_zone_vm_events(PGSCAN_DIRECT, zone, nr_scanned);
+                       __count_vm_events(PGSCAN_DIRECT, nr_scanned);
        }
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        if (nr_taken == 0)
                return 0;
 
-       nr_reclaimed = shrink_page_list(&page_list, zone, sc, TTU_UNMAP,
+       nr_reclaimed = shrink_page_list(&page_list, pgdat, sc, TTU_UNMAP,
                                &nr_dirty, &nr_unqueued_dirty, &nr_congested,
                                &nr_writeback, &nr_immediate,
                                false);
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
 
        if (global_reclaim(sc)) {
                if (current_is_kswapd())
-                       __count_zone_vm_events(PGSTEAL_KSWAPD, zone,
-                                              nr_reclaimed);
+                       __count_vm_events(PGSTEAL_KSWAPD, nr_reclaimed);
                else
-                       __count_zone_vm_events(PGSTEAL_DIRECT, zone,
-                                              nr_reclaimed);
+                       __count_vm_events(PGSTEAL_DIRECT, nr_reclaimed);
        }
 
        putback_inactive_pages(lruvec, &page_list);
 
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
+       __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken);
 
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        mem_cgroup_uncharge_list(&page_list);
        free_hot_cold_page_list(&page_list, true);
@@ -1661,7 +1774,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
         * are encountered in the nr_immediate check below.
         */
        if (nr_writeback && nr_writeback == nr_taken)
-               set_bit(ZONE_WRITEBACK, &zone->flags);
+               set_bit(PGDAT_WRITEBACK, &pgdat->flags);
 
        /*
         * Legacy memcg will stall in page writeback so avoid forcibly
@@ -1673,16 +1786,16 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
                 * backed by a congested BDI and wait_iff_congested will stall.
                 */
                if (nr_dirty && nr_dirty == nr_congested)
-                       set_bit(ZONE_CONGESTED, &zone->flags);
+                       set_bit(PGDAT_CONGESTED, &pgdat->flags);
 
                /*
                 * If dirty pages are scanned that are not queued for IO, it
                 * implies that flushers are not keeping up. In this case, flag
-                * the zone ZONE_DIRTY and kswapd will start writing pages from
+                * the pgdat PGDAT_DIRTY and kswapd will start writing pages from
                 * reclaim context.
                 */
                if (nr_unqueued_dirty == nr_taken)
-                       set_bit(ZONE_DIRTY, &zone->flags);
+                       set_bit(PGDAT_DIRTY, &pgdat->flags);
 
                /*
                 * If kswapd scans pages marked marked for immediate
@@ -1701,9 +1814,10 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
         */
        if (!sc->hibernation_mode && !current_is_kswapd() &&
            current_may_throttle())
-               wait_iff_congested(zone, BLK_RW_ASYNC, HZ/10);
+               wait_iff_congested(pgdat, BLK_RW_ASYNC, HZ/10);
 
-       trace_mm_vmscan_lru_shrink_inactive(zone, nr_scanned, nr_reclaimed,
+       trace_mm_vmscan_lru_shrink_inactive(pgdat->node_id,
+                       nr_scanned, nr_reclaimed,
                        sc->priority, file);
        return nr_reclaimed;
 }
@@ -1715,9 +1829,9 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
  * processes, from rmap.
  *
  * If the pages are mostly unmapped, the processing is fast and it is
- * appropriate to hold zone->lru_lock across the whole operation.  But if
+ * appropriate to hold zone_lru_lock across the whole operation.  But if
  * the pages are mapped, the processing is slow (page_referenced()) so we
- * should drop zone->lru_lock around each page.  It's impossible to balance
+ * should drop zone_lru_lock around each page.  It's impossible to balance
  * this, so instead we remove the pages from the LRU while processing them.
  * It is safe to rely on PG_active against the non-LRU pages in here because
  * nobody will play with that bit on a non-LRU page.
@@ -1731,20 +1845,20 @@ static void move_active_pages_to_lru(struct lruvec *lruvec,
                                     struct list_head *pages_to_free,
                                     enum lru_list lru)
 {
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        unsigned long pgmoved = 0;
        struct page *page;
        int nr_pages;
 
        while (!list_empty(list)) {
                page = lru_to_page(list);
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
 
                VM_BUG_ON_PAGE(PageLRU(page), page);
                SetPageLRU(page);
 
                nr_pages = hpage_nr_pages(page);
-               update_lru_size(lruvec, lru, nr_pages);
+               update_lru_size(lruvec, lru, page_zonenum(page), nr_pages);
                list_move(&page->lru, &lruvec->lists[lru]);
                pgmoved += nr_pages;
 
@@ -1754,10 +1868,10 @@ static void move_active_pages_to_lru(struct lruvec *lruvec,
                        del_page_from_lru_list(page, lruvec, lru);
 
                        if (unlikely(PageCompound(page))) {
-                               spin_unlock_irq(&zone->lru_lock);
+                               spin_unlock_irq(&pgdat->lru_lock);
                                mem_cgroup_uncharge(page);
                                (*get_compound_page_dtor(page))(page);
-                               spin_lock_irq(&zone->lru_lock);
+                               spin_lock_irq(&pgdat->lru_lock);
                        } else
                                list_add(&page->lru, pages_to_free);
                }
@@ -1783,7 +1897,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
        unsigned long nr_rotated = 0;
        isolate_mode_t isolate_mode = 0;
        int file = is_file_lru(lru);
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
 
        lru_add_drain();
 
@@ -1792,20 +1906,19 @@ static void shrink_active_list(unsigned long nr_to_scan,
        if (!sc->may_writepage)
                isolate_mode |= ISOLATE_CLEAN;
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
 
        nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &l_hold,
                                     &nr_scanned, sc, isolate_mode, lru);
 
-       update_lru_size(lruvec, lru, -nr_taken);
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, nr_taken);
+       __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
        reclaim_stat->recent_scanned[file] += nr_taken;
 
        if (global_reclaim(sc))
-               __mod_zone_page_state(zone, NR_PAGES_SCANNED, nr_scanned);
-       __count_zone_vm_events(PGREFILL, zone, nr_scanned);
+               __mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned);
+       __count_vm_events(PGREFILL, nr_scanned);
 
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        while (!list_empty(&l_hold)) {
                cond_resched();
@@ -1850,7 +1963,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
        /*
         * Move pages back to the lru list.
         */
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
        /*
         * Count referenced pages from currently used mappings as rotated,
         * even though only some of them are actually re-activated.  This
@@ -1861,8 +1974,8 @@ static void shrink_active_list(unsigned long nr_to_scan,
 
        move_active_pages_to_lru(lruvec, &l_active, &l_hold, lru);
        move_active_pages_to_lru(lruvec, &l_inactive, &l_hold, lru - LRU_ACTIVE);
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
-       spin_unlock_irq(&zone->lru_lock);
+       __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        mem_cgroup_uncharge_list(&l_hold);
        free_hot_cold_page_list(&l_hold, true);
@@ -1894,12 +2007,15 @@ static void shrink_active_list(unsigned long nr_to_scan,
  *    1TB     101        10GB
  *   10TB     320        32GB
  */
-static bool inactive_list_is_low(struct lruvec *lruvec, bool file)
+static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
+                                               struct scan_control *sc)
 {
        unsigned long inactive_ratio;
        unsigned long inactive;
        unsigned long active;
        unsigned long gb;
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
+       int zid;
 
        /*
         * If we don't have swap space, anonymous page deactivation
@@ -1911,6 +2027,27 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file)
        inactive = lruvec_lru_size(lruvec, file * LRU_FILE);
        active = lruvec_lru_size(lruvec, file * LRU_FILE + LRU_ACTIVE);
 
+       /*
+        * For zone-constrained allocations, it is necessary to check if
+        * deactivations are required for lowmem to be reclaimed. This
+        * calculates the inactive/active pages available in eligible zones.
+        */
+       for (zid = sc->reclaim_idx + 1; zid < MAX_NR_ZONES; zid++) {
+               struct zone *zone = &pgdat->node_zones[zid];
+               unsigned long inactive_zone, active_zone;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               inactive_zone = zone_page_state(zone,
+                               NR_ZONE_LRU_BASE + (file * LRU_FILE));
+               active_zone = zone_page_state(zone,
+                               NR_ZONE_LRU_BASE + (file * LRU_FILE) + LRU_ACTIVE);
+
+               inactive -= min(inactive, inactive_zone);
+               active -= min(active, active_zone);
+       }
+
        gb = (inactive + active) >> (30 - PAGE_SHIFT);
        if (gb)
                inactive_ratio = int_sqrt(10 * gb);
@@ -1924,7 +2061,7 @@ 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)))
+               if (inactive_list_is_low(lruvec, is_file_lru(lru), sc))
                        shrink_active_list(nr_to_scan, lruvec, sc, lru);
                return 0;
        }
@@ -1956,7 +2093,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
        struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
        u64 fraction[2];
        u64 denominator = 0;    /* gcc */
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        unsigned long anon_prio, file_prio;
        enum scan_balance scan_balance;
        unsigned long anon, file;
@@ -1977,7 +2114,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
         * well.
         */
        if (current_is_kswapd()) {
-               if (!zone_reclaimable(zone))
+               if (!pgdat_reclaimable(pgdat))
                        force_scan = true;
                if (!mem_cgroup_online(memcg))
                        force_scan = true;
@@ -2023,14 +2160,24 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
         * anon pages.  Try to detect this based on file LRU size.
         */
        if (global_reclaim(sc)) {
-               unsigned long zonefile;
-               unsigned long zonefree;
+               unsigned long pgdatfile;
+               unsigned long pgdatfree;
+               int z;
+               unsigned long total_high_wmark = 0;
 
-               zonefree = zone_page_state(zone, NR_FREE_PAGES);
-               zonefile = zone_page_state(zone, NR_ACTIVE_FILE) +
-                          zone_page_state(zone, NR_INACTIVE_FILE);
+               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);
 
-               if (unlikely(zonefile + zonefree <= high_wmark_pages(zone))) {
+               for (z = 0; z < MAX_NR_ZONES; z++) {
+                       struct zone *zone = &pgdat->node_zones[z];
+                       if (!populated_zone(zone))
+                               continue;
+
+                       total_high_wmark += high_wmark_pages(zone);
+               }
+
+               if (unlikely(pgdatfile + pgdatfree <= total_high_wmark)) {
                        scan_balance = SCAN_ANON;
                        goto out;
                }
@@ -2045,7 +2192,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
         * lruvec even if it has plenty of old anonymous pages unless the
         * system is under heavy pressure.
         */
-       if (!inactive_list_is_low(lruvec, true) &&
+       if (!inactive_list_is_low(lruvec, true, sc) &&
            lruvec_lru_size(lruvec, LRU_INACTIVE_FILE) >> sc->priority) {
                scan_balance = SCAN_FILE;
                goto out;
@@ -2077,7 +2224,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
        file  = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE) +
                lruvec_lru_size(lruvec, LRU_INACTIVE_FILE);
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
        if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) {
                reclaim_stat->recent_scanned[0] /= 2;
                reclaim_stat->recent_rotated[0] /= 2;
@@ -2098,7 +2245,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
 
        fp = file_prio * (reclaim_stat->recent_scanned[1] + 1);
        fp /= reclaim_stat->recent_rotated[1] + 1;
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        fraction[0] = ap;
        fraction[1] = fp;
@@ -2174,12 +2321,12 @@ static inline void init_tlb_ubc(void)
 #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
 
 /*
- * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
+ * This is a basic per-node page freer.  Used by both kswapd and direct reclaim.
  */
-static void shrink_zone_memcg(struct zone *zone, struct mem_cgroup *memcg,
+static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memcg,
                              struct scan_control *sc, unsigned long *lru_pages)
 {
-       struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+       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;
@@ -2287,7 +2434,7 @@ static void shrink_zone_memcg(struct zone *zone, struct mem_cgroup *memcg,
         * 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))
+       if (inactive_list_is_low(lruvec, false, sc))
                shrink_active_list(SWAP_CLUSTER_MAX, lruvec,
                                   sc, LRU_ACTIVE_ANON);
 
@@ -2312,13 +2459,14 @@ static bool in_reclaim_compaction(struct scan_control *sc)
  * calls try_to_compact_zone() that it will have enough free pages to succeed.
  * It will give up earlier than that if there is difficulty reclaiming pages.
  */
-static inline bool should_continue_reclaim(struct zone *zone,
+static inline bool should_continue_reclaim(struct pglist_data *pgdat,
                                        unsigned long nr_reclaimed,
                                        unsigned long nr_scanned,
                                        struct scan_control *sc)
 {
        unsigned long pages_for_compaction;
        unsigned long inactive_lru_pages;
+       int z;
 
        /* If not in reclaim/compaction mode, stop */
        if (!in_reclaim_compaction(sc))
@@ -2352,25 +2500,32 @@ static inline bool should_continue_reclaim(struct zone *zone,
         * inactive lists are large enough, continue reclaiming
         */
        pages_for_compaction = (2UL << sc->order);
-       inactive_lru_pages = zone_page_state(zone, NR_INACTIVE_FILE);
+       inactive_lru_pages = node_page_state(pgdat, NR_INACTIVE_FILE);
        if (get_nr_swap_pages() > 0)
-               inactive_lru_pages += zone_page_state(zone, NR_INACTIVE_ANON);
+               inactive_lru_pages += node_page_state(pgdat, NR_INACTIVE_ANON);
        if (sc->nr_reclaimed < pages_for_compaction &&
                        inactive_lru_pages > pages_for_compaction)
                return true;
 
        /* If compaction would go ahead or the allocation would succeed, stop */
-       switch (compaction_suitable(zone, sc->order, 0, 0)) {
-       case COMPACT_PARTIAL:
-       case COMPACT_CONTINUE:
-               return false;
-       default:
-               return true;
+       for (z = 0; z <= sc->reclaim_idx; z++) {
+               struct zone *zone = &pgdat->node_zones[z];
+               if (!populated_zone(zone))
+                       continue;
+
+               switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) {
+               case COMPACT_PARTIAL:
+               case COMPACT_CONTINUE:
+                       return false;
+               default:
+                       /* check next zone */
+                       ;
+               }
        }
+       return true;
 }
 
-static bool shrink_zone(struct zone *zone, struct scan_control *sc,
-                       bool is_classzone)
+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;
@@ -2379,10 +2534,10 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
        do {
                struct mem_cgroup *root = sc->target_mem_cgroup;
                struct mem_cgroup_reclaim_cookie reclaim = {
-                       .zone = zone,
+                       .pgdat = pgdat,
                        .priority = sc->priority,
                };
-               unsigned long zone_lru_pages = 0;
+               unsigned long node_lru_pages = 0;
                struct mem_cgroup *memcg;
 
                nr_reclaimed = sc->nr_reclaimed;
@@ -2403,11 +2558,11 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
                        reclaimed = sc->nr_reclaimed;
                        scanned = sc->nr_scanned;
 
-                       shrink_zone_memcg(zone, memcg, sc, &lru_pages);
-                       zone_lru_pages += lru_pages;
+                       shrink_node_memcg(pgdat, memcg, sc, &lru_pages);
+                       node_lru_pages += lru_pages;
 
-                       if (memcg && is_classzone)
-                               shrink_slab(sc->gfp_mask, zone_to_nid(zone),
+                       if (!global_reclaim(sc))
+                               shrink_slab(sc->gfp_mask, pgdat->node_id,
                                            memcg, sc->nr_scanned - scanned,
                                            lru_pages);
 
@@ -2419,7 +2574,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
                        /*
                         * Direct reclaim and kswapd have to scan all memory
                         * cgroups to fulfill the overall scan target for the
-                        * zone.
+                        * node.
                         *
                         * Limit reclaim, on the other hand, only cares about
                         * nr_to_reclaim pages to be reclaimed and it will
@@ -2437,10 +2592,10 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
                 * Shrink the slab caches in the same proportion that
                 * the eligible LRU pages were scanned.
                 */
-               if (global_reclaim(sc) && is_classzone)
-                       shrink_slab(sc->gfp_mask, zone_to_nid(zone), NULL,
+               if (global_reclaim(sc))
+                       shrink_slab(sc->gfp_mask, pgdat->node_id, NULL,
                                    sc->nr_scanned - nr_scanned,
-                                   zone_lru_pages);
+                                   node_lru_pages);
 
                if (reclaim_state) {
                        sc->nr_reclaimed += reclaim_state->reclaimed_slab;
@@ -2455,7 +2610,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
                if (sc->nr_reclaimed - nr_reclaimed)
                        reclaimable = true;
 
-       } while (should_continue_reclaim(zone, sc->nr_reclaimed - nr_reclaimed,
+       } while (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed,
                                         sc->nr_scanned - nr_scanned, sc));
 
        return reclaimable;
@@ -2465,9 +2620,9 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
  * Returns true if compaction should go ahead for a high-order request, or
  * the high-order allocation would succeed without compaction.
  */
-static inline bool compaction_ready(struct zone *zone, int order, int classzone_idx)
+static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
 {
-       unsigned long balance_gap, watermark;
+       unsigned long watermark;
        bool watermark_ok;
 
        /*
@@ -2476,23 +2631,21 @@ static inline bool compaction_ready(struct zone *zone, int order, int classzone_
         * there is a buffer of free pages available to give compaction
         * a reasonable chance of completing and allocating the page
         */
-       balance_gap = min(low_wmark_pages(zone), DIV_ROUND_UP(
-                       zone->managed_pages, KSWAPD_ZONE_BALANCE_GAP_RATIO));
-       watermark = high_wmark_pages(zone) + balance_gap + (2UL << order);
-       watermark_ok = zone_watermark_ok_safe(zone, 0, watermark, classzone_idx);
+       watermark = high_wmark_pages(zone) + (2UL << sc->order);
+       watermark_ok = zone_watermark_ok_safe(zone, 0, watermark, sc->reclaim_idx);
 
        /*
         * If compaction is deferred, reclaim up to a point where
         * compaction will have a chance of success when re-enabled
         */
-       if (compaction_deferred(zone, order))
+       if (compaction_deferred(zone, sc->order))
                return watermark_ok;
 
        /*
         * If compaction is not ready to start and allocation is not likely
         * to succeed without it, then keep reclaiming.
         */
-       if (compaction_suitable(zone, order, 0, classzone_idx) == COMPACT_SKIPPED)
+       if (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx) == COMPACT_SKIPPED)
                return false;
 
        return watermark_ok;
@@ -2503,14 +2656,6 @@ static inline bool compaction_ready(struct zone *zone, int order, int classzone_
  * try to reclaim pages from zones which will satisfy the caller's allocation
  * request.
  *
- * We reclaim from a zone even if that zone is over high_wmark_pages(zone).
- * Because:
- * a) The caller may be trying to free *extra* pages to satisfy a higher-order
- *    allocation or
- * b) The target zone may be at high_wmark_pages(zone) but the lower zones
- *    must go *over* high_wmark_pages(zone) to satisfy the `incremental min'
- *    zone defense algorithm.
- *
  * If a zone is deemed to be full of pinned pages then just give it a light
  * scan then give up on it.
  */
@@ -2521,7 +2666,7 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
        gfp_t orig_mask;
-       enum zone_type requested_highidx = gfp_zone(sc->gfp_mask);
+       pg_data_t *last_pgdat = NULL;
 
        /*
         * If the number of buffer_heads in the machine exceeds the maximum
@@ -2529,21 +2674,13 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
         * highmem pages could be pinning lowmem pages storing buffer_heads
         */
        orig_mask = sc->gfp_mask;
-       if (buffer_heads_over_limit)
+       if (buffer_heads_over_limit) {
                sc->gfp_mask |= __GFP_HIGHMEM;
+               sc->reclaim_idx = gfp_zone(sc->gfp_mask);
+       }
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
-                                       gfp_zone(sc->gfp_mask), sc->nodemask) {
-               enum zone_type classzone_idx;
-
-               if (!populated_zone(zone))
-                       continue;
-
-               classzone_idx = requested_highidx;
-               while (!populated_zone(zone->zone_pgdat->node_zones +
-                                                       classzone_idx))
-                       classzone_idx--;
-
+                                       sc->reclaim_idx, sc->nodemask) {
                /*
                 * Take care memory controller reclaiming has small influence
                 * to global LRU.
@@ -2554,7 +2691,7 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                                continue;
 
                        if (sc->priority != DEF_PRIORITY &&
-                           !zone_reclaimable(zone))
+                           !pgdat_reclaimable(zone->zone_pgdat))
                                continue;       /* Let kswapd poll it */
 
                        /*
@@ -2568,12 +2705,20 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                         */
                        if (IS_ENABLED(CONFIG_COMPACTION) &&
                            sc->order > PAGE_ALLOC_COSTLY_ORDER &&
-                           zonelist_zone_idx(z) <= requested_highidx &&
-                           compaction_ready(zone, sc->order, requested_highidx)) {
+                           compaction_ready(zone, sc)) {
                                sc->compaction_ready = true;
                                continue;
                        }
 
+                       /*
+                        * Shrink each node in the zonelist once. If the
+                        * zonelist is ordered by zone (not the default) then a
+                        * node may be shrunk multiple times but in that case
+                        * the user prefers lower zones being preserved.
+                        */
+                       if (zone->zone_pgdat == last_pgdat)
+                               continue;
+
                        /*
                         * This steals pages from memory cgroups over softlimit
                         * and returns the number of reclaimed pages and
@@ -2581,7 +2726,7 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                         * and balancing, not for a memcg's limit.
                         */
                        nr_soft_scanned = 0;
-                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone,
+                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone->zone_pgdat,
                                                sc->order, sc->gfp_mask,
                                                &nr_soft_scanned);
                        sc->nr_reclaimed += nr_soft_reclaimed;
@@ -2589,7 +2734,11 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                        /* need some check for avoid more shrink_zone() */
                }
 
-               shrink_zone(zone, sc, zone_idx(zone) == classzone_idx);
+               /* See comment about same check for global reclaim above */
+               if (zone->zone_pgdat == last_pgdat)
+                       continue;
+               last_pgdat = zone->zone_pgdat;
+               shrink_node(zone->zone_pgdat, sc);
        }
 
        /*
@@ -2625,7 +2774,7 @@ retry:
        delayacct_freepages_start();
 
        if (global_reclaim(sc))
-               count_vm_event(ALLOCSTALL);
+               __count_zid_vm_events(ALLOCSTALL, sc->reclaim_idx, 1);
 
        do {
                vmpressure_prio(sc->gfp_mask, sc->target_mem_cgroup,
@@ -2692,7 +2841,7 @@ static bool pfmemalloc_watermark_ok(pg_data_t *pgdat)
        for (i = 0; i <= ZONE_NORMAL; i++) {
                zone = &pgdat->node_zones[i];
                if (!populated_zone(zone) ||
-                   zone_reclaimable_pages(zone) == 0)
+                   pgdat_reclaimable_pages(pgdat) == 0)
                        continue;
 
                pfmemalloc_reserve += min_wmark_pages(zone);
@@ -2707,7 +2856,7 @@ static bool pfmemalloc_watermark_ok(pg_data_t *pgdat)
 
        /* kswapd must be awake if processes are being throttled */
        if (!wmark_ok && waitqueue_active(&pgdat->kswapd_wait)) {
-               pgdat->classzone_idx = min(pgdat->classzone_idx,
+               pgdat->kswapd_classzone_idx = min(pgdat->kswapd_classzone_idx,
                                                (enum zone_type)ZONE_NORMAL);
                wake_up_interruptible(&pgdat->kswapd_wait);
        }
@@ -2815,6 +2964,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
        struct scan_control sc = {
                .nr_to_reclaim = SWAP_CLUSTER_MAX,
                .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)),
+               .reclaim_idx = gfp_zone(gfp_mask),
                .order = order,
                .nodemask = nodemask,
                .priority = DEF_PRIORITY,
@@ -2833,7 +2983,8 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 
        trace_mm_vmscan_direct_reclaim_begin(order,
                                sc.may_writepage,
-                               gfp_mask);
+                               gfp_mask,
+                               sc.reclaim_idx);
 
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
@@ -2844,9 +2995,9 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 
 #ifdef CONFIG_MEMCG
 
-unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg,
+unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
                                                gfp_t gfp_mask, bool noswap,
-                                               struct zone *zone,
+                                               pg_data_t *pgdat,
                                                unsigned long *nr_scanned)
 {
        struct scan_control sc = {
@@ -2854,6 +3005,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg,
                .target_mem_cgroup = memcg,
                .may_writepage = !laptop_mode,
                .may_unmap = 1,
+               .reclaim_idx = MAX_NR_ZONES - 1,
                .may_swap = !noswap,
        };
        unsigned long lru_pages;
@@ -2863,16 +3015,17 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg,
 
        trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.order,
                                                      sc.may_writepage,
-                                                     sc.gfp_mask);
+                                                     sc.gfp_mask,
+                                                     sc.reclaim_idx);
 
        /*
         * NOTE: Although we can get the priority field, using it
         * here is not a good idea, since it limits the pages we can scan.
-        * if we don't reclaim here, the shrink_zone from balance_pgdat
+        * if we don't reclaim here, the shrink_node from balance_pgdat
         * will pick up pages from other mem cgroup's as well. We hack
         * the priority and make it zero.
         */
-       shrink_zone_memcg(zone, memcg, &sc, &lru_pages);
+       shrink_node_memcg(pgdat, memcg, &sc, &lru_pages);
 
        trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
@@ -2892,6 +3045,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX),
                .gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                                (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
+               .reclaim_idx = MAX_NR_ZONES - 1,
                .target_mem_cgroup = memcg,
                .priority = DEF_PRIORITY,
                .may_writepage = !laptop_mode,
@@ -2910,7 +3064,8 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
 
        trace_mm_vmscan_memcg_reclaim_begin(0,
                                            sc.may_writepage,
-                                           sc.gfp_mask);
+                                           sc.gfp_mask,
+                                           sc.reclaim_idx);
 
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
@@ -2920,7 +3075,8 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
 }
 #endif
 
-static void age_active_anon(struct zone *zone, struct scan_control *sc)
+static void age_active_anon(struct pglist_data *pgdat,
+                               struct scan_control *sc)
 {
        struct mem_cgroup *memcg;
 
@@ -2929,9 +3085,9 @@ static void age_active_anon(struct zone *zone, struct scan_control *sc)
 
        memcg = mem_cgroup_iter(NULL, NULL, NULL);
        do {
-               struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+               struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg);
 
-               if (inactive_list_is_low(lruvec, false))
+               if (inactive_list_is_low(lruvec, false, sc))
                        shrink_active_list(SWAP_CLUSTER_MAX, lruvec,
                                           sc, LRU_ACTIVE_ANON);
 
@@ -2939,82 +3095,21 @@ static void age_active_anon(struct zone *zone, struct scan_control *sc)
        } while (memcg);
 }
 
-static bool zone_balanced(struct zone *zone, int order, bool highorder,
-                       unsigned long balance_gap, int classzone_idx)
+static bool zone_balanced(struct zone *zone, int order, int classzone_idx)
 {
-       unsigned long mark = high_wmark_pages(zone) + balance_gap;
+       unsigned long mark = high_wmark_pages(zone);
+
+       if (!zone_watermark_ok_safe(zone, order, mark, classzone_idx))
+               return false;
 
        /*
-        * When checking from pgdat_balanced(), kswapd should stop and sleep
-        * when it reaches the high order-0 watermark and let kcompactd take
-        * over. Other callers such as wakeup_kswapd() want to determine the
-        * true high-order watermark.
+        * If any eligible zone is balanced then the node is not considered
+        * to be congested or dirty
         */
-       if (IS_ENABLED(CONFIG_COMPACTION) && !highorder) {
-               mark += (1UL << order);
-               order = 0;
-       }
-
-       return zone_watermark_ok_safe(zone, order, mark, classzone_idx);
-}
-
-/*
- * pgdat_balanced() is used when checking if a node is balanced.
- *
- * For order-0, all zones must be balanced!
- *
- * For high-order allocations only zones that meet watermarks and are in a
- * zone allowed by the callers classzone_idx are added to balanced_pages. The
- * total of balanced pages must be at least 25% of the zones allowed by
- * classzone_idx for the node to be considered balanced. Forcing all zones to
- * be balanced for high orders can cause excessive reclaim when there are
- * imbalanced zones.
- * The choice of 25% is due to
- *   o a 16M DMA zone that is balanced will not balance a zone on any
- *     reasonable sized machine
- *   o On all other machines, the top zone must be at least a reasonable
- *     percentage of the middle zones. For example, on 32-bit x86, highmem
- *     would need to be at least 256M for it to be balance a whole node.
- *     Similarly, on x86-64 the Normal zone would need to be at least 1G
- *     to balance a node on its own. These seemed like reasonable ratios.
- */
-static bool pgdat_balanced(pg_data_t *pgdat, int order, int classzone_idx)
-{
-       unsigned long managed_pages = 0;
-       unsigned long balanced_pages = 0;
-       int i;
-
-       /* Check the watermark levels */
-       for (i = 0; i <= classzone_idx; i++) {
-               struct zone *zone = pgdat->node_zones + i;
-
-               if (!populated_zone(zone))
-                       continue;
-
-               managed_pages += zone->managed_pages;
-
-               /*
-                * A special case here:
-                *
-                * balance_pgdat() skips over all_unreclaimable after
-                * DEF_PRIORITY. Effectively, it considers them balanced so
-                * they must be considered balanced here as well!
-                */
-               if (!zone_reclaimable(zone)) {
-                       balanced_pages += zone->managed_pages;
-                       continue;
-               }
+       clear_bit(PGDAT_CONGESTED, &zone->zone_pgdat->flags);
+       clear_bit(PGDAT_DIRTY, &zone->zone_pgdat->flags);
 
-               if (zone_balanced(zone, order, false, 0, i))
-                       balanced_pages += zone->managed_pages;
-               else if (!order)
-                       return false;
-       }
-
-       if (order)
-               return balanced_pages >= (managed_pages >> 2);
-       else
-               return true;
+       return true;
 }
 
 /*
@@ -3023,12 +3118,9 @@ static bool pgdat_balanced(pg_data_t *pgdat, int order, int classzone_idx)
  *
  * Returns true if kswapd is ready to sleep
  */
-static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
-                                       int classzone_idx)
+static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, int classzone_idx)
 {
-       /* If a direct reclaimer woke kswapd within HZ/10, it's premature */
-       if (remaining)
-               return false;
+       int i;
 
        /*
         * The throttled processes are normally woken up in balance_pgdat() as
@@ -3046,91 +3138,81 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
        if (waitqueue_active(&pgdat->pfmemalloc_wait))
                wake_up_all(&pgdat->pfmemalloc_wait);
 
-       return pgdat_balanced(pgdat, order, classzone_idx);
+       for (i = 0; i <= classzone_idx; i++) {
+               struct zone *zone = pgdat->node_zones + i;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               if (!zone_balanced(zone, order, classzone_idx))
+                       return false;
+       }
+
+       return true;
 }
 
 /*
- * kswapd shrinks the zone by the number of pages required to reach
- * the high watermark.
+ * kswapd shrinks a node of pages that are at or below the highest usable
+ * zone that is currently unbalanced.
  *
  * Returns true if kswapd scanned at least the requested number of pages to
  * reclaim or if the lack of progress was due to pages under writeback.
  * This is used to determine if the scanning priority needs to be raised.
  */
-static bool kswapd_shrink_zone(struct zone *zone,
-                              int classzone_idx,
+static bool kswapd_shrink_node(pg_data_t *pgdat,
                               struct scan_control *sc)
 {
-       unsigned long balance_gap;
-       bool lowmem_pressure;
+       struct zone *zone;
+       int z;
 
-       /* Reclaim above the high watermark. */
-       sc->nr_to_reclaim = max(SWAP_CLUSTER_MAX, high_wmark_pages(zone));
+       /* Reclaim a number of pages proportional to the number of zones */
+       sc->nr_to_reclaim = 0;
+       for (z = 0; z <= sc->reclaim_idx; z++) {
+               zone = pgdat->node_zones + z;
+               if (!populated_zone(zone))
+                       continue;
 
-       /*
-        * We put equal pressure on every zone, unless one zone has way too
-        * many pages free already. The "too many pages" is defined as the
-        * high wmark plus a "gap" where the gap is either the low
-        * watermark or 1% of the zone, whichever is smaller.
-        */
-       balance_gap = min(low_wmark_pages(zone), DIV_ROUND_UP(
-                       zone->managed_pages, KSWAPD_ZONE_BALANCE_GAP_RATIO));
+               sc->nr_to_reclaim += max(high_wmark_pages(zone), SWAP_CLUSTER_MAX);
+       }
 
        /*
-        * If there is no low memory pressure or the zone is balanced then no
-        * reclaim is necessary
+        * Historically care was taken to put equal pressure on all zones but
+        * now pressure is applied based on node LRU order.
         */
-       lowmem_pressure = (buffer_heads_over_limit && is_highmem(zone));
-       if (!lowmem_pressure && zone_balanced(zone, sc->order, false,
-                                               balance_gap, classzone_idx))
-               return true;
-
-       shrink_zone(zone, sc, zone_idx(zone) == classzone_idx);
-
-       clear_bit(ZONE_WRITEBACK, &zone->flags);
+       shrink_node(pgdat, sc);
 
        /*
-        * If a zone reaches its high watermark, consider it to be no longer
-        * congested. It's possible there are dirty pages backed by congested
-        * BDIs but as pressure is relieved, speculatively avoid congestion
-        * waits.
+        * Fragmentation may mean that the system cannot be rebalanced for
+        * high-order allocations. If twice the allocation size has been
+        * reclaimed then recheck watermarks only at order-0 to prevent
+        * excessive reclaim. Assume that a process requested a high-order
+        * can direct reclaim/compact.
         */
-       if (zone_reclaimable(zone) &&
-           zone_balanced(zone, sc->order, false, 0, classzone_idx)) {
-               clear_bit(ZONE_CONGESTED, &zone->flags);
-               clear_bit(ZONE_DIRTY, &zone->flags);
-       }
+       if (sc->order && sc->nr_reclaimed >= 2UL << sc->order)
+               sc->order = 0;
 
        return sc->nr_scanned >= sc->nr_to_reclaim;
 }
 
 /*
- * For kswapd, balance_pgdat() will work across all this node's zones until
- * they are all at high_wmark_pages(zone).
+ * For kswapd, balance_pgdat() will reclaim pages across a node from zones
+ * that are eligible for use by the caller until at least one zone is
+ * balanced.
  *
- * Returns the highest zone idx kswapd was reclaiming at
- *
- * There is special handling here for zones which are full of pinned pages.
- * This can happen if the pages are all mlocked, or if they are all used by
- * device drivers (say, ZONE_DMA).  Or if they are all in use by hugetlb.
- * What we do is to detect the case where all pages in the zone have been
- * scanned twice and there has been zero successful reclaim.  Mark the zone as
- * dead and from now on, only perform a short scan.  Basically we're polling
- * the zone for when the problem goes away.
+ * Returns the order kswapd finished reclaiming at.
  *
  * kswapd scans the zones in the highmem->normal->dma direction.  It skips
  * zones which have free_pages > high_wmark_pages(zone), but once a zone is
- * found to have free_pages <= high_wmark_pages(zone), we scan that zone and the
- * lower zones regardless of the number of free pages in the lower zones. This
- * interoperates with the page allocator fallback scheme to ensure that aging
- * of pages is balanced across the zones.
+ * found to have free_pages <= high_wmark_pages(zone), any page is that zone
+ * or lower is eligible for reclaim until at least one usable zone is
+ * balanced.
  */
 static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
 {
        int i;
-       int end_zone = 0;       /* Inclusive.  0 = ZONE_DMA */
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
+       struct zone *zone;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
                .order = order,
@@ -3145,100 +3227,77 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
                bool raise_priority = true;
 
                sc.nr_reclaimed = 0;
+               sc.reclaim_idx = classzone_idx;
 
                /*
-                * Scan in the highmem->dma direction for the highest
-                * zone which needs scanning
+                * If the number of buffer_heads exceeds the maximum allowed
+                * then consider reclaiming from all zones. This has a dual
+                * purpose -- on 64-bit systems it is expected that
+                * buffer_heads are stripped during active rotation. On 32-bit
+                * systems, highmem pages can pin lowmem memory and shrinking
+                * buffers can relieve lowmem pressure. Reclaim may still not
+                * go ahead if all eligible zones for the original allocation
+                * request are balanced to avoid excessive reclaim from kswapd.
                 */
-               for (i = pgdat->nr_zones - 1; i >= 0; i--) {
-                       struct zone *zone = pgdat->node_zones + i;
-
-                       if (!populated_zone(zone))
-                               continue;
-
-                       if (sc.priority != DEF_PRIORITY &&
-                           !zone_reclaimable(zone))
-                               continue;
-
-                       /*
-                        * Do some background aging of the anon list, to give
-                        * pages a chance to be referenced before reclaiming.
-                        */
-                       age_active_anon(zone, &sc);
+               if (buffer_heads_over_limit) {
+                       for (i = MAX_NR_ZONES - 1; i >= 0; i--) {
+                               zone = pgdat->node_zones + i;
+                               if (!populated_zone(zone))
+                                       continue;
 
-                       /*
-                        * If the number of buffer_heads in the machine
-                        * exceeds the maximum allowed level and this node
-                        * has a highmem zone, force kswapd to reclaim from
-                        * it to relieve lowmem pressure.
-                        */
-                       if (buffer_heads_over_limit && is_highmem_idx(i)) {
-                               end_zone = i;
+                               sc.reclaim_idx = i;
                                break;
                        }
+               }
 
-                       if (!zone_balanced(zone, order, false, 0, 0)) {
-                               end_zone = i;
-                               break;
-                       } else {
-                               /*
-                                * If balanced, clear the dirty and congested
-                                * flags
-                                */
-                               clear_bit(ZONE_CONGESTED, &zone->flags);
-                               clear_bit(ZONE_DIRTY, &zone->flags);
-                       }
+               /*
+                * Only reclaim if there are no eligible zones. Check from
+                * high to low zone as allocations prefer higher zones.
+                * Scanning from low to high zone would allow congestion to be
+                * cleared during a very small window when a small low
+                * zone was balanced even under extreme pressure when the
+                * overall node may be congested. Note that sc.reclaim_idx
+                * is not used as buffer_heads_over_limit may have adjusted
+                * it.
+                */
+               for (i = classzone_idx; i >= 0; i--) {
+                       zone = pgdat->node_zones + i;
+                       if (!populated_zone(zone))
+                               continue;
+
+                       if (zone_balanced(zone, sc.order, classzone_idx))
+                               goto out;
                }
 
-               if (i < 0)
-                       goto out;
+               /*
+                * Do some background aging of the anon list, to give
+                * pages a chance to be referenced before reclaiming. All
+                * pages are rotated regardless of classzone as this is
+                * about consistent aging.
+                */
+               age_active_anon(pgdat, &sc);
 
                /*
                 * If we're getting trouble reclaiming, start doing writepage
                 * even in laptop mode.
                 */
-               if (sc.priority < DEF_PRIORITY - 2)
+               if (sc.priority < DEF_PRIORITY - 2 || !pgdat_reclaimable(pgdat))
                        sc.may_writepage = 1;
 
+               /* Call soft limit reclaim before calling shrink_node. */
+               sc.nr_scanned = 0;
+               nr_soft_scanned = 0;
+               nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(pgdat, sc.order,
+                                               sc.gfp_mask, &nr_soft_scanned);
+               sc.nr_reclaimed += nr_soft_reclaimed;
+
                /*
-                * Now scan the zone in the dma->highmem direction, stopping
-                * at the last zone which needs scanning.
-                *
-                * We do this because the page allocator works in the opposite
-                * direction.  This prevents the page allocator from allocating
-                * pages behind kswapd's direction of progress, which would
-                * cause too much scanning of the lower zones.
+                * There should be no need to raise the scanning priority if
+                * enough pages are already being scanned that that high
+                * watermark would be met at 100% efficiency.
                 */
-               for (i = 0; i <= end_zone; i++) {
-                       struct zone *zone = pgdat->node_zones + i;
-
-                       if (!populated_zone(zone))
-                               continue;
-
-                       if (sc.priority != DEF_PRIORITY &&
-                           !zone_reclaimable(zone))
-                               continue;
-
-                       sc.nr_scanned = 0;
-
-                       nr_soft_scanned = 0;
-                       /*
-                        * Call soft limit reclaim before calling shrink_zone.
-                        */
-                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone,
-                                                       order, sc.gfp_mask,
-                                                       &nr_soft_scanned);
-                       sc.nr_reclaimed += nr_soft_reclaimed;
-
-                       /*
-                        * There should be no need to raise the scanning
-                        * priority if enough pages are already being scanned
-                        * that that high watermark would be met at 100%
-                        * efficiency.
-                        */
-                       if (kswapd_shrink_zone(zone, end_zone, &sc))
-                               raise_priority = false;
-               }
+               if (kswapd_shrink_node(pgdat, &sc))
+                       raise_priority = false;
 
                /*
                 * If the low watermark is met there is no need for processes
@@ -3259,19 +3318,20 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
                 */
                if (raise_priority || !sc.nr_reclaimed)
                        sc.priority--;
-       } while (sc.priority >= 1 &&
-                       !pgdat_balanced(pgdat, order, classzone_idx));
+       } while (sc.priority >= 1);
 
 out:
        /*
-        * Return the highest zone idx we were reclaiming at so
-        * prepare_kswapd_sleep() makes the same decisions as here.
+        * Return the order kswapd stopped reclaiming at as
+        * prepare_kswapd_sleep() takes it into account. If another caller
+        * entered the allocator slow path while kswapd was awake, order will
+        * remain at the higher level.
         */
-       return end_zone;
+       return sc.order;
 }
 
-static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
-                               int classzone_idx, int balanced_classzone_idx)
+static void kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_order,
+                               unsigned int classzone_idx)
 {
        long remaining = 0;
        DEFINE_WAIT(wait);
@@ -3282,8 +3342,7 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
        prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 
        /* Try to sleep for a short interval */
-       if (prepare_kswapd_sleep(pgdat, order, remaining,
-                                               balanced_classzone_idx)) {
+       if (prepare_kswapd_sleep(pgdat, reclaim_order, classzone_idx)) {
                /*
                 * Compaction records what page blocks it recently failed to
                 * isolate pages from and skips them in the future scanning.
@@ -3296,9 +3355,20 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
                 * We have freed the memory, now we should compact it to make
                 * allocation of the requested order possible.
                 */
-               wakeup_kcompactd(pgdat, order, classzone_idx);
+               wakeup_kcompactd(pgdat, alloc_order, classzone_idx);
 
                remaining = schedule_timeout(HZ/10);
+
+               /*
+                * If woken prematurely then reset kswapd_classzone_idx and
+                * order. The values will either be from a wakeup request or
+                * the previous request that slept prematurely.
+                */
+               if (remaining) {
+                       pgdat->kswapd_classzone_idx = max(pgdat->kswapd_classzone_idx, classzone_idx);
+                       pgdat->kswapd_order = max(pgdat->kswapd_order, reclaim_order);
+               }
+
                finish_wait(&pgdat->kswapd_wait, &wait);
                prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
        }
@@ -3307,8 +3377,8 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
         * After a short sleep, check if it was a premature sleep. If not, then
         * go fully to sleep until explicitly woken up.
         */
-       if (prepare_kswapd_sleep(pgdat, order, remaining,
-                                               balanced_classzone_idx)) {
+       if (!remaining &&
+           prepare_kswapd_sleep(pgdat, reclaim_order, classzone_idx)) {
                trace_mm_vmscan_kswapd_sleep(pgdat->node_id);
 
                /*
@@ -3349,9 +3419,7 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
  */
 static int kswapd(void *p)
 {
-       unsigned long order, new_order;
-       int classzone_idx, new_classzone_idx;
-       int balanced_classzone_idx;
+       unsigned int alloc_order, reclaim_order, classzone_idx;
        pg_data_t *pgdat = (pg_data_t*)p;
        struct task_struct *tsk = current;
 
@@ -3381,38 +3449,20 @@ static int kswapd(void *p)
        tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
        set_freezable();
 
-       order = new_order = 0;
-       classzone_idx = new_classzone_idx = pgdat->nr_zones - 1;
-       balanced_classzone_idx = classzone_idx;
+       pgdat->kswapd_order = alloc_order = reclaim_order = 0;
+       pgdat->kswapd_classzone_idx = classzone_idx = 0;
        for ( ; ; ) {
                bool ret;
 
-               /*
-                * While we were reclaiming, there might have been another
-                * wakeup, so check the values.
-                */
-               new_order = pgdat->kswapd_max_order;
-               new_classzone_idx = pgdat->classzone_idx;
-               pgdat->kswapd_max_order =  0;
-               pgdat->classzone_idx = pgdat->nr_zones - 1;
+kswapd_try_sleep:
+               kswapd_try_to_sleep(pgdat, alloc_order, reclaim_order,
+                                       classzone_idx);
 
-               if (order < new_order || classzone_idx > new_classzone_idx) {
-                       /*
-                        * Don't sleep if someone wants a larger 'order'
-                        * allocation or has tigher zone constraints
-                        */
-                       order = new_order;
-                       classzone_idx = new_classzone_idx;
-               } else {
-                       kswapd_try_to_sleep(pgdat, order, classzone_idx,
-                                               balanced_classzone_idx);
-                       order = pgdat->kswapd_max_order;
-                       classzone_idx = pgdat->classzone_idx;
-                       new_order = order;
-                       new_classzone_idx = classzone_idx;
-                       pgdat->kswapd_max_order = 0;
-                       pgdat->classzone_idx = pgdat->nr_zones - 1;
-               }
+               /* Read the new order and classzone_idx */
+               alloc_order = reclaim_order = pgdat->kswapd_order;
+               classzone_idx = pgdat->kswapd_classzone_idx;
+               pgdat->kswapd_order = 0;
+               pgdat->kswapd_classzone_idx = 0;
 
                ret = try_to_freeze();
                if (kthread_should_stop())
@@ -3422,11 +3472,25 @@ static int kswapd(void *p)
                 * We can speed up thawing tasks if we don't call balance_pgdat
                 * after returning from the refrigerator
                 */
-               if (!ret) {
-                       trace_mm_vmscan_kswapd_wake(pgdat->node_id, order);
-                       balanced_classzone_idx = balance_pgdat(pgdat, order,
-                                                               classzone_idx);
-               }
+               if (ret)
+                       continue;
+
+               /*
+                * Reclaim begins at the requested order but if a high-order
+                * reclaim fails then kswapd falls back to reclaiming for
+                * order-0. If that happens, kswapd will consider sleeping
+                * for the order it finished reclaiming at (reclaim_order)
+                * but kcompactd is woken to compact for the original
+                * request (alloc_order).
+                */
+               trace_mm_vmscan_kswapd_wake(pgdat->node_id, classzone_idx,
+                                               alloc_order);
+               reclaim_order = balance_pgdat(pgdat, alloc_order, classzone_idx);
+               if (reclaim_order < alloc_order)
+                       goto kswapd_try_sleep;
+
+               alloc_order = reclaim_order = pgdat->kswapd_order;
+               classzone_idx = pgdat->kswapd_classzone_idx;
        }
 
        tsk->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD);
@@ -3442,6 +3506,7 @@ static int kswapd(void *p)
 void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
 {
        pg_data_t *pgdat;
+       int z;
 
        if (!populated_zone(zone))
                return;
@@ -3449,14 +3514,20 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
        if (!cpuset_zone_allowed(zone, GFP_KERNEL | __GFP_HARDWALL))
                return;
        pgdat = zone->zone_pgdat;
-       if (pgdat->kswapd_max_order < order) {
-               pgdat->kswapd_max_order = order;
-               pgdat->classzone_idx = min(pgdat->classzone_idx, classzone_idx);
-       }
+       pgdat->kswapd_classzone_idx = max(pgdat->kswapd_classzone_idx, classzone_idx);
+       pgdat->kswapd_order = max(pgdat->kswapd_order, order);
        if (!waitqueue_active(&pgdat->kswapd_wait))
                return;
-       if (zone_balanced(zone, order, true, 0, 0))
-               return;
+
+       /* Only wake kswapd if all zones are unbalanced */
+       for (z = 0; z <= classzone_idx; z++) {
+               zone = pgdat->node_zones + z;
+               if (!populated_zone(zone))
+                       continue;
+
+               if (zone_balanced(zone, order, classzone_idx))
+                       return;
+       }
 
        trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, zone_idx(zone), order);
        wake_up_interruptible(&pgdat->kswapd_wait);
@@ -3477,6 +3548,7 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
        struct scan_control sc = {
                .nr_to_reclaim = nr_to_reclaim,
                .gfp_mask = GFP_HIGHUSER_MOVABLE,
+               .reclaim_idx = MAX_NR_ZONES - 1,
                .priority = DEF_PRIORITY,
                .may_writepage = 1,
                .may_unmap = 1,
@@ -3578,12 +3650,12 @@ module_init(kswapd_init)
 
 #ifdef CONFIG_NUMA
 /*
- * Zone reclaim mode
+ * Node reclaim mode
  *
- * If non-zero call zone_reclaim when the number of free pages falls below
+ * If non-zero call node_reclaim when the number of free pages falls below
  * the watermarks.
  */
-int zone_reclaim_mode __read_mostly;
+int node_reclaim_mode __read_mostly;
 
 #define RECLAIM_OFF 0
 #define RECLAIM_ZONE (1<<0)    /* Run shrink_inactive_list on the zone */
@@ -3591,14 +3663,14 @@ int zone_reclaim_mode __read_mostly;
 #define RECLAIM_UNMAP (1<<2)   /* Unmap pages during reclaim */
 
 /*
- * Priority for ZONE_RECLAIM. This determines the fraction of pages
+ * Priority for NODE_RECLAIM. This determines the fraction of pages
  * of a node considered for each zone_reclaim. 4 scans 1/16th of
  * a zone.
  */
-#define ZONE_RECLAIM_PRIORITY 4
+#define NODE_RECLAIM_PRIORITY 4
 
 /*
- * Percentage of pages in a zone that must be unmapped for zone_reclaim to
+ * Percentage of pages in a zone that must be unmapped for node_reclaim to
  * occur.
  */
 int sysctl_min_unmapped_ratio = 1;
@@ -3609,11 +3681,11 @@ int sysctl_min_unmapped_ratio = 1;
  */
 int sysctl_min_slab_ratio = 5;
 
-static inline unsigned long zone_unmapped_file_pages(struct zone *zone)
+static inline unsigned long node_unmapped_file_pages(struct pglist_data *pgdat)
 {
-       unsigned long file_mapped = zone_page_state(zone, NR_FILE_MAPPED);
-       unsigned long file_lru = zone_page_state(zone, NR_INACTIVE_FILE) +
-               zone_page_state(zone, NR_ACTIVE_FILE);
+       unsigned long file_mapped = node_page_state(pgdat, NR_FILE_MAPPED);
+       unsigned long file_lru = node_page_state(pgdat, NR_INACTIVE_FILE) +
+               node_page_state(pgdat, NR_ACTIVE_FILE);
 
        /*
         * It's possible for there to be more file mapped pages than
@@ -3624,7 +3696,7 @@ static inline unsigned long zone_unmapped_file_pages(struct zone *zone)
 }
 
 /* Work out how many page cache pages we can reclaim in this reclaim_mode */
-static unsigned long zone_pagecache_reclaimable(struct zone *zone)
+static unsigned long node_pagecache_reclaimable(struct pglist_data *pgdat)
 {
        unsigned long nr_pagecache_reclaimable;
        unsigned long delta = 0;
@@ -3632,17 +3704,17 @@ static unsigned long zone_pagecache_reclaimable(struct zone *zone)
        /*
         * If RECLAIM_UNMAP is set, then all file pages are considered
         * potentially reclaimable. Otherwise, we have to worry about
-        * pages like swapcache and zone_unmapped_file_pages() provides
+        * pages like swapcache and node_unmapped_file_pages() provides
         * a better estimate
         */
-       if (zone_reclaim_mode & RECLAIM_UNMAP)
-               nr_pagecache_reclaimable = zone_page_state(zone, NR_FILE_PAGES);
+       if (node_reclaim_mode & RECLAIM_UNMAP)
+               nr_pagecache_reclaimable = node_page_state(pgdat, NR_FILE_PAGES);
        else
-               nr_pagecache_reclaimable = zone_unmapped_file_pages(zone);
+               nr_pagecache_reclaimable = node_unmapped_file_pages(pgdat);
 
        /* If we can't clean pages, remove dirty pages from consideration */
-       if (!(zone_reclaim_mode & RECLAIM_WRITE))
-               delta += zone_page_state(zone, NR_FILE_DIRTY);
+       if (!(node_reclaim_mode & RECLAIM_WRITE))
+               delta += node_page_state(pgdat, NR_FILE_DIRTY);
 
        /* Watch for any possible underflows due to delta */
        if (unlikely(delta > nr_pagecache_reclaimable))
@@ -3652,22 +3724,24 @@ static unsigned long zone_pagecache_reclaimable(struct zone *zone)
 }
 
 /*
- * Try to free up some pages from this zone through reclaim.
+ * Try to free up some pages from this node through reclaim.
  */
-static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
+static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order)
 {
        /* Minimum pages needed in order to stay on node */
        const unsigned long nr_pages = 1 << order;
        struct task_struct *p = current;
        struct reclaim_state reclaim_state;
+       int classzone_idx = gfp_zone(gfp_mask);
        struct scan_control sc = {
                .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX),
                .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)),
                .order = order,
-               .priority = ZONE_RECLAIM_PRIORITY,
-               .may_writepage = !!(zone_reclaim_mode & RECLAIM_WRITE),
-               .may_unmap = !!(zone_reclaim_mode & RECLAIM_UNMAP),
+               .priority = NODE_RECLAIM_PRIORITY,
+               .may_writepage = !!(node_reclaim_mode & RECLAIM_WRITE),
+               .may_unmap = !!(node_reclaim_mode & RECLAIM_UNMAP),
                .may_swap = 1,
+               .reclaim_idx = classzone_idx,
        };
 
        cond_resched();
@@ -3681,13 +3755,13 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       if (zone_pagecache_reclaimable(zone) > zone->min_unmapped_pages) {
+       if (node_pagecache_reclaimable(pgdat) > pgdat->min_unmapped_pages) {
                /*
                 * Free memory by calling shrink zone with increasing
                 * priorities until we have enough memory freed.
                 */
                do {
-                       shrink_zone(zone, &sc, true);
+                       shrink_node(pgdat, &sc);
                } while (sc.nr_reclaimed < nr_pages && --sc.priority >= 0);
        }
 
@@ -3697,49 +3771,47 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
        return sc.nr_reclaimed >= nr_pages;
 }
 
-int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
+int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order)
 {
-       int node_id;
        int ret;
 
        /*
-        * Zone reclaim reclaims unmapped file backed pages and
+        * Node reclaim reclaims unmapped file backed pages and
         * slab pages if we are over the defined limits.
         *
         * A small portion of unmapped file backed pages is needed for
         * file I/O otherwise pages read by file I/O will be immediately
-        * thrown out if the zone is overallocated. So we do not reclaim
-        * if less than a specified percentage of the zone is used by
+        * thrown out if the node is overallocated. So we do not reclaim
+        * if less than a specified percentage of the node is used by
         * unmapped file backed pages.
         */
-       if (zone_pagecache_reclaimable(zone) <= zone->min_unmapped_pages &&
-           zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages)
-               return ZONE_RECLAIM_FULL;
+       if (node_pagecache_reclaimable(pgdat) <= pgdat->min_unmapped_pages &&
+           sum_zone_node_page_state(pgdat->node_id, NR_SLAB_RECLAIMABLE) <= pgdat->min_slab_pages)
+               return NODE_RECLAIM_FULL;
 
-       if (!zone_reclaimable(zone))
-               return ZONE_RECLAIM_FULL;
+       if (!pgdat_reclaimable(pgdat))
+               return NODE_RECLAIM_FULL;
 
        /*
         * Do not scan if the allocation should not be delayed.
         */
        if (!gfpflags_allow_blocking(gfp_mask) || (current->flags & PF_MEMALLOC))
-               return ZONE_RECLAIM_NOSCAN;
+               return NODE_RECLAIM_NOSCAN;
 
        /*
-        * Only run zone reclaim on the local zone or on zones that do not
+        * Only run node reclaim on the local node or on nodes that do not
         * have associated processors. This will favor the local processor
         * over remote processors and spread off node memory allocations
         * as wide as possible.
         */
-       node_id = zone_to_nid(zone);
-       if (node_state(node_id, N_CPU) && node_id != numa_node_id())
-               return ZONE_RECLAIM_NOSCAN;
+       if (node_state(pgdat->node_id, N_CPU) && pgdat->node_id != numa_node_id())
+               return NODE_RECLAIM_NOSCAN;
 
-       if (test_and_set_bit(ZONE_RECLAIM_LOCKED, &zone->flags))
-               return ZONE_RECLAIM_NOSCAN;
+       if (test_and_set_bit(PGDAT_RECLAIM_LOCKED, &pgdat->flags))
+               return NODE_RECLAIM_NOSCAN;
 
-       ret = __zone_reclaim(zone, gfp_mask, order);
-       clear_bit(ZONE_RECLAIM_LOCKED, &zone->flags);
+       ret = __node_reclaim(pgdat, gfp_mask, order);
+       clear_bit(PGDAT_RECLAIM_LOCKED, &pgdat->flags);
 
        if (!ret)
                count_vm_event(PGSCAN_ZONE_RECLAIM_FAILED);
@@ -3778,24 +3850,23 @@ int page_evictable(struct page *page)
 void check_move_unevictable_pages(struct page **pages, int nr_pages)
 {
        struct lruvec *lruvec;
-       struct zone *zone = NULL;
+       struct pglist_data *pgdat = NULL;
        int pgscanned = 0;
        int pgrescued = 0;
        int i;
 
        for (i = 0; i < nr_pages; i++) {
                struct page *page = pages[i];
-               struct zone *pagezone;
+               struct pglist_data *pagepgdat = page_pgdat(page);
 
                pgscanned++;
-               pagezone = page_zone(page);
-               if (pagezone != zone) {
-                       if (zone)
-                               spin_unlock_irq(&zone->lru_lock);
-                       zone = pagezone;
-                       spin_lock_irq(&zone->lru_lock);
+               if (pagepgdat != pgdat) {
+                       if (pgdat)
+                               spin_unlock_irq(&pgdat->lru_lock);
+                       pgdat = pagepgdat;
+                       spin_lock_irq(&pgdat->lru_lock);
                }
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
 
                if (!PageLRU(page) || !PageUnevictable(page))
                        continue;
@@ -3811,10 +3882,10 @@ void check_move_unevictable_pages(struct page **pages, int nr_pages)
                }
        }
 
-       if (zone) {
+       if (pgdat) {
                __count_vm_events(UNEVICTABLE_PGRESCUED, pgrescued);
                __count_vm_events(UNEVICTABLE_PGSCANNED, pgscanned);
-               spin_unlock_irq(&zone->lru_lock);
+               spin_unlock_irq(&pgdat->lru_lock);
        }
 }
 #endif /* CONFIG_SHMEM */
index 7997f52935c9b39a07ef67ef90de6bffffa3ab53..89cec42d19ffa8da5ad1e3c8e64ff4df1b3e562b 100644 (file)
@@ -86,8 +86,10 @@ void vm_events_fold_cpu(int cpu)
  *
  * vm_stat contains the global counters
  */
-atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;
-EXPORT_SYMBOL(vm_stat);
+atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;
+atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS] __cacheline_aligned_in_smp;
+EXPORT_SYMBOL(vm_zone_stat);
+EXPORT_SYMBOL(vm_node_stat);
 
 #ifdef CONFIG_SMP
 
@@ -167,19 +169,36 @@ int calculate_normal_threshold(struct zone *zone)
  */
 void refresh_zone_stat_thresholds(void)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int cpu;
        int threshold;
 
+       /* Zero current pgdat thresholds */
+       for_each_online_pgdat(pgdat) {
+               for_each_online_cpu(cpu) {
+                       per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold = 0;
+               }
+       }
+
        for_each_populated_zone(zone) {
+               struct pglist_data *pgdat = zone->zone_pgdat;
                unsigned long max_drift, tolerate_drift;
 
                threshold = calculate_normal_threshold(zone);
 
-               for_each_online_cpu(cpu)
+               for_each_online_cpu(cpu) {
+                       int pgdat_threshold;
+
                        per_cpu_ptr(zone->pageset, cpu)->stat_threshold
                                                        = threshold;
 
+                       /* Base nodestat threshold on the largest populated zone. */
+                       pgdat_threshold = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold;
+                       per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold
+                               = max(threshold, pgdat_threshold);
+               }
+
                /*
                 * Only set percpu_drift_mark if there is a danger that
                 * NR_FREE_PAGES reports the low watermark is ok when in fact
@@ -238,6 +257,26 @@ void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
 }
 EXPORT_SYMBOL(__mod_zone_page_state);
 
+void __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
+                               long delta)
+{
+       struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
+       s8 __percpu *p = pcp->vm_node_stat_diff + item;
+       long x;
+       long t;
+
+       x = delta + __this_cpu_read(*p);
+
+       t = __this_cpu_read(pcp->stat_threshold);
+
+       if (unlikely(x > t || x < -t)) {
+               node_page_state_add(x, pgdat, item);
+               x = 0;
+       }
+       __this_cpu_write(*p, x);
+}
+EXPORT_SYMBOL(__mod_node_page_state);
+
 /*
  * Optimized increment and decrement functions.
  *
@@ -277,12 +316,34 @@ void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
        }
 }
 
+void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
+       s8 __percpu *p = pcp->vm_node_stat_diff + item;
+       s8 v, t;
+
+       v = __this_cpu_inc_return(*p);
+       t = __this_cpu_read(pcp->stat_threshold);
+       if (unlikely(v > t)) {
+               s8 overstep = t >> 1;
+
+               node_page_state_add(v + overstep, pgdat, item);
+               __this_cpu_write(*p, -overstep);
+       }
+}
+
 void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
 {
        __inc_zone_state(page_zone(page), item);
 }
 EXPORT_SYMBOL(__inc_zone_page_state);
 
+void __inc_node_page_state(struct page *page, enum node_stat_item item)
+{
+       __inc_node_state(page_pgdat(page), item);
+}
+EXPORT_SYMBOL(__inc_node_page_state);
+
 void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
 {
        struct per_cpu_pageset __percpu *pcp = zone->pageset;
@@ -299,12 +360,34 @@ void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
        }
 }
 
+void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
+       s8 __percpu *p = pcp->vm_node_stat_diff + item;
+       s8 v, t;
+
+       v = __this_cpu_dec_return(*p);
+       t = __this_cpu_read(pcp->stat_threshold);
+       if (unlikely(v < - t)) {
+               s8 overstep = t >> 1;
+
+               node_page_state_add(v - overstep, pgdat, item);
+               __this_cpu_write(*p, overstep);
+       }
+}
+
 void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
 {
        __dec_zone_state(page_zone(page), item);
 }
 EXPORT_SYMBOL(__dec_zone_page_state);
 
+void __dec_node_page_state(struct page *page, enum node_stat_item item)
+{
+       __dec_node_state(page_pgdat(page), item);
+}
+EXPORT_SYMBOL(__dec_node_page_state);
+
 #ifdef CONFIG_HAVE_CMPXCHG_LOCAL
 /*
  * If we have cmpxchg_local support then we do not need to incur the overhead
@@ -318,8 +401,8 @@ EXPORT_SYMBOL(__dec_zone_page_state);
  *     1       Overstepping half of threshold
  *     -1      Overstepping minus half of threshold
 */
-static inline void mod_state(struct zone *zone, enum zone_stat_item item,
-                            long delta, int overstep_mode)
+static inline void mod_zone_state(struct zone *zone,
+       enum zone_stat_item item, long delta, int overstep_mode)
 {
        struct per_cpu_pageset __percpu *pcp = zone->pageset;
        s8 __percpu *p = pcp->vm_stat_diff + item;
@@ -359,26 +442,83 @@ static inline void mod_state(struct zone *zone, enum zone_stat_item item,
 void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
                         long delta)
 {
-       mod_state(zone, item, delta, 0);
+       mod_zone_state(zone, item, delta, 0);
 }
 EXPORT_SYMBOL(mod_zone_page_state);
 
-void inc_zone_state(struct zone *zone, enum zone_stat_item item)
-{
-       mod_state(zone, item, 1, 1);
-}
-
 void inc_zone_page_state(struct page *page, enum zone_stat_item item)
 {
-       mod_state(page_zone(page), item, 1, 1);
+       mod_zone_state(page_zone(page), item, 1, 1);
 }
 EXPORT_SYMBOL(inc_zone_page_state);
 
 void dec_zone_page_state(struct page *page, enum zone_stat_item item)
 {
-       mod_state(page_zone(page), item, -1, -1);
+       mod_zone_state(page_zone(page), item, -1, -1);
 }
 EXPORT_SYMBOL(dec_zone_page_state);
+
+static inline void mod_node_state(struct pglist_data *pgdat,
+       enum node_stat_item item, int delta, int overstep_mode)
+{
+       struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
+       s8 __percpu *p = pcp->vm_node_stat_diff + item;
+       long o, n, t, z;
+
+       do {
+               z = 0;  /* overflow to node counters */
+
+               /*
+                * The fetching of the stat_threshold is racy. We may apply
+                * a counter threshold to the wrong the cpu if we get
+                * rescheduled while executing here. However, the next
+                * counter update will apply the threshold again and
+                * therefore bring the counter under the threshold again.
+                *
+                * Most of the time the thresholds are the same anyways
+                * for all cpus in a node.
+                */
+               t = this_cpu_read(pcp->stat_threshold);
+
+               o = this_cpu_read(*p);
+               n = delta + o;
+
+               if (n > t || n < -t) {
+                       int os = overstep_mode * (t >> 1) ;
+
+                       /* Overflow must be added to node counters */
+                       z = n + os;
+                       n = -os;
+               }
+       } while (this_cpu_cmpxchg(*p, o, n) != o);
+
+       if (z)
+               node_page_state_add(z, pgdat, item);
+}
+
+void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
+                                       long delta)
+{
+       mod_node_state(pgdat, item, delta, 0);
+}
+EXPORT_SYMBOL(mod_node_page_state);
+
+void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       mod_node_state(pgdat, item, 1, 1);
+}
+
+void inc_node_page_state(struct page *page, enum node_stat_item item)
+{
+       mod_node_state(page_pgdat(page), item, 1, 1);
+}
+EXPORT_SYMBOL(inc_node_page_state);
+
+void dec_node_page_state(struct page *page, enum node_stat_item item)
+{
+       mod_node_state(page_pgdat(page), item, -1, -1);
+}
+EXPORT_SYMBOL(dec_node_page_state);
 #else
 /*
  * Use interrupt disable to serialize counter updates
@@ -394,15 +534,6 @@ void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
 }
 EXPORT_SYMBOL(mod_zone_page_state);
 
-void inc_zone_state(struct zone *zone, enum zone_stat_item item)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __inc_zone_state(zone, item);
-       local_irq_restore(flags);
-}
-
 void inc_zone_page_state(struct page *page, enum zone_stat_item item)
 {
        unsigned long flags;
@@ -424,21 +555,69 @@ void dec_zone_page_state(struct page *page, enum zone_stat_item item)
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(dec_zone_page_state);
-#endif
 
+void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __inc_node_state(pgdat, item);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(inc_node_state);
+
+void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
+                                       long delta)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __mod_node_page_state(pgdat, item, delta);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(mod_node_page_state);
+
+void inc_node_page_state(struct page *page, enum node_stat_item item)
+{
+       unsigned long flags;
+       struct pglist_data *pgdat;
+
+       pgdat = page_pgdat(page);
+       local_irq_save(flags);
+       __inc_node_state(pgdat, item);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(inc_node_page_state);
+
+void dec_node_page_state(struct page *page, enum node_stat_item item)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __dec_node_page_state(page, item);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(dec_node_page_state);
+#endif
 
 /*
  * Fold a differential into the global counters.
  * Returns the number of counters updated.
  */
-static int fold_diff(int *diff)
+static int fold_diff(int *zone_diff, int *node_diff)
 {
        int i;
        int changes = 0;
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-               if (diff[i]) {
-                       atomic_long_add(diff[i], &vm_stat[i]);
+               if (zone_diff[i]) {
+                       atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
+                       changes++;
+       }
+
+       for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+               if (node_diff[i]) {
+                       atomic_long_add(node_diff[i], &vm_node_stat[i]);
                        changes++;
        }
        return changes;
@@ -462,9 +641,11 @@ static int fold_diff(int *diff)
  */
 static int refresh_cpu_vm_stats(bool do_pagesets)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int i;
-       int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+       int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+       int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
        int changes = 0;
 
        for_each_populated_zone(zone) {
@@ -477,7 +658,7 @@ static int refresh_cpu_vm_stats(bool do_pagesets)
                        if (v) {
 
                                atomic_long_add(v, &zone->vm_stat[i]);
-                               global_diff[i] += v;
+                               global_zone_diff[i] += v;
 #ifdef CONFIG_NUMA
                                /* 3 seconds idle till flush */
                                __this_cpu_write(p->expire, 3);
@@ -516,7 +697,22 @@ static int refresh_cpu_vm_stats(bool do_pagesets)
                }
 #endif
        }
-       changes += fold_diff(global_diff);
+
+       for_each_online_pgdat(pgdat) {
+               struct per_cpu_nodestat __percpu *p = pgdat->per_cpu_nodestats;
+
+               for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
+                       int v;
+
+                       v = this_cpu_xchg(p->vm_node_stat_diff[i], 0);
+                       if (v) {
+                               atomic_long_add(v, &pgdat->vm_stat[i]);
+                               global_node_diff[i] += v;
+                       }
+               }
+       }
+
+       changes += fold_diff(global_zone_diff, global_node_diff);
        return changes;
 }
 
@@ -527,9 +723,11 @@ static int refresh_cpu_vm_stats(bool do_pagesets)
  */
 void cpu_vm_stats_fold(int cpu)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int i;
-       int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+       int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+       int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
 
        for_each_populated_zone(zone) {
                struct per_cpu_pageset *p;
@@ -543,11 +741,27 @@ void cpu_vm_stats_fold(int cpu)
                                v = p->vm_stat_diff[i];
                                p->vm_stat_diff[i] = 0;
                                atomic_long_add(v, &zone->vm_stat[i]);
-                               global_diff[i] += v;
+                               global_zone_diff[i] += v;
                        }
        }
 
-       fold_diff(global_diff);
+       for_each_online_pgdat(pgdat) {
+               struct per_cpu_nodestat *p;
+
+               p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu);
+
+               for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+                       if (p->vm_node_stat_diff[i]) {
+                               int v;
+
+                               v = p->vm_node_stat_diff[i];
+                               p->vm_node_stat_diff[i] = 0;
+                               atomic_long_add(v, &pgdat->vm_stat[i]);
+                               global_node_diff[i] += v;
+                       }
+       }
+
+       fold_diff(global_zone_diff, global_node_diff);
 }
 
 /*
@@ -563,16 +777,19 @@ void drain_zonestat(struct zone *zone, struct per_cpu_pageset *pset)
                        int v = pset->vm_stat_diff[i];
                        pset->vm_stat_diff[i] = 0;
                        atomic_long_add(v, &zone->vm_stat[i]);
-                       atomic_long_add(v, &vm_stat[i]);
+                       atomic_long_add(v, &vm_zone_stat[i]);
                }
 }
 #endif
 
 #ifdef CONFIG_NUMA
 /*
- * Determine the per node value of a stat item.
+ * Determine the per node value of a stat item. This function
+ * is called frequently in a NUMA machine, so try to be as
+ * frugal as possible.
  */
-unsigned long node_page_state(int node, enum zone_stat_item item)
+unsigned long sum_zone_node_page_state(int node,
+                                enum zone_stat_item item)
 {
        struct zone *zones = NODE_DATA(node)->node_zones;
        int i;
@@ -584,6 +801,19 @@ unsigned long node_page_state(int node, enum zone_stat_item item)
        return count;
 }
 
+/*
+ * Determine the per node value of a stat item.
+ */
+unsigned long node_page_state(struct pglist_data *pgdat,
+                               enum node_stat_item item)
+{
+       long x = atomic_long_read(&pgdat->vm_stat[item]);
+#ifdef CONFIG_SMP
+       if (x < 0)
+               x = 0;
+#endif
+       return x;
+}
 #endif
 
 #ifdef CONFIG_COMPACTION
@@ -691,33 +921,18 @@ int fragmentation_index(struct zone *zone, unsigned int order)
 const char * const vmstat_text[] = {
        /* enum zone_stat_item countes */
        "nr_free_pages",
-       "nr_alloc_batch",
-       "nr_inactive_anon",
-       "nr_active_anon",
-       "nr_inactive_file",
-       "nr_active_file",
-       "nr_unevictable",
+       "nr_zone_inactive_anon",
+       "nr_zone_active_anon",
+       "nr_zone_inactive_file",
+       "nr_zone_active_file",
+       "nr_zone_unevictable",
+       "nr_zone_write_pending",
        "nr_mlock",
-       "nr_anon_pages",
-       "nr_mapped",
-       "nr_file_pages",
-       "nr_dirty",
-       "nr_writeback",
        "nr_slab_reclaimable",
        "nr_slab_unreclaimable",
        "nr_page_table_pages",
        "nr_kernel_stack",
-       "nr_unstable",
        "nr_bounce",
-       "nr_vmscan_write",
-       "nr_vmscan_immediate_reclaim",
-       "nr_writeback_temp",
-       "nr_isolated_anon",
-       "nr_isolated_file",
-       "nr_shmem",
-       "nr_dirtied",
-       "nr_written",
-       "nr_pages_scanned",
 #if IS_ENABLED(CONFIG_ZSMALLOC)
        "nr_zspages",
 #endif
@@ -729,13 +944,35 @@ const char * const vmstat_text[] = {
        "numa_local",
        "numa_other",
 #endif
+       "nr_free_cma",
+
+       /* Node-based counters */
+       "nr_inactive_anon",
+       "nr_active_anon",
+       "nr_inactive_file",
+       "nr_active_file",
+       "nr_unevictable",
+       "nr_isolated_anon",
+       "nr_isolated_file",
+       "nr_pages_scanned",
        "workingset_refault",
        "workingset_activate",
        "workingset_nodereclaim",
-       "nr_anon_transparent_hugepages",
+       "nr_anon_pages",
+       "nr_mapped",
+       "nr_file_pages",
+       "nr_dirty",
+       "nr_writeback",
+       "nr_writeback_temp",
+       "nr_shmem",
        "nr_shmem_hugepages",
        "nr_shmem_pmdmapped",
-       "nr_free_cma",
+       "nr_anon_transparent_hugepages",
+       "nr_unstable",
+       "nr_vmscan_write",
+       "nr_vmscan_immediate_reclaim",
+       "nr_dirtied",
+       "nr_written",
 
        /* enum writeback_stat_item counters */
        "nr_dirty_threshold",
@@ -749,6 +986,8 @@ const char * const vmstat_text[] = {
        "pswpout",
 
        TEXTS_FOR_ZONES("pgalloc")
+       TEXTS_FOR_ZONES("allocstall")
+       TEXTS_FOR_ZONES("pgskip")
 
        "pgfree",
        "pgactivate",
@@ -758,11 +997,11 @@ const char * const vmstat_text[] = {
        "pgmajfault",
        "pglazyfreed",
 
-       TEXTS_FOR_ZONES("pgrefill")
-       TEXTS_FOR_ZONES("pgsteal_kswapd")
-       TEXTS_FOR_ZONES("pgsteal_direct")
-       TEXTS_FOR_ZONES("pgscan_kswapd")
-       TEXTS_FOR_ZONES("pgscan_direct")
+       "pgrefill",
+       "pgsteal_kswapd",
+       "pgsteal_direct",
+       "pgscan_kswapd",
+       "pgscan_direct",
        "pgscan_direct_throttle",
 
 #ifdef CONFIG_NUMA
@@ -774,7 +1013,6 @@ const char * const vmstat_text[] = {
        "kswapd_low_wmark_hit_quickly",
        "kswapd_high_wmark_hit_quickly",
        "pageoutrun",
-       "allocstall",
 
        "pgrotated",
 
@@ -1180,17 +1418,41 @@ static const struct file_operations pagetypeinfo_file_ops = {
        .release        = seq_release,
 };
 
+static bool is_zone_first_populated(pg_data_t *pgdat, struct zone *zone)
+{
+       int zid;
+
+       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+               struct zone *compare = &pgdat->node_zones[zid];
+
+               if (populated_zone(compare))
+                       return zone == compare;
+       }
+
+       /* The zone must be somewhere! */
+       WARN_ON_ONCE(1);
+       return false;
+}
+
 static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                                                        struct zone *zone)
 {
        int i;
        seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
+       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],
+                               node_page_state(pgdat, i));
+               }
+       }
        seq_printf(m,
                   "\n  pages free     %lu"
                   "\n        min      %lu"
                   "\n        low      %lu"
                   "\n        high     %lu"
-                  "\n        scanned  %lu"
+                  "\n   node_scanned  %lu"
                   "\n        spanned  %lu"
                   "\n        present  %lu"
                   "\n        managed  %lu",
@@ -1198,13 +1460,13 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                   min_wmark_pages(zone),
                   low_wmark_pages(zone),
                   high_wmark_pages(zone),
-                  zone_page_state(zone, NR_PAGES_SCANNED),
+                  node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED),
                   zone->spanned_pages,
                   zone->present_pages,
                   zone->managed_pages);
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-               seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
+               seq_printf(m, "\n      %-12s %lu", vmstat_text[i],
                                zone_page_state(zone, i));
 
        seq_printf(m,
@@ -1234,12 +1496,12 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
 #endif
        }
        seq_printf(m,
-                  "\n  all_unreclaimable: %u"
-                  "\n  start_pfn:         %lu"
-                  "\n  inactive_ratio:    %u",
-                  !zone_reclaimable(zone),
+                  "\n  node_unreclaimable:  %u"
+                  "\n  start_pfn:           %lu"
+                  "\n  node_inactive_ratio: %u",
+                  !pgdat_reclaimable(zone->zone_pgdat),
                   zone->zone_start_pfn,
-                  zone->inactive_ratio);
+                  zone->zone_pgdat->inactive_ratio);
        seq_putc(m, '\n');
 }
 
@@ -1287,6 +1549,7 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos)
        if (*pos >= ARRAY_SIZE(vmstat_text))
                return NULL;
        stat_items_size = NR_VM_ZONE_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
@@ -1301,6 +1564,10 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos)
                v[i] = global_page_state(i);
        v += NR_VM_ZONE_STAT_ITEMS;
 
+       for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+               v[i] = global_node_page_state(i);
+       v += NR_VM_NODE_STAT_ITEMS;
+
        global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
                            v + NR_DIRTY_THRESHOLD);
        v += NR_VM_WRITEBACK_STAT_ITEMS;
@@ -1325,7 +1592,6 @@ static int vmstat_show(struct seq_file *m, void *arg)
 {
        unsigned long *l = arg;
        unsigned long off = l - (unsigned long *)m->private;
-
        seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
        return 0;
 }
@@ -1390,13 +1656,12 @@ int vmstat_refresh(struct ctl_table *table, int write,
        if (err)
                return err;
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
-               val = atomic_long_read(&vm_stat[i]);
+               val = atomic_long_read(&vm_zone_stat[i]);
                if (val < 0) {
                        switch (i) {
-                       case NR_ALLOC_BATCH:
                        case NR_PAGES_SCANNED:
                                /*
-                                * These are often seen to go negative in
+                                * This is often seen to go negative in
                                 * recent kernels, but not to go permanently
                                 * negative.  Whilst it would be nicer not to
                                 * have exceptions, rooting them out would be
index 577277546d985db41aee898a3c69b1b0488d289b..69551cfae97bd50bece343da57e2d12a79c2b74f 100644 (file)
@@ -16,7 +16,7 @@
 /*
  *             Double CLOCK lists
  *
- * Per zone, two clock lists are maintained for file pages: the
+ * Per node, two clock lists are maintained for file pages: the
  * inactive and the active list.  Freshly faulted pages start out at
  * the head of the inactive list and page reclaim scans pages from the
  * tail.  Pages that are accessed multiple times on the inactive list
  *
  *             Implementation
  *
- * For each zone's file LRU lists, a counter for inactive evictions
- * and activations is maintained (zone->inactive_age).
+ * For each node's file LRU lists, a counter for inactive evictions
+ * and activations is maintained (node->inactive_age).
  *
  * On eviction, a snapshot of this counter (along with some bits to
- * identify the zone) is stored in the now empty page cache radix tree
+ * identify the node) is stored in the now empty page cache radix tree
  * slot of the evicted page.  This is called a shadow entry.
  *
  * On cache misses for which there are shadow entries, an eligible
  */
 
 #define EVICTION_SHIFT (RADIX_TREE_EXCEPTIONAL_ENTRY + \
-                        ZONES_SHIFT + NODES_SHIFT +    \
+                        NODES_SHIFT +  \
                         MEM_CGROUP_ID_SHIFT)
 #define EVICTION_MASK  (~0UL >> EVICTION_SHIFT)
 
  */
 static unsigned int bucket_order __read_mostly;
 
-static void *pack_shadow(int memcgid, struct zone *zone, unsigned long eviction)
+static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction)
 {
        eviction >>= bucket_order;
        eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid;
-       eviction = (eviction << NODES_SHIFT) | zone_to_nid(zone);
-       eviction = (eviction << ZONES_SHIFT) | zone_idx(zone);
+       eviction = (eviction << NODES_SHIFT) | pgdat->node_id;
        eviction = (eviction << RADIX_TREE_EXCEPTIONAL_SHIFT);
 
        return (void *)(eviction | RADIX_TREE_EXCEPTIONAL_ENTRY);
 }
 
-static void unpack_shadow(void *shadow, int *memcgidp, struct zone **zonep,
+static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
                          unsigned long *evictionp)
 {
        unsigned long entry = (unsigned long)shadow;
-       int memcgid, nid, zid;
+       int memcgid, nid;
 
        entry >>= RADIX_TREE_EXCEPTIONAL_SHIFT;
-       zid = entry & ((1UL << ZONES_SHIFT) - 1);
-       entry >>= ZONES_SHIFT;
        nid = entry & ((1UL << NODES_SHIFT) - 1);
        entry >>= NODES_SHIFT;
        memcgid = entry & ((1UL << MEM_CGROUP_ID_SHIFT) - 1);
        entry >>= MEM_CGROUP_ID_SHIFT;
 
        *memcgidp = memcgid;
-       *zonep = NODE_DATA(nid)->node_zones + zid;
+       *pgdat = NODE_DATA(nid);
        *evictionp = entry << bucket_order;
 }
 
@@ -208,7 +205,7 @@ static void unpack_shadow(void *shadow, int *memcgidp, struct zone **zonep,
 void *workingset_eviction(struct address_space *mapping, struct page *page)
 {
        struct mem_cgroup *memcg = page_memcg(page);
-       struct zone *zone = page_zone(page);
+       struct pglist_data *pgdat = page_pgdat(page);
        int memcgid = mem_cgroup_id(memcg);
        unsigned long eviction;
        struct lruvec *lruvec;
@@ -218,9 +215,9 @@ void *workingset_eviction(struct address_space *mapping, struct page *page)
        VM_BUG_ON_PAGE(page_count(page), page);
        VM_BUG_ON_PAGE(!PageLocked(page), page);
 
-       lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+       lruvec = mem_cgroup_lruvec(pgdat, memcg);
        eviction = atomic_long_inc_return(&lruvec->inactive_age);
-       return pack_shadow(memcgid, zone, eviction);
+       return pack_shadow(memcgid, pgdat, eviction);
 }
 
 /**
@@ -228,7 +225,7 @@ void *workingset_eviction(struct address_space *mapping, 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 zone it was allocated in.
+ * evicted page in the context of the node it was allocated in.
  *
  * Returns %true if the page should be activated, %false otherwise.
  */
@@ -240,10 +237,10 @@ bool workingset_refault(void *shadow)
        unsigned long eviction;
        struct lruvec *lruvec;
        unsigned long refault;
-       struct zone *zone;
+       struct pglist_data *pgdat;
        int memcgid;
 
-       unpack_shadow(shadow, &memcgid, &zone, &eviction);
+       unpack_shadow(shadow, &memcgid, &pgdat, &eviction);
 
        rcu_read_lock();
        /*
@@ -267,7 +264,7 @@ bool workingset_refault(void *shadow)
                rcu_read_unlock();
                return false;
        }
-       lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+       lruvec = mem_cgroup_lruvec(pgdat, memcg);
        refault = atomic_long_read(&lruvec->inactive_age);
        active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE);
        rcu_read_unlock();
@@ -290,10 +287,10 @@ bool workingset_refault(void *shadow)
         */
        refault_distance = (refault - eviction) & EVICTION_MASK;
 
-       inc_zone_state(zone, WORKINGSET_REFAULT);
+       inc_node_state(pgdat, WORKINGSET_REFAULT);
 
        if (refault_distance <= active_file) {
-               inc_zone_state(zone, WORKINGSET_ACTIVATE);
+               inc_node_state(pgdat, WORKINGSET_ACTIVATE);
                return true;
        }
        return false;
@@ -305,9 +302,10 @@ bool workingset_refault(void *shadow)
  */
 void workingset_activation(struct page *page)
 {
+       struct mem_cgroup *memcg;
        struct lruvec *lruvec;
 
-       lock_page_memcg(page);
+       rcu_read_lock();
        /*
         * Filter non-memcg pages here, e.g. unmap can call
         * mark_page_accessed() on VDSO pages.
@@ -315,12 +313,13 @@ void workingset_activation(struct page *page)
         * XXX: See workingset_refault() - this should return
         * root_mem_cgroup even for !CONFIG_MEMCG.
         */
-       if (!mem_cgroup_disabled() && !page_memcg(page))
+       memcg = page_memcg_rcu(page);
+       if (!mem_cgroup_disabled() && !memcg)
                goto out;
-       lruvec = mem_cgroup_zone_lruvec(page_zone(page), page_memcg(page));
+       lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
        atomic_long_inc(&lruvec->inactive_age);
 out:
-       unlock_page_memcg(page);
+       rcu_read_unlock();
 }
 
 /*
@@ -349,12 +348,13 @@ static unsigned long count_shadow_nodes(struct shrinker *shrinker,
        shadow_nodes = list_lru_shrink_count(&workingset_shadow_nodes, sc);
        local_irq_enable();
 
-       if (memcg_kmem_enabled())
+       if (memcg_kmem_enabled()) {
                pages = mem_cgroup_node_nr_lru_pages(sc->memcg, sc->nid,
                                                     LRU_ALL_FILE);
-       else
-               pages = node_page_state(sc->nid, NR_ACTIVE_FILE) +
-                       node_page_state(sc->nid, NR_INACTIVE_FILE);
+       } else {
+               pages = node_page_state(NODE_DATA(sc->nid), NR_ACTIVE_FILE) +
+                       node_page_state(NODE_DATA(sc->nid), NR_INACTIVE_FILE);
+       }
 
        /*
         * Active cache pages are limited to 50% of memory, and shadow
@@ -433,7 +433,7 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
                }
        }
        BUG_ON(node->count);
-       inc_zone_state(page_zone(virt_to_page(node)), WORKINGSET_NODERECLAIM);
+       inc_node_state(page_pgdat(virt_to_page(node)), WORKINGSET_NODERECLAIM);
        if (!__radix_tree_delete_node(&mapping->page_tree, node))
                BUG();
 
index 04176de6df705510b1da24ea6001174cbe1b46d8..b0bc023d25c539e05b5a874b65dcf575a136f271 100644 (file)
@@ -20,6 +20,7 @@
  *     page->freelist(index): links together all component pages of a zspage
  *             For the huge page, this is always 0, so we use this field
  *             to store handle.
+ *     page->units: first object offset in a subpage of zspage
  *
  * Usage of struct page flags:
  *     PG_private: identifies the first component page
  */
 #define ZS_SIZE_CLASS_DELTA    (PAGE_SIZE >> CLASS_BITS)
 
-/*
- * We do not maintain any list for completely empty or full pages
- */
 enum fullness_group {
        ZS_EMPTY,
        ZS_ALMOST_EMPTY,
@@ -467,11 +465,6 @@ static struct zpool_driver zs_zpool_driver = {
 MODULE_ALIAS("zpool-zsmalloc");
 #endif /* CONFIG_ZPOOL */
 
-static unsigned int get_maxobj_per_zspage(int size, int pages_per_zspage)
-{
-       return pages_per_zspage * PAGE_SIZE / size;
-}
-
 /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
 static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
 
@@ -635,8 +628,7 @@ static int zs_stats_size_show(struct seq_file *s, void *v)
                freeable = zs_can_compact(class);
                spin_unlock(&class->lock);
 
-               objs_per_zspage = get_maxobj_per_zspage(class->size,
-                               class->pages_per_zspage);
+               objs_per_zspage = class->objs_per_zspage;
                pages_used = obj_allocated / objs_per_zspage *
                                class->pages_per_zspage;
 
@@ -945,8 +937,8 @@ static void unpin_tag(unsigned long handle)
 static void reset_page(struct page *page)
 {
        __ClearPageMovable(page);
-       clear_bit(PG_private, &page->flags);
-       clear_bit(PG_private_2, &page->flags);
+       ClearPagePrivate(page);
+       ClearPagePrivate2(page);
        set_page_private(page, 0);
        page_mapcount_reset(page);
        ClearPageHugeObject(page);
@@ -1014,8 +1006,7 @@ static void __free_zspage(struct zs_pool *pool, struct size_class *class,
 
        cache_free_zspage(pool, zspage);
 
-       zs_stat_dec(class, OBJ_ALLOCATED, get_maxobj_per_zspage(
-                       class->size, class->pages_per_zspage));
+       zs_stat_dec(class, OBJ_ALLOCATED, class->objs_per_zspage);
        atomic_long_sub(class->pages_per_zspage,
                                        &pool->pages_allocated);
 }
@@ -1350,7 +1341,7 @@ static void zs_unregister_cpu_notifier(void)
        cpu_notifier_register_done();
 }
 
-static void init_zs_size_classes(void)
+static void __init init_zs_size_classes(void)
 {
        int nr;
 
@@ -1361,16 +1352,14 @@ static void init_zs_size_classes(void)
        zs_size_classes = nr;
 }
 
-static bool can_merge(struct size_class *prev, int size, int pages_per_zspage)
+static bool can_merge(struct size_class *prev, int pages_per_zspage,
+                                       int objs_per_zspage)
 {
-       if (prev->pages_per_zspage != pages_per_zspage)
-               return false;
+       if (prev->pages_per_zspage == pages_per_zspage &&
+               prev->objs_per_zspage == objs_per_zspage)
+               return true;
 
-       if (get_maxobj_per_zspage(prev->size, prev->pages_per_zspage)
-               != get_maxobj_per_zspage(size, pages_per_zspage))
-               return false;
-
-       return true;
+       return false;
 }
 
 static bool zspage_full(struct size_class *class, struct zspage *zspage)
@@ -1541,6 +1530,7 @@ static unsigned long obj_malloc(struct size_class *class,
  * zs_malloc - Allocate block of given size from pool.
  * @pool: pool to allocate from
  * @size: size of block to allocate
+ * @gfp: gfp flags when allocating object
  *
  * On success, handle to the allocated object is returned,
  * otherwise 0.
@@ -1592,8 +1582,7 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp)
        record_obj(handle, obj);
        atomic_long_add(class->pages_per_zspage,
                                &pool->pages_allocated);
-       zs_stat_inc(class, OBJ_ALLOCATED, get_maxobj_per_zspage(
-                       class->size, class->pages_per_zspage));
+       zs_stat_inc(class, OBJ_ALLOCATED, class->objs_per_zspage);
 
        /* We completely set up zspage so mark them as movable */
        SetZsPageMovable(pool, zspage);
@@ -1741,10 +1730,11 @@ static void zs_object_copy(struct size_class *class, unsigned long dst,
  * return handle.
  */
 static unsigned long find_alloced_obj(struct size_class *class,
-                                       struct page *page, int index)
+                                       struct page *page, int *obj_idx)
 {
        unsigned long head;
        int offset = 0;
+       int index = *obj_idx;
        unsigned long handle = 0;
        void *addr = kmap_atomic(page);
 
@@ -1765,6 +1755,9 @@ static unsigned long find_alloced_obj(struct size_class *class,
        }
 
        kunmap_atomic(addr);
+
+       *obj_idx = index;
+
        return handle;
 }
 
@@ -1776,7 +1769,7 @@ struct zs_compact_control {
        struct page *d_page;
         /* Starting object index within @s_page which used for live object
          * in the subpage. */
-       int index;
+       int obj_idx;
 };
 
 static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
@@ -1786,16 +1779,16 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
        unsigned long handle;
        struct page *s_page = cc->s_page;
        struct page *d_page = cc->d_page;
-       unsigned long index = cc->index;
+       int obj_idx = cc->obj_idx;
        int ret = 0;
 
        while (1) {
-               handle = find_alloced_obj(class, s_page, index);
+               handle = find_alloced_obj(class, s_page, &obj_idx);
                if (!handle) {
                        s_page = get_next_page(s_page);
                        if (!s_page)
                                break;
-                       index = 0;
+                       obj_idx = 0;
                        continue;
                }
 
@@ -1809,7 +1802,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
                used_obj = handle_to_obj(handle);
                free_obj = obj_malloc(class, get_zspage(d_page), handle);
                zs_object_copy(class, free_obj, used_obj);
-               index++;
+               obj_idx++;
                /*
                 * record_obj updates handle's value to free_obj and it will
                 * invalidate lock bit(ie, HANDLE_PIN_BIT) of handle, which
@@ -1824,7 +1817,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
 
        /* Remember last position in this iteration */
        cc->s_page = s_page;
-       cc->index = index;
+       cc->obj_idx = obj_idx;
 
        return ret;
 }
@@ -2181,8 +2174,7 @@ static int zs_register_migration(struct zs_pool *pool)
 static void zs_unregister_migration(struct zs_pool *pool)
 {
        flush_work(&pool->free_work);
-       if (pool->inode)
-               iput(pool->inode);
+       iput(pool->inode);
 }
 
 /*
@@ -2261,8 +2253,7 @@ static unsigned long zs_can_compact(struct size_class *class)
                return 0;
 
        obj_wasted = obj_allocated - obj_used;
-       obj_wasted /= get_maxobj_per_zspage(class->size,
-                       class->pages_per_zspage);
+       obj_wasted /= class->objs_per_zspage;
 
        return obj_wasted * class->pages_per_zspage;
 }
@@ -2279,7 +2270,7 @@ static void __zs_compact(struct zs_pool *pool, struct size_class *class)
                if (!zs_can_compact(class))
                        break;
 
-               cc.index = 0;
+               cc.obj_idx = 0;
                cc.s_page = get_first_page(src_zspage);
 
                while ((dst_zspage = isolate_zspage(class, false))) {
@@ -2398,7 +2389,7 @@ static int zs_register_shrinker(struct zs_pool *pool)
 
 /**
  * zs_create_pool - Creates an allocation pool to work from.
- * @flags: allocation flags used to allocate pool metadata
+ * @name: pool name to be created
  *
  * This function must be called before anything when using
  * the zsmalloc allocator.
@@ -2438,6 +2429,7 @@ struct zs_pool *zs_create_pool(const char *name)
        for (i = zs_size_classes - 1; i >= 0; i--) {
                int size;
                int pages_per_zspage;
+               int objs_per_zspage;
                struct size_class *class;
                int fullness = 0;
 
@@ -2445,6 +2437,7 @@ struct zs_pool *zs_create_pool(const char *name)
                if (size > ZS_MAX_ALLOC_SIZE)
                        size = ZS_MAX_ALLOC_SIZE;
                pages_per_zspage = get_pages_per_zspage(size);
+               objs_per_zspage = pages_per_zspage * PAGE_SIZE / size;
 
                /*
                 * size_class is used for normal zsmalloc operation such
@@ -2456,7 +2449,7 @@ struct zs_pool *zs_create_pool(const char *name)
                 * previous size_class if possible.
                 */
                if (prev_class) {
-                       if (can_merge(prev_class, size, pages_per_zspage)) {
+                       if (can_merge(prev_class, pages_per_zspage, objs_per_zspage)) {
                                pool->size_class[i] = prev_class;
                                continue;
                        }
@@ -2469,8 +2462,7 @@ struct zs_pool *zs_create_pool(const char *name)
                class->size = size;
                class->index = i;
                class->pages_per_zspage = pages_per_zspage;
-               class->objs_per_zspage = class->pages_per_zspage *
-                                               PAGE_SIZE / class->size;
+               class->objs_per_zspage = objs_per_zspage;
                spin_lock_init(&class->lock);
                pool->size_class[i] = class;
                for (fullness = ZS_EMPTY; fullness < NR_ZS_FULLNESS;
index 2a9c39f8824e027cbf0ea344f64273bdf971dce9..4ce07dc25573ed3d20f181f5b36327cb0f407fe3 100644 (file)
@@ -198,7 +198,7 @@ static inline void dev_base_seq_inc(struct net *net)
 
 static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
 {
-       unsigned int hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
+       unsigned int hash = full_name_hash(net, name, strnlen(name, IFNAMSIZ));
 
        return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)];
 }
index 559a58baff6ea5be2915ea6ed551a10c7adf3877..27a24571e96cbb456f219d7e24f1c7e5c787410f 100644 (file)
@@ -11,6 +11,13 @@ config SAMPLE_TRACE_EVENTS
        help
          This build trace event example modules.
 
+config SAMPLE_TRACE_PRINTK
+        tristate "Build trace_printk module - tests various trace_printk formats"
+       depends on EVENT_TRACING && m
+       help
+        This builds a module that calls trace_printk() and can be used to
+        test various trace_printk() calls from a module.
+
 config SAMPLE_KOBJECT
        tristate "Build kobject examples -- loadable modules only"
        depends on m
index 2e3b523d7097cb2a6c6a9d46939921c7df3cd8f6..1a20169d85acf9a6e54cdaa0cd83650ac53b7d0c 100644 (file)
@@ -2,4 +2,4 @@
 
 obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ trace_events/ livepatch/ \
                           hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
-                          configfs/ connector/ v4l/
+                          configfs/ connector/ v4l/ trace_printk/
diff --git a/samples/trace_printk/Makefile b/samples/trace_printk/Makefile
new file mode 100644 (file)
index 0000000..19900ab
--- /dev/null
@@ -0,0 +1,6 @@
+# builds a module that calls various trace_printk routines
+# then to use one (as root):  insmod <module_name.ko>
+
+# This module can also be used to test the trace_printk code.
+
+obj-$(CONFIG_SAMPLE_TRACE_PRINTK) += trace-printk.o
diff --git a/samples/trace_printk/trace-printk.c b/samples/trace_printk/trace-printk.c
new file mode 100644 (file)
index 0000000..e9e0040
--- /dev/null
@@ -0,0 +1,56 @@
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/irq_work.h>
+
+/* Must not be static to force gcc to consider these non constant */
+char *trace_printk_test_global_str =
+       "This is a dynamic string that will use trace_puts\n";
+
+char *trace_printk_test_global_str_irq =
+       "(irq) This is a dynamic string that will use trace_puts\n";
+
+char *trace_printk_test_global_str_fmt =
+       "%sThis is a %s that will use trace_printk\n";
+
+static struct irq_work irqwork;
+
+static void trace_printk_irq_work(struct irq_work *work)
+{
+       trace_printk("(irq) This is a static string that will use trace_bputs\n");
+       trace_printk(trace_printk_test_global_str_irq);
+
+       trace_printk("(irq) This is a %s that will use trace_bprintk()\n",
+                    "static string");
+
+       trace_printk(trace_printk_test_global_str_fmt,
+                    "(irq) ", "dynamic string");
+}
+
+static int __init trace_printk_init(void)
+{
+       init_irq_work(&irqwork, trace_printk_irq_work);
+
+       trace_printk("This is a static string that will use trace_bputs\n");
+       trace_printk(trace_printk_test_global_str);
+
+       /* Kick off printing in irq context */
+       irq_work_queue(&irqwork);
+
+       trace_printk("This is a %s that will use trace_bprintk()\n",
+                    "static string");
+
+       trace_printk(trace_printk_test_global_str_fmt, "", "dynamic string");
+
+       return 0;
+}
+
+static void __exit trace_printk_exit(void)
+{
+}
+
+module_init(trace_printk_init);
+module_exit(trace_printk_exit);
+
+MODULE_AUTHOR("Steven Rostedt");
+MODULE_DESCRIPTION("trace-printk");
+MODULE_LICENSE("GPL");
index 4904ced676d40289356aa3358f894fa7efa4b5c0..24a08363995adeeda264cacd801bebf9cc48b5c6 100755 (executable)
@@ -313,7 +313,6 @@ our $Sparse = qr{
                        __kernel|
                        __force|
                        __iomem|
-                       __pmem|
                        __must_check|
                        __init_refok|
                        __kprobes|
index 28414b0207ce58f1fdd8503da0f61a39ba5c7cfe..e3df905ab5b163fc4d423c8c7dff6d9609c63ba7 100644 (file)
@@ -186,24 +186,21 @@ EXPORT_SYMBOL_GPL(securityfs_create_dir);
  */
 void securityfs_remove(struct dentry *dentry)
 {
-       struct dentry *parent;
+       struct inode *dir;
 
        if (!dentry || IS_ERR(dentry))
                return;
 
-       parent = dentry->d_parent;
-       if (!parent || d_really_is_negative(parent))
-               return;
-
-       inode_lock(d_inode(parent));
+       dir = d_inode(dentry->d_parent);
+       inode_lock(dir);
        if (simple_positive(dentry)) {
                if (d_is_dir(dentry))
-                       simple_rmdir(d_inode(parent), dentry);
+                       simple_rmdir(dir, dentry);
                else
-                       simple_unlink(d_inode(parent), dentry);
+                       simple_unlink(dir, dentry);
                dput(dentry);
        }
-       inode_unlock(d_inode(parent));
+       inode_unlock(dir);
        simple_release_fs(&mount, &mount_count);
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
index a283f9e796c114465dc969a1224e72b328a1c927..23e5808a0970b69bfed64a92d608b05537bbc074 100644 (file)
@@ -413,7 +413,7 @@ void smk_insert_entry(struct smack_known *skp)
        unsigned int hash;
        struct hlist_head *head;
 
-       hash = full_name_hash(skp->smk_known, strlen(skp->smk_known));
+       hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known));
        head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
 
        hlist_add_head_rcu(&skp->smk_hashed, head);
@@ -433,7 +433,7 @@ struct smack_known *smk_find_entry(const char *string)
        struct hlist_head *head;
        struct smack_known *skp;
 
-       hash = full_name_hash(string, strlen(string));
+       hash = full_name_hash(NULL, string, strlen(string));
        head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
 
        hlist_for_each_entry_rcu(skp, head, smk_hashed)
index 0e995716cc258b40353f2e559081b0f55ba51b2b..1598b559ac425863f73825303f64d9ab168847b8 100644 (file)
@@ -154,7 +154,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
        if (!name)
                return NULL;
        len = strlen(name) + 1;
-       hash = full_name_hash((const unsigned char *) name, len - 1);
+       hash = full_name_hash(NULL, (const unsigned char *) name, len - 1);
        head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return NULL;
index b974a6997d7f8b7a81f8d2062c59a810b0a6c2d7..5fe3679137aeb76297305e3e73d7defe3ed4c004 100644 (file)
@@ -666,7 +666,7 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
        ptr->const_len = tomoyo_const_part_length(name);
        ptr->is_dir = len && (name[len - 1] == '/');
        ptr->is_patterned = (ptr->const_len < len);
-       ptr->hash = full_name_hash(name, len);
+       ptr->hash = full_name_hash(NULL, name, len);
 }
 
 /**
index 6da72290ac58228799f6e952a9f2eb45186629ac..368343f29dd0fae4be730799a56573b0f56a65c4 100644 (file)
@@ -32,6 +32,4 @@
 #define MAX9877_BYPASS                 (1 << 6)
 #define MAX9877_SHDN                   (1 << 7)
 
-extern int max9877_add_controls(struct snd_soc_codec *codec);
-
 #endif
index d388de72eacaa353ba14e3340a30ef64b63bcd97..28632ee683772bf26e9c7a5a740340b507a9e5d9 100644 (file)
@@ -947,7 +947,7 @@ GrpTable: Grp15
 4: XSAVE
 5: XRSTOR | lfence (11B)
 6: XSAVEOPT | clwb (66) | mfence (11B)
-7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B)
+7: clflush | clflushopt (66) | sfence (11B)
 EndTable
 
 GrpTable: Grp16
index 3918dd52e903c9c07db1c027d2680d743f145977..0f196eec9f48ab7b126ace056b8f28bc8b367f71 100644 (file)
 "0f c7 1d 78 56 34 12 \txrstors 0x12345678",},
 {{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "",
 "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%eax,%ecx,8)",},
-{{0x66, 0x0f, 0xae, 0xf8, }, 4, 0, "", "",
-"66 0f ae f8          \tpcommit ",},
index 9c8c61e06d5a49b8e075e02971395579544f0919..af25bc8240d0de5dab4fc34fb86f8339cf7aa9e4 100644 (file)
 "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%rax,%rcx,8)",},
 {{0x41, 0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "",
 "41 0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%r8,%rcx,8)",},
-{{0x66, 0x0f, 0xae, 0xf8, }, 4, 0, "", "",
-"66 0f ae f8          \tpcommit ",},
index 76e0ec379c8bb357ea886242ae33e244e8bed0bb..979487dae8d4e0a28120561820c567735133035d 100644 (file)
@@ -2655,10 +2655,6 @@ int main(void)
 
 #endif /* #ifndef __x86_64__ */
 
-       /* pcommit */
-
-       asm volatile("pcommit");
-
        /* Following line is a marker for the awk script - do not change */
        asm volatile("rdtsc"); /* Stop here */
 
index b1d491c2e7047c5ba7ef1dac4f86db697f8a4c19..fdde1bd3e3062bbf266ef165eb4dce8512f4d9b3 100644 (file)
@@ -608,6 +608,7 @@ static const struct {
        const char *compact;
 } gfp_compact_table[] = {
        { "GFP_TRANSHUGE",              "THP" },
+       { "GFP_TRANSHUGE_LIGHT",        "THL" },
        { "GFP_HIGHUSER_MOVABLE",       "HUM" },
        { "GFP_HIGHUSER",               "HU" },
        { "GFP_USER",                   "U" },
index ec378cd7b71ee4e067d0a4a9beb59413def3296c..767be7c760340bd33b7e4a18b9a8f3a71d9db33e 100644 (file)
@@ -1012,7 +1012,7 @@ GrpTable: Grp15
 4: XSAVE
 5: XRSTOR | lfence (11B)
 6: XSAVEOPT | clwb (66) | mfence (11B)
-7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B)
+7: clflush | clflushopt (66) | sfence (11B)
 EndTable
 
 GrpTable: Grp16
index 7859856771599531d156c322ac4ceb94596af27a..ad6dd05430192ffdba8d163f9855942fa75b4099 100644 (file)
@@ -11,12 +11,14 @@ ldflags-y += --wrap=__devm_release_region
 ldflags-y += --wrap=__request_region
 ldflags-y += --wrap=__release_region
 ldflags-y += --wrap=devm_memremap_pages
-ldflags-y += --wrap=phys_to_pfn_t
+ldflags-y += --wrap=insert_resource
+ldflags-y += --wrap=remove_resource
 
 DRIVERS := ../../../drivers
 NVDIMM_SRC := $(DRIVERS)/nvdimm
-ACPI_SRC := $(DRIVERS)/acpi
+ACPI_SRC := $(DRIVERS)/acpi/nfit
 DAX_SRC := $(DRIVERS)/dax
+ccflags-y := -I$(src)/$(NVDIMM_SRC)/
 
 obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
 obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o
@@ -27,10 +29,12 @@ obj-$(CONFIG_ACPI_NFIT) += nfit.o
 obj-$(CONFIG_DEV_DAX) += dax.o
 obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o
 
-nfit-y := $(ACPI_SRC)/nfit.o
+nfit-y := $(ACPI_SRC)/core.o
+nfit-$(CONFIG_X86_MCE) += $(ACPI_SRC)/mce.o
 nfit-y += config_check.o
 
 nd_pmem-y := $(NVDIMM_SRC)/pmem.o
+nd_pmem-y += pmem-dax.o
 nd_pmem-y += config_check.o
 
 nd_btt-y := $(NVDIMM_SRC)/btt.o
index adf18bfeca0068cedf19f9dd8b823822bbffac6c..878daf3429e8f822593aff99c490550e5d76ef93 100644 (file)
@@ -10,6 +10,7 @@ void check(void)
        BUILD_BUG_ON(!IS_MODULE(CONFIG_LIBNVDIMM));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_BLK_DEV_PMEM));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BTT));
+       BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_PFN));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BLK));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ACPI_NFIT));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_DEV_DAX));
diff --git a/tools/testing/nvdimm/pmem-dax.c b/tools/testing/nvdimm/pmem-dax.c
new file mode 100644 (file)
index 0000000..c9b8c48
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014-2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include "test/nfit_test.h"
+#include <linux/blkdev.h>
+#include <pmem.h>
+#include <nd.h>
+
+long pmem_direct_access(struct block_device *bdev, sector_t sector,
+               void **kaddr, pfn_t *pfn, long size)
+{
+       struct pmem_device *pmem = bdev->bd_queue->queuedata;
+       resource_size_t offset = sector * 512 + pmem->data_offset;
+
+       if (unlikely(is_bad_pmem(&pmem->bb, sector, size)))
+               return -EIO;
+
+       /*
+        * Limit dax to a single page at a time given vmalloc()-backed
+        * in the nfit_test case.
+        */
+       if (get_nfit_res(pmem->phys_addr + offset)) {
+               struct page *page;
+
+               *kaddr = pmem->virt_addr + offset;
+               page = vmalloc_to_page(pmem->virt_addr + offset);
+               *pfn = page_to_pfn_t(page);
+               dev_dbg_ratelimited(disk_to_dev(bdev->bd_disk)->parent,
+                               "%s: sector: %#llx pfn: %#lx\n", __func__,
+                               (unsigned long long) sector, page_to_pfn(page));
+
+               return PAGE_SIZE;
+       }
+
+       *kaddr = pmem->virt_addr + offset;
+       *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags);
+
+       /*
+        * If badblocks are present, limit known good range to the
+        * requested range.
+        */
+       if (unlikely(pmem->bb.count))
+               return size;
+       return pmem->size - pmem->pfn_pad - offset;
+}
index 9241064970fe72be96c300f544c03345df42ac81..d32f25bba42a35854364fa7eca200971bf4b02a1 100644 (file)
@@ -1,5 +1,5 @@
 ccflags-y := -I$(src)/../../../../drivers/nvdimm/
-ccflags-y += -I$(src)/../../../../drivers/acpi/
+ccflags-y += -I$(src)/../../../../drivers/acpi/nfit/
 
 obj-m += nfit_test.o
 obj-m += nfit_test_iomap.o
index c842095f2801b2183b734c66ae99fa45a6048945..c29f8dca9e67c1f95da2861078ffee61b258ed69 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/memremap.h>
 #include <linux/rculist.h>
 #include <linux/export.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/pfn_t.h>
 #include <linux/io.h>
 #include <linux/mm.h>
 #include "nfit_test.h"
@@ -52,7 +54,7 @@ static struct nfit_test_resource *__get_nfit_res(resource_size_t resource)
        return NULL;
 }
 
-static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
+struct nfit_test_resource *get_nfit_res(resource_size_t resource)
 {
        struct nfit_test_resource *res;
 
@@ -62,6 +64,7 @@ static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
 
        return res;
 }
+EXPORT_SYMBOL(get_nfit_res);
 
 void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
                void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
@@ -97,10 +100,6 @@ void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
 }
 EXPORT_SYMBOL(__wrap_devm_memremap);
 
-#ifdef __HAVE_ARCH_PTE_DEVMAP
-#include <linux/memremap.h>
-#include <linux/pfn_t.h>
-
 void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res,
                struct percpu_ref *ref, struct vmem_altmap *altmap)
 {
@@ -122,19 +121,6 @@ pfn_t __wrap_phys_to_pfn_t(phys_addr_t addr, unsigned long flags)
         return phys_to_pfn_t(addr, flags);
 }
 EXPORT_SYMBOL(__wrap_phys_to_pfn_t);
-#else
-/* to be removed post 4.5-rc1 */
-void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res)
-{
-       resource_size_t offset = res->start;
-       struct nfit_test_resource *nfit_res = get_nfit_res(offset);
-
-       if (nfit_res)
-               return nfit_res->buf + offset - nfit_res->res->start;
-       return devm_memremap_pages(dev, res);
-}
-EXPORT_SYMBOL(__wrap_devm_memremap_pages);
-#endif
 
 void *__wrap_memremap(resource_size_t offset, size_t size,
                unsigned long flags)
@@ -229,6 +215,22 @@ struct resource *__wrap___request_region(struct resource *parent,
 }
 EXPORT_SYMBOL(__wrap___request_region);
 
+int __wrap_insert_resource(struct resource *parent, struct resource *res)
+{
+       if (get_nfit_res(res->start))
+               return 0;
+       return insert_resource(parent, res);
+}
+EXPORT_SYMBOL(__wrap_insert_resource);
+
+int __wrap_remove_resource(struct resource *res)
+{
+       if (get_nfit_res(res->start))
+               return 0;
+       return remove_resource(res);
+}
+EXPORT_SYMBOL(__wrap_remove_resource);
+
 struct resource *__wrap___devm_request_region(struct device *dev,
                struct resource *parent, resource_size_t start,
                resource_size_t n, const char *name)
index c919866853a045fdeb1d7b2c0aae699cddd68200..5404efa578a3fcea18ce5bbab2a991e0c3d98b73 100644 (file)
 enum {
        NUM_PM  = 3,
        NUM_DCR = 5,
+       NUM_HINTS = 8,
        NUM_BDW = NUM_DCR,
        NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW,
        NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */,
        DIMM_SIZE = SZ_32M,
        LABEL_SIZE = SZ_128K,
+       SPA_VCD_SIZE = SZ_4M,
        SPA0_SIZE = DIMM_SIZE,
        SPA1_SIZE = DIMM_SIZE*2,
        SPA2_SIZE = DIMM_SIZE,
@@ -470,11 +472,7 @@ static void release_nfit_res(void *data)
        list_del(&nfit_res->list);
        spin_unlock(&nfit_test_lock);
 
-       if (is_vmalloc_addr(nfit_res->buf))
-               vfree(nfit_res->buf);
-       else
-               dma_free_coherent(nfit_res->dev, resource_size(res),
-                               nfit_res->buf, res->start);
+       vfree(nfit_res->buf);
        kfree(res);
        kfree(nfit_res);
 }
@@ -507,9 +505,7 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
 
        return nfit_res->buf;
  err:
-       if (buf && !is_vmalloc_addr(buf))
-               dma_free_coherent(dev, size, buf, *dma);
-       else if (buf)
+       if (buf)
                vfree(buf);
        kfree(res);
        kfree(nfit_res);
@@ -524,15 +520,6 @@ static void *test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma)
        return __test_alloc(t, size, dma, buf);
 }
 
-static void *test_alloc_coherent(struct nfit_test *t, size_t size,
-               dma_addr_t *dma)
-{
-       struct device *dev = &t->pdev.dev;
-       void *buf = dma_alloc_coherent(dev, size, dma, GFP_KERNEL);
-
-       return __test_alloc(t, size, dma, buf);
-}
-
 static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
 {
        int i;
@@ -584,7 +571,8 @@ static int nfit_test0_alloc(struct nfit_test *t)
                        + offsetof(struct acpi_nfit_control_region,
                                        window_size) * NUM_DCR
                        + sizeof(struct acpi_nfit_data_region) * NUM_BDW
-                       + sizeof(struct acpi_nfit_flush_address) * NUM_DCR;
+                       + (sizeof(struct acpi_nfit_flush_address)
+                                       + sizeof(u64) * NUM_HINTS) * NUM_DCR;
        int i;
 
        t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma);
@@ -592,15 +580,15 @@ static int nfit_test0_alloc(struct nfit_test *t)
                return -ENOMEM;
        t->nfit_size = nfit_size;
 
-       t->spa_set[0] = test_alloc_coherent(t, SPA0_SIZE, &t->spa_set_dma[0]);
+       t->spa_set[0] = test_alloc(t, SPA0_SIZE, &t->spa_set_dma[0]);
        if (!t->spa_set[0])
                return -ENOMEM;
 
-       t->spa_set[1] = test_alloc_coherent(t, SPA1_SIZE, &t->spa_set_dma[1]);
+       t->spa_set[1] = test_alloc(t, SPA1_SIZE, &t->spa_set_dma[1]);
        if (!t->spa_set[1])
                return -ENOMEM;
 
-       t->spa_set[2] = test_alloc_coherent(t, SPA0_SIZE, &t->spa_set_dma[2]);
+       t->spa_set[2] = test_alloc(t, SPA0_SIZE, &t->spa_set_dma[2]);
        if (!t->spa_set[2])
                return -ENOMEM;
 
@@ -614,7 +602,8 @@ static int nfit_test0_alloc(struct nfit_test *t)
                        return -ENOMEM;
                sprintf(t->label[i], "label%d", i);
 
-               t->flush[i] = test_alloc(t, 8, &t->flush_dma[i]);
+               t->flush[i] = test_alloc(t, sizeof(u64) * NUM_HINTS,
+                               &t->flush_dma[i]);
                if (!t->flush[i])
                        return -ENOMEM;
        }
@@ -630,7 +619,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
 
 static int nfit_test1_alloc(struct nfit_test *t)
 {
-       size_t nfit_size = sizeof(struct acpi_nfit_system_address)
+       size_t nfit_size = sizeof(struct acpi_nfit_system_address) * 2
                + sizeof(struct acpi_nfit_memory_map)
                + offsetof(struct acpi_nfit_control_region, window_size);
 
@@ -639,15 +628,31 @@ static int nfit_test1_alloc(struct nfit_test *t)
                return -ENOMEM;
        t->nfit_size = nfit_size;
 
-       t->spa_set[0] = test_alloc_coherent(t, SPA2_SIZE, &t->spa_set_dma[0]);
+       t->spa_set[0] = test_alloc(t, SPA2_SIZE, &t->spa_set_dma[0]);
        if (!t->spa_set[0])
                return -ENOMEM;
 
+       t->spa_set[1] = test_alloc(t, SPA_VCD_SIZE, &t->spa_set_dma[1]);
+       if (!t->spa_set[1])
+               return -ENOMEM;
+
        return ars_state_init(&t->pdev.dev, &t->ars_state);
 }
 
+static void dcr_common_init(struct acpi_nfit_control_region *dcr)
+{
+       dcr->vendor_id = 0xabcd;
+       dcr->device_id = 0;
+       dcr->revision_id = 1;
+       dcr->valid_fields = 1;
+       dcr->manufacturing_location = 0xa;
+       dcr->manufacturing_date = cpu_to_be16(2016);
+}
+
 static void nfit_test0_setup(struct nfit_test *t)
 {
+       const int flush_hint_size = sizeof(struct acpi_nfit_flush_address)
+               + (sizeof(u64) * NUM_HINTS);
        struct acpi_nfit_desc *acpi_desc;
        struct acpi_nfit_memory_map *memdev;
        void *nfit_buf = t->nfit_buf;
@@ -655,7 +660,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        struct acpi_nfit_control_region *dcr;
        struct acpi_nfit_data_region *bdw;
        struct acpi_nfit_flush_address *flush;
-       unsigned int offset;
+       unsigned int offset, i;
 
        /*
         * spa0 (interleave first half of dimm0 and dimm1, note storage
@@ -972,9 +977,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
        dcr->header.length = sizeof(struct acpi_nfit_control_region);
        dcr->region_index = 0+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[0];
        dcr->code = NFIT_FIC_BLK;
        dcr->windows = 1;
@@ -989,9 +992,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
        dcr->header.length = sizeof(struct acpi_nfit_control_region);
        dcr->region_index = 1+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[1];
        dcr->code = NFIT_FIC_BLK;
        dcr->windows = 1;
@@ -1006,9 +1007,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
        dcr->header.length = sizeof(struct acpi_nfit_control_region);
        dcr->region_index = 2+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[2];
        dcr->code = NFIT_FIC_BLK;
        dcr->windows = 1;
@@ -1023,9 +1022,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
        dcr->header.length = sizeof(struct acpi_nfit_control_region);
        dcr->region_index = 3+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[3];
        dcr->code = NFIT_FIC_BLK;
        dcr->windows = 1;
@@ -1042,9 +1039,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 4+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[0];
        dcr->code = NFIT_FIC_BYTEN;
        dcr->windows = 0;
@@ -1056,9 +1051,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 5+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[1];
        dcr->code = NFIT_FIC_BYTEN;
        dcr->windows = 0;
@@ -1070,9 +1063,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 6+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[2];
        dcr->code = NFIT_FIC_BYTEN;
        dcr->windows = 0;
@@ -1084,9 +1075,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 7+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[3];
        dcr->code = NFIT_FIC_BYTEN;
        dcr->windows = 0;
@@ -1141,45 +1130,47 @@ static void nfit_test0_setup(struct nfit_test *t)
        /* flush0 (dimm0) */
        flush = nfit_buf + offset;
        flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->header.length = flush_hint_size;
        flush->device_handle = handle[0];
-       flush->hint_count = 1;
-       flush->hint_address[0] = t->flush_dma[0];
+       flush->hint_count = NUM_HINTS;
+       for (i = 0; i < NUM_HINTS; i++)
+               flush->hint_address[i] = t->flush_dma[0] + i * sizeof(u64);
 
        /* flush1 (dimm1) */
-       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 1;
+       flush = nfit_buf + offset + flush_hint_size * 1;
        flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->header.length = flush_hint_size;
        flush->device_handle = handle[1];
-       flush->hint_count = 1;
-       flush->hint_address[0] = t->flush_dma[1];
+       flush->hint_count = NUM_HINTS;
+       for (i = 0; i < NUM_HINTS; i++)
+               flush->hint_address[i] = t->flush_dma[1] + i * sizeof(u64);
 
        /* flush2 (dimm2) */
-       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 2;
+       flush = nfit_buf + offset + flush_hint_size  * 2;
        flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->header.length = flush_hint_size;
        flush->device_handle = handle[2];
-       flush->hint_count = 1;
-       flush->hint_address[0] = t->flush_dma[2];
+       flush->hint_count = NUM_HINTS;
+       for (i = 0; i < NUM_HINTS; i++)
+               flush->hint_address[i] = t->flush_dma[2] + i * sizeof(u64);
 
        /* flush3 (dimm3) */
-       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 3;
+       flush = nfit_buf + offset + flush_hint_size * 3;
        flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->header.length = flush_hint_size;
        flush->device_handle = handle[3];
-       flush->hint_count = 1;
-       flush->hint_address[0] = t->flush_dma[3];
+       flush->hint_count = NUM_HINTS;
+       for (i = 0; i < NUM_HINTS; i++)
+               flush->hint_address[i] = t->flush_dma[3] + i * sizeof(u64);
 
        if (t->setup_hotplug) {
-               offset = offset + sizeof(struct acpi_nfit_flush_address) * 4;
+               offset = offset + flush_hint_size * 4;
                /* dcr-descriptor4: blk */
                dcr = nfit_buf + offset;
                dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
                dcr->header.length = sizeof(struct acpi_nfit_control_region);
                dcr->region_index = 8+1;
-               dcr->vendor_id = 0xabcd;
-               dcr->device_id = 0;
-               dcr->revision_id = 1;
+               dcr_common_init(dcr);
                dcr->serial_number = ~handle[4];
                dcr->code = NFIT_FIC_BLK;
                dcr->windows = 1;
@@ -1196,9 +1187,7 @@ static void nfit_test0_setup(struct nfit_test *t)
                dcr->header.length = offsetof(struct acpi_nfit_control_region,
                                window_size);
                dcr->region_index = 9+1;
-               dcr->vendor_id = 0xabcd;
-               dcr->device_id = 0;
-               dcr->revision_id = 1;
+               dcr_common_init(dcr);
                dcr->serial_number = ~handle[4];
                dcr->code = NFIT_FIC_BYTEN;
                dcr->windows = 0;
@@ -1300,10 +1289,12 @@ static void nfit_test0_setup(struct nfit_test *t)
                /* flush3 (dimm4) */
                flush = nfit_buf + offset;
                flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-               flush->header.length = sizeof(struct acpi_nfit_flush_address);
+               flush->header.length = flush_hint_size;
                flush->device_handle = handle[4];
-               flush->hint_count = 1;
-               flush->hint_address[0] = t->flush_dma[4];
+               flush->hint_count = NUM_HINTS;
+               for (i = 0; i < NUM_HINTS; i++)
+                       flush->hint_address[i] = t->flush_dma[4]
+                               + i * sizeof(u64);
        }
 
        post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE);
@@ -1339,7 +1330,16 @@ static void nfit_test1_setup(struct nfit_test *t)
        spa->address = t->spa_set_dma[0];
        spa->length = SPA2_SIZE;
 
-       offset += sizeof(*spa);
+       /* virtual cd region */
+       spa = nfit_buf + sizeof(*spa);
+       spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
+       spa->header.length = sizeof(*spa);
+       memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_VCD), 16);
+       spa->range_index = 0;
+       spa->address = t->spa_set_dma[1];
+       spa->length = SPA_VCD_SIZE;
+
+       offset += sizeof(*spa) * 2;
        /* mem-region0 (spa0, dimm0) */
        memdev = nfit_buf + offset;
        memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
@@ -1365,9 +1365,7 @@ static void nfit_test1_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 0+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~0;
        dcr->code = NFIT_FIC_BYTE;
        dcr->windows = 0;
@@ -1462,20 +1460,16 @@ static int nfit_test_probe(struct platform_device *pdev)
        nfit_test->setup(nfit_test);
        acpi_desc = &nfit_test->acpi_desc;
        acpi_nfit_desc_init(acpi_desc, &pdev->dev);
-       acpi_desc->nfit = nfit_test->nfit_buf;
        acpi_desc->blk_do_io = nfit_test_blk_do_io;
        nd_desc = &acpi_desc->nd_desc;
        nd_desc->provider_name = NULL;
+       nd_desc->module = THIS_MODULE;
        nd_desc->ndctl = nfit_test_ctl;
-       acpi_desc->nvdimm_bus = nvdimm_bus_register(&pdev->dev, nd_desc);
-       if (!acpi_desc->nvdimm_bus)
-               return -ENXIO;
 
-       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size);
-       if (rc) {
-               nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf,
+                       nfit_test->nfit_size);
+       if (rc)
                return rc;
-       }
 
        if (nfit_test->setup != nfit_test0_setup)
                return 0;
@@ -1483,22 +1477,16 @@ static int nfit_test_probe(struct platform_device *pdev)
        nfit_test->setup_hotplug = 1;
        nfit_test->setup(nfit_test);
 
-       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size);
-       if (rc) {
-               nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf,
+                       nfit_test->nfit_size);
+       if (rc)
                return rc;
-       }
 
        return 0;
 }
 
 static int nfit_test_remove(struct platform_device *pdev)
 {
-       struct nfit_test *nfit_test = to_nfit_test(&pdev->dev);
-       struct acpi_nfit_desc *acpi_desc = &nfit_test->acpi_desc;
-
-       nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
-
        return 0;
 }
 
@@ -1523,12 +1511,6 @@ static struct platform_driver nfit_test_driver = {
        .id_table = nfit_test_id,
 };
 
-#ifdef CONFIG_CMA_SIZE_MBYTES
-#define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
-#else
-#define CMA_SIZE_MBYTES 0
-#endif
-
 static __init int nfit_test_init(void)
 {
        int rc, i;
@@ -1538,7 +1520,6 @@ static __init int nfit_test_init(void)
        for (i = 0; i < NUM_NFITS; i++) {
                struct nfit_test *nfit_test;
                struct platform_device *pdev;
-               static int once;
 
                nfit_test = kzalloc(sizeof(*nfit_test), GFP_KERNEL);
                if (!nfit_test) {
@@ -1577,20 +1558,6 @@ static __init int nfit_test_init(void)
                        goto err_register;
 
                instances[i] = nfit_test;
-
-               if (!once++) {
-                       dma_addr_t dma;
-                       void *buf;
-
-                       buf = dma_alloc_coherent(&pdev->dev, SZ_128M, &dma,
-                                       GFP_KERNEL);
-                       if (!buf) {
-                               rc = -ENOMEM;
-                               dev_warn(&pdev->dev, "need 128M of free cma\n");
-                               goto err_register;
-                       }
-                       dma_free_coherent(&pdev->dev, SZ_128M, buf, dma);
-               }
        }
 
        rc = platform_driver_register(&nfit_test_driver);
index 96c5e16d7db9a6580419b572f2912b330bec6161..9f18e2a4a862d543a4275301d6629679a133d663 100644 (file)
@@ -12,6 +12,7 @@
  */
 #ifndef __NFIT_TEST_H__
 #define __NFIT_TEST_H__
+#include <linux/list.h>
 
 struct nfit_test_resource {
        struct list_head list;
@@ -26,4 +27,5 @@ void __iomem *__wrap_ioremap_nocache(resource_size_t offset,
 void __wrap_iounmap(volatile void __iomem *addr);
 void nfit_test_setup(nfit_test_lookup_fn lookup);
 void nfit_test_teardown(void);
+struct nfit_test_resource *get_nfit_res(resource_size_t resource);
 #endif