Merge tag 'mm-stable-2022-08-09' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Aug 2022 18:18:00 +0000 (11:18 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Aug 2022 18:18:00 +0000 (11:18 -0700)
Pull remaining MM updates from Andrew Morton:
 "Three patch series - two that perform cleanups and one feature:

   - hugetlb_vmemmap cleanups from Muchun Song

   - hardware poisoning support for 1GB hugepages, from Naoya Horiguchi

   - highmem documentation fixups from Fabio De Francesco"

* tag 'mm-stable-2022-08-09' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (23 commits)
  Documentation/mm: add details about kmap_local_page() and preemption
  highmem: delete a sentence from kmap_local_page() kdocs
  Documentation/mm: rrefer kmap_local_page() and avoid kmap()
  Documentation/mm: avoid invalid use of addresses from kmap_local_page()
  Documentation/mm: don't kmap*() pages which can't come from HIGHMEM
  highmem: specify that kmap_local_page() is callable from interrupts
  highmem: remove unneeded spaces in kmap_local_page() kdocs
  mm, hwpoison: enable memory error handling on 1GB hugepage
  mm, hwpoison: skip raw hwpoison page in freeing 1GB hugepage
  mm, hwpoison: make __page_handle_poison returns int
  mm, hwpoison: set PG_hwpoison for busy hugetlb pages
  mm, hwpoison: make unpoison aware of raw error info in hwpoisoned hugepage
  mm, hwpoison, hugetlb: support saving mechanism of raw error pages
  mm/hugetlb: make pud_huge() and follow_huge_pud() aware of non-present pud entry
  mm/hugetlb: check gigantic_page_runtime_supported() in return_unused_surplus_pages()
  mm: hugetlb_vmemmap: use PTRS_PER_PTE instead of PMD_SIZE / PAGE_SIZE
  mm: hugetlb_vmemmap: move code comments to vmemmap_dedup.rst
  mm: hugetlb_vmemmap: improve hugetlb_vmemmap code readability
  mm: hugetlb_vmemmap: replace early_param() with core_param()
  mm: hugetlb_vmemmap: move vmemmap code related to HugeTLB to hugetlb_vmemmap.c
  ...

416 files changed:
.clang-format
Documentation/ABI/testing/sysfs-bus-cxl
Documentation/admin-guide/hw-vuln/spectre.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml
Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml
Documentation/devicetree/bindings/gpio/x-powers,axp209-gpio.yaml
Documentation/devicetree/bindings/opp/opp-v2-base.yaml
Documentation/devicetree/bindings/opp/opp-v2-kryo-cpu.yaml
Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/nuvoton,wpcm450-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/pinctrl-mt8186.yaml
Documentation/devicetree/bindings/pinctrl/pinctrl-mt8192.yaml
Documentation/devicetree/bindings/pinctrl/pinctrl-mt8195.yaml
Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml
Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/renesas,pfc.yaml
Documentation/devicetree/bindings/pinctrl/renesas,rzv2m-pinctrl.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/sunplus,sp7021-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml
Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml
Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml
Documentation/devicetree/bindings/remoteproc/qcom,glink-edge.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sc7180-mss-pil.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/remoteproc/qcom,sc7280-mss-pil.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml
Documentation/devicetree/bindings/remoteproc/qcom,smd-edge.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml
Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml
Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml
Documentation/driver-api/cxl/memory-devices.rst
Documentation/fault-injection/fault-injection.rst
Documentation/kbuild/kconfig-language.rst
MAINTAINERS
Makefile
arch/arc/configs/axs101_defconfig
arch/arc/configs/axs103_defconfig
arch/arc/configs/axs103_smp_defconfig
arch/arc/configs/haps_hs_defconfig
arch/arc/configs/haps_hs_smp_defconfig
arch/arc/configs/hsdk_defconfig
arch/arc/configs/nsim_700_defconfig
arch/arc/configs/nsimosci_defconfig
arch/arc/configs/nsimosci_hs_defconfig
arch/arc/configs/nsimosci_hs_smp_defconfig
arch/arc/configs/tb10x_defconfig
arch/arc/configs/vdk_hs38_defconfig
arch/arc/configs/vdk_hs38_smp_defconfig
arch/arm/boot/dts/imxrt1170-pinfunc.h [new file with mode: 0644]
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/sun8i-a23-a33.dtsi
arch/arm/boot/dts/sun9i-a80.dtsi
arch/m68k/coldfire/device.c
arch/m68k/coldfire/intc-2.c
arch/m68k/coldfire/m523x.c
arch/powerpc/mm/mem.c
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/nospec-branch.h
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kvm/vmx/vmenter.S
block/bio.c
block/blk-map.c
block/fops.c
certs/Makefile
certs/blacklist_hashes.c
certs/blacklist_nohashes.c [deleted file]
certs/check-blacklist-hashes.awk [new file with mode: 0755]
crypto/af_alg.c
crypto/algif_hash.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/imx-cpufreq-dt.c
drivers/cpufreq/mediatek-cpufreq.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/cpufreq/qcom-cpufreq-nvmem.c
drivers/cpufreq/sti-cpufreq.c
drivers/cpufreq/sun50i-cpufreq-nvmem.c
drivers/cpufreq/tegra194-cpufreq.c
drivers/cpufreq/tegra20-cpufreq.c
drivers/cpufreq/ti-cpufreq.c
drivers/cpuidle/cpuidle.c
drivers/cxl/Kconfig
drivers/cxl/acpi.c
drivers/cxl/core/Makefile
drivers/cxl/core/core.h
drivers/cxl/core/hdm.c
drivers/cxl/core/mbox.c
drivers/cxl/core/memdev.c
drivers/cxl/core/pci.c
drivers/cxl/core/pmem.c
drivers/cxl/core/port.c
drivers/cxl/core/region.c [new file with mode: 0644]
drivers/cxl/cxl.h
drivers/cxl/cxlmem.h
drivers/cxl/cxlpci.h
drivers/cxl/mem.c
drivers/cxl/pci.c
drivers/cxl/pmem.c
drivers/cxl/port.c
drivers/devfreq/exynos-bus.c
drivers/devfreq/tegra30-devfreq.c
drivers/gpu/drm/lima/lima_devfreq.c
drivers/gpu/drm/panfrost/panfrost_devfreq.c
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/media/platform/qcom/venus/pm_helpers.c
drivers/memory/tegra/tegra124-emc.c
drivers/nvdimm/region_devs.c
drivers/opp/core.c
drivers/opp/cpu.c
drivers/opp/debugfs.c
drivers/opp/of.c
drivers/opp/opp.h
drivers/opp/ti-opp-supply.c
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/doe.c [new file with mode: 0644]
drivers/pci/probe.c
drivers/pinctrl/Kconfig
drivers/pinctrl/aspeed/pinmux-aspeed.h
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/core.c
drivers/pinctrl/freescale/pinctrl-imx93.c
drivers/pinctrl/intel/Kconfig
drivers/pinctrl/intel/Makefile
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/intel/pinctrl-intel.h
drivers/pinctrl/intel/pinctrl-lynxpoint.c
drivers/pinctrl/intel/pinctrl-merrifield.c
drivers/pinctrl/intel/pinctrl-meteorlake.c [new file with mode: 0644]
drivers/pinctrl/mediatek/pinctrl-mt8192.c
drivers/pinctrl/mvebu/pinctrl-mvebu.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-amd.c
drivers/pinctrl/pinctrl-amd.h
drivers/pinctrl/pinctrl-at91-pio4.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-axp209.c
drivers/pinctrl/pinctrl-ingenic.c
drivers/pinctrl/pinctrl-ocelot.c
drivers/pinctrl/pinctrl-starfive.c
drivers/pinctrl/pinctrl-zynqmp.c
drivers/pinctrl/qcom/Kconfig
drivers/pinctrl/qcom/Makefile
drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
drivers/pinctrl/qcom/pinctrl-lpass-lpi.h
drivers/pinctrl/qcom/pinctrl-msm8909.c [new file with mode: 0644]
drivers/pinctrl/qcom/pinctrl-msm8916.c
drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c
drivers/pinctrl/qcom/pinctrl-sm6375.c [new file with mode: 0644]
drivers/pinctrl/qcom/pinctrl-sm8250.c
drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
drivers/pinctrl/renesas/Kconfig
drivers/pinctrl/renesas/Makefile
drivers/pinctrl/renesas/core.c
drivers/pinctrl/renesas/pfc-r8a779f0.c
drivers/pinctrl/renesas/pfc-r8a779g0.c [new file with mode: 0644]
drivers/pinctrl/renesas/pinctrl-rzg2l.c
drivers/pinctrl/renesas/pinctrl-rzv2m.c [new file with mode: 0644]
drivers/pinctrl/renesas/sh_pfc.h
drivers/pinctrl/samsung/pinctrl-exynos.c
drivers/pinctrl/samsung/pinctrl-exynos.h
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/samsung/pinctrl-samsung.h
drivers/pinctrl/sunxi/Kconfig
drivers/pinctrl/sunxi/Makefile
drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c [new file with mode: 0644]
drivers/pinctrl/sunxi/pinctrl-sun50i-a100-r.c
drivers/pinctrl/sunxi/pinctrl-sun50i-a100.c
drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c
drivers/pinctrl/sunxi/pinctrl-sun50i-h6-r.c
drivers/pinctrl/sunxi/pinctrl-sun50i-h616-r.c
drivers/pinctrl/sunxi/pinctrl-sun50i-h616.c
drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a83t-r.c
drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/pinctrl/sunxi/pinctrl-sunxi.h
drivers/remoteproc/imx_rproc.c
drivers/remoteproc/keystone_remoteproc.c
drivers/remoteproc/mtk_scp.c
drivers/remoteproc/omap_remoteproc.c
drivers/remoteproc/pru_rproc.c
drivers/remoteproc/qcom_common.c
drivers/remoteproc/qcom_q6v5.c
drivers/remoteproc/qcom_q6v5_adsp.c
drivers/remoteproc/qcom_q6v5_mss.c
drivers/remoteproc/qcom_q6v5_pas.c
drivers/remoteproc/qcom_sysmon.c
drivers/remoteproc/qcom_wcnss.c
drivers/remoteproc/remoteproc_core.c
drivers/remoteproc/ti_k3_r5_remoteproc.c
drivers/rpmsg/mtk_rpmsg.c
drivers/rpmsg/qcom_glink_native.c
drivers/rpmsg/qcom_glink_ssr.c
drivers/rpmsg/qcom_smd.c
drivers/rpmsg/rpmsg_char.c
drivers/rpmsg/rpmsg_core.c
drivers/rpmsg/rpmsg_internal.h
drivers/soc/tegra/common.c
drivers/soc/tegra/pmc.c
drivers/thermal/Kconfig
drivers/thermal/intel/intel_tcc_cooling.c
drivers/thermal/thermal_sysfs.c
drivers/vhost/scsi.c
drivers/watchdog/armada_37xx_wdt.c
drivers/watchdog/bcm7038_wdt.c
drivers/watchdog/booke_wdt.c
drivers/watchdog/dw_wdt.c
drivers/watchdog/f71808e_wdt.c
drivers/watchdog/max77620_wdt.c
drivers/watchdog/mtk_wdt.c
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/pm8916_wdt.c
drivers/watchdog/realtek_otto_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sama5d4_wdt.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/st_lpc_wdt.c
drivers/watchdog/tegra_wdt.c
drivers/watchdog/wdat_wdt.c
fs/afs/cell.c
fs/afs/cmservice.c
fs/afs/internal.h
fs/afs/proc.c
fs/afs/rxrpc.c
fs/afs/server.c
fs/afs/vl_list.c
fs/afs/volume.c
fs/ceph/addr.c
fs/ceph/file.c
fs/cifs/file.c
fs/cifs/misc.c
fs/direct-io.c
fs/fscache/cookie.c
fs/fuse/dev.c
fs/fuse/file.c
fs/gfs2/file.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/iomap/direct-io.c
fs/ksmbd/auth.c
fs/ksmbd/auth.h
fs/ksmbd/connection.c
fs/ksmbd/connection.h
fs/ksmbd/mgmt/share_config.c
fs/ksmbd/mgmt/share_config.h
fs/ksmbd/mgmt/tree_connect.c
fs/ksmbd/mgmt/tree_connect.h
fs/ksmbd/mgmt/user_session.c
fs/ksmbd/mgmt/user_session.h
fs/ksmbd/oplock.c
fs/ksmbd/server.c
fs/ksmbd/smb2misc.c
fs/ksmbd/smb2pdu.c
fs/ksmbd/smb_common.h
fs/ksmbd/smbacl.c
fs/ksmbd/smbacl.h
fs/ksmbd/vfs.c
fs/ksmbd/vfs_cache.c
fs/lockd/svc4proc.c
fs/lockd/svclock.c
fs/lockd/svcproc.c
fs/lockd/xdr4.c
fs/namei.c
fs/nfs/direct.c
fs/nfsd/acl.h
fs/nfsd/filecache.c
fs/nfsd/filecache.h
fs/nfsd/netns.h
fs/nfsd/nfs2acl.c
fs/nfsd/nfs3acl.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfs4acl.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfsfh.c
fs/nfsd/nfsfh.h
fs/nfsd/nfsproc.c
fs/nfsd/state.h
fs/nfsd/trace.h
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/nfsd/xdr4.h
fs/ocfs2/namei.c
fs/read_write.c
fs/splice.c
include/dt-bindings/pinctrl/r7s9210-pinctrl.h
include/dt-bindings/pinctrl/rzg2l-pinctrl.h
include/dt-bindings/pinctrl/rzv2m-pinctrl.h [new file with mode: 0644]
include/linux/buffer_head.h
include/linux/dma-map-ops.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/fs.h
include/linux/ioport.h
include/linux/libnvdimm.h
include/linux/lockd/lockd.h
include/linux/lockd/xdr.h
include/linux/nfs_ssc.h
include/linux/pci-doe.h [new file with mode: 0644]
include/linux/pci_ids.h
include/linux/pinctrl/pinctrl.h
include/linux/pipe_fs_i.h
include/linux/pm_opp.h
include/linux/sunrpc/xdr.h
include/linux/sysfs.h
include/linux/uio.h
include/trace/events/afs.h
include/trace/events/fscache.h
include/trace/events/power.h
include/trace/events/sunrpc.h
include/uapi/linux/pci_regs.h
init/Kconfig
kernel/dma/coherent.c
kernel/module/Kconfig [new file with mode: 0644]
kernel/module/decompress.c
kernel/module/internal.h
kernel/module/kallsyms.c
kernel/module/main.c
kernel/module/procfs.c
kernel/resource.c
kernel/sysctl.c
lib/iov_iter.c
mm/Kconfig
mm/memblock.c
mm/shmem.c
net/9p/client.c
net/9p/protocol.c
net/9p/trans_virtio.c
net/core/datagram.c
net/core/skmsg.c
net/rds/message.c
net/sunrpc/svc_xprt.c
net/tls/tls_sw.c
scripts/Kconfig.include
scripts/Makefile.build
scripts/Makefile.compiler
scripts/Makefile.extrawarn
scripts/Makefile.modinst
scripts/Makefile.package
scripts/check-blacklist-hashes.awk [deleted file]
scripts/checkstack.pl
scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h [new file with mode: 0644]
scripts/dummy-tools/gcc
scripts/headers_install.sh
scripts/kconfig/qconf-cfg.sh
scripts/mod/file2alias.c
scripts/mod/modpost.c
scripts/mod/modpost.h
scripts/module.lds.S
scripts/package/mkspec
security/apparmor/Kconfig
security/apparmor/apparmorfs.c
security/apparmor/audit.c
security/apparmor/domain.c
security/apparmor/include/apparmor.h
security/apparmor/include/apparmorfs.h
security/apparmor/include/file.h
security/apparmor/include/ipc.h
security/apparmor/include/label.h
security/apparmor/include/lib.h
security/apparmor/include/path.h
security/apparmor/include/policy.h
security/apparmor/include/policy_ns.h
security/apparmor/include/policy_unpack.h
security/apparmor/include/secid.h
security/apparmor/include/task.h
security/apparmor/ipc.c
security/apparmor/label.c
security/apparmor/lib.c
security/apparmor/lsm.c
security/apparmor/mount.c
security/apparmor/net.c
security/apparmor/policy.c
security/apparmor/policy_ns.c
security/apparmor/policy_unpack.c
security/apparmor/policy_unpack_test.c
security/apparmor/procattr.c
security/apparmor/secid.c
security/apparmor/task.c
tools/arch/x86/include/asm/cpufeatures.h
tools/arch/x86/include/asm/msr-index.h
tools/testing/cxl/Kbuild
tools/testing/cxl/test/cxl.c
tools/testing/cxl/test/mem.c
tools/testing/cxl/test/mock.c
tools/testing/memblock/Makefile
tools/testing/memblock/README
tools/testing/memblock/TODO
tools/testing/memblock/internal.h
tools/testing/memblock/linux/memory_hotplug.h
tools/testing/memblock/main.c
tools/testing/memblock/scripts/Makefile.include
tools/testing/memblock/tests/alloc_api.c
tools/testing/memblock/tests/alloc_helpers_api.c
tools/testing/memblock/tests/alloc_nid_api.c
tools/testing/memblock/tests/basic_api.c
tools/testing/memblock/tests/common.c
tools/testing/memblock/tests/common.h
tools/thermal/tmon/sysfs.c

index 9b87ea1..1247d54 100644 (file)
@@ -516,6 +516,7 @@ ForEachMacros:
   - 'of_property_for_each_string'
   - 'of_property_for_each_u32'
   - 'pci_bus_for_each_resource'
+  - 'pci_doe_for_each_off'
   - 'pcl_for_each_chunk'
   - 'pcl_for_each_segment'
   - 'pcm_for_each_format'
index 7c2b846..8494ef2 100644 (file)
@@ -7,6 +7,7 @@ Description:
                all descendant memdevs for unbind. Writing '1' to this attribute
                flushes that work.
 
+
 What:          /sys/bus/cxl/devices/memX/firmware_version
 Date:          December, 2020
 KernelVersion: v5.12
@@ -16,6 +17,7 @@ Description:
                Memory Device Output Payload in the CXL-2.0
                specification.
 
+
 What:          /sys/bus/cxl/devices/memX/ram/size
 Date:          December, 2020
 KernelVersion: v5.12
@@ -25,6 +27,7 @@ Description:
                identically named field in the Identify Memory Device Output
                Payload in the CXL-2.0 specification.
 
+
 What:          /sys/bus/cxl/devices/memX/pmem/size
 Date:          December, 2020
 KernelVersion: v5.12
@@ -34,6 +37,7 @@ Description:
                identically named field in the Identify Memory Device Output
                Payload in the CXL-2.0 specification.
 
+
 What:          /sys/bus/cxl/devices/memX/serial
 Date:          January, 2022
 KernelVersion: v5.18
@@ -43,6 +47,7 @@ Description:
                capability. Mandatory for CXL devices, see CXL 2.0 8.1.12.2
                Memory Device PCIe Capabilities and Extended Capabilities.
 
+
 What:          /sys/bus/cxl/devices/memX/numa_node
 Date:          January, 2022
 KernelVersion: v5.18
@@ -52,114 +57,334 @@ Description:
                host PCI device for this memory device, emit the CPU node
                affinity for this device.
 
+
 What:          /sys/bus/cxl/devices/*/devtype
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               CXL device objects export the devtype attribute which mirrors
-               the same value communicated in the DEVTYPE environment variable
-               for uevents for devices on the "cxl" bus.
+               (RO) CXL device objects export the devtype attribute which
+               mirrors the same value communicated in the DEVTYPE environment
+               variable for uevents for devices on the "cxl" bus.
+
 
 What:          /sys/bus/cxl/devices/*/modalias
 Date:          December, 2021
 KernelVersion: v5.18
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               CXL device objects export the modalias attribute which mirrors
-               the same value communicated in the MODALIAS environment variable
-               for uevents for devices on the "cxl" bus.
+               (RO) CXL device objects export the modalias attribute which
+               mirrors the same value communicated in the MODALIAS environment
+               variable for uevents for devices on the "cxl" bus.
+
 
 What:          /sys/bus/cxl/devices/portX/uport
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               CXL port objects are enumerated from either a platform firmware
-               device (ACPI0017 and ACPI0016) or PCIe switch upstream port with
-               CXL component registers. The 'uport' symlink connects the CXL
-               portX object to the device that published the CXL port
+               (RO) CXL port objects are enumerated from either a platform
+               firmware device (ACPI0017 and ACPI0016) or PCIe switch upstream
+               port with CXL component registers. The 'uport' symlink connects
+               the CXL portX object to the device that published the CXL port
                capability.
 
+
 What:          /sys/bus/cxl/devices/portX/dportY
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               CXL port objects are enumerated from either a platform firmware
-               device (ACPI0017 and ACPI0016) or PCIe switch upstream port with
-               CXL component registers. The 'dportY' symlink identifies one or
-               more downstream ports that the upstream port may target in its
-               decode of CXL memory resources.  The 'Y' integer reflects the
-               hardware port unique-id used in the hardware decoder target
-               list.
+               (RO) CXL port objects are enumerated from either a platform
+               firmware device (ACPI0017 and ACPI0016) or PCIe switch upstream
+               port with CXL component registers. The 'dportY' symlink
+               identifies one or more downstream ports that the upstream port
+               may target in its decode of CXL memory resources.  The 'Y'
+               integer reflects the hardware port unique-id used in the
+               hardware decoder target list.
+
 
 What:          /sys/bus/cxl/devices/decoderX.Y
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               CXL decoder objects are enumerated from either a platform
+               (RO) CXL decoder objects are enumerated from either a platform
                firmware description, or a CXL HDM decoder register set in a
                PCIe device (see CXL 2.0 section 8.2.5.12 CXL HDM Decoder
                Capability Structure). The 'X' in decoderX.Y represents the
                cxl_port container of this decoder, and 'Y' represents the
                instance id of a given decoder resource.
 
+
 What:          /sys/bus/cxl/devices/decoderX.Y/{start,size}
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               The 'start' and 'size' attributes together convey the physical
-               address base and number of bytes mapped in the decoder's decode
-               window. For decoders of devtype "cxl_decoder_root" the address
-               range is fixed. For decoders of devtype "cxl_decoder_switch" the
-               address is bounded by the decode range of the cxl_port ancestor
-               of the decoder's cxl_port, and dynamically updates based on the
-               active memory regions in that address space.
+               (RO) The 'start' and 'size' attributes together convey the
+               physical address base and number of bytes mapped in the
+               decoder's decode window. For decoders of devtype
+               "cxl_decoder_root" the address range is fixed. For decoders of
+               devtype "cxl_decoder_switch" the address is bounded by the
+               decode range of the cxl_port ancestor of the decoder's cxl_port,
+               and dynamically updates based on the active memory regions in
+               that address space.
+
 
 What:          /sys/bus/cxl/devices/decoderX.Y/locked
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               CXL HDM decoders have the capability to lock the configuration
-               until the next device reset. For decoders of devtype
-               "cxl_decoder_root" there is no standard facility to unlock them.
-               For decoders of devtype "cxl_decoder_switch" a secondary bus
-               reset, of the PCIe bridge that provides the bus for this
-               decoders uport, unlocks / resets the decoder.
+               (RO) CXL HDM decoders have the capability to lock the
+               configuration until the next device reset. For decoders of
+               devtype "cxl_decoder_root" there is no standard facility to
+               unlock them.  For decoders of devtype "cxl_decoder_switch" a
+               secondary bus reset, of the PCIe bridge that provides the bus
+               for this decoders uport, unlocks / resets the decoder.
+
 
 What:          /sys/bus/cxl/devices/decoderX.Y/target_list
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               Display a comma separated list of the current decoder target
-               configuration. The list is ordered by the current configured
-               interleave order of the decoder's dport instances. Each entry in
-               the list is a dport id.
+               (RO) Display a comma separated list of the current decoder
+               target configuration. The list is ordered by the current
+               configured interleave order of the decoder's dport instances.
+               Each entry in the list is a dport id.
+
 
 What:          /sys/bus/cxl/devices/decoderX.Y/cap_{pmem,ram,type2,type3}
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               When a CXL decoder is of devtype "cxl_decoder_root", it
+               (RO) When a CXL decoder is of devtype "cxl_decoder_root", it
                represents a fixed memory window identified by platform
                firmware. A fixed window may only support a subset of memory
                types. The 'cap_*' attributes indicate whether persistent
                memory, volatile memory, accelerator memory, and / or expander
                memory may be mapped behind this decoder's memory window.
 
+
 What:          /sys/bus/cxl/devices/decoderX.Y/target_type
 Date:          June, 2021
 KernelVersion: v5.14
 Contact:       linux-cxl@vger.kernel.org
 Description:
-               When a CXL decoder is of devtype "cxl_decoder_switch", it can
-               optionally decode either accelerator memory (type-2) or expander
-               memory (type-3). The 'target_type' attribute indicates the
-               current setting which may dynamically change based on what
+               (RO) When a CXL decoder is of devtype "cxl_decoder_switch", it
+               can optionally decode either accelerator memory (type-2) or
+               expander memory (type-3). The 'target_type' attribute indicates
+               the current setting which may dynamically change based on what
                memory regions are activated in this decode hierarchy.
+
+
+What:          /sys/bus/cxl/devices/endpointX/CDAT
+Date:          July, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RO) If this sysfs entry is not present no DOE mailbox was
+               found to support CDAT data.  If it is present and the length of
+               the data is 0 reading the CDAT data failed.  Otherwise the CDAT
+               data is reported.
+
+
+What:          /sys/bus/cxl/devices/decoderX.Y/mode
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) When a CXL decoder is of devtype "cxl_decoder_endpoint" it
+               translates from a host physical address range, to a device local
+               address range. Device-local address ranges are further split
+               into a 'ram' (volatile memory) range and 'pmem' (persistent
+               memory) range. The 'mode' attribute emits one of 'ram', 'pmem',
+               'mixed', or 'none'. The 'mixed' indication is for error cases
+               when a decoder straddles the volatile/persistent partition
+               boundary, and 'none' indicates the decoder is not actively
+               decoding, or no DPA allocation policy has been set.
+
+               'mode' can be written, when the decoder is in the 'disabled'
+               state, with either 'ram' or 'pmem' to set the boundaries for the
+               next allocation.
+
+
+What:          /sys/bus/cxl/devices/decoderX.Y/dpa_resource
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RO) When a CXL decoder is of devtype "cxl_decoder_endpoint",
+               and its 'dpa_size' attribute is non-zero, this attribute
+               indicates the device physical address (DPA) base address of the
+               allocation.
+
+
+What:          /sys/bus/cxl/devices/decoderX.Y/dpa_size
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) When a CXL decoder is of devtype "cxl_decoder_endpoint" it
+               translates from a host physical address range, to a device local
+               address range. The range, base address plus length in bytes, of
+               DPA allocated to this decoder is conveyed in these 2 attributes.
+               Allocations can be mutated as long as the decoder is in the
+               disabled state. A write to 'dpa_size' releases the previous DPA
+               allocation and then attempts to allocate from the free capacity
+               in the device partition referred to by 'decoderX.Y/mode'.
+               Allocate and free requests can only be performed on the highest
+               instance number disabled decoder with non-zero size. I.e.
+               allocations are enforced to occur in increasing 'decoderX.Y/id'
+               order and frees are enforced to occur in decreasing
+               'decoderX.Y/id' order.
+
+
+What:          /sys/bus/cxl/devices/decoderX.Y/interleave_ways
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RO) The number of targets across which this decoder's host
+               physical address (HPA) memory range is interleaved. The device
+               maps every Nth block of HPA (of size ==
+               'interleave_granularity') to consecutive DPA addresses. The
+               decoder's position in the interleave is determined by the
+               device's (endpoint or switch) switch ancestry. For root
+               decoders their interleave is specified by platform firmware and
+               they only specify a downstream target order for host bridges.
+
+
+What:          /sys/bus/cxl/devices/decoderX.Y/interleave_granularity
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RO) The number of consecutive bytes of host physical address
+               space this decoder claims at address N before the decode rotates
+               to the next target in the interleave at address N +
+               interleave_granularity (assuming N is aligned to
+               interleave_granularity).
+
+
+What:          /sys/bus/cxl/devices/decoderX.Y/create_pmem_region
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) Write a string in the form 'regionZ' to start the process
+               of defining a new persistent memory region (interleave-set)
+               within the decode range bounded by root decoder 'decoderX.Y'.
+               The value written must match the current value returned from
+               reading this attribute. An atomic compare exchange operation is
+               done on write to assign the requested id to a region and
+               allocate the region-id for the next creation attempt. EBUSY is
+               returned if the region name written does not match the current
+               cached value.
+
+
+What:          /sys/bus/cxl/devices/decoderX.Y/delete_region
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (WO) Write a string in the form 'regionZ' to delete that region,
+               provided it is currently idle / not bound to a driver.
+
+
+What:          /sys/bus/cxl/devices/regionZ/uuid
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) Write a unique identifier for the region. This field must
+               be set for persistent regions and it must not conflict with the
+               UUID of another region.
+
+
+What:          /sys/bus/cxl/devices/regionZ/interleave_granularity
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) Set the number of consecutive bytes each device in the
+               interleave set will claim. The possible interleave granularity
+               values are determined by the CXL spec and the participating
+               devices.
+
+
+What:          /sys/bus/cxl/devices/regionZ/interleave_ways
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) Configures the number of devices participating in the
+               region is set by writing this value. Each device will provide
+               1/interleave_ways of storage for the region.
+
+
+What:          /sys/bus/cxl/devices/regionZ/size
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) System physical address space to be consumed by the region.
+               When written trigger the driver to allocate space out of the
+               parent root decoder's address space. When read the size of the
+               address space is reported and should match the span of the
+               region's resource attribute. Size shall be set after the
+               interleave configuration parameters. Once set it cannot be
+               changed, only freed by writing 0. The kernel makes no guarantees
+               that data is maintained over an address space freeing event, and
+               there is no guarantee that a free followed by an allocate
+               results in the same address being allocated.
+
+
+What:          /sys/bus/cxl/devices/regionZ/resource
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RO) A region is a contiguous partition of a CXL root decoder
+               address space. Region capacity is allocated by writing to the
+               size attribute, the resulting physical address space determined
+               by the driver is reflected here. It is therefore not useful to
+               read this before writing a value to the size attribute.
+
+
+What:          /sys/bus/cxl/devices/regionZ/target[0..N]
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) Write an endpoint decoder object name to 'targetX' where X
+               is the intended position of the endpoint device in the region
+               interleave and N is the 'interleave_ways' setting for the
+               region. ENXIO is returned if the write results in an impossible
+               to map decode scenario, like the endpoint is unreachable at that
+               position relative to the root decoder interleave. EBUSY is
+               returned if the position in the region is already occupied, or
+               if the region is not in a state to accept interleave
+               configuration changes. EINVAL is returned if the object name is
+               not an endpoint decoder. Once all positions have been
+               successfully written a final validation for decode conflicts is
+               performed before activating the region.
+
+
+What:          /sys/bus/cxl/devices/regionZ/commit
+Date:          May, 2022
+KernelVersion: v5.20
+Contact:       linux-cxl@vger.kernel.org
+Description:
+               (RW) Write a boolean 'true' string value to this attribute to
+               trigger the region to transition from the software programmed
+               state to the actively decoding in hardware state. The commit
+               operation in addition to validating that the region is in proper
+               configured state, validates that the decoders are being
+               committed in spec mandated order (last committed decoder id +
+               1), and checks that the hardware accepts the commit request.
+               Reading this value indicates whether the region is committed or
+               not.
index 9e95568..2ce2a38 100644 (file)
@@ -422,6 +422,14 @@ The possible values in this file are:
   'RSB filling'   Protection of RSB on context switch enabled
   =============   ===========================================
 
+  - EIBRS Post-barrier Return Stack Buffer (PBRSB) protection status:
+
+  ===========================  =======================================================
+  'PBRSB-eIBRS: SW sequence'   CPU is affected and protection of RSB on VMEXIT enabled
+  'PBRSB-eIBRS: Vulnerable'    CPU is vulnerable
+  'PBRSB-eIBRS: Not affected'  CPU is not affected by PBRSB
+  ===========================  =======================================================
+
 Full mitigation might require a microcode update from the CPU
 vendor. When the necessary microcode is not available, the kernel will
 report vulnerability.
index 8c06271..db5de5f 100644 (file)
        nopku           [X86] Disable Memory Protection Keys CPU feature found
                        in some Intel CPUs.
 
-       <module>.async_probe [KNL]
-                       Enable asynchronous probe on this module.
+       <module>.async_probe[=<bool>] [KNL]
+                       If no <bool> value is specified or if the value
+                       specified is not a valid <bool>, enable asynchronous
+                       probe on this module.  Otherwise, enable/disable
+                       asynchronous probe on this module as indicated by the
+                       <bool> value. See also: module.async_probe
 
        early_ioremap_debug [KNL]
                        Enable debug messages in early_ioremap support. This
                        For details see:
                        Documentation/admin-guide/hw-vuln/processor_mmio_stale_data.rst
 
+       module.async_probe=<bool>
+                       [KNL] When set to true, modules will use async probing
+                       by default. To enable/disable async probing for a
+                       specific module, use the module specific control that
+                       is documented under <module>.async_probe. When both
+                       module.async_probe and <module>.async_probe are
+                       specified, <module>.async_probe takes precedence for
+                       the specific module.
+
        module.sig_enforce
                        [KNL] When CONFIG_MODULE_SIG is set, this means that
                        modules without (valid) signatures will fail to load.
index 2f1b8b6..24fa3d8 100644 (file)
@@ -25,6 +25,7 @@ properties:
       - description: v2 of CPUFREQ HW (EPSS)
         items:
           - enum:
+              - qcom,sm6375-cpufreq-epss
               - qcom,sm8250-cpufreq-epss
           - const: qcom,cpufreq-epss
 
index 10b3a7a..a11e1b8 100644 (file)
@@ -22,6 +22,13 @@ select:
     compatible:
       contains:
         enum:
+          - qcom,apq8064
+          - qcom,apq8096
+          - qcom,ipq8064
+          - qcom,msm8939
+          - qcom,msm8960
+          - qcom,msm8974
+          - qcom,msm8996
           - qcom,qcs404
   required:
     - compatible
index 0f628b0..14486ae 100644 (file)
@@ -19,7 +19,13 @@ properties:
     oneOf:
       - enum:
           - x-powers,axp209-gpio
+          - x-powers,axp221-gpio
           - x-powers,axp813-gpio
+      - items:
+          - enum:
+              - x-powers,axp223-gpio
+              - x-powers,axp809-gpio
+          - const: x-powers,axp221-gpio
       - items:
           - const: x-powers,axp803-gpio
           - const: x-powers,axp813-gpio
index 76c8acd..66d0ec7 100644 (file)
@@ -50,6 +50,16 @@ patternProperties:
           property to uniquely identify the OPP nodes exists. Devices like power
           domains must have another (implementation dependent) property.
 
+          Entries for multiple clocks shall be provided in the same field, as
+          array of frequencies.  The OPP binding doesn't provide any provisions
+          to relate the values to their clocks or the order in which the clocks
+          need to be configured and that is left for the implementation
+          specific binding.
+        minItems: 1
+        maxItems: 16
+        items:
+          maxItems: 1
+
       opp-microvolt:
         description: |
           Voltage for the OPP
index 30f7b59..59663e8 100644 (file)
@@ -98,6 +98,8 @@ examples:
                 capacity-dmips-mhz = <1024>;
                 clocks = <&kryocc 0>;
                 operating-points-v2 = <&cluster0_opp>;
+                power-domains = <&cpr>;
+                power-domain-names = "cpr";
                 #cooling-cells = <2>;
                 next-level-cache = <&L2_0>;
                 L2_0: l2-cache {
@@ -115,6 +117,8 @@ examples:
                 capacity-dmips-mhz = <1024>;
                 clocks = <&kryocc 0>;
                 operating-points-v2 = <&cluster0_opp>;
+                power-domains = <&cpr>;
+                power-domain-names = "cpr";
                 #cooling-cells = <2>;
                 next-level-cache = <&L2_0>;
             };
@@ -128,6 +132,8 @@ examples:
                 capacity-dmips-mhz = <1024>;
                 clocks = <&kryocc 1>;
                 operating-points-v2 = <&cluster1_opp>;
+                power-domains = <&cpr>;
+                power-domain-names = "cpr";
                 #cooling-cells = <2>;
                 next-level-cache = <&L2_1>;
                 L2_1: l2-cache {
@@ -145,6 +151,8 @@ examples:
                 capacity-dmips-mhz = <1024>;
                 clocks = <&kryocc 1>;
                 operating-points-v2 = <&cluster1_opp>;
+                power-domains = <&cpr>;
+                power-domain-names = "cpr";
                 #cooling-cells = <2>;
                 next-level-cache = <&L2_1>;
             };
@@ -182,18 +190,21 @@ examples:
                 opp-microvolt = <905000 905000 1140000>;
                 opp-supported-hw = <0x7>;
                 clock-latency-ns = <200000>;
+                required-opps = <&cpr_opp1>;
             };
             opp-1401600000 {
                 opp-hz = /bits/ 64 <1401600000>;
                 opp-microvolt = <1140000 905000 1140000>;
                 opp-supported-hw = <0x5>;
                 clock-latency-ns = <200000>;
+                required-opps = <&cpr_opp2>;
             };
             opp-1593600000 {
                 opp-hz = /bits/ 64 <1593600000>;
                 opp-microvolt = <1140000 905000 1140000>;
                 opp-supported-hw = <0x1>;
                 clock-latency-ns = <200000>;
+                required-opps = <&cpr_opp3>;
             };
         };
 
@@ -207,24 +218,28 @@ examples:
                 opp-microvolt = <905000 905000 1140000>;
                 opp-supported-hw = <0x7>;
                 clock-latency-ns = <200000>;
+                required-opps = <&cpr_opp1>;
             };
             opp-1804800000 {
                 opp-hz = /bits/ 64 <1804800000>;
                 opp-microvolt = <1140000 905000 1140000>;
                 opp-supported-hw = <0x6>;
                 clock-latency-ns = <200000>;
+                required-opps = <&cpr_opp4>;
             };
             opp-1900800000 {
                 opp-hz = /bits/ 64 <1900800000>;
                 opp-microvolt = <1140000 905000 1140000>;
                 opp-supported-hw = <0x4>;
                 clock-latency-ns = <200000>;
+                required-opps = <&cpr_opp5>;
             };
             opp-2150400000 {
                 opp-hz = /bits/ 64 <2150400000>;
                 opp-microvolt = <1140000 905000 1140000>;
                 opp-supported-hw = <0x1>;
                 clock-latency-ns = <200000>;
+                required-opps = <&cpr_opp6>;
             };
         };
 
index 0681b9a..d19d65c 100644 (file)
@@ -46,6 +46,7 @@ properties:
       - allwinner,sun8i-v3s-pinctrl
       - allwinner,sun9i-a80-pinctrl
       - allwinner,sun9i-a80-r-pinctrl
+      - allwinner,sun20i-d1-pinctrl
       - allwinner,sun50i-a64-pinctrl
       - allwinner,sun50i-a64-r-pinctrl
       - allwinner,sun50i-a100-pinctrl
@@ -80,9 +81,6 @@ properties:
       - const: hosc
       - const: losc
 
-  resets:
-    maxItems: 1
-
   gpio-controller: true
   interrupt-controller: true
   gpio-line-names: true
@@ -181,6 +179,18 @@ allOf:
           minItems: 7
           maxItems: 7
 
+  - if:
+      properties:
+        compatible:
+          enum:
+            - allwinner,sun20i-d1-pinctrl
+
+    then:
+      properties:
+        interrupts:
+          minItems: 6
+          maxItems: 6
+
   - if:
       properties:
         compatible:
index 47a56b8..7a11beb 100644 (file)
@@ -152,7 +152,7 @@ examples:
       pinctrl-names = "default";
       pinctrl-0 = <&pinctrl_uid>, <&pinmux_uid>;
 
-      uid {
+      button-uid {
         label = "UID";
         linux,code = <102>;
         gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
index 8a2bb86..1eeb885 100644 (file)
@@ -28,6 +28,8 @@ properties:
   gpio-ranges:
     maxItems: 1
 
+  gpio-line-names: true
+
   reg:
     description: |
       Physical address base for gpio base registers. There are 8 different GPIO
@@ -105,31 +107,8 @@ patternProperties:
           drive-strength:
             enum: [2, 4, 6, 8, 10, 12, 14, 16]
 
-          mediatek,drive-strength-adv:
-            description: |
-              Describe the specific driving setup property.
-              For I2C pins, the existing generic driving setup can only support
-              2/4/6/8/10/12/14/16mA driving. But in specific driving setup, they
-              can support 0.125/0.25/0.5/1mA adjustment. If we enable specific
-              driving setup, the existing generic setup will be disabled.
-              The specific driving setup is controlled by E1E0EN.
-              When E1=0/E0=0, the strength is 0.125mA.
-              When E1=0/E0=1, the strength is 0.25mA.
-              When E1=1/E0=0, the strength is 0.5mA.
-              When E1=1/E0=1, the strength is 1mA.
-              EN is used to enable or disable the specific driving setup.
-              Valid arguments are described as below:
-              0: (E1, E0, EN) = (0, 0, 0)
-              1: (E1, E0, EN) = (0, 0, 1)
-              2: (E1, E0, EN) = (0, 1, 0)
-              3: (E1, E0, EN) = (0, 1, 1)
-              4: (E1, E0, EN) = (1, 0, 0)
-              5: (E1, E0, EN) = (1, 0, 1)
-              6: (E1, E0, EN) = (1, 1, 0)
-              7: (E1, E0, EN) = (1, 1, 1)
-              So the valid arguments are from 0 to 7.
-            $ref: /schemas/types.yaml#/definitions/uint32
-            enum: [0, 1, 2, 3, 4, 5, 6, 7]
+          drive-strength-microamp:
+            enum: [125, 250, 500, 1000]
 
           bias-pull-down:
             oneOf:
@@ -291,7 +270,7 @@ examples:
           pinmux = <PINMUX_GPIO127__FUNC_SCL0>,
                    <PINMUX_GPIO128__FUNC_SDA0>;
           bias-pull-up = <MTK_PULL_SET_RSEL_001>;
-          mediatek,drive-strength-adv = <7>;
+          drive-strength-microamp = <1000>;
         };
       };
     };
index c90a132..e0e943e 100644 (file)
@@ -80,46 +80,30 @@ patternProperties:
               dt-bindings/pinctrl/mt65xx.h. It can only support 2/4/6/8/10/12/14/16mA in mt8192.
             enum: [2, 4, 6, 8, 10, 12, 14, 16]
 
-          mediatek,drive-strength-adv:
-            description: |
-              Describe the specific driving setup property.
-              For I2C pins, the existing generic driving setup can only support
-              2/4/6/8/10/12/14/16mA driving. But in specific driving setup, they
-              can support 0.125/0.25/0.5/1mA adjustment. If we enable specific
-              driving setup, the existing generic setup will be disabled.
-              The specific driving setup is controlled by E1E0EN.
-              When E1=0/E0=0, the strength is 0.125mA.
-              When E1=0/E0=1, the strength is 0.25mA.
-              When E1=1/E0=0, the strength is 0.5mA.
-              When E1=1/E0=1, the strength is 1mA.
-              EN is used to enable or disable the specific driving setup.
-              Valid arguments are described as below:
-              0: (E1, E0, EN) = (0, 0, 0)
-              1: (E1, E0, EN) = (0, 0, 1)
-              2: (E1, E0, EN) = (0, 1, 0)
-              3: (E1, E0, EN) = (0, 1, 1)
-              4: (E1, E0, EN) = (1, 0, 0)
-              5: (E1, E0, EN) = (1, 0, 1)
-              6: (E1, E0, EN) = (1, 1, 0)
-              7: (E1, E0, EN) = (1, 1, 1)
-              So the valid arguments are from 0 to 7.
-            $ref: /schemas/types.yaml#/definitions/uint32
-            enum: [0, 1, 2, 3, 4, 5, 6, 7]
-
-          mediatek,pull-up-adv:
-            description: |
-              Pull up settings for 2 pull resistors, R0 and R1. User can
-              configure those special pins. Valid arguments are described as below:
-              0: (R1, R0) = (0, 0) which means R1 disabled and R0 disabled.
-              1: (R1, R0) = (0, 1) which means R1 disabled and R0 enabled.
-              2: (R1, R0) = (1, 0) which means R1 enabled and R0 disabled.
-              3: (R1, R0) = (1, 1) which means R1 enabled and R0 enabled.
-            $ref: /schemas/types.yaml#/definitions/uint32
-            enum: [0, 1, 2, 3]
-
-          bias-pull-down: true
-
-          bias-pull-up: true
+          drive-strength-microamp:
+            enum: [125, 250, 500, 1000]
+
+          bias-pull-down:
+            oneOf:
+              - type: boolean
+                description: normal pull down.
+              - enum: [100, 101, 102, 103]
+                description: PUPD/R1/R0 pull down type. See MTK_PUPD_SET_R1R0_
+                  defines in dt-bindings/pinctrl/mt65xx.h.
+              - enum: [200, 201, 202, 203]
+                description: RSEL pull down type. See MTK_PULL_SET_RSEL_
+                  defines in dt-bindings/pinctrl/mt65xx.h.
+
+          bias-pull-up:
+            oneOf:
+              - type: boolean
+                description: normal pull up.
+              - enum: [100, 101, 102, 103]
+                description: PUPD/R1/R0 pull up type. See MTK_PUPD_SET_R1R0_
+                  defines in dt-bindings/pinctrl/mt65xx.h.
+              - enum: [200, 201, 202, 203]
+                description: RSEL pull up type. See MTK_PULL_SET_RSEL_
+                  defines in dt-bindings/pinctrl/mt65xx.h.
 
           bias-disable: true
 
index c5b7555..66fe17e 100644 (file)
@@ -29,6 +29,8 @@ properties:
     description: gpio valid number range.
     maxItems: 1
 
+  gpio-line-names: true
+
   reg:
     description: |
       Physical address base for gpio base registers. There are 8 GPIO
@@ -49,7 +51,7 @@ properties:
     description: The interrupt outputs to sysirq.
     maxItems: 1
 
-  mediatek,rsel_resistance_in_si_unit:
+  mediatek,rsel-resistance-in-si-unit:
     type: boolean
     description: |
       Identifying i2c pins pull up/down type which is RSEL. It can support
@@ -98,31 +100,8 @@ patternProperties:
           drive-strength:
             enum: [2, 4, 6, 8, 10, 12, 14, 16]
 
-          mediatek,drive-strength-adv:
-            description: |
-              Describe the specific driving setup property.
-              For I2C pins, the existing generic driving setup can only support
-              2/4/6/8/10/12/14/16mA driving. But in specific driving setup, they
-              can support 0.125/0.25/0.5/1mA adjustment. If we enable specific
-              driving setup, the existing generic setup will be disabled.
-              The specific driving setup is controlled by E1E0EN.
-              When E1=0/E0=0, the strength is 0.125mA.
-              When E1=0/E0=1, the strength is 0.25mA.
-              When E1=1/E0=0, the strength is 0.5mA.
-              When E1=1/E0=1, the strength is 1mA.
-              EN is used to enable or disable the specific driving setup.
-              Valid arguments are described as below:
-              0: (E1, E0, EN) = (0, 0, 0)
-              1: (E1, E0, EN) = (0, 0, 1)
-              2: (E1, E0, EN) = (0, 1, 0)
-              3: (E1, E0, EN) = (0, 1, 1)
-              4: (E1, E0, EN) = (1, 0, 0)
-              5: (E1, E0, EN) = (1, 0, 1)
-              6: (E1, E0, EN) = (1, 1, 0)
-              7: (E1, E0, EN) = (1, 1, 1)
-              So the valid arguments are from 0 to 7.
-            $ref: /schemas/types.yaml#/definitions/uint32
-            enum: [0, 1, 2, 3, 4, 5, 6, 7]
+          drive-strength-microamp:
+            enum: [125, 250, 500, 1000]
 
           bias-pull-down:
             oneOf:
@@ -142,7 +121,7 @@ patternProperties:
               "MTK_PUPD_SET_R1R0_11" define in mt8195.
               For pull down type is RSEL, it can add RSEL define & resistance
               value(ohm) to set different resistance by identifying property
-              "mediatek,rsel_resistance_in_si_unit".
+              "mediatek,rsel-resistance-in-si-unit".
               It can support "MTK_PULL_SET_RSEL_000" & "MTK_PULL_SET_RSEL_001"
               & "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011"
               & "MTK_PULL_SET_RSEL_100" & "MTK_PULL_SET_RSEL_101"
@@ -161,7 +140,7 @@ patternProperties:
               };
               An example of using si unit resistance value(ohm):
               &pio {
-                mediatek,rsel_resistance_in_si_unit;
+                mediatek,rsel-resistance-in-si-unit;
               }
               pincontroller {
                 i2c0_pin {
@@ -190,7 +169,7 @@ patternProperties:
               "MTK_PUPD_SET_R1R0_11" define in mt8195.
               For pull up type is RSEL, it can add RSEL define & resistance
               value(ohm) to set different resistance by identifying property
-              "mediatek,rsel_resistance_in_si_unit".
+              "mediatek,rsel-resistance-in-si-unit".
               It can support "MTK_PULL_SET_RSEL_000" & "MTK_PULL_SET_RSEL_001"
               & "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011"
               & "MTK_PULL_SET_RSEL_100" & "MTK_PULL_SET_RSEL_101"
@@ -209,7 +188,7 @@ patternProperties:
               };
               An example of using si unit resistance value(ohm):
               &pio {
-                mediatek,rsel_resistance_in_si_unit;
+                mediatek,rsel-resistance-in-si-unit;
               }
               pincontroller {
                 i2c0-pins {
@@ -302,7 +281,7 @@ examples:
           pinmux = <PINMUX_GPIO8__FUNC_SDA0>,
                    <PINMUX_GPIO9__FUNC_SCL0>;
           bias-disable;
-          mediatek,drive-strength-adv = <7>;
+          drive-strength-microamp = <1000>;
         };
       };
     };
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml
new file mode 100644 (file)
index 0000000..e035300
--- /dev/null
@@ -0,0 +1,152 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,msm8909-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. MSM8909 TLMM block
+
+maintainers:
+  - Stephan Gerhold <stephan@gerhold.net>
+
+description: |
+  This binding describes the Top Level Mode Multiplexer (TLMM) block found
+  in the MSM8909 platform.
+
+allOf:
+  - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+  compatible:
+    const: qcom,msm8909-tlmm
+
+  reg:
+    maxItems: 1
+
+  interrupts: true
+  interrupt-controller: true
+  '#interrupt-cells': true
+  gpio-controller: true
+  gpio-reserved-ranges: true
+  '#gpio-cells': true
+  gpio-ranges: true
+  wakeup-parent: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+patternProperties:
+  '-state$':
+    oneOf:
+      - $ref: "#/$defs/qcom-msm8909-tlmm-state"
+      - patternProperties:
+          ".*":
+            $ref: "#/$defs/qcom-msm8909-tlmm-state"
+
+$defs:
+  qcom-msm8909-tlmm-state:
+    type: object
+    description:
+      Pinctrl node's client devices use subnodes for desired pin configuration.
+      Client device subnodes use below standard properties.
+    $ref: "qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state"
+
+    properties:
+      pins:
+        description:
+          List of gpio pins affected by the properties specified in this
+          subnode.
+        items:
+          oneOf:
+            - pattern: "^gpio([0-9]|[1-9][0-9]|10[0-9]|11[0-7])$"
+            - enum: [ sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd,
+                      sdc2_data, qdsd_clk, qdsd_cmd, qdsd_data0, qdsd_data1,
+                      qdsd_data2, qdsd_data3 ]
+        minItems: 1
+        maxItems: 16
+
+      function:
+        description:
+          Specify the alternative function to be configured for the specified
+          pins.
+        enum: [ adsp_ext, atest_bbrx0, atest_bbrx1, atest_char, atest_char0,
+                atest_char1, atest_char2, atest_char3, atest_combodac,
+                atest_gpsadc0, atest_gpsadc1, atest_wlan0, atest_wlan1,
+                bimc_dte0, bimc_dte1, blsp_i2c1, blsp_i2c2, blsp_i2c3,
+                blsp_i2c4, blsp_i2c5, blsp_i2c6, blsp_spi1, blsp_spi1_cs1,
+                blsp_spi1_cs2, blsp_spi1_cs3, blsp_spi2, blsp_spi2_cs1,
+                blsp_spi2_cs2, blsp_spi2_cs3, blsp_spi3, blsp_spi3_cs1,
+                blsp_spi3_cs2, blsp_spi3_cs3, blsp_spi4, blsp_spi5, blsp_spi6,
+                blsp_uart1, blsp_uart2, blsp_uim1, blsp_uim2, cam_mclk,
+                cci_async, cci_timer0, cci_timer1, cci_timer2, cdc_pdm0,
+                dbg_out, dmic0_clk, dmic0_data, ebi0_wrcdc, ebi2_a, ebi2_lcd,
+                ext_lpass, gcc_gp1_clk_a, gcc_gp1_clk_b, gcc_gp2_clk_a,
+                gcc_gp2_clk_b, gcc_gp3_clk_a, gcc_gp3_clk_b, gcc_plltest, gpio,
+                gsm0_tx, ldo_en, ldo_update, m_voc, mdp_vsync, modem_tsync,
+                nav_pps, nav_tsync, pa_indicator, pbs0, pbs1, pbs2,
+                pri_mi2s_data0_a, pri_mi2s_data0_b, pri_mi2s_data1_a,
+                pri_mi2s_data1_b, pri_mi2s_mclk_a, pri_mi2s_mclk_b,
+                pri_mi2s_sck_a, pri_mi2s_sck_b, pri_mi2s_ws_a, pri_mi2s_ws_b,
+                prng_rosc, pwr_crypto_enabled_a, pwr_crypto_enabled_b,
+                pwr_modem_enabled_a, pwr_modem_enabled_b, pwr_nav_enabled_a,
+                pwr_nav_enabled_b, qdss_cti_trig_in_a0, qdss_cti_trig_in_a1,
+                qdss_cti_trig_in_b0, qdss_cti_trig_in_b1, qdss_cti_trig_out_a0,
+                qdss_cti_trig_out_a1, qdss_cti_trig_out_b0,
+                qdss_cti_trig_out_b1, qdss_traceclk_a, qdss_tracectl_a,
+                qdss_tracedata_a, qdss_tracedata_b, sd_write, sec_mi2s,
+                smb_int, ssbi0, ssbi1, uim1_clk, uim1_data, uim1_present,
+                uim1_reset, uim2_clk, uim2_data, uim2_present, uim2_reset,
+                uim3_clk, uim3_data, uim3_present, uim3_reset, uim_batt,
+                wcss_bt, wcss_fm, wcss_wlan ]
+
+      bias-disable: true
+      bias-pull-down: true
+      bias-pull-up: true
+      drive-strength: true
+      input-enable: true
+      output-high: true
+      output-low: true
+
+    required:
+      - pins
+      - function
+
+    additionalProperties: false
+
+examples:
+  - |
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+        pinctrl@1000000 {
+                compatible = "qcom,msm8909-tlmm";
+                reg = <0x1000000 0x300000>;
+                interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+                gpio-controller;
+                #gpio-cells = <2>;
+                gpio-ranges = <&tlmm 0 0 117>;
+                interrupt-controller;
+                #interrupt-cells = <2>;
+
+                gpio-wo-subnode-state {
+                        pins = "gpio1";
+                        function = "gpio";
+                };
+
+                uart-w-subnodes-state {
+                        rx {
+                                pins = "gpio4";
+                                function = "blsp_uart1";
+                                bias-pull-up;
+                        };
+
+                        tx {
+                                pins = "gpio5";
+                                function = "blsp_uart1";
+                                bias-disable;
+                        };
+                };
+        };
+...
index 6f2efc3..694898f 100644 (file)
@@ -52,6 +52,7 @@ properties:
           - qcom,pmi8998-gpio
           - qcom,pmk8350-gpio
           - qcom,pmm8155au-gpio
+          - qcom,pmp8074-gpio
           - qcom,pmr735a-gpio
           - qcom,pmr735b-gpio
           - qcom,pms405-gpio
@@ -158,6 +159,7 @@ allOf:
         compatible:
           contains:
             enum:
+              - qcom,pm8226-gpio
               - qcom,pm8350b-gpio
               - qcom,pm8950-gpio
     then:
@@ -233,6 +235,7 @@ allOf:
               - qcom,pm8150b-gpio
               - qcom,pm8150l-gpio
               - qcom,pmc8180c-gpio
+              - qcom,pmp8074-gpio
               - qcom,pms405-gpio
     then:
       properties:
@@ -415,6 +418,7 @@ $defs:
                  - gpio1-gpio10 for pmi8994
                  - gpio1-gpio4 for pmk8350
                  - gpio1-gpio10 for pmm8155au
+                 - gpio1-gpio12 for pmp8074 (holes on gpio1 and gpio12)
                  - gpio1-gpio4 for pmr735a
                  - gpio1-gpio4 for pmr735b
                  - gpio1-gpio12 for pms405 (holes on gpio1, gpio9
index d32ee32..33d1d37 100644 (file)
@@ -19,6 +19,11 @@ properties:
   compatible:
     const: qcom,sc7280-lpass-lpi-pinctrl
 
+  qcom,adsp-bypass-mode:
+    description:
+      Tells ADSP is in bypass mode.
+    type: boolean
+
   reg:
     minItems: 2
     maxItems: 2
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml
new file mode 100644 (file)
index 0000000..3908807
--- /dev/null
@@ -0,0 +1,158 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,sm6375-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. SM6375 TLMM block
+
+maintainers:
+  - Konrad Dybcio <konrad.dybcio@somainline.org>
+
+description: |
+  This binding describes the Top Level Mode Multiplexer (TLMM) block found
+  in the SM6375 platform.
+
+allOf:
+  - $ref: "pinctrl.yaml#"
+  - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+  compatible:
+    const: qcom,sm6375-tlmm
+
+  reg:
+    maxItems: 1
+
+  interrupts: true
+  interrupt-controller: true
+  '#interrupt-cells': true
+  gpio-controller: true
+  gpio-reserved-ranges: true
+  '#gpio-cells': true
+  gpio-ranges: true
+  wakeup-parent: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+patternProperties:
+  '-state$':
+    oneOf:
+      - $ref: "#/$defs/qcom-sm6375-tlmm-state"
+      - patternProperties:
+          ".*":
+            $ref: "#/$defs/qcom-sm6375-tlmm-state"
+
+$defs:
+  qcom-sm6375-tlmm-state:
+    type: object
+    description:
+      Pinctrl node's client devices use subnodes for desired pin configuration.
+      Client device subnodes use below standard properties.
+    $ref: "qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state"
+
+    properties:
+      pins:
+        description:
+          List of gpio pins affected by the properties specified in this
+          subnode.
+        items:
+          oneOf:
+            - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-4][0-9]|15[0-6])$"
+            - enum: [ ufs_reset, sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk,
+                      sdc2_cmd, sdc2_data ]
+        minItems: 1
+        maxItems: 36
+
+      function:
+        description:
+          Specify the alternative function to be configured for the specified
+          pins.
+
+        enum: [ adsp_ext, agera_pll, atest_char, atest_char0, atest_char1,
+                atest_char2, atest_char3, atest_tsens, atest_tsens2,
+                atest_usb1, atest_usb10, atest_usb11, atest_usb12,
+                atest_usb13, atest_usb2, atest_usb20, atest_usb21,
+                atest_usb22, atest_usb23, audio_ref, btfm_slimbus, cam_mclk,
+                cci_async, cci_i2c, cci_timer0, cci_timer1, cci_timer2,
+                cci_timer3, cci_timer4, cri_trng, dbg_out, ddr_bist,
+                ddr_pxi0, ddr_pxi1, ddr_pxi2, ddr_pxi3, dp_hot, edp_lcd,
+                gcc_gp1, gcc_gp2, gcc_gp3, gp_pdm0, gp_pdm1, gp_pdm2, gpio,
+                gps_tx, ibi_i3c, jitter_bist, ldo_en, ldo_update, lpass_ext,
+                m_voc, mclk, mdp_vsync, mdp_vsync0, mdp_vsync1, mdp_vsync2,
+                mdp_vsync3, mi2s_0, mi2s_1, mi2s_2, mss_lte, nav_gpio,
+                nav_pps, pa_indicator, phase_flag0, phase_flag1, phase_flag10,
+                phase_flag11, phase_flag12, phase_flag13, phase_flag14,
+                phase_flag15, phase_flag16, phase_flag17, phase_flag18,
+                phase_flag19, phase_flag2, phase_flag20, phase_flag21,
+                phase_flag22, phase_flag23, phase_flag24, phase_flag25,
+                phase_flag26, phase_flag27, phase_flag28, phase_flag29,
+                phase_flag3, phase_flag30, phase_flag31, phase_flag4,
+                phase_flag5, phase_flag6, phase_flag7, phase_flag8,
+                phase_flag9, pll_bist, pll_bypassnl, pll_clk, pll_reset,
+                prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti,
+                qdss_gpio, qdss_gpio0, qdss_gpio1, qdss_gpio10, qdss_gpio11,
+                qdss_gpio12, qdss_gpio13, qdss_gpio14, qdss_gpio15,
+                qdss_gpio2, qdss_gpio3, qdss_gpio4, qdss_gpio5, qdss_gpio6,
+                qdss_gpio7, qdss_gpio8, qdss_gpio9, qlink0_enable,
+                qlink0_request, qlink0_wmss, qlink1_enable, qlink1_request,
+                qlink1_wmss, qup00, qup01, qup02, qup10, qup11_f1, qup11_f2,
+                qup12, qup13_f1, qup13_f2, qup14, sd_write, sdc1_tb, sdc2_tb,
+                sp_cmu, tgu_ch0, tgu_ch1, tgu_ch2, tgu_ch3, tsense_pwm1,
+                tsense_pwm2, uim1_clk, uim1_data, uim1_present, uim1_reset,
+                uim2_clk, uim2_data, uim2_present, uim2_reset, usb2phy_ac,
+                usb_phy, vfr_1, vsense_trigger, wlan1_adc0, wlan1_adc1,
+                wlan2_adc0, wlan2_adc1 ]
+
+
+      bias-disable: true
+      bias-pull-down: true
+      bias-pull-up: true
+      drive-strength: true
+      input-enable: true
+      output-high: true
+      output-low: true
+
+    required:
+      - pins
+      - function
+
+    additionalProperties: false
+
+examples:
+  - |
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        pinctrl@500000 {
+                compatible = "qcom,sm6375-tlmm";
+                reg = <0x00500000 0x800000>;
+                interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>;
+                gpio-controller;
+                #gpio-cells = <2>;
+                interrupt-controller;
+                #interrupt-cells = <2>;
+                gpio-ranges = <&tlmm 0 0 157>;
+
+                gpio-wo-subnode-state {
+                        pins = "gpio1";
+                        function = "gpio";
+                };
+
+                uart-w-subnodes-state {
+                        rx {
+                                pins = "gpio18";
+                                function = "qup13_f2";
+                                bias-pull-up;
+                        };
+
+                        tx {
+                                pins = "gpio19";
+                                function = "qup13_f2";
+                                bias-disable;
+                        };
+                };
+        };
+...
index 2a57df7..4fc758f 100644 (file)
@@ -45,6 +45,7 @@ properties:
       - renesas,pfc-r8a77995    # R-Car D3
       - renesas,pfc-r8a779a0    # R-Car V3U
       - renesas,pfc-r8a779f0    # R-Car S4-8
+      - renesas,pfc-r8a779g0    # R-Car V4H
       - renesas,pfc-sh73a0      # SH-Mobile AG5
 
   reg:
diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzv2m-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzv2m-pinctrl.yaml
new file mode 100644 (file)
index 0000000..eac6245
--- /dev/null
@@ -0,0 +1,170 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/renesas,rzv2m-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/V2M combined Pin and GPIO controller
+
+maintainers:
+  - Geert Uytterhoeven <geert+renesas@glider.be>
+  - Phil Edworthy <phil.edworthy@renesas.com>
+
+description:
+  The Renesas RZ/V2M SoC features a combined Pin and GPIO controller.
+  Pin multiplexing and GPIO configuration is performed on a per-pin basis.
+  Each port features up to 16 pins, each of them configurable for GPIO function
+  (port mode) or in alternate function mode.
+  Up to 8 different alternate function modes exist for each single pin.
+
+properties:
+  compatible:
+    const: renesas,r9a09g011-pinctrl # RZ/V2M
+
+  reg:
+    maxItems: 1
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 2
+    description:
+      The first cell contains the global GPIO port index, constructed using the
+      RZV2M_GPIO() helper macro in <dt-bindings/pinctrl/rzv2m-pinctrl.h> and the
+      second cell represents consumer flag as mentioned in ../gpio/gpio.txt
+      E.g. "RZV2M_GPIO(8, 1)" for P8_1.
+
+  gpio-ranges:
+    maxItems: 1
+
+  interrupts:
+    description: INEXINT[0..38] corresponding to individual pin inputs.
+    maxItems: 39
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+additionalProperties:
+  anyOf:
+    - type: object
+      allOf:
+        - $ref: pincfg-node.yaml#
+        - $ref: pinmux-node.yaml#
+
+      description:
+        Pin controller client devices use pin configuration subnodes (children
+        and grandchildren) for desired pin configuration.
+        Client device subnodes use below standard properties.
+
+      properties:
+        phandle: true
+        pinmux:
+          description:
+            Values are constructed from GPIO port number, pin number, and
+            alternate function configuration number using the RZV2M_PORT_PINMUX()
+            helper macro in <dt-bindings/pinctrl/rzv2m-pinctrl.h>.
+        pins: true
+        bias-disable: true
+        bias-pull-down: true
+        bias-pull-up: true
+        drive-strength-microamp:
+          # Superset of supported values
+          enum: [ 1600, 1800, 2000, 3200, 3800, 4000, 6400, 7800, 8000,
+                  9000, 9600, 11000, 12000, 13000, 18000 ]
+        slew-rate:
+          description: 0 is slow slew rate, 1 is fast slew rate
+          enum: [ 0, 1 ]
+        gpio-hog: true
+        gpios: true
+        output-high: true
+        output-low: true
+        line-name: true
+
+    - type: object
+      properties:
+        phandle: true
+
+      additionalProperties:
+        $ref: "#/additionalProperties/anyOf/0"
+
+allOf:
+  - $ref: "pinctrl.yaml#"
+
+required:
+  - compatible
+  - reg
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+  - interrupts
+  - clocks
+  - power-domains
+  - resets
+
+examples:
+  - |
+    #include <dt-bindings/pinctrl/rzv2m-pinctrl.h>
+    #include <dt-bindings/clock/r9a09g011-cpg.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    pinctrl: pinctrl@b6250000 {
+            compatible = "renesas,r9a09g011-pinctrl";
+            reg = <0xb6250000 0x800>;
+
+            gpio-controller;
+            #gpio-cells = <2>;
+            gpio-ranges = <&pinctrl 0 0 352>;
+            interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&cpg CPG_MOD R9A09G011_PFC_PCLK>;
+            resets = <&cpg R9A09G011_PFC_PRESETN>;
+            power-domains = <&cpg>;
+
+            i2c2_pins: i2c2 {
+                    pinmux = <RZV2M_PORT_PINMUX(3, 8, 2)>, /* SDA */
+                             <RZV2M_PORT_PINMUX(3, 9, 2)>; /* SCL */
+            };
+    };
index 335ffc1..d35dcc4 100644 (file)
@@ -59,6 +59,7 @@ properties:
 patternProperties:
   '^gpio@[0-9a-f]*$':
     type: object
+    additionalProperties: false
     properties:
       gpio-controller: true
       '#gpio-cells':
@@ -68,8 +69,7 @@ patternProperties:
         maxItems: 1
       clocks:
         maxItems: 1
-      reset:
-        minItems: 1
+      resets:
         maxItems: 1
       gpio-ranges:
         minItems: 1
index d8e75b3..15092fd 100644 (file)
@@ -288,11 +288,14 @@ required:
 
 additionalProperties: false
 
+allOf:
+  - $ref: "pinctrl.yaml#"
+
 examples:
   - |
     #include <dt-bindings/pinctrl/sppctl-sp7021.h>
 
-    pinctl@9c000100 {
+    pinctrl@9c000100 {
         compatible = "sunplus,sp7021-pctl";
         reg = <0x9c000100 0x100>, <0x9c000300 0x100>,
               <0x9c0032e4 0x1c>, <0x9c000080 0x20>;
index 2722dc7..1e2b9b6 100644 (file)
@@ -274,6 +274,10 @@ patternProperties:
           slew-rate:
             enum: [0, 1]
 
+          output-enable:
+            description:
+              This will internally disable the tri-state for MIO pins.
+
           drive-strength:
             description:
               Selects the drive strength for MIO pins, in mA.
index eec3b9c..7e091ea 100644 (file)
@@ -18,6 +18,7 @@ properties:
     enum:
       - mediatek,mt8183-scp
       - mediatek,mt8186-scp
+      - mediatek,mt8188-scp
       - mediatek,mt8192-scp
       - mediatek,mt8195-scp
 
@@ -80,6 +81,7 @@ allOf:
           enum:
             - mediatek,mt8183-scp
             - mediatek,mt8186-scp
+            - mediatek,mt8188-scp
     then:
       properties:
         reg:
index 947f945..3072af5 100644 (file)
@@ -67,13 +67,28 @@ properties:
     minItems: 1
     maxItems: 8
 
+  interconnects:
+    maxItems: 1
+
   interrupts:
     minItems: 5
-    maxItems: 6
+    items:
+      - description: Watchdog interrupt
+      - description: Fatal interrupt
+      - description: Ready interrupt
+      - description: Handover interrupt
+      - description: Stop acknowledge interrupt
+      - description: Shutdown acknowledge interrupt
 
   interrupt-names:
     minItems: 5
-    maxItems: 6
+    items:
+      - const: wdog
+      - const: fatal
+      - const: ready
+      - const: handover
+      - const: stop-ack
+      - const: shutdown-ack
 
   resets:
     minItems: 1
@@ -116,7 +131,6 @@ properties:
       - description: Stop the modem
 
   qcom,smem-state-names:
-    $ref: /schemas/types.yaml#/definitions/string-array
     description: The names of the state bits used for SMP2P output
     items:
       - const: stop
@@ -134,13 +148,13 @@ properties:
       three offsets within syscon for q6, modem and nc halt registers.
 
   smd-edge:
-    type: object
+    $ref: /schemas/remoteproc/qcom,smd-edge.yaml#
     description:
       Qualcomm Shared Memory subnode which represents communication edge,
       channels and devices related to the ADSP.
 
   glink-edge:
-    type: object
+    $ref: /schemas/remoteproc/qcom,glink-edge.yaml#
     description:
       Qualcomm G-Link subnode which represents communication edge, channels
       and devices related to the ADSP.
@@ -315,19 +329,9 @@ allOf:
     then:
       properties:
         interrupts:
-          items:
-            - description: Watchdog interrupt
-            - description: Fatal interrupt
-            - description: Ready interrupt
-            - description: Handover interrupt
-            - description: Stop acknowledge interrupt
+          maxItems: 5
         interrupt-names:
-          items:
-            - const: wdog
-            - const: fatal
-            - const: ready
-            - const: handover
-            - const: stop-ack
+          maxItems: 5
 
   - if:
       properties:
@@ -345,21 +349,9 @@ allOf:
     then:
       properties:
         interrupts:
-          items:
-            - description: Watchdog interrupt
-            - description: Fatal interrupt
-            - description: Ready interrupt
-            - description: Handover interrupt
-            - description: Stop acknowledge interrupt
-            - description: Shutdown acknowledge interrupt
+          minItems: 6
         interrupt-names:
-          items:
-            - const: wdog
-            - const: fatal
-            - const: ready
-            - const: handover
-            - const: stop-ack
-            - const: shutdown-ack
+          minItems: 6
 
   - if:
       properties:
@@ -379,6 +371,8 @@ allOf:
               - qcom,msm8226-adsp-pil
               - qcom,msm8996-adsp-pil
               - qcom,msm8998-adsp-pas
+              - qcom,sm8150-adsp-pas
+              - qcom,sm8150-cdsp-pas
     then:
       properties:
         power-domains:
@@ -442,19 +436,6 @@ allOf:
             - const: cx
             - const: mx
 
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sm8150-adsp-pas
-              - qcom,sm8150-cdsp-pas
-    then:
-      properties:
-        power-domains:
-          items:
-            - description: CX power domain
-
   - if:
       properties:
         compatible:
@@ -594,11 +575,12 @@ allOf:
 examples:
   - |
     #include <dt-bindings/clock/qcom,rpmcc.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
     #include <dt-bindings/interrupt-controller/irq.h>
     adsp {
         compatible = "qcom,msm8974-adsp-pil";
 
-        interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>,
+        interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
                       <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
                       <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
                       <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
@@ -620,7 +602,7 @@ examples:
         qcom,smem-state-names = "stop";
 
         smd-edge {
-            interrupts = <0 156 IRQ_TYPE_EDGE_RISING>;
+            interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
 
             qcom,ipc = <&apcs 8 8>;
             qcom,smd-edge = <1>;
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,glink-edge.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,glink-edge.yaml
new file mode 100644 (file)
index 0000000..fa69f7b
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,glink-edge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm G-Link Edge communication channel nodes
+
+maintainers:
+  - Bjorn Andersson <bjorn.andersson@linaro.org>
+
+description:
+  Qualcomm G-Link subnode represents communication edge, channels and devices
+  related to the remote processor.
+
+properties:
+  $nodename:
+    const: "glink-edge"
+
+  apr:
+    $ref: /schemas/soc/qcom/qcom,apr.yaml#
+    description:
+      Qualcomm APR/GPR (Asynchronous/Generic Packet Router)
+
+  fastrpc:
+    type: object
+    description:
+      See Documentation/devicetree/bindings/misc/qcom,fastrpc.txt
+
+  interrupts:
+    maxItems: 1
+
+  label:
+    description: The names of the state bits used for SMP2P output
+
+  mboxes:
+    maxItems: 1
+
+  qcom,remote-pid:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      ID of the shared memory used by GLINK for communication with remote
+      processor.
+
+required:
+  - interrupts
+  - label
+  - mboxes
+  - qcom,remote-pid
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/mailbox/qcom-ipcc.h>
+
+    remoteproc@8a00000 {
+        reg = <0x08a00000 0x10000>;
+        // ...
+
+        glink-edge {
+            interrupts-extended = <&ipcc IPCC_CLIENT_WPSS
+                                         IPCC_MPROC_SIGNAL_GLINK_QMP
+                                         IRQ_TYPE_EDGE_RISING>;
+            mboxes = <&ipcc IPCC_CLIENT_WPSS
+                            IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+            label = "wpss";
+            qcom,remote-pid = <13>;
+        };
+    };
index 658f96f..d0ebd16 100644 (file)
@@ -14,8 +14,6 @@ on the Qualcomm Hexagon core.
                    "qcom,msm8974-mss-pil"
                    "qcom,msm8996-mss-pil"
                    "qcom,msm8998-mss-pil"
-                   "qcom,sc7180-mss-pil"
-                   "qcom,sc7280-mss-pil"
                    "qcom,sdm845-mss-pil"
 
 - reg:
@@ -47,8 +45,6 @@ on the Qualcomm Hexagon core.
                    must be "wdog", "fatal", "ready", "handover", "stop-ack"
        qcom,msm8996-mss-pil:
        qcom,msm8998-mss-pil:
-       qcom,sc7180-mss-pil:
-       qcom,sc7280-mss-pil:
        qcom,sdm845-mss-pil:
                    must be "wdog", "fatal", "ready", "handover", "stop-ack",
                    "shutdown-ack"
@@ -86,11 +82,6 @@ on the Qualcomm Hexagon core.
        qcom,msm8998-mss-pil:
                    must be "iface", "bus", "mem", "xo", "gpll0_mss",
                    "snoc_axi", "mnoc_axi", "qdss"
-       qcom,sc7180-mss-pil:
-                   must be "iface", "bus", "xo", "snoc_axi", "mnoc_axi",
-                   "nav"
-       qcom,sc7280-mss-pil:
-                   must be "iface", "xo", "snoc_axi", "offline", "pka"
        qcom,sdm845-mss-pil:
                    must be "iface", "bus", "mem", "xo", "gpll0_mss",
                    "snoc_axi", "mnoc_axi", "prng"
@@ -102,7 +93,7 @@ on the Qualcomm Hexagon core.
                    reference to the list of 3 reset-controllers for the
                    wcss sub-system
                    reference to the list of 2 reset-controllers for the modem
-                   sub-system on SC7180, SC7280, SDM845 SoCs
+                   sub-system on SDM845 SoCs
 
 - reset-names:
        Usage: required
@@ -111,7 +102,7 @@ on the Qualcomm Hexagon core.
                    must be "wcss_aon_reset", "wcss_reset", "wcss_q6_reset"
                    for the wcss sub-system
                    must be "mss_restart", "pdc_reset" for the modem
-                   sub-system on SC7180, SC7280, SDM845 SoCs
+                   sub-system on SDM845 SoCs
 
 For devices where the mba and mpss sub-nodes are not specified, mba/mpss region
 should be referenced as follows:
@@ -176,10 +167,6 @@ For the compatible string below the following supplies are required:
        qcom,msm8996-mss-pil:
        qcom,msm8998-mss-pil:
                    must be "cx", "mx"
-       qcom,sc7180-mss-pil:
-                   must be "cx", "mx", "mss"
-       qcom,sc7280-mss-pil:
-                   must be "cx", "mss"
        qcom,sdm845-mss-pil:
                    must be "cx", "mx", "mss"
 
@@ -205,36 +192,6 @@ For the compatible string below the following supplies are required:
        Definition: a phandle reference to a syscon representing TCSR followed
                    by the three offsets within syscon for q6, modem and nc
                    halt registers.
-                   a phandle reference to a syscon representing TCSR followed
-                   by the four offsets within syscon for q6, modem, nc and vq6
-                   halt registers on SC7280 SoCs.
-
-For the compatible strings below the following phandle references are required:
-  "qcom,sc7180-mss-pil"
-- qcom,spare-regs:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: a phandle reference to a syscon representing TCSR followed
-                   by the offset within syscon for conn_box_spare0 register
-                   used by the modem sub-system running on SC7180 SoC.
-
-For the compatible strings below the following phandle references are required:
-  "qcom,sc7280-mss-pil"
-- qcom,ext-regs:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: two phandle references to syscons representing TCSR_REG and
-                   TCSR register space followed by the two offsets within the syscon
-                   to force_clk_en/rscc_disable and axim1_clk_off/crypto_clk_off
-                   registers respectively.
-
-- qcom,qaccept-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 mdm, cx and axi
-                   qaccept registers used by the modem sub-system running on
-                   SC7280 SoC.
 
 The Hexagon node must contain iommus property as described in ../iommu/iommu.txt
 on platforms which do not have TrustZone.
@@ -257,29 +214,23 @@ related to the Hexagon.  See ../soc/qcom/qcom,smd.yaml and
 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>;
+       remoteproc@fc880000 {
+               compatible = "qcom,msm8974-mss-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";
+               interrupts-extended = <&intc GIC_SPI 24 IRQ_TYPE_EDGE_RISING>,
+                                     <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                                     <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                                     <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                                     <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+               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>;
+                        <&gcc GCC_BOOT_ROM_AHB_CLK>,
+                        <&xo_board>;
+               clock-names = "iface", "bus", "mem", "xo";
 
                resets = <&gcc GCC_MSS_RESTART>;
                reset-names = "mss_restart";
@@ -289,6 +240,8 @@ Hexagon, as it is found on MSM8974 boards.
                mx-supply = <&pm8841_s1>;
                pll-supply = <&pm8941_l12>;
 
+               qcom,halt-regs = <&tcsr_mutex_block 0x1180 0x1200 0x1280>;
+
                qcom,smem-states = <&modem_smp2p_out 0>;
                qcom,smem-state-names = "stop";
 
@@ -299,4 +252,13 @@ Hexagon, as it is found on MSM8974 boards.
                mpss {
                        memory-region = <&mpss_region>;
                };
+
+               smd-edge {
+                       interrupts = <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&apcs 8 12>;
+                       qcom,smd-edge = <0>;
+
+                       label = "modem";
+               };
        };
index 31413cf..06f5f93 100644 (file)
@@ -90,7 +90,6 @@ properties:
       - description: Stop the modem
 
   qcom,smem-state-names:
-    $ref: /schemas/types.yaml#/definitions/string
     description: The names of the state bits used for SMP2P output
     items:
       - const: stop
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-mss-pil.yaml
new file mode 100644 (file)
index 0000000..e76c861
--- /dev/null
@@ -0,0 +1,245 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,sc7180-mss-pil.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SC7180 MSS Peripheral Image Loader
+
+maintainers:
+  - Sibi Sankar <quic_sibis@quicinc.com>
+
+description:
+  This document describes the hardware for a component that loads and boots firmware
+  on the Qualcomm Technology Inc. SC7180 Modem Hexagon Core.
+
+properties:
+  compatible:
+    enum:
+      - qcom,sc7180-mss-pil
+
+  reg:
+    items:
+      - description: MSS QDSP6 registers
+      - description: RMB registers
+
+  reg-names:
+    items:
+      - const: qdsp6
+      - const: rmb
+
+  iommus:
+    items:
+      - description: MSA Stream 1
+      - description: MSA Stream 2
+
+  interrupts:
+    items:
+      - description: Watchdog interrupt
+      - description: Fatal interrupt
+      - description: Ready interrupt
+      - description: Handover interrupt
+      - description: Stop acknowledge interrupt
+      - description: Shutdown acknowledge interrupt
+
+  interrupt-names:
+    items:
+      - const: wdog
+      - const: fatal
+      - const: ready
+      - const: handover
+      - const: stop-ack
+      - const: shutdown-ack
+
+  clocks:
+    items:
+      - description: GCC MSS IFACE clock
+      - description: GCC MSS BUS clock
+      - description: GCC MSS NAV clock
+      - description: GCC MSS SNOC_AXI clock
+      - description: GCC MSS MFAB_AXIS clock
+      - description: RPMH XO clock
+
+  clock-names:
+    items:
+      - const: iface
+      - const: bus
+      - const: nav
+      - const: snoc_axi
+      - const: mnoc_axi
+      - const: xo
+
+  power-domains:
+    items:
+      - description: CX power domain
+      - description: MX power domain
+      - description: MSS power domain
+
+  power-domain-names:
+    items:
+      - const: cx
+      - const: mx
+      - const: mss
+
+  resets:
+    items:
+      - description: AOSS restart
+      - description: PDC reset
+
+  reset-names:
+    items:
+      - const: mss_restart
+      - const: pdc_reset
+
+  memory-region:
+    items:
+      - description: MBA reserved region
+      - description: modem reserved region
+
+  firmware-name:
+    $ref: /schemas/types.yaml#/definitions/string-array
+    items:
+      - description: Name of MBA firmware
+      - description: Name of modem firmware
+
+  qcom,halt-regs:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description:
+      Halt registers are used to halt transactions of various sub-components
+      within MSS.
+    items:
+      - items:
+          - description: phandle to TCSR_MUTEX registers
+          - description: offset to the Q6 halt register
+          - description: offset to the modem halt register
+          - description: offset to the nc halt register
+
+  qcom,spare-regs:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description:
+      Spare registers are multipurpose registers used for errata
+      handling.
+    items:
+      - items:
+          - description: phandle to TCSR_MUTEX registers
+          - description: offset to the conn_box_spare0 register
+
+  qcom,qmp:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Reference to the AOSS side-channel message RAM.
+
+  qcom,smem-states:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: States used by the AP to signal the Hexagon core
+    items:
+      - description: Stop the modem
+
+  qcom,smem-state-names:
+    description: The names of the state bits used for SMP2P output
+    const: stop
+
+  glink-edge:
+    $ref: qcom,glink-edge.yaml#
+    description:
+      Qualcomm G-Link subnode which represents communication edge, channels
+      and devices related to the DSP.
+
+    properties:
+      interrupts:
+        items:
+          - description: IRQ from MSS to GLINK
+
+      mboxes:
+        items:
+          - description: Mailbox for communication between APPS and MSS
+
+      label:
+        const: modem
+
+      apr: false
+      fastrpc: false
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - iommus
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - power-domains
+  - power-domain-names
+  - resets
+  - reset-names
+  - qcom,halt-regs
+  - qcom,spare-regs
+  - memory-region
+  - qcom,qmp
+  - qcom,smem-states
+  - qcom,smem-state-names
+  - glink-edge
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sc7180.h>
+    #include <dt-bindings/clock/qcom,rpmh.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/power/qcom-rpmpd.h>
+    #include <dt-bindings/reset/qcom,sdm845-aoss.h>
+    #include <dt-bindings/reset/qcom,sdm845-pdc.h>
+
+    remoteproc_mpss: remoteproc@4080000 {
+        compatible = "qcom,sc7180-mss-pil";
+        reg = <0x04080000 0x10000>, <0x04180000 0x48>;
+        reg-names = "qdsp6", "rmb";
+
+        iommus = <&apps_smmu 0x461 0x0>, <&apps_smmu 0x444 0x3>;
+
+        interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 7 IRQ_TYPE_EDGE_RISING>;
+
+        interrupt-names = "wdog", "fatal", "ready", "handover",
+                          "stop-ack", "shutdown-ack";
+
+        clocks = <&gcc GCC_MSS_CFG_AHB_CLK>,
+                 <&gcc GCC_MSS_Q6_MEMNOC_AXI_CLK>,
+                 <&gcc GCC_MSS_NAV_AXI_CLK>,
+                 <&gcc GCC_MSS_SNOC_AXI_CLK>,
+                 <&gcc GCC_MSS_MFAB_AXIS_CLK>,
+                 <&rpmhcc RPMH_CXO_CLK>;
+        clock-names = "iface", "bus", "nav", "snoc_axi",
+                      "mnoc_axi", "xo";
+
+        power-domains = <&rpmhpd SC7180_CX>,
+                        <&rpmhpd SC7180_MX>,
+                        <&rpmhpd SC7180_MSS>;
+        power-domain-names = "cx", "mx", "mss";
+
+        memory-region = <&mba_mem>, <&mpss_mem>;
+
+        qcom,qmp = <&aoss_qmp>;
+
+        qcom,smem-states = <&modem_smp2p_out 0>;
+        qcom,smem-state-names = "stop";
+
+        resets = <&aoss_reset AOSS_CC_MSS_RESTART>,
+                 <&pdc_reset PDC_MODEM_SYNC_RESET>;
+        reset-names = "mss_restart", "pdc_reset";
+
+        qcom,halt-regs = <&tcsr_mutex_regs 0x23000 0x25000 0x24000>;
+        qcom,spare-regs = <&tcsr_regs 0xb3e4>;
+
+        glink-edge {
+            interrupts = <GIC_SPI 449 IRQ_TYPE_EDGE_RISING>;
+            mboxes = <&apss_shared 12>;
+            qcom,remote-pid = <1>;
+            label = "modem";
+        };
+    };
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-mss-pil.yaml
new file mode 100644 (file)
index 0000000..da1a5de
--- /dev/null
@@ -0,0 +1,266 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,sc7280-mss-pil.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SC7280 MSS Peripheral Image Loader
+
+maintainers:
+  - Sibi Sankar <quic_sibis@quicinc.com>
+
+description:
+  This document describes the hardware for a component that loads and boots firmware
+  on the Qualcomm Technology Inc. SC7280 Modem Hexagon Core.
+
+properties:
+  compatible:
+    enum:
+      - qcom,sc7280-mss-pil
+
+  reg:
+    items:
+      - description: MSS QDSP6 registers
+      - description: RMB registers
+
+  reg-names:
+    items:
+      - const: qdsp6
+      - const: rmb
+
+  iommus:
+    items:
+      - description: MSA Stream 1
+      - description: MSA Stream 2
+
+  interconnects:
+    items:
+      - description: Path leading to system memory
+
+  interrupts:
+    items:
+      - description: Watchdog interrupt
+      - description: Fatal interrupt
+      - description: Ready interrupt
+      - description: Handover interrupt
+      - description: Stop acknowledge interrupt
+      - description: Shutdown acknowledge interrupt
+
+  interrupt-names:
+    items:
+      - const: wdog
+      - const: fatal
+      - const: ready
+      - const: handover
+      - const: stop-ack
+      - const: shutdown-ack
+
+  clocks:
+    items:
+      - description: GCC MSS IFACE clock
+      - description: GCC MSS OFFLINE clock
+      - description: GCC MSS SNOC_AXI clock
+      - description: RPMH PKA clock
+      - description: RPMH XO clock
+
+  clock-names:
+    items:
+      - const: iface
+      - const: offline
+      - const: snoc_axi
+      - const: pka
+      - const: xo
+
+  power-domains:
+    items:
+      - description: CX power domain
+      - description: MSS power domain
+
+  power-domain-names:
+    items:
+      - const: cx
+      - const: mss
+
+  resets:
+    items:
+      - description: AOSS restart
+      - description: PDC reset
+
+  reset-names:
+    items:
+      - const: mss_restart
+      - const: pdc_reset
+
+  memory-region:
+    items:
+      - description: MBA reserved region
+      - description: modem reserved region
+
+  firmware-name:
+    $ref: /schemas/types.yaml#/definitions/string-array
+    items:
+      - description: Name of MBA firmware
+      - description: Name of modem firmware
+
+  qcom,halt-regs:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description:
+      Halt registers are used to halt transactions of various sub-components
+      within MSS.
+    items:
+      - items:
+          - description: phandle to TCSR_MUTEX registers
+          - description: offset to the Q6 halt register
+          - description: offset to the modem halt register
+          - description: offset to the nc halt register
+          - description: offset to the vq6 halt register
+
+  qcom,ext-regs:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: EXT registers are used for various power related functionality
+    items:
+      - items:
+          - description: phandle to TCSR_REG registers
+          - description: offset to the force_clk_en register
+          - description: offset to the rscc_disable register
+      - items:
+          - description: phandle to TCSR_MUTEX registers
+          - description: offset to the axim1_clk_off register
+          - description: offset to the crypto_clk_off register
+
+  qcom,qaccept-regs:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: QACCEPT registers are used to bring up/down Q-channels
+    items:
+      - items:
+          - description: phandle to TCSR_MUTEX registers
+          - description: offset to the mdm qaccept register
+          - description: offset to the cx qaccept register
+          - description: offset to the axi qaccept register
+
+  qcom,qmp:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Reference to the AOSS side-channel message RAM.
+
+  qcom,smem-states:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: States used by the AP to signal the Hexagon core
+    items:
+      - description: Stop the modem
+
+  qcom,smem-state-names:
+    description: The names of the state bits used for SMP2P output
+    const: stop
+
+  glink-edge:
+    $ref: qcom,glink-edge.yaml#
+    description:
+      Qualcomm G-Link subnode which represents communication edge, channels
+      and devices related to the DSP.
+
+    properties:
+      interrupts:
+        items:
+          - description: IRQ from MSS to GLINK
+
+      mboxes:
+        items:
+          - description: Mailbox for communication between APPS and MSS
+
+      label:
+        const: modem
+
+      apr: false
+      fastrpc: false
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - iommus
+  - interconnects
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - power-domains
+  - power-domain-names
+  - resets
+  - reset-names
+  - qcom,halt-regs
+  - qcom,ext-regs
+  - qcom,qaccept-regs
+  - memory-region
+  - qcom,qmp
+  - qcom,smem-states
+  - qcom,smem-state-names
+  - glink-edge
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sc7280.h>
+    #include <dt-bindings/clock/qcom,rpmh.h>
+    #include <dt-bindings/interconnect/qcom,sc7280.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/mailbox/qcom-ipcc.h>
+    #include <dt-bindings/power/qcom-rpmpd.h>
+    #include <dt-bindings/reset/qcom,sdm845-aoss.h>
+    #include <dt-bindings/reset/qcom,sdm845-pdc.h>
+
+    remoteproc_mpss: remoteproc@4080000 {
+        compatible = "qcom,sc7280-mss-pil";
+        reg = <0x04080000 0x10000>, <0x04180000 0x48>;
+        reg-names = "qdsp6", "rmb";
+
+        iommus = <&apps_smmu 0x124 0x0>, <&apps_smmu 0x488 0x7>;
+
+        interconnects = <&mc_virt MASTER_LLCC 0 &mc_virt SLAVE_EBI1 0>;
+
+        interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>,
+                              <&modem_smp2p_in 7 IRQ_TYPE_EDGE_RISING>;
+
+        interrupt-names = "wdog", "fatal", "ready", "handover",
+                          "stop-ack", "shutdown-ack";
+
+        clocks = <&gcc GCC_MSS_CFG_AHB_CLK>,
+                 <&gcc GCC_MSS_OFFLINE_AXI_CLK>,
+                 <&gcc GCC_MSS_SNOC_AXI_CLK>,
+                 <&rpmhcc RPMH_PKA_CLK>,
+                 <&rpmhcc RPMH_CXO_CLK>;
+        clock-names = "iface", "offline", "snoc_axi", "pka", "xo";
+
+        power-domains = <&rpmhpd SC7280_CX>,
+                        <&rpmhpd SC7280_MSS>;
+        power-domain-names = "cx", "mss";
+
+        memory-region = <&mba_mem>, <&mpss_mem>;
+
+        qcom,qmp = <&aoss_qmp>;
+
+        qcom,smem-states = <&modem_smp2p_out 0>;
+        qcom,smem-state-names = "stop";
+
+        resets = <&aoss_reset AOSS_CC_MSS_RESTART>,
+                 <&pdc_reset PDC_MODEM_SYNC_RESET>;
+        reset-names = "mss_restart", "pdc_reset";
+
+        qcom,halt-regs = <&tcsr_mutex 0x23000 0x25000 0x28000 0x33000>;
+        qcom,ext-regs = <&tcsr 0x10000 0x10004>, <&tcsr_mutex 0x26004 0x26008>;
+        qcom,qaccept-regs = <&tcsr_mutex 0x23030 0x23040 0x23020>;
+
+        glink-edge {
+            interrupts-extended = <&ipcc IPCC_CLIENT_MPSS
+                                   IPCC_MPROC_SIGNAL_GLINK_QMP
+                                   IRQ_TYPE_EDGE_RISING>;
+            mboxes = <&ipcc IPCC_CLIENT_MPSS
+                      IPCC_MPROC_SIGNAL_GLINK_QMP>;
+            label = "modem";
+            qcom,remote-pid = <1>;
+        };
+    };
index d99a729..3f06d66 100644 (file)
@@ -76,7 +76,7 @@ properties:
       - const: pdc_sync
 
   memory-region:
-    $ref: /schemas/types.yaml#/definitions/phandle
+    maxItems: 1
     description: Reference to the reserved-memory for the Hexagon core
 
   firmware-name:
@@ -102,13 +102,12 @@ properties:
       - description: Stop the modem
 
   qcom,smem-state-names:
-    $ref: /schemas/types.yaml#/definitions/string
     description: The names of the state bits used for SMP2P output
     const: stop
 
   glink-edge:
-    type: object
-    description: |
+    $ref: qcom,glink-edge.yaml#
+    description:
       Qualcomm G-Link subnode which represents communication edge, channels
       and devices related to the ADSP.
 
@@ -122,21 +121,11 @@ properties:
           - description: Mailbox for communication between APPS and WPSS
 
       label:
-        description: The names of the state bits used for SMP2P output
         items:
           - const: wpss
 
-      qcom,remote-pid:
-        $ref: /schemas/types.yaml#/definitions/uint32
-        description: ID of the shared memory used by GLINK for communication with WPSS
-
-    required:
-      - interrupts
-      - mboxes
-      - label
-      - qcom,remote-pid
-
-    additionalProperties: false
+      apr: false
+      fastrpc: false
 
 required:
   - compatible
index 1535bbb..20df83a 100644 (file)
@@ -90,7 +90,6 @@ properties:
       - description: Stop the modem
 
   qcom,smem-state-names:
-    $ref: /schemas/types.yaml#/definitions/string
     description: The names of the state bits used for SMP2P output
     items:
       - const: stop
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,smd-edge.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,smd-edge.yaml
new file mode 100644 (file)
index 0000000..06eebf7
--- /dev/null
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,smd-edge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SMD Edge communication channel nodes
+
+maintainers:
+  - Bjorn Andersson <bjorn.andersson@linaro.org>
+
+description:
+  Qualcomm SMD subnode represents a remote subsystem or a remote processor of
+  some sort - or in SMD language an "edge". The name of the edges are not
+  important.
+  See also Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml
+
+properties:
+  $nodename:
+    const: "smd-edge"
+
+  interrupts:
+    maxItems: 1
+
+  label:
+    description:
+      Name of the edge, used for debugging and identification purposes. The
+      node name will be used if this is not present.
+
+  mboxes:
+    maxItems: 1
+    description:
+      Reference to the mailbox representing the outgoing doorbell in APCS for
+      this client.
+
+  qcom,ipc:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle to a syscon node representing the APCS registers
+          - description: u32 representing offset to the register within the syscon
+          - description: u32 representing the ipc bit within the register
+    description:
+      Three entries specifying the outgoing ipc bit used for signaling the
+      remote processor.
+
+  qcom,smd-edge:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The identifier of the remote processor in the smd channel allocation
+      table.
+
+  qcom,remote-pid:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The identifier for the remote processor as known by the rest of the
+      system.
+
+required:
+  - interrupts
+  - qcom,smd-edge
+
+oneOf:
+  - required:
+      - mboxes
+  - required:
+      - qcom,ipc
+
+additionalProperties: true
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/mailbox/qcom-ipcc.h>
+
+    remoteproc {
+        // ...
+
+        smd-edge {
+            interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+
+            qcom,ipc = <&apcs 8 8>;
+            qcom,smd-edge = <1>;
+        };
+    };
index d7c3a78..cd55d80 100644 (file)
@@ -36,17 +36,18 @@ properties:
     enum:
       - ti,am3356-pru   # for AM335x SoC family (AM3356+ SoCs only)
       - ti,am4376-pru   # for AM437x SoC family (AM4376+ SoCs only)
+      - ti,am5728-pru   # for AM57xx SoC family
+      - ti,am625-pru    # for PRUs in K3 AM62x SoC family
       - ti,am642-pru    # for PRUs in K3 AM64x SoC family
       - ti,am642-rtu    # for RTUs in K3 AM64x SoC family
       - ti,am642-tx-pru # for Tx_PRUs in K3 AM64x SoC family
-      - ti,am5728-pru   # for AM57xx SoC family
-      - ti,k2g-pru      # for 66AK2G SoC family
       - ti,am654-pru    # for PRUs in K3 AM65x SoC family
       - ti,am654-rtu    # for RTUs in K3 AM65x SoC family
       - ti,am654-tx-pru # for Tx_PRUs in K3 AM65x SR2.0 SoCs
       - ti,j721e-pru    # for PRUs in K3 J721E SoC family
       - ti,j721e-rtu    # for RTUs in K3 J721E SoC family
       - ti,j721e-tx-pru # for Tx_PRUs in K3 J721E SoC family
+      - ti,k2g-pru      # for 66AK2G SoC family
 
   reg:
     items:
index bca07bb..62bebb5 100644 (file)
@@ -28,44 +28,6 @@ patternProperties:
       edges are not important.
 
     properties:
-      interrupts:
-        maxItems: 1
-
-      label:
-        $ref: /schemas/types.yaml#/definitions/string
-        description:
-          Name of the edge, used for debugging and identification purposes. The
-          node name will be used if this is not present.
-
-      mboxes:
-        maxItems: 1
-        description:
-          Reference to the mailbox representing the outgoing doorbell in APCS for
-          this client.
-
-      qcom,ipc:
-        $ref: /schemas/types.yaml#/definitions/phandle-array
-        items:
-          - items:
-              - description: phandle to a syscon node representing the APCS registers
-              - description: u32 representing offset to the register within the syscon
-              - description: u32 representing the ipc bit within the register
-        description:
-          Three entries specifying the outgoing ipc bit used for signaling the
-          remote processor.
-
-      qcom,smd-edge:
-        $ref: /schemas/types.yaml#/definitions/uint32
-        description:
-          The identifier of the remote processor in the smd channel allocation
-          table.
-
-      qcom,remote-pid:
-        $ref: /schemas/types.yaml#/definitions/uint32
-        description:
-          The identifier for the remote processor as known by the rest of the
-          system.
-
       rpm-requests:
         type: object
         description:
@@ -89,17 +51,7 @@ patternProperties:
 
         additionalProperties: true
 
-    required:
-      - interrupts
-      - qcom,smd-edge
-
-    oneOf:
-      - required:
-          - mboxes
-      - required:
-          - qcom,ipc
-
-    additionalProperties: false
+    unevaluatedProperties: false
 
 required:
   - compatible
index 2bd6b4a..d8ac0be 100644 (file)
@@ -24,6 +24,7 @@ properties:
               - qcom,apss-wdt-sc8280xp
               - qcom,apss-wdt-sdm845
               - qcom,apss-wdt-sdx55
+              - qcom,apss-wdt-sdx65
               - qcom,apss-wdt-sm6350
               - qcom,apss-wdt-sm8150
               - qcom,apss-wdt-sm8250
index 11b220a..099245f 100644 (file)
@@ -29,6 +29,7 @@ properties:
       - realtek,rtl8380-wdt
       - realtek,rtl8390-wdt
       - realtek,rtl9300-wdt
+      - realtek,rtl9310-wdt
 
   reg:
     maxItems: 1
index db476bb..5149ecd 100644 (file)
@@ -362,6 +362,14 @@ CXL Core
 .. kernel-doc:: drivers/cxl/core/mbox.c
    :doc: cxl mbox
 
+CXL Regions
+-----------
+.. kernel-doc:: drivers/cxl/core/region.c
+   :doc: cxl core region
+
+.. kernel-doc:: drivers/cxl/core/region.c
+   :identifiers:
+
 External Interfaces
 ===================
 
index eb9c2d9..17779a2 100644 (file)
@@ -169,6 +169,13 @@ configuration of fault-injection capabilities.
        default is 'N', setting it to 'Y' will disable disconnect
        injection on the RPC server.
 
+- /sys/kernel/debug/fail_sunrpc/ignore-cache-wait:
+
+       Format: { 'Y' | 'N' }
+
+       default is 'N', setting it to 'Y' will disable cache wait
+       injection on the RPC server.
+
 - /sys/kernel/debug/fail_function/inject:
 
        Format: { 'function-name' | '!function-name' | '' }
index a717384..7fb3986 100644 (file)
@@ -672,7 +672,7 @@ Future kconfig work
 Work on kconfig is welcomed on both areas of clarifying semantics and on
 evaluating the use of a full SAT solver for it. A full SAT solver can be
 desirable to enable more complex dependency mappings and / or queries,
-for instance on possible use case for a SAT solver could be that of handling
+for instance one possible use case for a SAT solver could be that of handling
 the current known recursive dependency issues. It is not known if this would
 address such issues but such evaluation is desirable. If support for a full SAT
 solver proves too complex or that it cannot address recursive dependency issues
index 32f51b6..9b6c0f0 100644 (file)
@@ -1390,10 +1390,14 @@ F:      include/uapi/linux/apm_bios.h
 
 APPARMOR SECURITY MODULE
 M:     John Johansen <john.johansen@canonical.com>
-L:     apparmor@lists.ubuntu.com (subscribers-only, general discussion)
+M:     John Johansen <john@apparmor.net>
+L:     apparmor@lists.ubuntu.com (moderated for non-subscribers)
 S:     Supported
-W:     wiki.apparmor.net
+W:     apparmor.net
+B:     https://gitlab.com/apparmor/apparmor-kernel
+C:     irc://irc.oftc.net/apparmor
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
+T:     https://gitlab.com/apparmor/apparmor-kernel.git
 F:     Documentation/admin-guide/LSM/apparmor.rst
 F:     security/apparmor/
 
@@ -4783,7 +4787,6 @@ L:        keyrings@vger.kernel.org
 S:     Maintained
 F:     Documentation/admin-guide/module-signing.rst
 F:     certs/
-F:     scripts/check-blacklist-hashes.awk
 F:     scripts/sign-file.c
 F:     tools/certs/
 
@@ -11063,6 +11066,7 @@ R:      Sergey Senozhatsky <senozhatsky@chromium.org>
 L:     linux-cifs@vger.kernel.org
 S:     Maintained
 T:     git git://git.samba.org/ksmbd.git
+F:     Documentation/filesystems/cifs/ksmbd.rst
 F:     fs/ksmbd/
 F:     fs/smbfs_common/
 
@@ -13745,6 +13749,7 @@ S:      Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next
 F:     include/linux/module.h
 F:     kernel/module/
+F:     scripts/module*
 
 MONOLITHIC POWER SYSTEM PMIC DRIVER
 M:     Saravanan Sekar <sravanhome@gmail.com>
@@ -16056,6 +16061,7 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
 F:     Documentation/devicetree/bindings/pinctrl/
 F:     Documentation/driver-api/pin-control.rst
 F:     drivers/pinctrl/
+F:     include/dt-bindings/pinctrl/
 F:     include/linux/pinctrl/
 
 PIN CONTROLLER - AMD
index dc6295f..60a7e3e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -129,6 +129,9 @@ endif
 $(if $(word 2, $(KBUILD_EXTMOD)), \
        $(error building multiple external modules is not supported))
 
+$(foreach x, % :, $(if $(findstring $x, $(KBUILD_EXTMOD)), \
+       $(error module directory path cannot contain '$x')))
+
 # Remove trailing slashes
 ifneq ($(filter %/, $(KBUILD_EXTMOD)),)
 KBUILD_EXTMOD := $(shell dirname $(KBUILD_EXTMOD).)
@@ -755,8 +758,6 @@ KBUILD_CFLAGS       += $(call cc-disable-warning, address-of-packed-member)
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
 KBUILD_CFLAGS += -O2
-else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
-KBUILD_CFLAGS += -O3
 else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
 KBUILD_CFLAGS += -Os
 endif
@@ -1370,16 +1371,21 @@ endif
 
 ifneq ($(dtstree),)
 
-%.dtb: include/config/kernel.release scripts_dtc
+%.dtb: dtbs_prepare
        $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
 
-%.dtbo: include/config/kernel.release scripts_dtc
+%.dtbo: dtbs_prepare
        $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
 
-PHONY += dtbs dtbs_install dtbs_check
-dtbs: include/config/kernel.release scripts_dtc
+PHONY += dtbs dtbs_prepare dtbs_install dtbs_check
+dtbs: dtbs_prepare
        $(Q)$(MAKE) $(build)=$(dtstree)
 
+# include/config/kernel.release is actually needed when installing DTBs because
+# INSTALL_DTBS_PATH contains $(KERNELRELEASE). However, we do not want to make
+# dtbs_install depend on it as dtbs_install may run as root.
+dtbs_prepare: include/config/kernel.release scripts_dtc
+
 ifneq ($(filter dtbs_check, $(MAKECMDGOALS)),)
 export CHECK_DTBS=y
 dtbs: dt_binding_check
index 0016149..e31a8eb 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
index 5b03158..e0e8567 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
index d4eec39..fcbc952 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
index 7337cdf..d87ad7e 100644 (file)
@@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_EXPERT=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_COMPAT_BRK is not set
index bc92722..8d82cdb 100644 (file)
@@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
index aa00007..f856b03 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_RAM=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
index 326f6cd..a1ce12b 100644 (file)
@@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
index bf39a00..ca10f4a 100644 (file)
@@ -10,7 +10,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
index 7121bd7..31b6ec3 100644 (file)
@@ -10,7 +10,6 @@ CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
index f9863b2..41a0037 100644 (file)
@@ -8,7 +8,6 @@ CONFIG_IKCONFIG_PROC=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_KPROBES=y
index a12656e..d93b650 100644 (file)
@@ -14,7 +14,6 @@ CONFIG_INITRAMFS_SOURCE="../tb10x-rootfs.cpio"
 CONFIG_INITRAMFS_ROOT_UID=2100
 CONFIG_INITRAMFS_ROOT_GID=501
 # CONFIG_RD_GZIP is not set
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_AIO is not set
 CONFIG_EMBEDDED=y
index d7c858d..0c3b214 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
index 015c1d4..f9ad9d3 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/arm/boot/dts/imxrt1170-pinfunc.h b/arch/arm/boot/dts/imxrt1170-pinfunc.h
new file mode 100644 (file)
index 0000000..3b9fff2
--- /dev/null
@@ -0,0 +1,1561 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2021
+ * Author(s): Jesse Taube <Mr.Bossman075@gmail.com>
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_IMXRT1170_PINFUNC_H
+#define _DT_BINDINGS_PINCTRL_IMXRT1170_PINFUNC_H
+
+#define IMX_PAD_SION           0x40000000
+
+/*
+ * The pin function ID is a tuple of
+ * <mux_reg conf_reg input_reg mux_mode input_val>
+ */
+
+#define IOMUXC_GPIO_LPSR_00_FLEXCAN3_TX                                0x000 0x040 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_00_MIC_CLK                            0x000 0x040 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_00_MQS_RIGHT                          0x000 0x040 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_00_ARM_CM4_EVENTO                     0x000 0x040 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_00_GPIO_MUX6_IO00                     0x000 0x040 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_00_LPUART12_TXD                       0x000 0x040 0x0B0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_00_SAI4_MCLK                          0x000 0x040 0x0C8 0x7 0x0
+#define IOMUXC_GPIO_LPSR_00_GPIO12_IO00                                0x000 0x040 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_01_FLEXCAN3_RX                                0x004 0x044 0x080 0x0 0x0
+#define IOMUXC_GPIO_LPSR_01_MIC_BITSTREAM0                     0x004 0x044 0x0B4 0x1 0x0
+#define IOMUXC_GPIO_LPSR_01_MQS_LEFT                           0x004 0x044 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_01_ARM_CM4_EVENTI                     0x004 0x044 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_01_GPIO_MUX6_IO01                     0x004 0x044 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_01_LPUART12_RXD                       0x004 0x044 0x0AC 0x6 0x0
+#define IOMUXC_GPIO_LPSR_01_GPIO12_IO01                                0x004 0x044 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_02_GPIO12_IO02                                0x008 0x048 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_02_SRC_BOOT_MODE00                    0x008 0x048 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_02_LPSPI5_SCK                         0x008 0x048 0x098 0x1 0x0
+#define IOMUXC_GPIO_LPSR_02_SAI4_TX_DATA                       0x008 0x048 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_02_MQS_RIGHT                          0x008 0x048 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_02_GPIO_MUX6_IO02                     0x008 0x048 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_LPSR_03_SRC_BOOT_MODE01                    0x00C 0x04C 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_03_LPSPI5_PCS0                                0x00C 0x04C 0x094 0x1 0x0
+#define IOMUXC_GPIO_LPSR_03_SAI4_TX_SYNC                       0x00C 0x04C 0x0DC 0x2 0x0
+#define IOMUXC_GPIO_LPSR_03_MQS_LEFT                           0x00C 0x04C 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_03_GPIO_MUX6_IO03                     0x00C 0x04C 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_03_GPIO12_IO03                                0x00C 0x04C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_04_LPI2C5_SDA                         0x010 0x050 0x088 0x0 0x0
+#define IOMUXC_GPIO_LPSR_04_LPSPI5_SOUT                                0x010 0x050 0x0A0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_04_SAI4_TX_BCLK                       0x010 0x050 0x0D8 0x2 0x0
+#define IOMUXC_GPIO_LPSR_04_LPUART12_RTS_B                     0x010 0x050 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_04_GPIO_MUX6_IO04                     0x010 0x050 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_04_LPUART11_TXD                       0x010 0x050 0x0A8 0x6 0x0
+#define IOMUXC_GPIO_LPSR_04_GPIO12_IO04                                0x010 0x050 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_05_GPIO12_IO05                                0x014 0x054 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_05_LPI2C5_SCL                         0x014 0x054 0x084 0x0 0x0
+#define IOMUXC_GPIO_LPSR_05_LPSPI5_SIN                         0x014 0x054 0x09C 0x1 0x0
+#define IOMUXC_GPIO_LPSR_05_SAI4_MCLK                          0x014 0x054 0x0C8 0x2 0x1
+#define IOMUXC_GPIO_LPSR_05_LPUART12_CTS_B                     0x014 0x054 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_05_GPIO_MUX6_IO05                     0x014 0x054 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_05_LPUART11_RXD                       0x014 0x054 0x0A4 0x6 0x0
+#define IOMUXC_GPIO_LPSR_05_NMI_GLUE_NMI                       0x014 0x054 0x0C4 0x7 0x0
+
+#define IOMUXC_GPIO_LPSR_06_LPI2C6_SDA                         0x018 0x058 0x090 0x0 0x0
+#define IOMUXC_GPIO_LPSR_06_SAI4_RX_DATA                       0x018 0x058 0x0D0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_06_LPUART12_TXD                       0x018 0x058 0x0B0 0x3 0x1
+#define IOMUXC_GPIO_LPSR_06_LPSPI6_PCS3                                0x018 0x058 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_06_GPIO_MUX6_IO06                     0x018 0x058 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_06_FLEXCAN3_TX                                0x018 0x058 0x0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_06_PIT2_TRIGGER3                      0x018 0x058 0x0 0x7 0x0
+#define IOMUXC_GPIO_LPSR_06_LPSPI5_PCS1                                0x018 0x058 0x0 0x8 0x0
+#define IOMUXC_GPIO_LPSR_06_GPIO12_IO06                                0x018 0x058 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_07_LPI2C6_SCL                         0x01C 0x05C 0x08C 0x0 0x0
+#define IOMUXC_GPIO_LPSR_07_SAI4_RX_BCLK                       0x01C 0x05C 0x0CC 0x2 0x0
+#define IOMUXC_GPIO_LPSR_07_LPUART12_RXD                       0x01C 0x05C 0x0AC 0x3 0x1
+#define IOMUXC_GPIO_LPSR_07_LPSPI6_PCS2                                0x01C 0x05C 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_07_GPIO_MUX6_IO07                     0x01C 0x05C 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_07_FLEXCAN3_RX                                0x01C 0x05C 0x080 0x6 0x1
+#define IOMUXC_GPIO_LPSR_07_PIT2_TRIGGER2                      0x01C 0x05C 0x0 0x7 0x0
+#define IOMUXC_GPIO_LPSR_07_LPSPI5_PCS2                                0x01C 0x05C 0x0 0x8 0x0
+#define IOMUXC_GPIO_LPSR_07_GPIO12_IO07                                0x01C 0x05C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_08_GPIO12_IO08                                0x020 0x060 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_08_LPUART11_TXD                       0x020 0x060 0x0A8 0x0 0x1
+#define IOMUXC_GPIO_LPSR_08_FLEXCAN3_TX                                0x020 0x060 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_08_SAI4_RX_SYNC                       0x020 0x060 0x0D4 0x2 0x0
+#define IOMUXC_GPIO_LPSR_08_MIC_CLK                            0x020 0x060 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_08_LPSPI6_PCS1                                0x020 0x060 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_08_GPIO_MUX6_IO08                     0x020 0x060 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_08_LPI2C5_SDA                         0x020 0x060 0x088 0x6 0x1
+#define IOMUXC_GPIO_LPSR_08_PIT2_TRIGGER1                      0x020 0x060 0x0 0x7 0x0
+#define IOMUXC_GPIO_LPSR_08_LPSPI5_PCS3                                0x020 0x060 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_LPSR_09_GPIO12_IO09                                0x024 0x064 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_09_LPUART11_RXD                       0x024 0x064 0x0A4 0x0 0x1
+#define IOMUXC_GPIO_LPSR_09_FLEXCAN3_RX                                0x024 0x064 0x080 0x1 0x2
+#define IOMUXC_GPIO_LPSR_09_PIT2_TRIGGER0                      0x024 0x064 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_09_MIC_BITSTREAM0                     0x024 0x064 0x0B4 0x3 0x1
+#define IOMUXC_GPIO_LPSR_09_LPSPI6_PCS0                                0x024 0x064 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_09_GPIO_MUX6_IO09                     0x024 0x064 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_09_LPI2C5_SCL                         0x024 0x064 0x084 0x6 0x1
+#define IOMUXC_GPIO_LPSR_09_SAI4_TX_DATA                       0x024 0x064 0x0 0x7 0x0
+
+#define IOMUXC_GPIO_LPSR_10_GPIO12_IO10                                0x028 0x068 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_10_JTAG_MUX_TRSTB                     0x028 0x068 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_10_LPUART11_CTS_B                     0x028 0x068 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_10_LPI2C6_SDA                         0x028 0x068 0x090 0x2 0x1
+#define IOMUXC_GPIO_LPSR_10_MIC_BITSTREAM1                     0x028 0x068 0x0B8 0x3 0x0
+#define IOMUXC_GPIO_LPSR_10_LPSPI6_SCK                         0x028 0x068 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_10_GPIO_MUX6_IO10                     0x028 0x068 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_10_LPI2C5_SCLS                                0x028 0x068 0x0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_10_SAI4_TX_SYNC                       0x028 0x068 0x0DC 0x7 0x1
+#define IOMUXC_GPIO_LPSR_10_LPUART12_TXD                       0x028 0x068 0x0B0 0x8 0x2
+
+#define IOMUXC_GPIO_LPSR_11_JTAG_MUX_TDO                       0x02C 0x06C 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_11_LPUART11_RTS_B                     0x02C 0x06C 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_11_LPI2C6_SCL                         0x02C 0x06C 0x08C 0x2 0x1
+#define IOMUXC_GPIO_LPSR_11_MIC_BITSTREAM2                     0x02C 0x06C 0x0BC 0x3 0x0
+#define IOMUXC_GPIO_LPSR_11_LPSPI6_SOUT                                0x02C 0x06C 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_11_GPIO_MUX6_IO11                     0x02C 0x06C 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_11_LPI2C5_SDAS                                0x02C 0x06C 0x0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_11_ARM_TRACE_SWO                      0x02C 0x06C 0x0 0x7 0x0
+#define IOMUXC_GPIO_LPSR_11_LPUART12_RXD                       0x02C 0x06C 0x0AC 0x8 0x2
+#define IOMUXC_GPIO_LPSR_11_GPIO12_IO11                                0x02C 0x06C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_12_GPIO12_IO12                                0x030 0x070 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_12_JTAG_MUX_TDI                       0x030 0x070 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_12_PIT2_TRIGGER0                      0x030 0x070 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_12_MIC_BITSTREAM3                     0x030 0x070 0x0C0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_12_LPSPI6_SIN                         0x030 0x070 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_12_GPIO_MUX6_IO12                     0x030 0x070 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_12_LPI2C5_HREQ                                0x030 0x070 0x0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_12_SAI4_TX_BCLK                       0x030 0x070 0x0D8 0x7 0x1
+#define IOMUXC_GPIO_LPSR_12_LPSPI5_SCK                         0x030 0x070 0x098 0x8 0x1
+
+#define IOMUXC_GPIO_LPSR_13_GPIO12_IO13                                0x034 0x074 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_13_JTAG_MUX_MOD                       0x034 0x074 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_13_MIC_BITSTREAM1                     0x034 0x074 0x0B8 0x1 0x1
+#define IOMUXC_GPIO_LPSR_13_PIT2_TRIGGER1                      0x034 0x074 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_13_GPIO_MUX6_IO13                     0x034 0x074 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_13_SAI4_RX_DATA                       0x034 0x074 0x0D0 0x7 0x1
+#define IOMUXC_GPIO_LPSR_13_LPSPI5_PCS0                                0x034 0x074 0x094 0x8 0x1
+
+#define IOMUXC_GPIO_LPSR_14_JTAG_MUX_TCK                       0x038 0x078 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_14_MIC_BITSTREAM2                     0x038 0x078 0x0BC 0x1 0x1
+#define IOMUXC_GPIO_LPSR_14_PIT2_TRIGGER2                      0x038 0x078 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_14_GPIO_MUX6_IO14                     0x038 0x078 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_14_SAI4_RX_BCLK                       0x038 0x078 0x0CC 0x7 0x1
+#define IOMUXC_GPIO_LPSR_14_LPSPI5_SOUT                                0x038 0x078 0x0A0 0x8 0x1
+#define IOMUXC_GPIO_LPSR_14_GPIO12_IO14                                0x038 0x078 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_15_GPIO12_IO15                                0x03C 0x07C 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_15_JTAG_MUX_TMS                       0x03C 0x07C 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_15_MIC_BITSTREAM3                     0x03C 0x07C 0x0C0 0x1 0x1
+#define IOMUXC_GPIO_LPSR_15_PIT2_TRIGGER3                      0x03C 0x07C 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_15_GPIO_MUX6_IO15                     0x03C 0x07C 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_15_SAI4_RX_SYNC                       0x03C 0x07C 0x0D4 0x7 0x1
+#define IOMUXC_GPIO_LPSR_15_LPSPI5_SIN                         0x03C 0x07C 0x09C 0x8 0x1
+
+#define IOMUXC_WAKEUP_DIG_GPIO13_IO00                          0x40C94000 0x40C94040 0x0 0x5 0x0
+#define IOMUXC_WAKEUP_DIG_NMI_GLUE_NMI                         0x40C94000 0x40C94040 0x0C4 0x7 0x1
+
+#define IOMUXC_PMIC_ON_REQ_DIG_SNVS_LP_PMIC_ON_REQ             0x40C94004 0x40C94044 0x0 0x0 0x0
+#define IOMUXC_PMIC_ON_REQ_DIG_GPIO13_IO01                     0x40C94004 0x40C94044 0x0 0x5 0x0
+
+#define IOMUXC_PMIC_STBY_REQ_DIG_CCM_PMIC_VSTBY_REQ            0x40C94008 0x40C94048 0x0 0x0 0x0
+#define IOMUXC_PMIC_STBY_REQ_DIG_GPIO13_IO02                   0x40C94008 0x40C94048 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_00_DIG_SNVS_TAMPER0                   0x40C9400C 0x40C9404C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_00_DIG_GPIO13_IO03                    0x40C9400C 0x40C9404C 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_01_DIG_SNVS_TAMPER1                   0x40C94010 0x40C94050 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_01_DIG_GPIO13_IO04                    0x40C94010 0x40C94050 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_02_DIG_SNVS_TAMPER2                   0x40C94014 0x40C94054 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_02_DIG_GPIO13_IO05                    0x40C94014 0x40C94054 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_03_DIG_SNVS_TAMPER3                   0x40C94018 0x40C94058 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_03_DIG_GPIO13_IO06                    0x40C94018 0x40C94058 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_04_DIG_SNVS_TAMPER4                   0x40C9401C 0x40C9405C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_04_DIG_GPIO13_IO07                    0x40C9401C 0x40C9405C 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_05_DIG_SNVS_TAMPER5                   0x40C94020 0x40C94060 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_05_DIG_GPIO13_IO08                    0x40C94020 0x40C94060 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_06_DIG_SNVS_TAMPER6                   0x40C94024 0x40C94064 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_06_DIG_GPIO13_IO09                    0x40C94024 0x40C94064 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_07_DIG_SNVS_TAMPER7                   0x40C94028 0x40C94068 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_07_DIG_GPIO13_IO10                    0x40C94028 0x40C94068 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_08_DIG_SNVS_TAMPER8                   0x40C9402C 0x40C9406C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_08_DIG_GPIO13_IO11                    0x40C9402C 0x40C9406C 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_09_DIG_SNVS_TAMPER9                   0x40C94030 0x40C94070 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_09_DIG_GPIO13_IO12                    0x40C94030 0x40C94070 0x0 0x5 0x0
+
+#define IOMUXC_TEST_MODE_DIG                                   0x0 0x40C94034 0x0 0x0 0x0
+
+#define IOMUXC_POR_B_DIG                                       0x0 0x40C94038 0x0 0x0 0x0
+
+#define IOMUXC_ONOFF_DIG                                       0x0 0x40C9403C 0x0 0x0 0x0
+
+#define IOMUXC_GPIO_EMC_B1_00_SEMC_DATA00                      0x010 0x254 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_00_FLEXPWM4_PWM0_A                  0x010 0x254 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_00_GPIO_MUX1_IO00                   0x010 0x254 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_00_FLEXIO1_D00                      0x010 0x254 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_00_GPIO7_IO00                       0x010 0x254 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_01_GPIO7_IO01                       0x014 0x258 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_01_SEMC_DATA01                      0x014 0x258 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_01_FLEXPWM4_PWM0_B                  0x014 0x258 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_01_GPIO_MUX1_IO01                   0x014 0x258 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_01_FLEXIO1_D01                      0x014 0x258 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_02_SEMC_DATA02                      0x018 0x25C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_02_FLEXPWM4_PWM1_A                  0x018 0x25C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_02_GPIO_MUX1_IO02                   0x018 0x25C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_02_FLEXIO1_D02                      0x018 0x25C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_02_GPIO7_IO02                       0x018 0x25C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_03_SEMC_DATA03                      0x01C 0x260 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_03_FLEXPWM4_PWM1_B                  0x01C 0x260 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_03_GPIO_MUX1_IO03                   0x01C 0x260 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_03_FLEXIO1_D03                      0x01C 0x260 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_03_GPIO7_IO03                       0x01C 0x260 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_04_GPIO7_IO04                       0x020 0x264 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_04_SEMC_DATA04                      0x020 0x264 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_04_FLEXPWM4_PWM2_A                  0x020 0x264 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_04_GPIO_MUX1_IO04                   0x020 0x264 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_04_FLEXIO1_D04                      0x020 0x264 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_05_SEMC_DATA05                      0x024 0x268 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_05_FLEXPWM4_PWM2_B                  0x024 0x268 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_05_GPIO_MUX1_IO05                   0x024 0x268 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_05_FLEXIO1_D05                      0x024 0x268 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_05_GPIO7_IO05                       0x024 0x268 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_06_SEMC_DATA06                      0x028 0x26C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_06_FLEXPWM2_PWM0_A                  0x028 0x26C 0x518 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_06_GPIO_MUX1_IO06                   0x028 0x26C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_06_FLEXIO1_D06                      0x028 0x26C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_06_GPIO7_IO06                       0x028 0x26C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_07_GPIO7_IO07                       0x02C 0x270 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_07_SEMC_DATA07                      0x02C 0x270 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_07_FLEXPWM2_PWM0_B                  0x02C 0x270 0x524 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_07_GPIO_MUX1_IO07                   0x02C 0x270 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_07_FLEXIO1_D07                      0x02C 0x270 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_08_SEMC_DM00                                0x030 0x274 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_08_FLEXPWM2_PWM1_A                  0x030 0x274 0x51C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_08_GPIO_MUX1_IO08                   0x030 0x274 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_08_FLEXIO1_D08                      0x030 0x274 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_08_GPIO7_IO08                       0x030 0x274 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_09_SEMC_ADDR00                      0x034 0x278 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_09_FLEXPWM2_PWM1_B                  0x034 0x278 0x528 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_09_GPT5_CAPTURE1                    0x034 0x278 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_09_GPIO_MUX1_IO09                   0x034 0x278 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_09_FLEXIO1_D09                      0x034 0x278 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_09_GPIO7_IO09                       0x034 0x278 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_10_SEMC_ADDR01                      0x038 0x27C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_10_FLEXPWM2_PWM2_A                  0x038 0x27C 0x520 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_10_GPT5_CAPTURE2                    0x038 0x27C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_10_GPIO_MUX1_IO10                   0x038 0x27C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_10_FLEXIO1_D10                      0x038 0x27C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_10_GPIO7_IO10                       0x038 0x27C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_11_GPIO7_IO11                       0x03C 0x280 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_11_SEMC_ADDR02                      0x03C 0x280 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_11_FLEXPWM2_PWM2_B                  0x03C 0x280 0x52C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_11_GPT5_COMPARE1                    0x03C 0x280 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_11_GPIO_MUX1_IO11                   0x03C 0x280 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_11_FLEXIO1_D11                      0x03C 0x280 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_12_SEMC_ADDR03                      0x040 0x284 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_12_XBAR1_INOUT04                    0x040 0x284 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_12_GPT5_COMPARE2                    0x040 0x284 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_12_GPIO_MUX1_IO12                   0x040 0x284 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_12_FLEXIO1_D12                      0x040 0x284 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_12_GPIO7_IO12                       0x040 0x284 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_13_SEMC_ADDR04                      0x044 0x288 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_13_XBAR1_INOUT05                    0x044 0x288 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_13_GPT5_COMPARE3                    0x044 0x288 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_13_GPIO_MUX1_IO13                   0x044 0x288 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_13_FLEXIO1_D13                      0x044 0x288 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_13_GPIO7_IO13                       0x044 0x288 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_14_GPIO7_IO14                       0x048 0x28C 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_14_SEMC_ADDR05                      0x048 0x28C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_14_XBAR1_INOUT06                    0x048 0x28C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_14_GPT5_CLK                         0x048 0x28C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_14_GPIO_MUX1_IO14                   0x048 0x28C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_14_FLEXIO1_D14                      0x048 0x28C 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_15_SEMC_ADDR06                      0x04C 0x290 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_15_XBAR1_INOUT07                    0x04C 0x290 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_15_GPIO_MUX1_IO15                   0x04C 0x290 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_15_FLEXIO1_D15                      0x04C 0x290 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_15_GPIO7_IO15                       0x04C 0x290 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_16_SEMC_ADDR07                      0x050 0x294 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_16_XBAR1_INOUT08                    0x050 0x294 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_16_GPIO_MUX1_IO16                   0x050 0x294 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_16_FLEXIO1_D16                      0x050 0x294 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_16_GPIO7_IO16                       0x050 0x294 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_17_GPIO7_IO17                       0x054 0x298 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_17_SEMC_ADDR08                      0x054 0x298 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_17_FLEXPWM4_PWM3_A                  0x054 0x298 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_17_TMR1_TIMER0                      0x054 0x298 0x63C 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_17_GPIO_MUX1_IO17                   0x054 0x298 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_17_FLEXIO1_D17                      0x054 0x298 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_18_SEMC_ADDR09                      0x058 0x29C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_18_FLEXPWM4_PWM3_B                  0x058 0x29C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_18_TMR2_TIMER0                      0x058 0x29C 0x648 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_18_GPIO_MUX1_IO18                   0x058 0x29C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_18_FLEXIO1_D18                      0x058 0x29C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_18_GPIO7_IO18                       0x058 0x29C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_19_SEMC_ADDR11                      0x05C 0x2A0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_19_FLEXPWM2_PWM3_A                  0x05C 0x2A0 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_19_TMR3_TIMER0                      0x05C 0x2A0 0x654 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_19_GPIO_MUX1_IO19                   0x05C 0x2A0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_19_FLEXIO1_D19                      0x05C 0x2A0 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_19_GPIO7_IO19                       0x05C 0x2A0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_20_SEMC_ADDR12                      0x060 0x2A4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_20_FLEXPWM2_PWM3_B                  0x060 0x2A4 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_20_TMR4_TIMER0                      0x060 0x2A4 0x660 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_20_GPIO_MUX1_IO20                   0x060 0x2A4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_20_FLEXIO1_D20                      0x060 0x2A4 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_20_GPIO7_IO20                       0x060 0x2A4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_21_GPIO7_IO21                       0x064 0x2A8 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_21_SEMC_BA0                         0x064 0x2A8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_21_FLEXPWM3_PWM3_A                  0x064 0x2A8 0x53C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_21_GPIO_MUX1_IO21                   0x064 0x2A8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_21_FLEXIO1_D21                      0x064 0x2A8 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_22_GPIO7_IO22                       0x068 0x2AC 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_22_SEMC_BA1                         0x068 0x2AC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_22_FLEXPWM3_PWM3_B                  0x068 0x2AC 0x54C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_22_GPIO_MUX1_IO22                   0x068 0x2AC 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_22_FLEXIO1_D22                      0x068 0x2AC 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_23_SEMC_ADDR10                      0x06C 0x2B0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_23_FLEXPWM1_PWM0_A                  0x06C 0x2B0 0x500 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_23_GPIO_MUX1_IO23                   0x06C 0x2B0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_23_FLEXIO1_D23                      0x06C 0x2B0 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_23_GPIO7_IO23                       0x06C 0x2B0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_24_GPIO7_IO24                       0x070 0x2B4 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_24_SEMC_CAS                         0x070 0x2B4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_24_FLEXPWM1_PWM0_B                  0x070 0x2B4 0x50C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_24_GPIO_MUX1_IO24                   0x070 0x2B4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_24_FLEXIO1_D24                      0x070 0x2B4 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_25_GPIO7_IO25                       0x074 0x2B8 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_25_SEMC_RAS                         0x074 0x2B8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_25_FLEXPWM1_PWM1_A                  0x074 0x2B8 0x504 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_25_GPIO_MUX1_IO25                   0x074 0x2B8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_25_FLEXIO1_D25                      0x074 0x2B8 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_26_SEMC_CLK                         0x078 0x2BC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_26_FLEXPWM1_PWM1_B                  0x078 0x2BC 0x510 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_26_GPIO_MUX1_IO26                   0x078 0x2BC 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_26_FLEXIO1_D26                      0x078 0x2BC 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_26_GPIO7_IO26                       0x078 0x2BC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_27_GPIO7_IO27                       0x07C 0x2C0 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_27_SEMC_CKE                         0x07C 0x2C0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_27_FLEXPWM1_PWM2_A                  0x07C 0x2C0 0x508 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_27_GPIO_MUX1_IO27                   0x07C 0x2C0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_27_FLEXIO1_D27                      0x07C 0x2C0 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_28_GPIO7_IO28                       0x080 0x2C4 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_28_SEMC_WE                          0x080 0x2C4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_28_FLEXPWM1_PWM2_B                  0x080 0x2C4 0x514 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_28_GPIO_MUX1_IO28                   0x080 0x2C4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_28_FLEXIO1_D28                      0x080 0x2C4 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_29_SEMC_CS0                         0x084 0x2C8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_29_FLEXPWM3_PWM0_A                  0x084 0x2C8 0x530 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_29_GPIO_MUX1_IO29                   0x084 0x2C8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_29_FLEXIO1_D29                      0x084 0x2C8 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_29_GPIO7_IO29                       0x084 0x2C8 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_30_SEMC_DATA08                      0x088 0x2CC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_30_FLEXPWM3_PWM0_B                  0x088 0x2CC 0x540 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_30_GPIO_MUX1_IO30                   0x088 0x2CC 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_30_FLEXIO1_D30                      0x088 0x2CC 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_30_GPIO7_IO30                       0x088 0x2CC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_31_GPIO7_IO31                       0x08C 0x2D0 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_31_SEMC_DATA09                      0x08C 0x2D0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_31_FLEXPWM3_PWM1_A                  0x08C 0x2D0 0x534 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_31_GPIO_MUX1_IO31                   0x08C 0x2D0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_31_FLEXIO1_D31                      0x08C 0x2D0 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_32_GPIO8_IO00                       0x090 0x2D4 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_32_SEMC_DATA10                      0x090 0x2D4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_32_FLEXPWM3_PWM1_B                  0x090 0x2D4 0x544 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_32_GPIO_MUX2_IO00                   0x090 0x2D4 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_33_SEMC_DATA11                      0x094 0x2D8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_33_FLEXPWM3_PWM2_A                  0x094 0x2D8 0x538 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_33_GPIO_MUX2_IO01                   0x094 0x2D8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_33_GPIO8_IO01                       0x094 0x2D8 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_34_GPIO8_IO02                       0x098 0x2DC 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_34_SEMC_DATA12                      0x098 0x2DC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_34_FLEXPWM3_PWM2_B                  0x098 0x2DC 0x548 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_34_GPIO_MUX2_IO02                   0x098 0x2DC 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_35_GPIO8_IO03                       0x09C 0x2E0 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_35_SEMC_DATA13                      0x09C 0x2E0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_35_XBAR1_INOUT09                    0x09C 0x2E0 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_35_GPIO_MUX2_IO03                   0x09C 0x2E0 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_36_SEMC_DATA14                      0x0A0 0x2E4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_36_XBAR1_INOUT10                    0x0A0 0x2E4 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_36_GPIO_MUX2_IO04                   0x0A0 0x2E4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_36_GPIO8_IO04                       0x0A0 0x2E4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_37_GPIO8_IO05                       0x0A4 0x2E8 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_37_SEMC_DATA15                      0x0A4 0x2E8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_37_XBAR1_INOUT11                    0x0A4 0x2E8 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_37_GPIO_MUX2_IO05                   0x0A4 0x2E8 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_38_GPIO8_IO06                       0x0A8 0x2EC 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_38_SEMC_DM01                                0x0A8 0x2EC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_38_FLEXPWM1_PWM3_A                  0x0A8 0x2EC 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_38_TMR1_TIMER1                      0x0A8 0x2EC 0x640 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_38_GPIO_MUX2_IO06                   0x0A8 0x2EC 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_39_SEMC_DQS                         0x0AC 0x2F0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_39_FLEXPWM1_PWM3_B                  0x0AC 0x2F0 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_39_TMR2_TIMER1                      0x0AC 0x2F0 0x64C 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_39_GPIO_MUX2_IO07                   0x0AC 0x2F0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_39_GPIO8_IO07                       0x0AC 0x2F0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_40_SEMC_RDY                         0x0B0 0x2F4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_40_XBAR1_INOUT12                    0x0B0 0x2F4 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_40_MQS_RIGHT                                0x0B0 0x2F4 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_40_LPUART6_TXD                      0x0B0 0x2F4 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B1_40_GPIO_MUX2_IO08                   0x0B0 0x2F4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_40_ENET_1G_MDC                      0x0B0 0x2F4 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B1_40_CCM_CLKO1                                0x0B0 0x2F4 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B1_40_GPIO8_IO08                       0x0B0 0x2F4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_41_GPIO8_IO09                       0x0B4 0x2F8 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_41_SEMC_CSX00                       0x0B4 0x2F8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_41_XBAR1_INOUT13                    0x0B4 0x2F8 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_41_MQS_LEFT                         0x0B4 0x2F8 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_41_LPUART6_RXD                      0x0B4 0x2F8 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B1_41_FLEXSPI2_B_DATA07                        0x0B4 0x2F8 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B1_41_GPIO_MUX2_IO09                   0x0B4 0x2F8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_41_ENET_1G_MDIO                     0x0B4 0x2F8 0x4C8 0x7 0x0
+#define IOMUXC_GPIO_EMC_B1_41_CCM_CLKO2                                0x0B4 0x2F8 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_EMC_B2_00_SEMC_DATA16                      0x0B8 0x2FC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_00_CCM_ENET_REF_CLK_25M             0x0B8 0x2FC 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_00_TMR3_TIMER1                      0x0B8 0x2FC 0x658 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_00_LPUART6_CTS_B                    0x0B8 0x2FC 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_00_FLEXSPI2_B_DATA06                        0x0B8 0x2FC 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_00_GPIO_MUX2_IO10                   0x0B8 0x2FC 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_00_XBAR1_INOUT20                    0x0B8 0x2FC 0x6D8 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_00_ENET_QOS_1588_EVENT1_OUT         0x0B8 0x2FC 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_00_LPSPI1_SCK                       0x0B8 0x2FC 0x5D0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_00_LPI2C2_SCL                       0x0B8 0x2FC 0x5B4 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_00_GPIO8_IO10                       0x0B8 0x2FC 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_00_FLEXPWM3_PWM0_A                  0x0B8 0x2FC 0x530 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_01_SEMC_DATA17                      0x0BC 0x300 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_01_USDHC2_CD_B                      0x0BC 0x300 0x6D0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_01_TMR4_TIMER1                      0x0BC 0x300 0x664 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_01_LPUART6_RTS_B                    0x0BC 0x300 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_01_FLEXSPI2_B_DATA05                        0x0BC 0x300 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_01_GPIO_MUX2_IO11                   0x0BC 0x300 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_01_XBAR1_INOUT21                    0x0BC 0x300 0x6DC 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_01_ENET_QOS_1588_EVENT1_IN          0x0BC 0x300 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_01_LPSPI1_PCS0                      0x0BC 0x300 0x5CC 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_01_LPI2C2_SDA                       0x0BC 0x300 0x5B8 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_01_GPIO8_IO11                       0x0BC 0x300 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_01_FLEXPWM3_PWM0_B                  0x0BC 0x300 0x540 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_02_SEMC_DATA18                      0x0C0 0x304 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_02_USDHC2_WP                                0x0C0 0x304 0x6D4 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_02_VIDEO_MUX_CSI_DATA23             0x0C0 0x304 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_02_FLEXSPI2_B_DATA04                        0x0C0 0x304 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_02_GPIO_MUX2_IO12                   0x0C0 0x304 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_02_XBAR1_INOUT22                    0x0C0 0x304 0x6E0 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_02_ENET_QOS_1588_EVENT1_AUX_IN      0x0C0 0x304 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_02_LPSPI1_SOUT                      0x0C0 0x304 0x5D8 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_02_GPIO8_IO12                       0x0C0 0x304 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_02_FLEXPWM3_PWM1_A                  0x0C0 0x304 0x534 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_03_SEMC_DATA19                      0x0C4 0x308 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_03_USDHC2_VSELECT                   0x0C4 0x308 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_03_VIDEO_MUX_CSI_DATA22             0x0C4 0x308 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_03_FLEXSPI2_B_DATA03                        0x0C4 0x308 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_03_GPIO_MUX2_IO13                   0x0C4 0x308 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_03_XBAR1_INOUT23                    0x0C4 0x308 0x6E4 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_03_ENET_1G_TX_DATA03                        0x0C4 0x308 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_03_LPSPI1_SIN                       0x0C4 0x308 0x5D4 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_03_GPIO8_IO13                       0x0C4 0x308 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_03_FLEXPWM3_PWM1_B                  0x0C4 0x308 0x544 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_04_SEMC_DATA20                      0x0C8 0x30C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_04_USDHC2_RESET_B                   0x0C8 0x30C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_04_SAI2_MCLK                                0x0C8 0x30C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_04_VIDEO_MUX_CSI_DATA21             0x0C8 0x30C 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_04_FLEXSPI2_B_DATA02                        0x0C8 0x30C 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_04_GPIO_MUX2_IO14                   0x0C8 0x30C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_04_XBAR1_INOUT24                    0x0C8 0x30C 0x6E8 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_04_ENET_1G_TX_DATA02                        0x0C8 0x30C 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_04_LPSPI3_SCK                       0x0C8 0x30C 0x600 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_04_GPIO8_IO14                       0x0C8 0x30C 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_04_FLEXPWM3_PWM2_A                  0x0C8 0x30C 0x538 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_05_SEMC_DATA21                      0x0CC 0x310 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_05_GPT3_CLK                         0x0CC 0x310 0x598 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_05_SAI2_RX_SYNC                     0x0CC 0x310 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_05_VIDEO_MUX_CSI_DATA20             0x0CC 0x310 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_05_FLEXSPI2_B_DATA01                        0x0CC 0x310 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_05_GPIO_MUX2_IO15                   0x0CC 0x310 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_05_XBAR1_INOUT25                    0x0CC 0x310 0x6EC 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_05_ENET_1G_RX_CLK                   0x0CC 0x310 0x4CC 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_05_LPSPI3_PCS0                      0x0CC 0x310 0x5F0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_05_PIT1_TRIGGER0                    0x0CC 0x310 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_05_GPIO8_IO15                       0x0CC 0x310 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_05_FLEXPWM3_PWM2_B                  0x0CC 0x310 0x548 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_06_SEMC_DATA22                      0x0D0 0x314 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_06_GPT3_CAPTURE1                    0x0D0 0x314 0x590 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_06_GPIO8_IO16                       0x0D0 0x314 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_06_SAI2_RX_BCLK                     0x0D0 0x314 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_06_FLEXPWM3_PWM3_A                  0x0D0 0x314 0x53C 0xB 0x1
+#define IOMUXC_GPIO_EMC_B2_06_VIDEO_MUX_CSI_DATA19             0x0D0 0x314 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_06_FLEXSPI2_B_DATA00                        0x0D0 0x314 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_06_GPIO_MUX2_IO16                   0x0D0 0x314 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_06_XBAR1_INOUT26                    0x0D0 0x314 0x6F0 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_06_ENET_1G_TX_ER                    0x0D0 0x314 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_06_LPSPI3_SOUT                      0x0D0 0x314 0x608 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_06_PIT1_TRIGGER1                    0x0D0 0x314 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_EMC_B2_07_SEMC_DATA23                      0x0D4 0x318 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_07_GPT3_CAPTURE2                    0x0D4 0x318 0x594 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_07_SAI2_RX_DATA                     0x0D4 0x318 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_07_VIDEO_MUX_CSI_DATA18             0x0D4 0x318 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_07_FLEXSPI2_B_DQS                   0x0D4 0x318 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_07_GPIO_MUX2_IO17                   0x0D4 0x318 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_07_XBAR1_INOUT27                    0x0D4 0x318 0x6F4 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_07_ENET_1G_RX_DATA03                        0x0D4 0x318 0x4DC 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_07_LPSPI3_SIN                       0x0D4 0x318 0x604 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_07_PIT1_TRIGGER2                    0x0D4 0x318 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_07_GPIO8_IO17                       0x0D4 0x318 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_07_FLEXPWM3_PWM3_B                  0x0D4 0x318 0x54C 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_08_SEMC_DM02                                0x0D8 0x31C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_08_GPT3_COMPARE1                    0x0D8 0x31C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_08_SAI2_TX_DATA                     0x0D8 0x31C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_08_VIDEO_MUX_CSI_DATA17             0x0D8 0x31C 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_08_FLEXSPI2_B_SS0_B                 0x0D8 0x31C 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_08_GPIO_MUX2_IO18                   0x0D8 0x31C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_08_XBAR1_INOUT28                    0x0D8 0x31C 0x6F8 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_08_ENET_1G_RX_DATA02                        0x0D8 0x31C 0x4D8 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_08_LPSPI3_PCS1                      0x0D8 0x31C 0x5F4 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_08_PIT1_TRIGGER3                    0x0D8 0x31C 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_08_GPIO8_IO18                       0x0D8 0x31C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_09_GPIO8_IO19                       0x0DC 0x320 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_09_SEMC_DATA24                      0x0DC 0x320 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_09_GPT3_COMPARE2                    0x0DC 0x320 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_09_SAI2_TX_BCLK                     0x0DC 0x320 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_09_VIDEO_MUX_CSI_DATA16             0x0DC 0x320 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_09_FLEXSPI2_B_SCLK                  0x0DC 0x320 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_09_GPIO_MUX2_IO19                   0x0DC 0x320 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_09_XBAR1_INOUT29                    0x0DC 0x320 0x6FC 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_09_ENET_1G_CRS                      0x0DC 0x320 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_09_LPSPI3_PCS2                      0x0DC 0x320 0x5F8 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_09_TMR1_TIMER0                      0x0DC 0x320 0x63C 0x9 0x1
+
+#define IOMUXC_GPIO_EMC_B2_10_GPIO8_IO20                       0x0E0 0x324 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_10_SEMC_DATA25                      0x0E0 0x324 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_10_GPT3_COMPARE3                    0x0E0 0x324 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_10_SAI2_TX_SYNC                     0x0E0 0x324 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_10_VIDEO_MUX_CSI_FIELD              0x0E0 0x324 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_10_FLEXSPI2_A_SCLK                  0x0E0 0x324 0x58C 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_10_GPIO_MUX2_IO20                   0x0E0 0x324 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_10_XBAR1_INOUT30                    0x0E0 0x324 0x700 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_10_ENET_1G_COL                      0x0E0 0x324 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_10_LPSPI3_PCS3                      0x0E0 0x324 0x5FC 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_10_TMR1_TIMER1                      0x0E0 0x324 0x640 0x9 0x1
+
+#define IOMUXC_GPIO_EMC_B2_11_SEMC_DATA26                      0x0E4 0x328 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_11_SPDIF_IN                         0x0E4 0x328 0x6B4 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_11_ENET_1G_TX_DATA00                        0x0E4 0x328 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_11_SAI3_RX_SYNC                     0x0E4 0x328 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_11_FLEXSPI2_A_SS0_B                 0x0E4 0x328 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_11_GPIO_MUX2_IO21                   0x0E4 0x328 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_11_XBAR1_INOUT31                    0x0E4 0x328 0x704 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_11_EMVSIM1_IO                       0x0E4 0x328 0x69C 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_11_TMR1_TIMER2                      0x0E4 0x328 0x644 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_11_GPIO8_IO21                       0x0E4 0x328 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_12_SEMC_DATA27                      0x0E8 0x32C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_12_SPDIF_OUT                                0x0E8 0x32C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_12_ENET_1G_TX_DATA01                        0x0E8 0x32C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_12_SAI3_RX_BCLK                     0x0E8 0x32C 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_12_FLEXSPI2_A_DQS                   0x0E8 0x32C 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_12_GPIO_MUX2_IO22                   0x0E8 0x32C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_12_XBAR1_INOUT32                    0x0E8 0x32C 0x708 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_12_EMVSIM1_CLK                      0x0E8 0x32C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_12_TMR1_TIMER3                      0x0E8 0x32C 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_12_GPIO8_IO22                       0x0E8 0x32C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_13_GPIO8_IO23                       0x0EC 0x330 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_13_SEMC_DATA28                      0x0EC 0x330 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_13_ENET_1G_TX_EN                    0x0EC 0x330 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_13_SAI3_RX_DATA                     0x0EC 0x330 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_13_FLEXSPI2_A_DATA00                        0x0EC 0x330 0x57C 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_13_GPIO_MUX2_IO23                   0x0EC 0x330 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_13_XBAR1_INOUT33                    0x0EC 0x330 0x70C 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_13_EMVSIM1_RST                      0x0EC 0x330 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_13_TMR2_TIMER0                      0x0EC 0x330 0x648 0x9 0x1
+
+#define IOMUXC_GPIO_EMC_B2_14_SEMC_DATA29                      0x0F0 0x334 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_14_ENET_1G_TX_CLK_IO                        0x0F0 0x334 0x4E8 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_14_SAI3_TX_DATA                     0x0F0 0x334 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_14_FLEXSPI2_A_DATA01                        0x0F0 0x334 0x580 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_14_GPIO_MUX2_IO24                   0x0F0 0x334 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_14_XBAR1_INOUT34                    0x0F0 0x334 0x710 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_14_SFA_ipp_do_atx_clk_under_test    0x0F0 0x334 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_14_EMVSIM1_SVEN                     0x0F0 0x334 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_14_TMR2_TIMER1                      0x0F0 0x334 0x64C 0x9 0x1
+#define IOMUXC_GPIO_EMC_B2_14_GPIO8_IO24                       0x0F0 0x334 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_15_SEMC_DATA30                      0x0F4 0x338 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_15_ENET_1G_RX_DATA00                        0x0F4 0x338 0x4D0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_15_SAI3_TX_BCLK                     0x0F4 0x338 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_15_FLEXSPI2_A_DATA02                        0x0F4 0x338 0x584 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_15_GPIO_MUX2_IO25                   0x0F4 0x338 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_15_XBAR1_INOUT35                    0x0F4 0x338 0x714 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_15_EMVSIM1_PD                       0x0F4 0x338 0x6A0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_15_TMR2_TIMER2                      0x0F4 0x338 0x650 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_15_GPIO8_IO25                       0x0F4 0x338 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_16_GPIO8_IO26                       0x0F8 0x33C 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_16_SEMC_DATA31                      0x0F8 0x33C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_16_XBAR1_INOUT14                    0x0F8 0x33C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_16_ENET_1G_RX_DATA01                        0x0F8 0x33C 0x4D4 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_16_SAI3_TX_SYNC                     0x0F8 0x33C 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_16_FLEXSPI2_A_DATA03                        0x0F8 0x33C 0x588 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_16_GPIO_MUX2_IO26                   0x0F8 0x33C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_16_EMVSIM1_POWER_FAIL               0x0F8 0x33C 0x6A4 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_16_TMR2_TIMER3                      0x0F8 0x33C 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_EMC_B2_17_SEMC_DM03                                0x0FC 0x340 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_17_XBAR1_INOUT15                    0x0FC 0x340 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_17_ENET_1G_RX_EN                    0x0FC 0x340 0x4E0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_17_SAI3_MCLK                                0x0FC 0x340 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_17_FLEXSPI2_A_DATA04                        0x0FC 0x340 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_17_GPIO_MUX2_IO27                   0x0FC 0x340 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_17_WDOG1_ANY                                0x0FC 0x340 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_17_TMR3_TIMER0                      0x0FC 0x340 0x654 0x9 0x1
+#define IOMUXC_GPIO_EMC_B2_17_GPIO8_IO27                       0x0FC 0x340 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_18_SEMC_DQS4                                0x100 0x344 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_18_XBAR1_INOUT16                    0x100 0x344 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_18_ENET_1G_RX_ER                    0x100 0x344 0x4E4 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_18_EWM_OUT_B                                0x100 0x344 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_18_FLEXSPI2_A_DATA05                        0x100 0x344 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_18_GPIO_MUX2_IO28                   0x100 0x344 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_18_FLEXSPI1_A_DQS                   0x100 0x344 0x550 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_18_WDOG1_B                          0x100 0x344 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_18_TMR3_TIMER1                      0x100 0x344 0x658 0x9 0x1
+#define IOMUXC_GPIO_EMC_B2_18_GPIO8_IO28                       0x100 0x344 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_19_GPIO8_IO29                       0x104 0x348 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_19_SEMC_CLKX00                      0x104 0x348 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_19_ENET_MDC                         0x104 0x348 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_19_ENET_1G_MDC                      0x104 0x348 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_19_ENET_1G_REF_CLK                  0x104 0x348 0x4C4 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_19_FLEXSPI2_A_DATA06                        0x104 0x348 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_19_GPIO_MUX2_IO29                   0x104 0x348 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_19_ENET_QOS_MDC                     0x104 0x348 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_19_TMR3_TIMER2                      0x104 0x348 0x65C 0x9 0x0
+
+#define IOMUXC_GPIO_EMC_B2_20_GPIO8_IO30                       0x108 0x34C 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_20_SEMC_CLKX01                      0x108 0x34C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_20_ENET_MDIO                                0x108 0x34C 0x4AC 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_20_ENET_1G_MDIO                     0x108 0x34C 0x4C8 0x2 0x1
+#define IOMUXC_GPIO_EMC_B2_20_ENET_QOS_REF_CLK                 0x108 0x34C 0x4A0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_20_FLEXSPI2_A_DATA07                        0x108 0x34C 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_20_GPIO_MUX2_IO30                   0x108 0x34C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_20_ENET_QOS_MDIO                    0x108 0x34C 0x4EC 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_20_TMR3_TIMER3                      0x108 0x34C 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_00_GPIO8_IO31                           0x10C 0x350 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_00_EMVSIM1_IO                           0x10C 0x350 0x69C 0x0 0x1
+#define IOMUXC_GPIO_AD_00_FLEXCAN2_TX                          0x10C 0x350 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_00_ENET_1G_1588_EVENT1_IN               0x10C 0x350 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_00_GPT2_CAPTURE1                                0x10C 0x350 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_00_FLEXPWM1_PWM0_A                      0x10C 0x350 0x500 0x4 0x1
+#define IOMUXC_GPIO_AD_00_GPIO_MUX2_IO31                       0x10C 0x350 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_00_LPUART7_TXD                          0x10C 0x350 0x630 0x6 0x0
+#define IOMUXC_GPIO_AD_00_FLEXIO2_D00                          0x10C 0x350 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_00_FLEXSPI2_B_SS1_B                     0x10C 0x350 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_01_GPIO9_IO00                           0x110 0x354 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_01_EMVSIM1_CLK                          0x110 0x354 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_01_FLEXCAN2_RX                          0x110 0x354 0x49C 0x1 0x0
+#define IOMUXC_GPIO_AD_01_ENET_1G_1588_EVENT1_OUT              0x110 0x354 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_01_GPT2_CAPTURE2                                0x110 0x354 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_01_FLEXPWM1_PWM0_B                      0x110 0x354 0x50C 0x4 0x1
+#define IOMUXC_GPIO_AD_01_GPIO_MUX3_IO00                       0x110 0x354 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_01_LPUART7_RXD                          0x110 0x354 0x62C 0x6 0x0
+#define IOMUXC_GPIO_AD_01_FLEXIO2_D01                          0x110 0x354 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_01_FLEXSPI2_A_SS1_B                     0x110 0x354 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_02_GPIO9_IO01                           0x114 0x358 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_02_EMVSIM1_RST                          0x114 0x358 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_02_LPUART7_CTS_B                                0x114 0x358 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_02_ENET_1G_1588_EVENT2_IN               0x114 0x358 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_02_GPT2_COMPARE1                                0x114 0x358 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_02_FLEXPWM1_PWM1_A                      0x114 0x358 0x504 0x4 0x1
+#define IOMUXC_GPIO_AD_02_GPIO_MUX3_IO01                       0x114 0x358 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_02_LPUART8_TXD                          0x114 0x358 0x638 0x6 0x0
+#define IOMUXC_GPIO_AD_02_FLEXIO2_D02                          0x114 0x358 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_02_VIDEO_MUX_EXT_DCIC1                  0x114 0x358 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_03_GPIO9_IO02                           0x118 0x35C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_03_EMVSIM1_SVEN                         0x118 0x35C 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_03_LPUART7_RTS_B                                0x118 0x35C 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_03_ENET_1G_1588_EVENT2_OUT              0x118 0x35C 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_03_GPT2_COMPARE2                                0x118 0x35C 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_03_FLEXPWM1_PWM1_B                      0x118 0x35C 0x510 0x4 0x1
+#define IOMUXC_GPIO_AD_03_GPIO_MUX3_IO02                       0x118 0x35C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_03_LPUART8_RXD                          0x118 0x35C 0x634 0x6 0x0
+#define IOMUXC_GPIO_AD_03_FLEXIO2_D03                          0x118 0x35C 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_03_VIDEO_MUX_EXT_DCIC2                  0x118 0x35C 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_04_EMVSIM1_PD                           0x11C 0x360 0x6A0 0x0 0x1
+#define IOMUXC_GPIO_AD_04_LPUART8_CTS_B                                0x11C 0x360 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_04_ENET_1G_1588_EVENT3_IN               0x11C 0x360 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_04_GPT2_COMPARE3                                0x11C 0x360 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_04_FLEXPWM1_PWM2_A                      0x11C 0x360 0x508 0x4 0x1
+#define IOMUXC_GPIO_AD_04_GPIO_MUX3_IO03                       0x11C 0x360 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_04_WDOG1_B                              0x11C 0x360 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_04_FLEXIO2_D04                          0x11C 0x360 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_04_TMR4_TIMER0                          0x11C 0x360 0x660 0x9 0x1
+#define IOMUXC_GPIO_AD_04_GPIO9_IO03                           0x11C 0x360 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_05_EMVSIM1_POWER_FAIL                   0x120 0x364 0x6A4 0x0 0x1
+#define IOMUXC_GPIO_AD_05_LPUART8_RTS_B                                0x120 0x364 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_05_ENET_1G_1588_EVENT3_OUT              0x120 0x364 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_05_GPT2_CLK                             0x120 0x364 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_05_FLEXPWM1_PWM2_B                      0x120 0x364 0x514 0x4 0x1
+#define IOMUXC_GPIO_AD_05_GPIO_MUX3_IO04                       0x120 0x364 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_05_WDOG2_B                              0x120 0x364 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_05_FLEXIO2_D05                          0x120 0x364 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_05_TMR4_TIMER1                          0x120 0x364 0x664 0x9 0x1
+#define IOMUXC_GPIO_AD_05_GPIO9_IO04                           0x120 0x364 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_06_USB_OTG2_OC                          0x124 0x368 0x6B8 0x0 0x0
+#define IOMUXC_GPIO_AD_06_FLEXCAN1_TX                          0x124 0x368 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_06_EMVSIM2_IO                           0x124 0x368 0x6A8 0x2 0x0
+#define IOMUXC_GPIO_AD_06_GPT3_CAPTURE1                                0x124 0x368 0x590 0x3 0x1
+#define IOMUXC_GPIO_AD_06_VIDEO_MUX_CSI_DATA15                 0x124 0x368 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_06_GPIO_MUX3_IO05                       0x124 0x368 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_06_ENET_1588_EVENT1_IN                  0x124 0x368 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_06_FLEXIO2_D06                          0x124 0x368 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_06_TMR4_TIMER2                          0x124 0x368 0x668 0x9 0x0
+#define IOMUXC_GPIO_AD_06_GPIO9_IO05                           0x124 0x368 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_06_FLEXPWM1_PWM0_X                      0x124 0x368 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_07_USB_OTG2_PWR                         0x128 0x36C 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_07_FLEXCAN1_RX                          0x128 0x36C 0x498 0x1 0x0
+#define IOMUXC_GPIO_AD_07_EMVSIM2_CLK                          0x128 0x36C 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_07_GPT3_CAPTURE2                                0x128 0x36C 0x594 0x3 0x1
+#define IOMUXC_GPIO_AD_07_VIDEO_MUX_CSI_DATA14                 0x128 0x36C 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_07_GPIO_MUX3_IO06                       0x128 0x36C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_07_ENET_1588_EVENT1_OUT                 0x128 0x36C 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_07_FLEXIO2_D07                          0x128 0x36C 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_07_TMR4_TIMER3                          0x128 0x36C 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_07_GPIO9_IO06                           0x128 0x36C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_07_FLEXPWM1_PWM1_X                      0x128 0x36C 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_08_USBPHY2_OTG_ID                       0x12C 0x370 0x6C4 0x0 0x0
+#define IOMUXC_GPIO_AD_08_LPI2C1_SCL                           0x12C 0x370 0x5AC 0x1 0x0
+#define IOMUXC_GPIO_AD_08_EMVSIM2_RST                          0x12C 0x370 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_08_GPT3_COMPARE1                                0x12C 0x370 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_08_VIDEO_MUX_CSI_DATA13                 0x12C 0x370 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_08_GPIO_MUX3_IO07                       0x12C 0x370 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_08_ENET_1588_EVENT2_IN                  0x12C 0x370 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_08_FLEXIO2_D08                          0x12C 0x370 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_08_GPIO9_IO07                           0x12C 0x370 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_08_FLEXPWM1_PWM2_X                      0x12C 0x370 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_09_USBPHY1_OTG_ID                       0x130 0x374 0x6C0 0x0 0x0
+#define IOMUXC_GPIO_AD_09_LPI2C1_SDA                           0x130 0x374 0x5B0 0x1 0x0
+#define IOMUXC_GPIO_AD_09_EMVSIM2_SVEN                         0x130 0x374 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_09_GPT3_COMPARE2                                0x130 0x374 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_09_VIDEO_MUX_CSI_DATA12                 0x130 0x374 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_09_GPIO_MUX3_IO08                       0x130 0x374 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_09_ENET_1588_EVENT2_OUT                 0x130 0x374 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_09_FLEXIO2_D09                          0x130 0x374 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_09_GPIO9_IO08                           0x130 0x374 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_09_FLEXPWM1_PWM3_X                      0x130 0x374 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_10_USB_OTG1_PWR                         0x134 0x378 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_10_LPI2C1_SCLS                          0x134 0x378 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_10_EMVSIM2_PD                           0x134 0x378 0x6AC 0x2 0x0
+#define IOMUXC_GPIO_AD_10_GPT3_COMPARE3                                0x134 0x378 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_10_VIDEO_MUX_CSI_DATA11                 0x134 0x378 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_10_GPIO_MUX3_IO09                       0x134 0x378 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_10_ENET_1588_EVENT3_IN                  0x134 0x378 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_10_FLEXIO2_D10                          0x134 0x378 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_10_GPIO9_IO09                           0x134 0x378 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_10_FLEXPWM2_PWM0_X                      0x134 0x378 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_11_USB_OTG1_OC                          0x138 0x37C 0x6BC 0x0 0x0
+#define IOMUXC_GPIO_AD_11_LPI2C1_SDAS                          0x138 0x37C 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_11_EMVSIM2_POWER_FAIL                   0x138 0x37C 0x6B0 0x2 0x0
+#define IOMUXC_GPIO_AD_11_GPT3_CLK                             0x138 0x37C 0x598 0x3 0x1
+#define IOMUXC_GPIO_AD_11_VIDEO_MUX_CSI_DATA10                 0x138 0x37C 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_11_GPIO_MUX3_IO10                       0x138 0x37C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_11_ENET_1588_EVENT3_OUT                 0x138 0x37C 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_11_FLEXIO2_D11                          0x138 0x37C 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_11_GPIO9_IO10                           0x138 0x37C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_11_FLEXPWM2_PWM1_X                      0x138 0x37C 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_12_SPDIF_LOCK                           0x13C 0x380 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_12_LPI2C1_HREQ                          0x13C 0x380 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_12_GPT1_CAPTURE1                                0x13C 0x380 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_12_FLEXSPI1_B_DATA03                    0x13C 0x380 0x570 0x3 0x0
+#define IOMUXC_GPIO_AD_12_VIDEO_MUX_CSI_PIXCLK                 0x13C 0x380 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_12_GPIO_MUX3_IO11                       0x13C 0x380 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_12_ENET_TX_DATA03                       0x13C 0x380 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_12_FLEXIO2_D12                          0x13C 0x380 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_12_EWM_OUT_B                            0x13C 0x380 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_12_GPIO9_IO11                           0x13C 0x380 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_12_FLEXPWM2_PWM2_X                      0x13C 0x380 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_13_SPDIF_SR_CLK                         0x140 0x384 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_13_PIT1_TRIGGER0                                0x140 0x384 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_13_GPT1_CAPTURE2                                0x140 0x384 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_13_FLEXSPI1_B_DATA02                    0x140 0x384 0x56C 0x3 0x0
+#define IOMUXC_GPIO_AD_13_VIDEO_MUX_CSI_MCLK                   0x140 0x384 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_13_GPIO_MUX3_IO12                       0x140 0x384 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_13_ENET_TX_DATA02                       0x140 0x384 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_13_FLEXIO2_D13                          0x140 0x384 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_13_REF_CLK_32K                          0x140 0x384 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_13_GPIO9_IO12                           0x140 0x384 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_13_FLEXPWM2_PWM3_X                      0x140 0x384 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_14_SPDIF_EXT_CLK                                0x144 0x388 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_14_REF_CLK_24M                          0x144 0x388 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_14_GPT1_COMPARE1                                0x144 0x388 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_14_FLEXSPI1_B_DATA01                    0x144 0x388 0x568 0x3 0x0
+#define IOMUXC_GPIO_AD_14_VIDEO_MUX_CSI_VSYNC                  0x144 0x388 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_14_GPIO_MUX3_IO13                       0x144 0x388 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_14_ENET_RX_CLK                          0x144 0x388 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_14_FLEXIO2_D14                          0x144 0x388 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_14_CCM_ENET_REF_CLK_25M                 0x144 0x388 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_14_GPIO9_IO13                           0x144 0x388 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_14_FLEXPWM3_PWM0_X                      0x144 0x388 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_15_GPIO9_IO14                           0x148 0x38C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_15_FLEXPWM3_PWM1_X                      0x148 0x38C 0x0 0xB 0x0
+#define IOMUXC_GPIO_AD_15_SPDIF_IN                             0x148 0x38C 0x6B4 0x0 0x1
+#define IOMUXC_GPIO_AD_15_LPUART10_TXD                         0x148 0x38C 0x628 0x1 0x0
+#define IOMUXC_GPIO_AD_15_GPT1_COMPARE2                                0x148 0x38C 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_15_FLEXSPI1_B_DATA00                    0x148 0x38C 0x564 0x3 0x0
+#define IOMUXC_GPIO_AD_15_VIDEO_MUX_CSI_HSYNC                  0x148 0x38C 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_15_GPIO_MUX3_IO14                       0x148 0x38C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_15_ENET_TX_ER                           0x148 0x38C 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_15_FLEXIO2_D15                          0x148 0x38C 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_AD_16_SPDIF_OUT                            0x14C 0x390 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_16_LPUART10_RXD                         0x14C 0x390 0x624 0x1 0x0
+#define IOMUXC_GPIO_AD_16_GPT1_COMPARE3                                0x14C 0x390 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_16_FLEXSPI1_B_SCLK                      0x14C 0x390 0x578 0x3 0x0
+#define IOMUXC_GPIO_AD_16_VIDEO_MUX_CSI_DATA09                 0x14C 0x390 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_16_GPIO_MUX3_IO15                       0x14C 0x390 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_16_ENET_RX_DATA03                       0x14C 0x390 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_16_FLEXIO2_D16                          0x14C 0x390 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_16_ENET_1G_MDC                          0x14C 0x390 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_16_GPIO9_IO15                           0x14C 0x390 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_16_FLEXPWM3_PWM2_X                      0x14C 0x390 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_17_SAI1_MCLK                            0x150 0x394 0x66C 0x0 0x0
+#define IOMUXC_GPIO_AD_17_ACMP1_OUT                            0x150 0x394 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_17_GPT1_CLK                             0x150 0x394 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_17_FLEXSPI1_A_DQS                       0x150 0x394 0x550 0x3 0x1
+#define IOMUXC_GPIO_AD_17_VIDEO_MUX_CSI_DATA08                 0x150 0x394 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_17_GPIO_MUX3_IO16                       0x150 0x394 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_17_ENET_RX_DATA02                       0x150 0x394 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_17_FLEXIO2_D17                          0x150 0x394 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_17_ENET_1G_MDIO                         0x150 0x394 0x4C8 0x9 0x2
+#define IOMUXC_GPIO_AD_17_GPIO9_IO16                           0x150 0x394 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_17_FLEXPWM3_PWM3_X                      0x150 0x394 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_18_GPIO9_IO17                           0x154 0x398 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_18_FLEXPWM4_PWM0_X                      0x154 0x398 0x0 0xB 0x0
+#define IOMUXC_GPIO_AD_18_SAI1_RX_SYNC                         0x154 0x398 0x678 0x0 0x0
+#define IOMUXC_GPIO_AD_18_ACMP2_OUT                            0x154 0x398 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_18_LPSPI1_PCS1                          0x154 0x398 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_18_FLEXSPI1_A_SS0_B                     0x154 0x398 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_18_VIDEO_MUX_CSI_DATA07                 0x154 0x398 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_18_GPIO_MUX3_IO17                       0x154 0x398 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_18_ENET_CRS                             0x154 0x398 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_18_FLEXIO2_D18                          0x154 0x398 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_18_LPI2C2_SCL                           0x154 0x398 0x5B4 0x9 0x1
+
+#define IOMUXC_GPIO_AD_19_SAI1_RX_BCLK                         0x158 0x39C 0x670 0x0 0x0
+#define IOMUXC_GPIO_AD_19_ACMP3_OUT                            0x158 0x39C 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_19_LPSPI1_PCS2                          0x158 0x39C 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_19_FLEXSPI1_A_SCLK                      0x158 0x39C 0x574 0x3 0x0
+#define IOMUXC_GPIO_AD_19_VIDEO_MUX_CSI_DATA06                 0x158 0x39C 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_19_GPIO_MUX3_IO18                       0x158 0x39C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_19_ENET_COL                             0x158 0x39C 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_19_FLEXIO2_D19                          0x158 0x39C 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_19_LPI2C2_SDA                           0x158 0x39C 0x5B8 0x9 0x1
+#define IOMUXC_GPIO_AD_19_GPIO9_IO18                           0x158 0x39C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_19_FLEXPWM4_PWM1_X                      0x158 0x39C 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_20_SAI1_RX_DATA00                       0x15C 0x3A0 0x674 0x0 0x0
+#define IOMUXC_GPIO_AD_20_ACMP4_OUT                            0x15C 0x3A0 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_20_LPSPI1_PCS3                          0x15C 0x3A0 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_20_FLEXSPI1_A_DATA00                    0x15C 0x3A0 0x554 0x3 0x0
+#define IOMUXC_GPIO_AD_20_VIDEO_MUX_CSI_DATA05                 0x15C 0x3A0 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_20_GPIO_MUX3_IO19                       0x15C 0x3A0 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_20_KPP_ROW07                            0x15C 0x3A0 0x5A8 0x6 0x0
+#define IOMUXC_GPIO_AD_20_FLEXIO2_D20                          0x15C 0x3A0 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_20_ENET_QOS_1588_EVENT2_OUT             0x15C 0x3A0 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_20_GPIO9_IO19                           0x15C 0x3A0 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_20_FLEXPWM4_PWM2_X                      0x15C 0x3A0 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_21_SAI1_TX_DATA00                       0x160 0x3A4 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_21_LPSPI2_PCS1                          0x160 0x3A4 0x5E0 0x2 0x0
+#define IOMUXC_GPIO_AD_21_FLEXSPI1_A_DATA01                    0x160 0x3A4 0x558 0x3 0x0
+#define IOMUXC_GPIO_AD_21_VIDEO_MUX_CSI_DATA04                 0x160 0x3A4 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_21_GPIO_MUX3_IO20                       0x160 0x3A4 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_21_KPP_COL07                            0x160 0x3A4 0x5A0 0x6 0x0
+#define IOMUXC_GPIO_AD_21_FLEXIO2_D21                          0x160 0x3A4 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_21_ENET_QOS_1588_EVENT2_IN              0x160 0x3A4 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_21_GPIO9_IO20                           0x160 0x3A4 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_21_FLEXPWM4_PWM3_X                      0x160 0x3A4 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_22_GPIO9_IO21                           0x164 0x3A8 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_22_SAI1_TX_BCLK                         0x164 0x3A8 0x67C 0x0 0x0
+#define IOMUXC_GPIO_AD_22_LPSPI2_PCS2                          0x164 0x3A8 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_22_FLEXSPI1_A_DATA02                    0x164 0x3A8 0x55C 0x3 0x0
+#define IOMUXC_GPIO_AD_22_VIDEO_MUX_CSI_DATA03                 0x164 0x3A8 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_22_GPIO_MUX3_IO21                       0x164 0x3A8 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_22_KPP_ROW06                            0x164 0x3A8 0x5A4 0x6 0x0
+#define IOMUXC_GPIO_AD_22_FLEXIO2_D22                          0x164 0x3A8 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_22_ENET_QOS_1588_EVENT3_OUT             0x164 0x3A8 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_23_SAI1_TX_SYNC                         0x168 0x3AC 0x680 0x0 0x0
+#define IOMUXC_GPIO_AD_23_LPSPI2_PCS3                          0x168 0x3AC 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_23_FLEXSPI1_A_DATA03                    0x168 0x3AC 0x560 0x3 0x0
+#define IOMUXC_GPIO_AD_23_VIDEO_MUX_CSI_DATA02                 0x168 0x3AC 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_23_GPIO_MUX3_IO22                       0x168 0x3AC 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_23_KPP_COL06                            0x168 0x3AC 0x59C 0x6 0x0
+#define IOMUXC_GPIO_AD_23_FLEXIO2_D23                          0x168 0x3AC 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_23_ENET_QOS_1588_EVENT3_IN              0x168 0x3AC 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_23_GPIO9_IO22                           0x168 0x3AC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_24_LPUART1_TXD                          0x16C 0x3B0 0x620 0x0 0x0
+#define IOMUXC_GPIO_AD_24_LPSPI2_SCK                           0x16C 0x3B0 0x5E4 0x1 0x0
+#define IOMUXC_GPIO_AD_24_VIDEO_MUX_CSI_DATA00                 0x16C 0x3B0 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_24_ENET_RX_EN                           0x16C 0x3B0 0x4B8 0x3 0x0
+#define IOMUXC_GPIO_AD_24_FLEXPWM2_PWM0_A                      0x16C 0x3B0 0x518 0x4 0x1
+#define IOMUXC_GPIO_AD_24_GPIO_MUX3_IO23                       0x16C 0x3B0 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_24_KPP_ROW05                            0x16C 0x3B0 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_24_FLEXIO2_D24                          0x16C 0x3B0 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_24_LPI2C4_SCL                           0x16C 0x3B0 0x5C4 0x9 0x0
+#define IOMUXC_GPIO_AD_24_GPIO9_IO23                           0x16C 0x3B0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_25_GPIO9_IO24                           0x170 0x3B4 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_25_LPUART1_RXD                          0x170 0x3B4 0x61C 0x0 0x0
+#define IOMUXC_GPIO_AD_25_LPSPI2_PCS0                          0x170 0x3B4 0x5DC 0x1 0x0
+#define IOMUXC_GPIO_AD_25_VIDEO_MUX_CSI_DATA01                 0x170 0x3B4 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_25_ENET_RX_ER                           0x170 0x3B4 0x4BC 0x3 0x0
+#define IOMUXC_GPIO_AD_25_FLEXPWM2_PWM0_B                      0x170 0x3B4 0x524 0x4 0x1
+#define IOMUXC_GPIO_AD_25_GPIO_MUX3_IO24                       0x170 0x3B4 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_25_KPP_COL05                            0x170 0x3B4 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_25_FLEXIO2_D25                          0x170 0x3B4 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_25_LPI2C4_SDA                           0x170 0x3B4 0x5C8 0x9 0x0
+
+#define IOMUXC_GPIO_AD_26_LPUART1_CTS_B                                0x174 0x3B8 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_26_LPSPI2_SOUT                          0x174 0x3B8 0x5EC 0x1 0x0
+#define IOMUXC_GPIO_AD_26_SEMC_CSX01                           0x174 0x3B8 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_26_ENET_RX_DATA00                       0x174 0x3B8 0x4B0 0x3 0x0
+#define IOMUXC_GPIO_AD_26_FLEXPWM2_PWM1_A                      0x174 0x3B8 0x51C 0x4 0x1
+#define IOMUXC_GPIO_AD_26_GPIO_MUX3_IO25                       0x174 0x3B8 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_26_KPP_ROW04                            0x174 0x3B8 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_26_FLEXIO2_D26                          0x174 0x3B8 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_26_ENET_QOS_MDC                         0x174 0x3B8 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_26_GPIO9_IO25                           0x174 0x3B8 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_26_USDHC2_CD_B                          0x174 0x3B8 0x6D0 0xB 0x1
+
+#define IOMUXC_GPIO_AD_27_LPUART1_RTS_B                                0x178 0x3BC 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_27_LPSPI2_SIN                           0x178 0x3BC 0x5E8 0x1 0x0
+#define IOMUXC_GPIO_AD_27_SEMC_CSX02                           0x178 0x3BC 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_27_ENET_RX_DATA01                       0x178 0x3BC 0x4B4 0x3 0x0
+#define IOMUXC_GPIO_AD_27_FLEXPWM2_PWM1_B                      0x178 0x3BC 0x528 0x4 0x1
+#define IOMUXC_GPIO_AD_27_GPIO_MUX3_IO26                       0x178 0x3BC 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_27_KPP_COL04                            0x178 0x3BC 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_27_FLEXIO2_D27                          0x178 0x3BC 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_27_ENET_QOS_MDIO                                0x178 0x3BC 0x4EC 0x9 0x1
+#define IOMUXC_GPIO_AD_27_GPIO9_IO26                           0x178 0x3BC 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_27_USDHC2_WP                            0x178 0x3BC 0x6D4 0xB 0x1
+
+#define IOMUXC_GPIO_AD_28_GPIO9_IO27                           0x17C 0x3C0 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_28_USDHC2_VSELECT                       0x17C 0x3C0 0x0 0xB 0x0
+#define IOMUXC_GPIO_AD_28_LPSPI1_SCK                           0x17C 0x3C0 0x5D0 0x0 0x1
+#define IOMUXC_GPIO_AD_28_LPUART5_TXD                          0x17C 0x3C0 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_28_SEMC_CSX03                           0x17C 0x3C0 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_28_ENET_TX_EN                           0x17C 0x3C0 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_28_FLEXPWM2_PWM2_A                      0x17C 0x3C0 0x520 0x4 0x1
+#define IOMUXC_GPIO_AD_28_GPIO_MUX3_IO27                       0x17C 0x3C0 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_28_KPP_ROW03                            0x17C 0x3C0 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_28_FLEXIO2_D28                          0x17C 0x3C0 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_28_VIDEO_MUX_EXT_DCIC1                  0x17C 0x3C0 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_29_LPSPI1_PCS0                          0x180 0x3C4 0x5CC 0x0 0x1
+#define IOMUXC_GPIO_AD_29_LPUART5_RXD                          0x180 0x3C4 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_29_ENET_REF_CLK                         0x180 0x3C4 0x4A8 0x2 0x0
+#define IOMUXC_GPIO_AD_29_ENET_TX_CLK                          0x180 0x3C4 0x4C0 0x3 0x0
+#define IOMUXC_GPIO_AD_29_FLEXPWM2_PWM2_B                      0x180 0x3C4 0x52C 0x4 0x1
+#define IOMUXC_GPIO_AD_29_GPIO_MUX3_IO28                       0x180 0x3C4 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_29_KPP_COL03                            0x180 0x3C4 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_29_FLEXIO2_D29                          0x180 0x3C4 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_29_VIDEO_MUX_EXT_DCIC2                  0x180 0x3C4 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_29_GPIO9_IO28                           0x180 0x3C4 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_29_USDHC2_RESET_B                       0x180 0x3C4 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_30_LPSPI1_SOUT                          0x184 0x3C8 0x5D8 0x0 0x1
+#define IOMUXC_GPIO_AD_30_USB_OTG2_OC                          0x184 0x3C8 0x6B8 0x1 0x1
+#define IOMUXC_GPIO_AD_30_FLEXCAN2_TX                          0x184 0x3C8 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_30_ENET_TX_DATA00                       0x184 0x3C8 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_30_LPUART3_TXD                          0x184 0x3C8 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_30_GPIO_MUX3_IO29                       0x184 0x3C8 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_30_KPP_ROW02                            0x184 0x3C8 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_30_FLEXIO2_D30                          0x184 0x3C8 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_30_WDOG2_RESET_B_DEB                    0x184 0x3C8 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_30_GPIO9_IO29                           0x184 0x3C8 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_31_LPSPI1_SIN                           0x188 0x3CC 0x5D4 0x0 0x1
+#define IOMUXC_GPIO_AD_31_USB_OTG2_PWR                         0x188 0x3CC 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_31_FLEXCAN2_RX                          0x188 0x3CC 0x49C 0x2 0x1
+#define IOMUXC_GPIO_AD_31_ENET_TX_DATA01                       0x188 0x3CC 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_31_LPUART3_RXD                          0x188 0x3CC 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_31_GPIO_MUX3_IO30                       0x188 0x3CC 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_31_KPP_COL02                            0x188 0x3CC 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_31_FLEXIO2_D31                          0x188 0x3CC 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_31_WDOG1_RESET_B_DEB                    0x188 0x3CC 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_31_GPIO9_IO30                           0x188 0x3CC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_32_GPIO9_IO31                           0x18C 0x3D0 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_32_LPI2C1_SCL                           0x18C 0x3D0 0x5AC 0x0 0x1
+#define IOMUXC_GPIO_AD_32_USBPHY2_OTG_ID                       0x18C 0x3D0 0x6C4 0x1 0x1
+#define IOMUXC_GPIO_AD_32_PGMC_PMIC_RDY                                0x18C 0x3D0 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_32_ENET_MDC                             0x18C 0x3D0 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_32_USDHC1_CD_B                          0x18C 0x3D0 0x6C8 0x4 0x0
+#define IOMUXC_GPIO_AD_32_GPIO_MUX3_IO31                       0x18C 0x3D0 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_32_KPP_ROW01                            0x18C 0x3D0 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_32_LPUART10_TXD                         0x18C 0x3D0 0x628 0x8 0x1
+#define IOMUXC_GPIO_AD_32_ENET_1G_MDC                          0x18C 0x3D0 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_33_LPI2C1_SDA                           0x190 0x3D4 0x5B0 0x0 0x1
+#define IOMUXC_GPIO_AD_33_USBPHY1_OTG_ID                       0x190 0x3D4 0x6C0 0x1 0x1
+#define IOMUXC_GPIO_AD_33_XBAR1_INOUT17                                0x190 0x3D4 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_33_ENET_MDIO                            0x190 0x3D4 0x4AC 0x3 0x1
+#define IOMUXC_GPIO_AD_33_USDHC1_WP                            0x190 0x3D4 0x6CC 0x4 0x0
+#define IOMUXC_GPIO_AD_33_GPIO_MUX4_IO00                       0x190 0x3D4 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_33_KPP_COL01                            0x190 0x3D4 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_33_LPUART10_RXD                         0x190 0x3D4 0x624 0x8 0x1
+#define IOMUXC_GPIO_AD_33_ENET_1G_MDIO                         0x190 0x3D4 0x4C8 0x9 0x3
+#define IOMUXC_GPIO_AD_33_GPIO10_IO00                          0x190 0x3D4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_34_ENET_1G_1588_EVENT0_IN               0x194 0x3D8 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_34_USB_OTG1_PWR                         0x194 0x3D8 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_34_XBAR1_INOUT18                                0x194 0x3D8 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_34_ENET_1588_EVENT0_IN                  0x194 0x3D8 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_34_USDHC1_VSELECT                       0x194 0x3D8 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_34_GPIO_MUX4_IO01                       0x194 0x3D8 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_34_KPP_ROW00                            0x194 0x3D8 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_34_LPUART10_CTS_B                       0x194 0x3D8 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_34_WDOG1_ANY                            0x194 0x3D8 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_34_GPIO10_IO01                          0x194 0x3D8 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_35_GPIO10_IO02                          0x198 0x3DC 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_35_ENET_1G_1588_EVENT0_OUT              0x198 0x3DC 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_35_USB_OTG1_OC                          0x198 0x3DC 0x6BC 0x1 0x1
+#define IOMUXC_GPIO_AD_35_XBAR1_INOUT19                                0x198 0x3DC 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_35_ENET_1588_EVENT0_OUT                 0x198 0x3DC 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_35_USDHC1_RESET_B                       0x198 0x3DC 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_35_GPIO_MUX4_IO02                       0x198 0x3DC 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_35_KPP_COL00                            0x198 0x3DC 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_35_LPUART10_RTS_B                       0x198 0x3DC 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_35_FLEXSPI1_B_SS1_B                     0x198 0x3DC 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_SD_B1_00_USDHC1_CMD                                0x19C 0x3E0 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_00_XBAR1_INOUT20                     0x19C 0x3E0 0x6D8 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_00_GPT4_CAPTURE1                     0x19C 0x3E0 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_00_GPIO_MUX4_IO03                    0x19C 0x3E0 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_00_FLEXSPI2_A_SS0_B                  0x19C 0x3E0 0x0 0x6 0x0
+#define IOMUXC_GPIO_SD_B1_00_KPP_ROW07                         0x19C 0x3E0 0x5A8 0x8 0x1
+#define IOMUXC_GPIO_SD_B1_00_GPIO10_IO03                       0x19C 0x3E0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B1_01_USDHC1_CLK                                0x1A0 0x3E4 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_01_XBAR1_INOUT21                     0x1A0 0x3E4 0x6DC 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_01_GPT4_CAPTURE2                     0x1A0 0x3E4 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_01_GPIO_MUX4_IO04                    0x1A0 0x3E4 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_01_FLEXSPI2_A_SCLK                   0x1A0 0x3E4 0x58C 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_01_KPP_COL07                         0x1A0 0x3E4 0x5A0 0x8 0x1
+#define IOMUXC_GPIO_SD_B1_01_GPIO10_IO04                       0x1A0 0x3E4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B1_02_GPIO10_IO05                       0x1A4 0x3E8 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B1_02_USDHC1_DATA0                      0x1A4 0x3E8 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_02_XBAR1_INOUT22                     0x1A4 0x3E8 0x6E0 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_02_GPT4_COMPARE1                     0x1A4 0x3E8 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_02_GPIO_MUX4_IO05                    0x1A4 0x3E8 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_02_FLEXSPI2_A_DATA00                 0x1A4 0x3E8 0x57C 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_02_KPP_ROW06                         0x1A4 0x3E8 0x5A4 0x8 0x1
+#define IOMUXC_GPIO_SD_B1_02_FLEXSPI1_A_SS1_B                  0x1A4 0x3E8 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_SD_B1_03_USDHC1_DATA1                      0x1A8 0x3EC 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_03_XBAR1_INOUT23                     0x1A8 0x3EC 0x6E4 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_03_GPT4_COMPARE2                     0x1A8 0x3EC 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_03_GPIO_MUX4_IO06                    0x1A8 0x3EC 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_03_FLEXSPI2_A_DATA01                 0x1A8 0x3EC 0x580 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_03_KPP_COL06                         0x1A8 0x3EC 0x59C 0x8 0x1
+#define IOMUXC_GPIO_SD_B1_03_FLEXSPI1_B_SS1_B                  0x1A8 0x3EC 0x0 0x9 0x0
+#define IOMUXC_GPIO_SD_B1_03_GPIO10_IO06                       0x1A8 0x3EC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B1_04_USDHC1_DATA2                      0x1AC 0x3F0 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_04_XBAR1_INOUT24                     0x1AC 0x3F0 0x6E8 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_04_GPT4_COMPARE3                     0x1AC 0x3F0 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_04_GPIO_MUX4_IO07                    0x1AC 0x3F0 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_04_FLEXSPI2_A_DATA02                 0x1AC 0x3F0 0x584 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_04_FLEXSPI1_B_SS0_B                  0x1AC 0x3F0 0x0 0x8 0x0
+#define IOMUXC_GPIO_SD_B1_04_ENET_QOS_1588_EVENT2_AUX_IN       0x1AC 0x3F0 0x0 0x9 0x0
+#define IOMUXC_GPIO_SD_B1_04_GPIO10_IO07                       0x1AC 0x3F0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B1_05_GPIO10_IO08                       0x1B0 0x3F4 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B1_05_USDHC1_DATA3                      0x1B0 0x3F4 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_05_XBAR1_INOUT25                     0x1B0 0x3F4 0x6EC 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_05_GPT4_CLK                          0x1B0 0x3F4 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_05_GPIO_MUX4_IO08                    0x1B0 0x3F4 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_05_FLEXSPI2_A_DATA03                 0x1B0 0x3F4 0x588 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_05_FLEXSPI1_B_DQS                    0x1B0 0x3F4 0x0 0x8 0x0
+#define IOMUXC_GPIO_SD_B1_05_ENET_QOS_1588_EVENT3_AUX_IN       0x1B0 0x3F4 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_SD_B2_00_GPIO10_IO09                       0x1B4 0x3F8 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_00_USDHC2_DATA3                      0x1B4 0x3F8 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_00_FLEXSPI1_B_DATA03                 0x1B4 0x3F8 0x570 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_00_ENET_1G_RX_EN                     0x1B4 0x3F8 0x4E0 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_00_LPUART9_TXD                       0x1B4 0x3F8 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_00_LPSPI4_SCK                                0x1B4 0x3F8 0x610 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_00_GPIO_MUX4_IO09                    0x1B4 0x3F8 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_01_USDHC2_DATA2                      0x1B8 0x3FC 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_01_FLEXSPI1_B_DATA02                 0x1B8 0x3FC 0x56C 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_01_ENET_1G_RX_CLK                    0x1B8 0x3FC 0x4CC 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_01_LPUART9_RXD                       0x1B8 0x3FC 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_01_LPSPI4_PCS0                       0x1B8 0x3FC 0x60C 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_01_GPIO_MUX4_IO10                    0x1B8 0x3FC 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_01_GPIO10_IO10                       0x1B8 0x3FC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B2_02_GPIO10_IO11                       0x1BC 0x400 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_02_USDHC2_DATA1                      0x1BC 0x400 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_02_FLEXSPI1_B_DATA01                 0x1BC 0x400 0x568 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_02_ENET_1G_RX_DATA00                 0x1BC 0x400 0x4D0 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_02_LPUART9_CTS_B                     0x1BC 0x400 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_02_LPSPI4_SOUT                       0x1BC 0x400 0x618 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_02_GPIO_MUX4_IO11                    0x1BC 0x400 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_03_GPIO10_IO12                       0x1C0 0x404 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_03_USDHC2_DATA0                      0x1C0 0x404 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_03_FLEXSPI1_B_DATA00                 0x1C0 0x404 0x564 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_03_ENET_1G_RX_DATA01                 0x1C0 0x404 0x4D4 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_03_LPUART9_RTS_B                     0x1C0 0x404 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_03_LPSPI4_SIN                                0x1C0 0x404 0x614 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_03_GPIO_MUX4_IO12                    0x1C0 0x404 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_04_USDHC2_CLK                                0x1C4 0x408 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_04_FLEXSPI1_B_SCLK                   0x1C4 0x408 0x578 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_04_ENET_1G_RX_DATA02                 0x1C4 0x408 0x4D8 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_04_FLEXSPI1_A_SS1_B                  0x1C4 0x408 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_04_LPSPI4_PCS1                       0x1C4 0x408 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_04_GPIO_MUX4_IO13                    0x1C4 0x408 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_04_GPIO10_IO13                       0x1C4 0x408 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B2_05_GPIO10_IO14                       0x1C8 0x40C 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_05_USDHC2_CMD                                0x1C8 0x40C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_05_FLEXSPI1_A_DQS                    0x1C8 0x40C 0x550 0x1 0x2
+#define IOMUXC_GPIO_SD_B2_05_ENET_1G_RX_DATA03                 0x1C8 0x40C 0x4DC 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_05_FLEXSPI1_B_SS0_B                  0x1C8 0x40C 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_05_LPSPI4_PCS2                       0x1C8 0x40C 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_05_GPIO_MUX4_IO14                    0x1C8 0x40C 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_06_GPIO10_IO15                       0x1CC 0x410 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_06_USDHC2_RESET_B                    0x1CC 0x410 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_06_FLEXSPI1_A_SS0_B                  0x1CC 0x410 0x0 0x1 0x0
+#define IOMUXC_GPIO_SD_B2_06_ENET_1G_TX_DATA03                 0x1CC 0x410 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_06_LPSPI4_PCS3                       0x1CC 0x410 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_06_GPT6_CAPTURE1                     0x1CC 0x410 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_06_GPIO_MUX4_IO15                    0x1CC 0x410 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_07_USDHC2_STROBE                     0x1D0 0x414 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_07_FLEXSPI1_A_SCLK                   0x1D0 0x414 0x574 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_07_ENET_1G_TX_DATA02                 0x1D0 0x414 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_07_LPUART3_CTS_B                     0x1D0 0x414 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_07_GPT6_CAPTURE2                     0x1D0 0x414 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_07_GPIO_MUX4_IO16                    0x1D0 0x414 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_07_LPSPI2_SCK                                0x1D0 0x414 0x5E4 0x6 0x1
+#define IOMUXC_GPIO_SD_B2_07_ENET_TX_ER                                0x1D0 0x414 0x0 0x8 0x0
+#define IOMUXC_GPIO_SD_B2_07_ENET_QOS_REF_CLK                  0x1D0 0x414 0x4A0 0x9 0x1
+#define IOMUXC_GPIO_SD_B2_07_GPIO10_IO16                       0x1D0 0x414 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B2_08_GPIO10_IO17                       0x1D4 0x418 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_08_USDHC2_DATA4                      0x1D4 0x418 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_08_FLEXSPI1_A_DATA00                 0x1D4 0x418 0x554 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_08_ENET_1G_TX_DATA01                 0x1D4 0x418 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_08_LPUART3_RTS_B                     0x1D4 0x418 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_08_GPT6_COMPARE1                     0x1D4 0x418 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_08_GPIO_MUX4_IO17                    0x1D4 0x418 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_08_LPSPI2_PCS0                       0x1D4 0x418 0x5DC 0x6 0x1
+
+#define IOMUXC_GPIO_SD_B2_09_GPIO10_IO18                       0x1D8 0x41C 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_09_USDHC2_DATA5                      0x1D8 0x41C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_09_FLEXSPI1_A_DATA01                 0x1D8 0x41C 0x558 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_09_ENET_1G_TX_DATA00                 0x1D8 0x41C 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_09_LPUART5_CTS_B                     0x1D8 0x41C 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_09_GPT6_COMPARE2                     0x1D8 0x41C 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_09_GPIO_MUX4_IO18                    0x1D8 0x41C 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_09_LPSPI2_SOUT                       0x1D8 0x41C 0x5EC 0x6 0x1
+
+#define IOMUXC_GPIO_SD_B2_10_GPIO10_IO19                       0x1DC 0x420 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_10_USDHC2_DATA6                      0x1DC 0x420 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_10_FLEXSPI1_A_DATA02                 0x1DC 0x420 0x55C 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_10_ENET_1G_TX_EN                     0x1DC 0x420 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_10_LPUART5_RTS_B                     0x1DC 0x420 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_10_GPT6_COMPARE3                     0x1DC 0x420 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_10_GPIO_MUX4_IO19                    0x1DC 0x420 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_10_LPSPI2_SIN                                0x1DC 0x420 0x5E8 0x6 0x1
+
+#define IOMUXC_GPIO_SD_B2_11_USDHC2_DATA7                      0x1E0 0x424 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_11_FLEXSPI1_A_DATA03                 0x1E0 0x424 0x560 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_11_ENET_1G_TX_CLK_IO                 0x1E0 0x424 0x4E8 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_11_ENET_1G_REF_CLK                   0x1E0 0x424 0x4C4 0x3 0x1
+#define IOMUXC_GPIO_SD_B2_11_GPT6_CLK                          0x1E0 0x424 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_11_GPIO_MUX4_IO20                    0x1E0 0x424 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_11_LPSPI2_PCS1                       0x1E0 0x424 0x5E0 0x6 0x1
+#define IOMUXC_GPIO_SD_B2_11_GPIO10_IO20                       0x1E0 0x424 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_00_VIDEO_MUX_LCDIF_CLK             0x1E4 0x428 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_00_ENET_1G_RX_EN                   0x1E4 0x428 0x4E0 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_00_TMR1_TIMER0                     0x1E4 0x428 0x63C 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_00_XBAR1_INOUT26                   0x1E4 0x428 0x6F0 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_00_GPIO_MUX4_IO21                  0x1E4 0x428 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_00_ENET_QOS_RX_EN                  0x1E4 0x428 0x4F8 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_00_GPIO10_IO21                     0x1E4 0x428 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_01_VIDEO_MUX_LCDIF_ENABLE          0x1E8 0x42C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_01_ENET_1G_RX_CLK                  0x1E8 0x42C 0x4CC 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_01_ENET_1G_RX_ER                   0x1E8 0x42C 0x4E4 0x2 0x1
+#define IOMUXC_GPIO_DISP_B1_01_TMR1_TIMER1                     0x1E8 0x42C 0x640 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_01_XBAR1_INOUT27                   0x1E8 0x42C 0x6F4 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_01_GPIO_MUX4_IO22                  0x1E8 0x42C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_01_ENET_QOS_RX_CLK                 0x1E8 0x42C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_01_ENET_QOS_RX_ER                  0x1E8 0x42C 0x4FC 0x9 0x0
+#define IOMUXC_GPIO_DISP_B1_01_GPIO10_IO22                     0x1E8 0x42C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_02_GPIO10_IO23                     0x1EC 0x430 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B1_02_VIDEO_MUX_LCDIF_HSYNC           0x1EC 0x430 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_02_ENET_1G_RX_DATA00               0x1EC 0x430 0x4D0 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_02_LPI2C3_SCL                      0x1EC 0x430 0x5BC 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_02_TMR1_TIMER2                     0x1EC 0x430 0x644 0x3 0x1
+#define IOMUXC_GPIO_DISP_B1_02_XBAR1_INOUT28                   0x1EC 0x430 0x6F8 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_02_GPIO_MUX4_IO23                  0x1EC 0x430 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_02_ENET_QOS_RX_DATA00              0x1EC 0x430 0x4F0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_02_LPUART1_TXD                     0x1EC 0x430 0x620 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B1_03_VIDEO_MUX_LCDIF_VSYNC           0x1F0 0x434 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_03_ENET_1G_RX_DATA01               0x1F0 0x434 0x4D4 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_03_LPI2C3_SDA                      0x1F0 0x434 0x5C0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_03_TMR2_TIMER0                     0x1F0 0x434 0x648 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_03_XBAR1_INOUT29                   0x1F0 0x434 0x6FC 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_03_GPIO_MUX4_IO24                  0x1F0 0x434 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_03_ENET_QOS_RX_DATA01              0x1F0 0x434 0x4F4 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_03_LPUART1_RXD                     0x1F0 0x434 0x61C 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_03_GPIO10_IO24                     0x1F0 0x434 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_04_VIDEO_MUX_LCDIF_DATA00          0x1F4 0x438 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_04_ENET_1G_RX_DATA02               0x1F4 0x438 0x4D8 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_04_LPUART4_RXD                     0x1F4 0x438 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_04_TMR2_TIMER1                     0x1F4 0x438 0x64C 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_04_XBAR1_INOUT30                   0x1F4 0x438 0x700 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_04_GPIO_MUX4_IO25                  0x1F4 0x438 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_04_ENET_QOS_RX_DATA02              0x1F4 0x438 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_04_LPSPI3_SCK                      0x1F4 0x438 0x600 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_04_GPIO10_IO25                     0x1F4 0x438 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_05_GPIO10_IO26                     0x1F8 0x43C 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B1_05_VIDEO_MUX_LCDIF_DATA01          0x1F8 0x43C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_05_ENET_1G_RX_DATA03               0x1F8 0x43C 0x4DC 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_05_LPUART4_CTS_B                   0x1F8 0x43C 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_05_TMR2_TIMER2                     0x1F8 0x43C 0x650 0x3 0x1
+#define IOMUXC_GPIO_DISP_B1_05_XBAR1_INOUT31                   0x1F8 0x43C 0x704 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_05_GPIO_MUX4_IO26                  0x1F8 0x43C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_05_ENET_QOS_RX_DATA03              0x1F8 0x43C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_05_LPSPI3_SIN                      0x1F8 0x43C 0x604 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B1_06_VIDEO_MUX_LCDIF_DATA02          0x1FC 0x440 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_06_ENET_1G_TX_DATA03               0x1FC 0x440 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_06_LPUART4_TXD                     0x1FC 0x440 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_06_TMR3_TIMER0                     0x1FC 0x440 0x654 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_06_XBAR1_INOUT32                   0x1FC 0x440 0x708 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_06_GPIO_MUX4_IO27                  0x1FC 0x440 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_06_SRC_BT_CFG00                    0x1FC 0x440 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_06_ENET_QOS_TX_DATA03              0x1FC 0x440 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_06_LPSPI3_SOUT                     0x1FC 0x440 0x608 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_06_GPIO10_IO27                     0x1FC 0x440 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_07_VIDEO_MUX_LCDIF_DATA03          0x200 0x444 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_07_ENET_1G_TX_DATA02               0x200 0x444 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_07_LPUART4_RTS_B                   0x200 0x444 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_07_TMR3_TIMER1                     0x200 0x444 0x658 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_07_XBAR1_INOUT33                   0x200 0x444 0x70C 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_07_GPIO_MUX4_IO28                  0x200 0x444 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_07_SRC_BT_CFG01                    0x200 0x444 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_07_ENET_QOS_TX_DATA02              0x200 0x444 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_07_LPSPI3_PCS0                     0x200 0x444 0x5F0 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_07_GPIO10_IO28                     0x200 0x444 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_08_GPIO10_IO29                     0x204 0x448 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B1_08_VIDEO_MUX_LCDIF_DATA04          0x204 0x448 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_08_ENET_1G_TX_DATA01               0x204 0x448 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_08_USDHC1_CD_B                     0x204 0x448 0x6C8 0x2 0x1
+#define IOMUXC_GPIO_DISP_B1_08_TMR3_TIMER2                     0x204 0x448 0x65C 0x3 0x1
+#define IOMUXC_GPIO_DISP_B1_08_XBAR1_INOUT34                   0x204 0x448 0x710 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_08_GPIO_MUX4_IO29                  0x204 0x448 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_08_SRC_BT_CFG02                    0x204 0x448 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_08_ENET_QOS_TX_DATA01              0x204 0x448 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_08_LPSPI3_PCS1                     0x204 0x448 0x5F4 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B1_09_VIDEO_MUX_LCDIF_DATA05          0x208 0x44C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_09_ENET_1G_TX_DATA00               0x208 0x44C 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_09_USDHC1_WP                       0x208 0x44C 0x6CC 0x2 0x1
+#define IOMUXC_GPIO_DISP_B1_09_TMR4_TIMER0                     0x208 0x44C 0x660 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_09_XBAR1_INOUT35                   0x208 0x44C 0x714 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_09_GPIO_MUX4_IO30                  0x208 0x44C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_09_SRC_BT_CFG03                    0x208 0x44C 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_09_ENET_QOS_TX_DATA00              0x208 0x44C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_09_LPSPI3_PCS2                     0x208 0x44C 0x5F8 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_09_GPIO10_IO30                     0x208 0x44C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_10_VIDEO_MUX_LCDIF_DATA06          0x20C 0x450 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_10_ENET_1G_TX_EN                   0x20C 0x450 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_10_USDHC1_RESET_B                  0x20C 0x450 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_10_TMR4_TIMER1                     0x20C 0x450 0x664 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_10_XBAR1_INOUT36                   0x20C 0x450 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B1_10_GPIO_MUX4_IO31                  0x20C 0x450 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_10_SRC_BT_CFG04                    0x20C 0x450 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_10_ENET_QOS_TX_EN                  0x20C 0x450 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_10_LPSPI3_PCS3                     0x20C 0x450 0x5FC 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_10_GPIO10_IO31                     0x20C 0x450 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_11_VIDEO_MUX_LCDIF_DATA07          0x210 0x454 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_11_ENET_1G_TX_CLK_IO               0x210 0x454 0x4E8 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_11_ENET_1G_REF_CLK                 0x210 0x454 0x4C4 0x2 0x2
+#define IOMUXC_GPIO_DISP_B1_11_TMR4_TIMER2                     0x210 0x454 0x668 0x3 0x1
+#define IOMUXC_GPIO_DISP_B1_11_XBAR1_INOUT37                   0x210 0x454 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B1_11_GPIO_MUX5_IO00                  0x210 0x454 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_11_SRC_BT_CFG05                    0x210 0x454 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_11_ENET_QOS_TX_CLK                 0x210 0x454 0x4A4 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_11_ENET_QOS_REF_CLK                        0x210 0x454 0x4A0 0x9 0x2
+#define IOMUXC_GPIO_DISP_B1_11_GPIO11_IO00                     0x210 0x454 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_00_GPIO11_IO01                     0x214 0x458 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_00_VIDEO_MUX_LCDIF_DATA08          0x214 0x458 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_00_WDOG1_B                         0x214 0x458 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_00_MQS_RIGHT                       0x214 0x458 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_00_ENET_1G_TX_ER                   0x214 0x458 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_00_SAI1_TX_DATA03                  0x214 0x458 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_00_GPIO_MUX5_IO01                  0x214 0x458 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_00_SRC_BT_CFG06                    0x214 0x458 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_00_ENET_QOS_TX_ER                  0x214 0x458 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_DISP_B2_01_VIDEO_MUX_LCDIF_DATA09          0x218 0x45C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_01_USDHC1_VSELECT                  0x218 0x45C 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_01_MQS_LEFT                                0x218 0x45C 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_01_WDOG2_B                         0x218 0x45C 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_01_SAI1_TX_DATA02                  0x218 0x45C 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_01_GPIO_MUX5_IO02                  0x218 0x45C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_01_SRC_BT_CFG07                    0x218 0x45C 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_01_EWM_OUT_B                       0x218 0x45C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_01_CCM_ENET_REF_CLK_25M            0x218 0x45C 0x0 0x9 0x0
+#define IOMUXC_GPIO_DISP_B2_01_GPIO11_IO02                     0x218 0x45C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_02_GPIO11_IO03                     0x21C 0x460 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_02_VIDEO_MUX_LCDIF_DATA10          0x21C 0x460 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_02_ENET_TX_DATA00                  0x21C 0x460 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_02_PIT1_TRIGGER3                   0x21C 0x460 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_02_ARM_TRACE00                     0x21C 0x460 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_02_SAI1_TX_DATA01                  0x21C 0x460 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_02_GPIO_MUX5_IO03                  0x21C 0x460 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_02_SRC_BT_CFG08                    0x21C 0x460 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_02_ENET_QOS_TX_DATA00              0x21C 0x460 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_DISP_B2_03_GPIO11_IO04                     0x220 0x464 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_03_VIDEO_MUX_LCDIF_DATA11          0x220 0x464 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_03_ENET_TX_DATA01                  0x220 0x464 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_03_PIT1_TRIGGER2                   0x220 0x464 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_03_ARM_TRACE01                     0x220 0x464 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_03_SAI1_MCLK                       0x220 0x464 0x66C 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_03_GPIO_MUX5_IO04                  0x220 0x464 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_03_SRC_BT_CFG09                    0x220 0x464 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_03_ENET_QOS_TX_DATA01              0x220 0x464 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_DISP_B2_04_VIDEO_MUX_LCDIF_DATA12          0x224 0x468 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_04_ENET_TX_EN                      0x224 0x468 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_04_PIT1_TRIGGER1                   0x224 0x468 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_04_ARM_TRACE02                     0x224 0x468 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_04_SAI1_RX_SYNC                    0x224 0x468 0x678 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_04_GPIO_MUX5_IO05                  0x224 0x468 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_04_SRC_BT_CFG10                    0x224 0x468 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_04_ENET_QOS_TX_EN                  0x224 0x468 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_04_GPIO11_IO05                     0x224 0x468 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_05_GPIO11_IO06                     0x228 0x46C 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_05_VIDEO_MUX_LCDIF_DATA13          0x228 0x46C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_05_ENET_TX_CLK                     0x228 0x46C 0x4C0 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_05_ENET_REF_CLK                    0x228 0x46C 0x4A8 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_05_ARM_TRACE03                     0x228 0x46C 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_05_SAI1_RX_BCLK                    0x228 0x46C 0x670 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_05_GPIO_MUX5_IO06                  0x228 0x46C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_05_SRC_BT_CFG11                    0x228 0x46C 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_05_ENET_QOS_TX_CLK                 0x228 0x46C 0x4A4 0x8 0x1
+
+#define IOMUXC_GPIO_DISP_B2_06_GPIO11_IO07                     0x22C 0x470 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_06_VIDEO_MUX_LCDIF_DATA14          0x22C 0x470 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_06_ENET_RX_DATA00                  0x22C 0x470 0x4B0 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_06_LPUART7_TXD                     0x22C 0x470 0x630 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_06_ARM_TRACE_CLK                   0x22C 0x470 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_06_SAI1_RX_DATA00                  0x22C 0x470 0x674 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_06_GPIO_MUX5_IO07                  0x22C 0x470 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_06_ENET_QOS_RX_DATA00              0x22C 0x470 0x4F0 0x8 0x1
+
+#define IOMUXC_GPIO_DISP_B2_07_VIDEO_MUX_LCDIF_DATA15          0x230 0x474 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_07_ENET_RX_DATA01                  0x230 0x474 0x4B4 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_07_LPUART7_RXD                     0x230 0x474 0x62C 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_07_ARM_TRACE_SWO                   0x230 0x474 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_07_SAI1_TX_DATA00                  0x230 0x474 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_07_GPIO_MUX5_IO08                  0x230 0x474 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_07_ENET_QOS_RX_DATA01              0x230 0x474 0x4F4 0x8 0x1
+#define IOMUXC_GPIO_DISP_B2_07_GPIO11_IO08                     0x230 0x474 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_08_GPIO11_IO09                     0x234 0x478 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_08_VIDEO_MUX_LCDIF_DATA16          0x234 0x478 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_08_ENET_RX_EN                      0x234 0x478 0x4B8 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_08_LPUART8_TXD                     0x234 0x478 0x638 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_08_ARM_CM7_EVENTO                  0x234 0x478 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_08_SAI1_TX_BCLK                    0x234 0x478 0x67C 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_08_GPIO_MUX5_IO09                  0x234 0x478 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_08_ENET_QOS_RX_EN                  0x234 0x478 0x4F8 0x8 0x1
+#define IOMUXC_GPIO_DISP_B2_08_LPUART1_TXD                     0x234 0x478 0x620 0x9 0x2
+
+#define IOMUXC_GPIO_DISP_B2_09_GPIO11_IO10                     0x238 0x47C 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_09_VIDEO_MUX_LCDIF_DATA17          0x238 0x47C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_09_ENET_RX_ER                      0x238 0x47C 0x4BC 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_09_LPUART8_RXD                     0x238 0x47C 0x634 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_09_ARM_CM7_EVENTI                  0x238 0x47C 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_09_SAI1_TX_SYNC                    0x238 0x47C 0x680 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_09_GPIO_MUX5_IO10                  0x238 0x47C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_09_ENET_QOS_RX_ER                  0x238 0x47C 0x4FC 0x8 0x1
+#define IOMUXC_GPIO_DISP_B2_09_LPUART1_RXD                     0x238 0x47C 0x61C 0x9 0x2
+
+#define IOMUXC_GPIO_DISP_B2_10_GPIO11_IO11                     0x23C 0x480 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_10_VIDEO_MUX_LCDIF_DATA18          0x23C 0x480 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_10_EMVSIM2_IO                      0x23C 0x480 0x6A8 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_10_LPUART2_TXD                     0x23C 0x480 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_10_WDOG2_RESET_B_DEB               0x23C 0x480 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_10_XBAR1_INOUT38                   0x23C 0x480 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_10_GPIO_MUX5_IO11                  0x23C 0x480 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_10_LPI2C3_SCL                      0x23C 0x480 0x5BC 0x6 0x1
+#define IOMUXC_GPIO_DISP_B2_10_ENET_QOS_RX_ER                  0x23C 0x480 0x4FC 0x8 0x2
+#define IOMUXC_GPIO_DISP_B2_10_SPDIF_IN                                0x23C 0x480 0x6B4 0x9 0x2
+
+#define IOMUXC_GPIO_DISP_B2_11_VIDEO_MUX_LCDIF_DATA19          0x240 0x484 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_11_EMVSIM2_CLK                     0x240 0x484 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_11_LPUART2_RXD                     0x240 0x484 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_11_WDOG1_RESET_B_DEB               0x240 0x484 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_11_XBAR1_INOUT39                   0x240 0x484 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_11_GPIO_MUX5_IO12                  0x240 0x484 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_11_LPI2C3_SDA                      0x240 0x484 0x5C0 0x6 0x1
+#define IOMUXC_GPIO_DISP_B2_11_ENET_QOS_CRS                    0x240 0x484 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_11_SPDIF_OUT                       0x240 0x484 0x0 0x9 0x0
+#define IOMUXC_GPIO_DISP_B2_11_GPIO11_IO12                     0x240 0x484 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_12_GPIO11_IO13                     0x244 0x488 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_12_VIDEO_MUX_LCDIF_DATA20          0x244 0x488 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_12_EMVSIM2_RST                     0x244 0x488 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_12_FLEXCAN1_TX                     0x244 0x488 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_12_LPUART2_CTS_B                   0x244 0x488 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_12_XBAR1_INOUT40                   0x244 0x488 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_12_GPIO_MUX5_IO13                  0x244 0x488 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_12_LPI2C4_SCL                      0x244 0x488 0x5C4 0x6 0x1
+#define IOMUXC_GPIO_DISP_B2_12_ENET_QOS_COL                    0x244 0x488 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_12_LPSPI4_SCK                      0x244 0x488 0x610 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B2_13_GPIO11_IO14                     0x248 0x48C 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_13_VIDEO_MUX_LCDIF_DATA21          0x248 0x48C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_13_EMVSIM2_SVEN                    0x248 0x48C 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_13_FLEXCAN1_RX                     0x248 0x48C 0x498 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_13_LPUART2_RTS_B                   0x248 0x48C 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_13_ENET_REF_CLK                    0x248 0x48C 0x4A8 0x4 0x2
+#define IOMUXC_GPIO_DISP_B2_13_GPIO_MUX5_IO14                  0x248 0x48C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_13_LPI2C4_SDA                      0x248 0x48C 0x5C8 0x6 0x1
+#define IOMUXC_GPIO_DISP_B2_13_ENET_QOS_1588_EVENT0_OUT                0x248 0x48C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_13_LPSPI4_SIN                      0x248 0x48C 0x614 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B2_14_GPIO_MUX5_IO15                  0x24C 0x490 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_14_FLEXCAN1_TX                     0x24C 0x490 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_14_ENET_QOS_1588_EVENT0_IN         0x24C 0x490 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_14_LPSPI4_SOUT                     0x24C 0x490 0x618 0x9 0x1
+#define IOMUXC_GPIO_DISP_B2_14_GPIO11_IO15                     0x24C 0x490 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_14_VIDEO_MUX_LCDIF_DATA22          0x24C 0x490 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_14_EMVSIM2_PD                      0x24C 0x490 0x6AC 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_14_WDOG2_B                         0x24C 0x490 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_14_VIDEO_MUX_EXT_DCIC1             0x24C 0x490 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_14_ENET_1G_REF_CLK                 0x24C 0x490 0x4C4 0x4 0x3
+
+#define IOMUXC_GPIO_DISP_B2_15_VIDEO_MUX_LCDIF_DATA23          0x250 0x494 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_15_EMVSIM2_POWER_FAIL              0x250 0x494 0x6B0 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_15_WDOG1_B                         0x250 0x494 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_15_VIDEO_MUX_EXT_DCIC2             0x250 0x494 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_15_PIT1_TRIGGER0                   0x250 0x494 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_15_GPIO_MUX5_IO16                  0x250 0x494 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_15_FLEXCAN1_RX                     0x250 0x494 0x498 0x6 0x2
+#define IOMUXC_GPIO_DISP_B2_15_ENET_QOS_1588_EVENT0_AUX_IN     0x250 0x494 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_15_LPSPI4_PCS0                     0x250 0x494 0x60C 0x9 0x1
+#define IOMUXC_GPIO_DISP_B2_15_GPIO11_IO16                     0x250 0x494 0x0 0xA 0x0
+
+#endif  /* _DT_BINDINGS_PINCTRL_IMXRT1170_PINFUNC_H */
index 70e634b..6cdadba 100644 (file)
                                     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&apb0_gates 0>, <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
-                       resets = <&apb0_rst 0>;
                        gpio-controller;
                        interrupt-controller;
                        #interrupt-cells = <3>;
index 1a262a0..f630ab5 100644 (file)
                        interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&apb0_gates 0>, <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
-                       resets = <&apb0_rst 0>;
                        gpio-controller;
                        interrupt-controller;
                        #interrupt-cells = <3>;
index ce4fa67..7d3f330 100644 (file)
                                     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&apbs_gates 0>, <&osc24M>, <&osc32k>;
                        clock-names = "apb", "hosc", "losc";
-                       resets = <&apbs_rst 0>;
                        gpio-controller;
                        interrupt-controller;
                        #interrupt-cells = <3>;
index 4218750..7dab467 100644 (file)
@@ -581,7 +581,7 @@ static struct platform_device mcf_esdhc = {
 };
 #endif /* MCFSDHC_BASE */
 
-#if IS_ENABLED(CONFIG_CAN_FLEXCAN)
+#ifdef MCFFLEXCAN_SIZE
 
 #include <linux/can/platform/flexcan.h>
 
@@ -620,7 +620,7 @@ static struct platform_device mcf_flexcan0 = {
        .resource = mcf5441x_flexcan0_resource,
        .dev.platform_data = &mcf5441x_flexcan_info,
 };
-#endif /* IS_ENABLED(CONFIG_CAN_FLEXCAN) */
+#endif /* MCFFLEXCAN_SIZE */
 
 static struct platform_device *mcf_devices[] __initdata = {
        &mcf_uart,
@@ -657,7 +657,7 @@ static struct platform_device *mcf_devices[] __initdata = {
 #ifdef MCFSDHC_BASE
        &mcf_esdhc,
 #endif
-#if IS_ENABLED(CONFIG_CAN_FLEXCAN)
+#ifdef MCFFLEXCAN_SIZE
        &mcf_flexcan0,
 #endif
 };
index 9950933..f74f0e4 100644 (file)
@@ -7,7 +7,7 @@
  * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
  * controllers, and the 547x and 548x families which have only one of them.
  *
- * The external 7 fixed interrupts are part the the Edge Port unit of these
+ * The external 7 fixed interrupts are part of the Edge Port unit of these
  * ColdFire parts. They can be configured as level or edge triggered.
  *
  * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
index 193c178..83a9973 100644 (file)
@@ -28,7 +28,7 @@
 DEFINE_CLK(pll, "pll.0", MCF_CLK);
 DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
 
-struct clk_lookup m523x_clk_lookup[] = {
+static struct clk_lookup m523x_clk_lookup[] = {
        CLKDEV_INIT(NULL, "pll.0", &clk_pll),
        CLKDEV_INIT(NULL, "sys.0", &clk_sys),
        CLKDEV_INIT("mcfpit.0", NULL, &clk_pll),
index 7b0d286..01772e7 100644 (file)
@@ -55,6 +55,7 @@ int memory_add_physaddr_to_nid(u64 start)
 {
        return hot_add_scn_to_nid(start);
 }
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
 #endif
 
 int __weak create_section_mapping(unsigned long start, unsigned long end,
index 14ed039..235dc85 100644 (file)
 #define X86_FEATURE_RETHUNK            (11*32+14) /* "" Use REturn THUNK */
 #define X86_FEATURE_UNRET              (11*32+15) /* "" AMD BTB untrain return */
 #define X86_FEATURE_USE_IBPB_FW                (11*32+16) /* "" Use IBPB during runtime firmware calls */
+#define X86_FEATURE_RSB_VMEXIT_LITE    (11*32+17) /* "" Fill RSB on VM exit when EIBRS is enabled */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_BUG_SRBDS                  X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
 #define X86_BUG_MMIO_STALE_DATA                X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
 #define X86_BUG_RETBLEED               X86_BUG(26) /* CPU is affected by RETBleed */
+#define X86_BUG_EIBRS_PBRSB            X86_BUG(27) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 182b2a1..6674bdb 100644 (file)
                                                 * are restricted to targets in
                                                 * kernel.
                                                 */
+#define ARCH_CAP_PBRSB_NO              BIT(24) /*
+                                                * Not susceptible to Post-Barrier
+                                                * Return Stack Buffer Predictions.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
index cba9420..e64fd20 100644 (file)
@@ -60,7 +60,9 @@
 774:                                           \
        add     $(BITS_PER_LONG/8) * 2, sp;     \
        dec     reg;                            \
-       jnz     771b;
+       jnz     771b;                           \
+       /* barrier for jnz misprediction */     \
+       lfence;
 
 #ifdef __ASSEMBLY__
 
 #endif
 .endm
 
+.macro ISSUE_UNBALANCED_RET_GUARD
+       ANNOTATE_INTRA_FUNCTION_CALL
+       call .Lunbalanced_ret_guard_\@
+       int3
+.Lunbalanced_ret_guard_\@:
+       add $(BITS_PER_LONG/8), %_ASM_SP
+       lfence
+.endm
+
  /*
   * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
   * monstrosity above, manually.
   */
-.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
+.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req ftr2
+.ifb \ftr2
        ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
+.else
+       ALTERNATIVE_2 "jmp .Lskip_rsb_\@", "", \ftr, "jmp .Lunbalanced_\@", \ftr2
+.endif
        __FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
+.Lunbalanced_\@:
+       ISSUE_UNBALANCED_RET_GUARD
 .Lskip_rsb_\@:
 .endm
 
index 6761668..9f7e751 100644 (file)
@@ -1335,6 +1335,53 @@ static void __init spec_ctrl_disable_kernel_rrsba(void)
        }
 }
 
+static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_mitigation mode)
+{
+       /*
+        * Similar to context switches, there are two types of RSB attacks
+        * after VM exit:
+        *
+        * 1) RSB underflow
+        *
+        * 2) Poisoned RSB entry
+        *
+        * When retpoline is enabled, both are mitigated by filling/clearing
+        * the RSB.
+        *
+        * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
+        * prediction isolation protections, RSB still needs to be cleared
+        * because of #2.  Note that SMEP provides no protection here, unlike
+        * user-space-poisoned RSB entries.
+        *
+        * eIBRS should protect against RSB poisoning, but if the EIBRS_PBRSB
+        * bug is present then a LITE version of RSB protection is required,
+        * just a single call needs to retire before a RET is executed.
+        */
+       switch (mode) {
+       case SPECTRE_V2_NONE:
+               return;
+
+       case SPECTRE_V2_EIBRS_LFENCE:
+       case SPECTRE_V2_EIBRS:
+               if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) {
+                       setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT_LITE);
+                       pr_info("Spectre v2 / PBRSB-eIBRS: Retire a single CALL on VMEXIT\n");
+               }
+               return;
+
+       case SPECTRE_V2_EIBRS_RETPOLINE:
+       case SPECTRE_V2_RETPOLINE:
+       case SPECTRE_V2_LFENCE:
+       case SPECTRE_V2_IBRS:
+               setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+               pr_info("Spectre v2 / SpectreRSB : Filling RSB on VMEXIT\n");
+               return;
+       }
+
+       pr_warn_once("Unknown Spectre v2 mode, disabling RSB mitigation at VM exit");
+       dump_stack();
+}
+
 static void __init spectre_v2_select_mitigation(void)
 {
        enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
@@ -1485,28 +1532,7 @@ static void __init spectre_v2_select_mitigation(void)
        setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
        pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
 
-       /*
-        * Similar to context switches, there are two types of RSB attacks
-        * after vmexit:
-        *
-        * 1) RSB underflow
-        *
-        * 2) Poisoned RSB entry
-        *
-        * When retpoline is enabled, both are mitigated by filling/clearing
-        * the RSB.
-        *
-        * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
-        * prediction isolation protections, RSB still needs to be cleared
-        * because of #2.  Note that SMEP provides no protection here, unlike
-        * user-space-poisoned RSB entries.
-        *
-        * eIBRS, on the other hand, has RSB-poisoning protections, so it
-        * doesn't need RSB clearing after vmexit.
-        */
-       if (boot_cpu_has(X86_FEATURE_RETPOLINE) ||
-           boot_cpu_has(X86_FEATURE_KERNEL_IBRS))
-               setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+       spectre_v2_determine_rsb_fill_type_at_vmexit(mode);
 
        /*
         * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
@@ -2292,6 +2318,19 @@ static char *ibpb_state(void)
        return "";
 }
 
+static char *pbrsb_eibrs_state(void)
+{
+       if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) {
+               if (boot_cpu_has(X86_FEATURE_RSB_VMEXIT_LITE) ||
+                   boot_cpu_has(X86_FEATURE_RSB_VMEXIT))
+                       return ", PBRSB-eIBRS: SW sequence";
+               else
+                       return ", PBRSB-eIBRS: Vulnerable";
+       } else {
+               return ", PBRSB-eIBRS: Not affected";
+       }
+}
+
 static ssize_t spectre_v2_show_state(char *buf)
 {
        if (spectre_v2_enabled == SPECTRE_V2_LFENCE)
@@ -2304,12 +2343,13 @@ static ssize_t spectre_v2_show_state(char *buf)
            spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE)
                return sprintf(buf, "Vulnerable: eIBRS+LFENCE with unprivileged eBPF and SMT\n");
 
-       return sprintf(buf, "%s%s%s%s%s%s\n",
+       return sprintf(buf, "%s%s%s%s%s%s%s\n",
                       spectre_v2_strings[spectre_v2_enabled],
                       ibpb_state(),
                       boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "",
                       stibp_state(),
                       boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "",
+                      pbrsb_eibrs_state(),
                       spectre_v2_module_string());
 }
 
index 736262a..64a73f4 100644 (file)
@@ -1135,6 +1135,7 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
 #define NO_SWAPGS              BIT(6)
 #define NO_ITLB_MULTIHIT       BIT(7)
 #define NO_SPECTRE_V2          BIT(8)
+#define NO_EIBRS_PBRSB         BIT(9)
 
 #define VULNWL(vendor, family, model, whitelist)       \
        X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, whitelist)
@@ -1177,7 +1178,7 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
 
        VULNWL_INTEL(ATOM_GOLDMONT,             NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
        VULNWL_INTEL(ATOM_GOLDMONT_D,           NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
-       VULNWL_INTEL(ATOM_GOLDMONT_PLUS,        NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
+       VULNWL_INTEL(ATOM_GOLDMONT_PLUS,        NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB),
 
        /*
         * Technically, swapgs isn't serializing on AMD (despite it previously
@@ -1187,7 +1188,9 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
         * good enough for our purposes.
         */
 
-       VULNWL_INTEL(ATOM_TREMONT_D,            NO_ITLB_MULTIHIT),
+       VULNWL_INTEL(ATOM_TREMONT,              NO_EIBRS_PBRSB),
+       VULNWL_INTEL(ATOM_TREMONT_L,            NO_EIBRS_PBRSB),
+       VULNWL_INTEL(ATOM_TREMONT_D,            NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB),
 
        /* AMD Family 0xf - 0x12 */
        VULNWL_AMD(0x0f,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
@@ -1365,6 +1368,11 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
                        setup_force_cpu_bug(X86_BUG_RETBLEED);
        }
 
+       if (cpu_has(c, X86_FEATURE_IBRS_ENHANCED) &&
+           !cpu_matches(cpu_vuln_whitelist, NO_EIBRS_PBRSB) &&
+           !(ia32_cap & ARCH_CAP_PBRSB_NO))
+               setup_force_cpu_bug(X86_BUG_EIBRS_PBRSB);
+
        if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
                return;
 
index 4182c7f..6de96b9 100644 (file)
@@ -227,11 +227,13 @@ SYM_INNER_LABEL(vmx_vmexit, SYM_L_GLOBAL)
         * entries and (in some cases) RSB underflow.
         *
         * eIBRS has its own protection against poisoned RSB, so it doesn't
-        * need the RSB filling sequence.  But it does need to be enabled
-        * before the first unbalanced RET.
+        * need the RSB filling sequence.  But it does need to be enabled, and a
+        * single call to retire, before the first unbalanced RET.
          */
 
-       FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT
+       FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT,\
+                          X86_FEATURE_RSB_VMEXIT_LITE
+
 
        pop %_ASM_ARG2  /* @flags */
        pop %_ASM_ARG1  /* @vmx */
index d6eb90d..3d3a267 100644 (file)
@@ -1200,7 +1200,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
        struct page **pages = (struct page **)bv;
        ssize_t size, left;
        unsigned len, i = 0;
-       size_t offset;
+       size_t offset, trim;
        int ret = 0;
 
        /*
@@ -1218,16 +1218,19 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
         * result to ensure the bio's total size is correct. The remainder of
         * the iov data will be picked up in the next bio iteration.
         */
-       size = iov_iter_get_pages(iter, pages, UINT_MAX - bio->bi_iter.bi_size,
+       size = iov_iter_get_pages2(iter, pages, UINT_MAX - bio->bi_iter.bi_size,
                                  nr_pages, &offset);
-       if (size > 0) {
-               nr_pages = DIV_ROUND_UP(offset + size, PAGE_SIZE);
-               size = ALIGN_DOWN(size, bdev_logical_block_size(bio->bi_bdev));
-       } else
-               nr_pages = 0;
-
-       if (unlikely(size <= 0)) {
-               ret = size ? size : -EFAULT;
+       if (unlikely(size <= 0))
+               return size ? size : -EFAULT;
+
+       nr_pages = DIV_ROUND_UP(offset + size, PAGE_SIZE);
+
+       trim = size & (bdev_logical_block_size(bio->bi_bdev) - 1);
+       iov_iter_revert(iter, trim);
+
+       size -= trim;
+       if (unlikely(!size)) {
+               ret = -EFAULT;
                goto out;
        }
 
@@ -1246,7 +1249,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
                offset = 0;
        }
 
-       iov_iter_advance(iter, size - left);
+       iov_iter_revert(iter, left);
 out:
        while (i < nr_pages)
                put_page(pages[i++]);
index df8b066..7196a6b 100644 (file)
@@ -254,7 +254,7 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
                size_t offs, added = 0;
                int npages;
 
-               bytes = iov_iter_get_pages_alloc(iter, &pages, LONG_MAX, &offs);
+               bytes = iov_iter_get_pages_alloc2(iter, &pages, LONG_MAX, &offs);
                if (unlikely(bytes <= 0)) {
                        ret = bytes ? bytes : -EFAULT;
                        goto out_unmap;
@@ -284,7 +284,6 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
                                bytes -= n;
                                offs = 0;
                        }
-                       iov_iter_advance(iter, added);
                }
                /*
                 * release the pages we didn't map into the bio, if any
@@ -293,8 +292,10 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
                        put_page(pages[j++]);
                kvfree(pages);
                /* couldn't stuff something into bio? */
-               if (bytes)
+               if (bytes) {
+                       iov_iter_revert(iter, bytes);
                        break;
+               }
        }
 
        ret = blk_rq_append_bio(rq, bio);
index a564cd8..b907425 100644 (file)
@@ -75,7 +75,7 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
 
        if (iov_iter_rw(iter) == READ) {
                bio_init(&bio, bdev, vecs, nr_pages, REQ_OP_READ);
-               if (iter_is_iovec(iter))
+               if (user_backed_iter(iter))
                        should_dirty = true;
        } else {
                bio_init(&bio, bdev, vecs, nr_pages, dio_bio_write_op(iocb));
@@ -204,7 +204,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
        }
 
        dio->size = 0;
-       if (is_read && iter_is_iovec(iter))
+       if (is_read && user_backed_iter(iter))
                dio->flags |= DIO_SHOULD_DIRTY;
 
        blk_start_plug(&plug);
@@ -335,7 +335,7 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
        dio->size = bio->bi_iter.bi_size;
 
        if (is_read) {
-               if (iter_is_iovec(iter)) {
+               if (user_backed_iter(iter)) {
                        dio->flags |= DIO_SHOULD_DIRTY;
                        bio_set_pages_dirty(bio);
                }
index 88a73b2..9486ed9 100644 (file)
@@ -4,24 +4,22 @@
 #
 
 obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
-obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o
+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o blacklist_hashes.o
 obj-$(CONFIG_SYSTEM_REVOCATION_LIST) += revocation_certificates.o
-ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),)
 
 $(obj)/blacklist_hashes.o: $(obj)/blacklist_hash_list
 CFLAGS_blacklist_hashes.o := -I $(obj)
 
 quiet_cmd_check_and_copy_blacklist_hash_list = GEN     $@
       cmd_check_and_copy_blacklist_hash_list = \
-       $(AWK) -f $(srctree)/scripts/check-blacklist-hashes.awk $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) >&2; \
-       cat $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) > $@
+       $(if $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST), \
+       $(AWK) -f $(srctree)/$(src)/check-blacklist-hashes.awk $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) >&2; \
+       { cat $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST); echo $(comma) NULL; } > $@, \
+       echo NULL > $@)
 
 $(obj)/blacklist_hash_list: $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) FORCE
        $(call if_changed,check_and_copy_blacklist_hash_list)
-obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o
-else
-obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_nohashes.o
-endif
+
 targets += blacklist_hash_list
 
 quiet_cmd_extract_certs  = CERT    $@
index 86d66fe..0c5476a 100644 (file)
@@ -3,5 +3,4 @@
 
 const char __initconst *const blacklist_hashes[] = {
 #include "blacklist_hash_list"
-       , NULL
 };
diff --git a/certs/blacklist_nohashes.c b/certs/blacklist_nohashes.c
deleted file mode 100644 (file)
index 753b703..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "blacklist.h"
-
-const char __initconst *const blacklist_hashes[] = {
-       NULL
-};
diff --git a/certs/check-blacklist-hashes.awk b/certs/check-blacklist-hashes.awk
new file mode 100755 (executable)
index 0000000..107c1d3
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/awk -f
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright © 2020, Microsoft Corporation. All rights reserved.
+#
+# Author: Mickaël Salaün <mic@linux.microsoft.com>
+#
+# Check that a CONFIG_SYSTEM_BLACKLIST_HASH_LIST file contains a valid array of
+# hash strings.  Such string must start with a prefix ("tbs" or "bin"), then a
+# colon (":"), and finally an even number of hexadecimal lowercase characters
+# (up to 128).
+
+BEGIN {
+       RS = ","
+}
+{
+       if (!match($0, "^[ \t\n\r]*\"([^\"]*)\"[ \t\n\r]*$", part1)) {
+               print "Not a string (item " NR "):", $0;
+               exit 1;
+       }
+       if (!match(part1[1], "^(tbs|bin):(.*)$", part2)) {
+               print "Unknown prefix (item " NR "):", part1[1];
+               exit 1;
+       }
+       if (!match(part2[2], "^([0-9a-f]+)$", part3)) {
+               print "Not a lowercase hexadecimal string (item " NR "):", part2[2];
+               exit 1;
+       }
+       if (length(part3[1]) > 128) {
+               print "Hash string too long (item " NR "):", part3[1];
+               exit 1;
+       }
+       if (length(part3[1]) % 2 == 1) {
+               print "Not an even number of hexadecimal characters (item " NR "):", part3[1];
+               exit 1;
+       }
+}
index c8289b7..e893c0f 100644 (file)
@@ -404,7 +404,7 @@ int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len)
        ssize_t n;
        int npages, i;
 
-       n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
+       n = iov_iter_get_pages2(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
        if (n < 0)
                return n;
 
@@ -1191,7 +1191,6 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
                len += err;
                atomic_add(err, &ctx->rcvused);
                rsgl->sg_num_bytes = err;
-               iov_iter_advance(&msg->msg_iter, err);
        }
 
        *outlen = len;
index 50f7b22..1d017ec 100644 (file)
@@ -102,11 +102,12 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
                err = crypto_wait_req(crypto_ahash_update(&ctx->req),
                                      &ctx->wait);
                af_alg_free_sg(&ctx->sgl);
-               if (err)
+               if (err) {
+                       iov_iter_revert(&msg->msg_iter, len);
                        goto unlock;
+               }
 
                copied += len;
-               iov_iter_advance(&msg->msg_iter, len);
        }
 
        err = 0;
index 8fcaba5..d69d13a 100644 (file)
@@ -29,9 +29,9 @@ struct private_data {
 
        cpumask_var_t cpus;
        struct device *cpu_dev;
-       struct opp_table *opp_table;
        struct cpufreq_frequency_table *freq_table;
        bool have_static_opps;
+       int opp_token;
 };
 
 static LIST_HEAD(priv_list);
@@ -193,7 +193,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
        struct private_data *priv;
        struct device *cpu_dev;
        bool fallback = false;
-       const char *reg_name;
+       const char *reg_name[] = { NULL, NULL };
        int ret;
 
        /* Check if this CPU is already covered by some other policy */
@@ -218,12 +218,11 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
         * OPP layer will be taking care of regulators now, but it needs to know
         * the name of the regulator first.
         */
-       reg_name = find_supply_name(cpu_dev);
-       if (reg_name) {
-               priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, &reg_name,
-                                                           1);
-               if (IS_ERR(priv->opp_table)) {
-                       ret = PTR_ERR(priv->opp_table);
+       reg_name[0] = find_supply_name(cpu_dev);
+       if (reg_name[0]) {
+               priv->opp_token = dev_pm_opp_set_regulators(cpu_dev, reg_name);
+               if (priv->opp_token < 0) {
+                       ret = priv->opp_token;
                        if (ret != -EPROBE_DEFER)
                                dev_err(cpu_dev, "failed to set regulators: %d\n",
                                        ret);
@@ -295,7 +294,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
 out:
        if (priv->have_static_opps)
                dev_pm_opp_of_cpumask_remove_table(priv->cpus);
-       dev_pm_opp_put_regulators(priv->opp_table);
+       dev_pm_opp_put_regulators(priv->opp_token);
 free_cpumask:
        free_cpumask_var(priv->cpus);
        return ret;
@@ -309,7 +308,7 @@ static void dt_cpufreq_release(void)
                dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &priv->freq_table);
                if (priv->have_static_opps)
                        dev_pm_opp_of_cpumask_remove_table(priv->cpus);
-               dev_pm_opp_put_regulators(priv->opp_table);
+               dev_pm_opp_put_regulators(priv->opp_token);
                free_cpumask_var(priv->cpus);
                list_del(&priv->node);
        }
index 954eef2..7820c4e 100644 (file)
@@ -1348,15 +1348,15 @@ static int cpufreq_online(unsigned int cpu)
        }
 
        if (!new_policy && cpufreq_driver->online) {
+               /* Recover policy->cpus using related_cpus */
+               cpumask_copy(policy->cpus, policy->related_cpus);
+
                ret = cpufreq_driver->online(policy);
                if (ret) {
                        pr_debug("%s: %d: initialization failed\n", __func__,
                                 __LINE__);
                        goto out_exit_policy;
                }
-
-               /* Recover policy->cpus using related_cpus */
-               cpumask_copy(policy->cpus, policy->related_cpus);
        } else {
                cpumask_copy(policy->cpus, cpumask_of(cpu));
 
index 3fe9125..76e553a 100644 (file)
@@ -31,8 +31,8 @@
 
 /* cpufreq-dt device registered by imx-cpufreq-dt */
 static struct platform_device *cpufreq_dt_pdev;
-static struct opp_table *cpufreq_opp_table;
 static struct device *cpu_dev;
+static int cpufreq_opp_token;
 
 enum IMX7ULP_CPUFREQ_CLKS {
        ARM,
@@ -153,9 +153,9 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n",
                        speed_grade, mkt_segment, supported_hw[0], supported_hw[1]);
 
-       cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
-       if (IS_ERR(cpufreq_opp_table)) {
-               ret = PTR_ERR(cpufreq_opp_table);
+       cpufreq_opp_token = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
+       if (cpufreq_opp_token < 0) {
+               ret = cpufreq_opp_token;
                dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret);
                return ret;
        }
@@ -163,7 +163,7 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
        cpufreq_dt_pdev = platform_device_register_data(
                        &pdev->dev, "cpufreq-dt", -1, NULL, 0);
        if (IS_ERR(cpufreq_dt_pdev)) {
-               dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+               dev_pm_opp_put_supported_hw(cpufreq_opp_token);
                ret = PTR_ERR(cpufreq_dt_pdev);
                dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret);
                return ret;
@@ -176,7 +176,7 @@ static int imx_cpufreq_dt_remove(struct platform_device *pdev)
 {
        platform_device_unregister(cpufreq_dt_pdev);
        if (!of_machine_is_compatible("fsl,imx7ulp"))
-               dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+               dev_pm_opp_put_supported_hw(cpufreq_opp_token);
        else
                clk_bulk_put(ARRAY_SIZE(imx7ulp_clks), imx7ulp_clks);
 
index 76f6b38..7f2680b 100644 (file)
@@ -478,6 +478,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
        if (info->soc_data->ccifreq_supported) {
                info->vproc_on_boot = regulator_get_voltage(info->proc_reg);
                if (info->vproc_on_boot < 0) {
+                       ret = info->vproc_on_boot;
                        dev_err(info->cpu_dev,
                                "invalid Vproc value: %d\n", info->vproc_on_boot);
                        goto out_disable_inter_clock;
index 36c7958..d5ef3c6 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/pm_opp.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/units.h>
 
 #define LUT_MAX_ENTRIES                        40U
 #define LUT_SRC                                GENMASK(31, 30)
@@ -26,8 +27,6 @@
 
 #define GT_IRQ_STATUS                  BIT(2)
 
-#define HZ_PER_KHZ                     1000
-
 struct qcom_cpufreq_soc_data {
        u32 reg_enable;
        u32 reg_domain_state;
@@ -428,7 +427,7 @@ static int qcom_cpufreq_hw_lmh_init(struct cpufreq_policy *policy, int index)
                return 0;
        }
 
-       ret = irq_set_affinity_hint(data->throttle_irq, policy->cpus);
+       ret = irq_set_affinity_and_hint(data->throttle_irq, policy->cpus);
        if (ret)
                dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n",
                        data->irq_name, data->throttle_irq);
@@ -445,7 +444,11 @@ static int qcom_cpufreq_hw_cpu_online(struct cpufreq_policy *policy)
        if (data->throttle_irq <= 0)
                return 0;
 
-       ret = irq_set_affinity_hint(data->throttle_irq, policy->cpus);
+       mutex_lock(&data->throttle_lock);
+       data->cancel_throttle = false;
+       mutex_unlock(&data->throttle_lock);
+
+       ret = irq_set_affinity_and_hint(data->throttle_irq, policy->cpus);
        if (ret)
                dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n",
                        data->irq_name, data->throttle_irq);
@@ -465,7 +468,8 @@ static int qcom_cpufreq_hw_cpu_offline(struct cpufreq_policy *policy)
        mutex_unlock(&data->throttle_lock);
 
        cancel_delayed_work_sync(&data->throttle_work);
-       irq_set_affinity_hint(data->throttle_irq, NULL);
+       irq_set_affinity_and_hint(data->throttle_irq, NULL);
+       disable_irq_nosync(data->throttle_irq);
 
        return 0;
 }
index 6dfa869..863548f 100644 (file)
@@ -55,9 +55,7 @@ struct qcom_cpufreq_match_data {
 };
 
 struct qcom_cpufreq_drv {
-       struct opp_table **names_opp_tables;
-       struct opp_table **hw_opp_tables;
-       struct opp_table **genpd_opp_tables;
+       int *opp_tokens;
        u32 versions;
        const struct qcom_cpufreq_match_data *data;
 };
@@ -315,72 +313,43 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
        }
        of_node_put(np);
 
-       drv->names_opp_tables = kcalloc(num_possible_cpus(),
-                                 sizeof(*drv->names_opp_tables),
+       drv->opp_tokens = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tokens),
                                  GFP_KERNEL);
-       if (!drv->names_opp_tables) {
+       if (!drv->opp_tokens) {
                ret = -ENOMEM;
                goto free_drv;
        }
-       drv->hw_opp_tables = kcalloc(num_possible_cpus(),
-                                 sizeof(*drv->hw_opp_tables),
-                                 GFP_KERNEL);
-       if (!drv->hw_opp_tables) {
-               ret = -ENOMEM;
-               goto free_opp_names;
-       }
-
-       drv->genpd_opp_tables = kcalloc(num_possible_cpus(),
-                                       sizeof(*drv->genpd_opp_tables),
-                                       GFP_KERNEL);
-       if (!drv->genpd_opp_tables) {
-               ret = -ENOMEM;
-               goto free_opp;
-       }
 
        for_each_possible_cpu(cpu) {
+               struct dev_pm_opp_config config = {
+                       .supported_hw = NULL,
+               };
+
                cpu_dev = get_cpu_device(cpu);
                if (NULL == cpu_dev) {
                        ret = -ENODEV;
-                       goto free_genpd_opp;
+                       goto free_opp;
                }
 
                if (drv->data->get_version) {
+                       config.supported_hw = &drv->versions;
+                       config.supported_hw_count = 1;
 
-                       if (pvs_name) {
-                               drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name(
-                                                                    cpu_dev,
-                                                                    pvs_name);
-                               if (IS_ERR(drv->names_opp_tables[cpu])) {
-                                       ret = PTR_ERR(drv->names_opp_tables[cpu]);
-                                       dev_err(cpu_dev, "Failed to add OPP name %s\n",
-                                               pvs_name);
-                                       goto free_opp;
-                               }
-                       }
-
-                       drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw(
-                                                                        cpu_dev, &drv->versions, 1);
-                       if (IS_ERR(drv->hw_opp_tables[cpu])) {
-                               ret = PTR_ERR(drv->hw_opp_tables[cpu]);
-                               dev_err(cpu_dev,
-                                       "Failed to set supported hardware\n");
-                               goto free_genpd_opp;
-                       }
+                       if (pvs_name)
+                               config.prop_name = pvs_name;
                }
 
                if (drv->data->genpd_names) {
-                       drv->genpd_opp_tables[cpu] =
-                               dev_pm_opp_attach_genpd(cpu_dev,
-                                                       drv->data->genpd_names,
-                                                       NULL);
-                       if (IS_ERR(drv->genpd_opp_tables[cpu])) {
-                               ret = PTR_ERR(drv->genpd_opp_tables[cpu]);
-                               if (ret != -EPROBE_DEFER)
-                                       dev_err(cpu_dev,
-                                               "Could not attach to pm_domain: %d\n",
-                                               ret);
-                               goto free_genpd_opp;
+                       config.genpd_names = drv->data->genpd_names;
+                       config.virt_devs = NULL;
+               }
+
+               if (config.supported_hw || config.genpd_names) {
+                       drv->opp_tokens[cpu] = dev_pm_opp_set_config(cpu_dev, &config);
+                       if (drv->opp_tokens[cpu] < 0) {
+                               ret = drv->opp_tokens[cpu];
+                               dev_err(cpu_dev, "Failed to set OPP config\n");
+                               goto free_opp;
                        }
                }
        }
@@ -395,27 +364,10 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
        ret = PTR_ERR(cpufreq_dt_pdev);
        dev_err(cpu_dev, "Failed to register platform device\n");
 
-free_genpd_opp:
-       for_each_possible_cpu(cpu) {
-               if (IS_ERR(drv->genpd_opp_tables[cpu]))
-                       break;
-               dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
-       }
-       kfree(drv->genpd_opp_tables);
 free_opp:
-       for_each_possible_cpu(cpu) {
-               if (IS_ERR(drv->names_opp_tables[cpu]))
-                       break;
-               dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
-       }
-       for_each_possible_cpu(cpu) {
-               if (IS_ERR(drv->hw_opp_tables[cpu]))
-                       break;
-               dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
-       }
-       kfree(drv->hw_opp_tables);
-free_opp_names:
-       kfree(drv->names_opp_tables);
+       for_each_possible_cpu(cpu)
+               dev_pm_opp_clear_config(drv->opp_tokens[cpu]);
+       kfree(drv->opp_tokens);
 free_drv:
        kfree(drv);
 
@@ -429,15 +381,10 @@ static int qcom_cpufreq_remove(struct platform_device *pdev)
 
        platform_device_unregister(cpufreq_dt_pdev);
 
-       for_each_possible_cpu(cpu) {
-               dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
-               dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
-               dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
-       }
+       for_each_possible_cpu(cpu)
+               dev_pm_opp_clear_config(drv->opp_tokens[cpu]);
 
-       kfree(drv->names_opp_tables);
-       kfree(drv->hw_opp_tables);
-       kfree(drv->genpd_opp_tables);
+       kfree(drv->opp_tokens);
        kfree(drv);
 
        return 0;
index fdb0a72..a67df90 100644 (file)
@@ -156,9 +156,13 @@ static int sti_cpufreq_set_opp_info(void)
        unsigned int hw_info_offset;
        unsigned int version[VERSION_ELEMENTS];
        int pcode, substrate, major, minor;
-       int ret;
+       int opp_token, ret;
        char name[MAX_PCODE_NAME_LEN];
-       struct opp_table *opp_table;
+       struct dev_pm_opp_config config = {
+               .supported_hw = version,
+               .supported_hw_count = ARRAY_SIZE(version),
+               .prop_name = name,
+       };
 
        reg_fields = sti_cpufreq_match();
        if (!reg_fields) {
@@ -210,21 +214,14 @@ use_defaults:
 
        snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode);
 
-       opp_table = dev_pm_opp_set_prop_name(dev, name);
-       if (IS_ERR(opp_table)) {
-               dev_err(dev, "Failed to set prop name\n");
-               return PTR_ERR(opp_table);
-       }
-
        version[0] = BIT(major);
        version[1] = BIT(minor);
        version[2] = BIT(substrate);
 
-       opp_table = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
-       if (IS_ERR(opp_table)) {
-               dev_err(dev, "Failed to set supported hardware\n");
-               ret = PTR_ERR(opp_table);
-               goto err_put_prop_name;
+       opp_token = dev_pm_opp_set_config(dev, &config);
+       if (opp_token < 0) {
+               dev_err(dev, "Failed to set OPP config\n");
+               return opp_token;
        }
 
        dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
@@ -233,10 +230,6 @@ use_defaults:
                version[0], version[1], version[2]);
 
        return 0;
-
-err_put_prop_name:
-       dev_pm_opp_put_prop_name(opp_table);
-       return ret;
 }
 
 static int sti_cpufreq_fetch_syscon_registers(void)
index 75e1bf3..a492258 100644 (file)
@@ -86,20 +86,20 @@ static int sun50i_cpufreq_get_efuse(u32 *versions)
 
 static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
 {
-       struct opp_table **opp_tables;
+       int *opp_tokens;
        char name[MAX_NAME_LEN];
        unsigned int cpu;
        u32 speed = 0;
        int ret;
 
-       opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables),
+       opp_tokens = kcalloc(num_possible_cpus(), sizeof(*opp_tokens),
                             GFP_KERNEL);
-       if (!opp_tables)
+       if (!opp_tokens)
                return -ENOMEM;
 
        ret = sun50i_cpufreq_get_efuse(&speed);
        if (ret) {
-               kfree(opp_tables);
+               kfree(opp_tokens);
                return ret;
        }
 
@@ -113,9 +113,9 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
                        goto free_opp;
                }
 
-               opp_tables[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
-               if (IS_ERR(opp_tables[cpu])) {
-                       ret = PTR_ERR(opp_tables[cpu]);
+               opp_tokens[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
+               if (opp_tokens[cpu] < 0) {
+                       ret = opp_tokens[cpu];
                        pr_err("Failed to set prop name\n");
                        goto free_opp;
                }
@@ -124,7 +124,7 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
        cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
                                                          NULL, 0);
        if (!IS_ERR(cpufreq_dt_pdev)) {
-               platform_set_drvdata(pdev, opp_tables);
+               platform_set_drvdata(pdev, opp_tokens);
                return 0;
        }
 
@@ -132,27 +132,24 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
        pr_err("Failed to register platform device\n");
 
 free_opp:
-       for_each_possible_cpu(cpu) {
-               if (IS_ERR_OR_NULL(opp_tables[cpu]))
-                       break;
-               dev_pm_opp_put_prop_name(opp_tables[cpu]);
-       }
-       kfree(opp_tables);
+       for_each_possible_cpu(cpu)
+               dev_pm_opp_put_prop_name(opp_tokens[cpu]);
+       kfree(opp_tokens);
 
        return ret;
 }
 
 static int sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
 {
-       struct opp_table **opp_tables = platform_get_drvdata(pdev);
+       int *opp_tokens = platform_get_drvdata(pdev);
        unsigned int cpu;
 
        platform_device_unregister(cpufreq_dt_pdev);
 
        for_each_possible_cpu(cpu)
-               dev_pm_opp_put_prop_name(opp_tables[cpu]);
+               dev_pm_opp_put_prop_name(opp_tokens[cpu]);
 
-       kfree(opp_tables);
+       kfree(opp_tokens);
 
        return 0;
 }
index 2a6a987..1216046 100644 (file)
@@ -162,7 +162,7 @@ static struct tegra_cpufreq_ops tegra234_cpufreq_ops = {
        .set_cpu_ndiv = tegra234_set_cpu_ndiv,
 };
 
-const struct tegra_cpufreq_soc tegra234_cpufreq_soc = {
+static const struct tegra_cpufreq_soc tegra234_cpufreq_soc = {
        .ops = &tegra234_cpufreq_ops,
        .actmon_cntr_base = 0x9000,
        .maxcpus_per_cluster = 4,
@@ -430,7 +430,7 @@ static struct tegra_cpufreq_ops tegra194_cpufreq_ops = {
        .set_cpu_ndiv = tegra194_set_cpu_ndiv,
 };
 
-const struct tegra_cpufreq_soc tegra194_cpufreq_soc = {
+static const struct tegra_cpufreq_soc tegra194_cpufreq_soc = {
        .ops = &tegra194_cpufreq_ops,
        .maxcpus_per_cluster = 2,
 };
index e8db3d7..ab7ac7d 100644 (file)
@@ -32,9 +32,9 @@ static bool cpu0_node_has_opp_v2_prop(void)
        return ret;
 }
 
-static void tegra20_cpufreq_put_supported_hw(void *opp_table)
+static void tegra20_cpufreq_put_supported_hw(void *opp_token)
 {
-       dev_pm_opp_put_supported_hw(opp_table);
+       dev_pm_opp_put_supported_hw((unsigned long) opp_token);
 }
 
 static void tegra20_cpufreq_dt_unregister(void *cpufreq_dt)
@@ -45,7 +45,6 @@ static void tegra20_cpufreq_dt_unregister(void *cpufreq_dt)
 static int tegra20_cpufreq_probe(struct platform_device *pdev)
 {
        struct platform_device *cpufreq_dt;
-       struct opp_table *opp_table;
        struct device *cpu_dev;
        u32 versions[2];
        int err;
@@ -71,16 +70,15 @@ static int tegra20_cpufreq_probe(struct platform_device *pdev)
        if (WARN_ON(!cpu_dev))
                return -ENODEV;
 
-       opp_table = dev_pm_opp_set_supported_hw(cpu_dev, versions, 2);
-       err = PTR_ERR_OR_ZERO(opp_table);
-       if (err) {
+       err = dev_pm_opp_set_supported_hw(cpu_dev, versions, 2);
+       if (err < 0) {
                dev_err(&pdev->dev, "failed to set supported hw: %d\n", err);
                return err;
        }
 
        err = devm_add_action_or_reset(&pdev->dev,
                                       tegra20_cpufreq_put_supported_hw,
-                                      opp_table);
+                                      (void *)((unsigned long) err));
        if (err)
                return err;
 
index 8f9fdd8..df85a77 100644 (file)
@@ -60,7 +60,6 @@ struct ti_cpufreq_data {
        struct device_node *opp_node;
        struct regmap *syscon;
        const struct ti_cpufreq_soc_data *soc_data;
-       struct opp_table *opp_table;
 };
 
 static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
@@ -173,7 +172,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = {
  *    seems to always read as 0).
  */
 
-static const char * const omap3_reg_names[] = {"cpu0", "vbb"};
+static const char * const omap3_reg_names[] = {"cpu0", "vbb", NULL};
 
 static struct ti_cpufreq_soc_data omap36xx_soc_data = {
        .reg_names = omap3_reg_names,
@@ -324,10 +323,13 @@ static int ti_cpufreq_probe(struct platform_device *pdev)
 {
        u32 version[VERSION_COUNT];
        const struct of_device_id *match;
-       struct opp_table *ti_opp_table;
        struct ti_cpufreq_data *opp_data;
-       const char * const default_reg_names[] = {"vdd", "vbb"};
+       const char * const default_reg_names[] = {"vdd", "vbb", NULL};
        int ret;
+       struct dev_pm_opp_config config = {
+               .supported_hw = version,
+               .supported_hw_count = ARRAY_SIZE(version),
+       };
 
        match = dev_get_platdata(&pdev->dev);
        if (!match)
@@ -370,33 +372,21 @@ static int ti_cpufreq_probe(struct platform_device *pdev)
        if (ret)
                goto fail_put_node;
 
-       ti_opp_table = dev_pm_opp_set_supported_hw(opp_data->cpu_dev,
-                                                  version, VERSION_COUNT);
-       if (IS_ERR(ti_opp_table)) {
-               dev_err(opp_data->cpu_dev,
-                       "Failed to set supported hardware\n");
-               ret = PTR_ERR(ti_opp_table);
-               goto fail_put_node;
-       }
-
-       opp_data->opp_table = ti_opp_table;
-
        if (opp_data->soc_data->multi_regulator) {
-               const char * const *reg_names = default_reg_names;
-
                if (opp_data->soc_data->reg_names)
-                       reg_names = opp_data->soc_data->reg_names;
-               ti_opp_table = dev_pm_opp_set_regulators(opp_data->cpu_dev,
-                                                        reg_names,
-                                                        ARRAY_SIZE(default_reg_names));
-               if (IS_ERR(ti_opp_table)) {
-                       dev_pm_opp_put_supported_hw(opp_data->opp_table);
-                       ret =  PTR_ERR(ti_opp_table);
-                       goto fail_put_node;
-               }
+                       config.regulator_names = opp_data->soc_data->reg_names;
+               else
+                       config.regulator_names = default_reg_names;
+       }
+
+       ret = dev_pm_opp_set_config(opp_data->cpu_dev, &config);
+       if (ret < 0) {
+               dev_err(opp_data->cpu_dev, "Failed to set OPP config\n");
+               goto fail_put_node;
        }
 
        of_node_put(opp_data->opp_node);
+
 register_cpufreq_dt:
        platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
 
index 62dd956..6eceb19 100644 (file)
@@ -8,6 +8,7 @@
  * This code is licenced under the GPL.
  */
 
+#include "linux/percpu-defs.h"
 #include <linux/clockchips.h>
 #include <linux/kernel.h>
 #include <linux/mutex.h>
@@ -279,6 +280,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
 
                                /* Shallower states are enabled, so update. */
                                dev->states_usage[entered_state].above++;
+                               trace_cpu_idle_miss(dev->cpu, entered_state, false);
                                break;
                        }
                } else if (diff > delay) {
@@ -290,8 +292,10 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
                                 * Update if a deeper state would have been a
                                 * better match for the observed idle duration.
                                 */
-                               if (diff - delay >= drv->states[i].target_residency_ns)
+                               if (diff - delay >= drv->states[i].target_residency_ns) {
                                        dev->states_usage[entered_state].below++;
+                                       trace_cpu_idle_miss(dev->cpu, entered_state, true);
+                               }
 
                                break;
                        }
index f64e398..768ced3 100644 (file)
@@ -2,6 +2,7 @@
 menuconfig CXL_BUS
        tristate "CXL (Compute Express Link) Devices Support"
        depends on PCI
+       select PCI_DOE
        help
          CXL is a bus that is electrically compatible with PCI Express, but
          layers three protocols on that signalling (CXL.io, CXL.cache, and
@@ -102,4 +103,12 @@ config CXL_SUSPEND
        def_bool y
        depends on SUSPEND && CXL_MEM
 
+config CXL_REGION
+       bool
+       default CXL_BUS
+       # For MAX_PHYSMEM_BITS
+       depends on SPARSEMEM
+       select MEMREGION
+       select GET_FREE_REGION
+
 endif
index 40286f5..fb64968 100644 (file)
@@ -9,10 +9,6 @@
 #include "cxlpci.h"
 #include "cxl.h"
 
-/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
-#define CFMWS_INTERLEAVE_WAYS(x)       (1 << (x)->interleave_ways)
-#define CFMWS_INTERLEAVE_GRANULARITY(x)        ((x)->granularity + 8)
-
 static unsigned long cfmws_to_decoder_flags(int restrictions)
 {
        unsigned long flags = CXL_DECODER_F_ENABLE;
@@ -34,7 +30,8 @@ static unsigned long cfmws_to_decoder_flags(int restrictions)
 static int cxl_acpi_cfmws_verify(struct device *dev,
                                 struct acpi_cedt_cfmws *cfmws)
 {
-       int expected_len;
+       int rc, expected_len;
+       unsigned int ways;
 
        if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) {
                dev_err(dev, "CFMWS Unsupported Interleave Arithmetic\n");
@@ -51,14 +48,14 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
                return -EINVAL;
        }
 
-       if (CFMWS_INTERLEAVE_WAYS(cfmws) > CXL_DECODER_MAX_INTERLEAVE) {
-               dev_err(dev, "CFMWS Interleave Ways (%d) too large\n",
-                       CFMWS_INTERLEAVE_WAYS(cfmws));
+       rc = cxl_to_ways(cfmws->interleave_ways, &ways);
+       if (rc) {
+               dev_err(dev, "CFMWS Interleave Ways (%d) invalid\n",
+                       cfmws->interleave_ways);
                return -EINVAL;
        }
 
-       expected_len = struct_size((cfmws), interleave_targets,
-                                  CFMWS_INTERLEAVE_WAYS(cfmws));
+       expected_len = struct_size(cfmws, interleave_targets, ways);
 
        if (cfmws->header.length < expected_len) {
                dev_err(dev, "CFMWS length %d less than expected %d\n",
@@ -76,6 +73,8 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
 struct cxl_cfmws_context {
        struct device *dev;
        struct cxl_port *root_port;
+       struct resource *cxl_res;
+       int id;
 };
 
 static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
@@ -84,10 +83,14 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
        int target_map[CXL_DECODER_MAX_INTERLEAVE];
        struct cxl_cfmws_context *ctx = arg;
        struct cxl_port *root_port = ctx->root_port;
+       struct resource *cxl_res = ctx->cxl_res;
+       struct cxl_root_decoder *cxlrd;
        struct device *dev = ctx->dev;
        struct acpi_cedt_cfmws *cfmws;
        struct cxl_decoder *cxld;
-       int rc, i;
+       unsigned int ways, i, ig;
+       struct resource *res;
+       int rc;
 
        cfmws = (struct acpi_cedt_cfmws *) header;
 
@@ -99,19 +102,51 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
                return 0;
        }
 
-       for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++)
+       rc = cxl_to_ways(cfmws->interleave_ways, &ways);
+       if (rc)
+               return rc;
+       rc = cxl_to_granularity(cfmws->granularity, &ig);
+       if (rc)
+               return rc;
+       for (i = 0; i < ways; i++)
                target_map[i] = cfmws->interleave_targets[i];
 
-       cxld = cxl_root_decoder_alloc(root_port, CFMWS_INTERLEAVE_WAYS(cfmws));
-       if (IS_ERR(cxld))
+       res = kzalloc(sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
+
+       res->name = kasprintf(GFP_KERNEL, "CXL Window %d", ctx->id++);
+       if (!res->name)
+               goto err_name;
+
+       res->start = cfmws->base_hpa;
+       res->end = cfmws->base_hpa + cfmws->window_size - 1;
+       res->flags = IORESOURCE_MEM;
+
+       /* add to the local resource tracking to establish a sort order */
+       rc = insert_resource(cxl_res, res);
+       if (rc)
+               goto err_insert;
+
+       cxlrd = cxl_root_decoder_alloc(root_port, ways);
+       if (IS_ERR(cxlrd))
                return 0;
 
+       cxld = &cxlrd->cxlsd.cxld;
        cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
        cxld->target_type = CXL_DECODER_EXPANDER;
-       cxld->platform_res = (struct resource)DEFINE_RES_MEM(cfmws->base_hpa,
-                                                            cfmws->window_size);
-       cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws);
-       cxld->interleave_granularity = CFMWS_INTERLEAVE_GRANULARITY(cfmws);
+       cxld->hpa_range = (struct range) {
+               .start = res->start,
+               .end = res->end,
+       };
+       cxld->interleave_ways = ways;
+       /*
+        * Minimize the x1 granularity to advertise support for any
+        * valid region granularity
+        */
+       if (ways == 1)
+               ig = CXL_DECODER_MIN_GRANULARITY;
+       cxld->interleave_granularity = ig;
 
        rc = cxl_decoder_add(cxld, target_map);
        if (rc)
@@ -119,15 +154,22 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
        else
                rc = cxl_decoder_autoremove(dev, cxld);
        if (rc) {
-               dev_err(dev, "Failed to add decoder for %pr\n",
-                       &cxld->platform_res);
+               dev_err(dev, "Failed to add decode range [%#llx - %#llx]\n",
+                       cxld->hpa_range.start, cxld->hpa_range.end);
                return 0;
        }
-       dev_dbg(dev, "add: %s node: %d range %pr\n", dev_name(&cxld->dev),
-               phys_to_target_node(cxld->platform_res.start),
-               &cxld->platform_res);
+       dev_dbg(dev, "add: %s node: %d range [%#llx - %#llx]\n",
+               dev_name(&cxld->dev),
+               phys_to_target_node(cxld->hpa_range.start),
+               cxld->hpa_range.start, cxld->hpa_range.end);
 
        return 0;
+
+err_insert:
+       kfree(res->name);
+err_name:
+       kfree(res);
+       return -ENOMEM;
 }
 
 __mock struct acpi_device *to_cxl_host_bridge(struct device *host,
@@ -175,8 +217,7 @@ static int add_host_bridge_uport(struct device *match, void *arg)
        if (rc)
                return rc;
 
-       port = devm_cxl_add_port(host, match, dport->component_reg_phys,
-                                root_port);
+       port = devm_cxl_add_port(host, match, dport->component_reg_phys, dport);
        if (IS_ERR(port))
                return PTR_ERR(port);
        dev_dbg(host, "%s: add: %s\n", dev_name(match), dev_name(&port->dev));
@@ -282,9 +323,127 @@ static void cxl_acpi_lock_reset_class(void *dev)
        device_lock_reset_class(dev);
 }
 
+static void del_cxl_resource(struct resource *res)
+{
+       kfree(res->name);
+       kfree(res);
+}
+
+static void cxl_set_public_resource(struct resource *priv, struct resource *pub)
+{
+       priv->desc = (unsigned long) pub;
+}
+
+static struct resource *cxl_get_public_resource(struct resource *priv)
+{
+       return (struct resource *) priv->desc;
+}
+
+static void remove_cxl_resources(void *data)
+{
+       struct resource *res, *next, *cxl = data;
+
+       for (res = cxl->child; res; res = next) {
+               struct resource *victim = cxl_get_public_resource(res);
+
+               next = res->sibling;
+               remove_resource(res);
+
+               if (victim) {
+                       remove_resource(victim);
+                       kfree(victim);
+               }
+
+               del_cxl_resource(res);
+       }
+}
+
+/**
+ * add_cxl_resources() - reflect CXL fixed memory windows in iomem_resource
+ * @cxl_res: A standalone resource tree where each CXL window is a sibling
+ *
+ * Walk each CXL window in @cxl_res and add it to iomem_resource potentially
+ * expanding its boundaries to ensure that any conflicting resources become
+ * children. If a window is expanded it may then conflict with a another window
+ * entry and require the window to be truncated or trimmed. Consider this
+ * situation:
+ *
+ * |-- "CXL Window 0" --||----- "CXL Window 1" -----|
+ * |--------------- "System RAM" -------------|
+ *
+ * ...where platform firmware has established as System RAM resource across 2
+ * windows, but has left some portion of window 1 for dynamic CXL region
+ * provisioning. In this case "Window 0" will span the entirety of the "System
+ * RAM" span, and "CXL Window 1" is truncated to the remaining tail past the end
+ * of that "System RAM" resource.
+ */
+static int add_cxl_resources(struct resource *cxl_res)
+{
+       struct resource *res, *new, *next;
+
+       for (res = cxl_res->child; res; res = next) {
+               new = kzalloc(sizeof(*new), GFP_KERNEL);
+               if (!new)
+                       return -ENOMEM;
+               new->name = res->name;
+               new->start = res->start;
+               new->end = res->end;
+               new->flags = IORESOURCE_MEM;
+               new->desc = IORES_DESC_CXL;
+
+               /*
+                * Record the public resource in the private cxl_res tree for
+                * later removal.
+                */
+               cxl_set_public_resource(res, new);
+
+               insert_resource_expand_to_fit(&iomem_resource, new);
+
+               next = res->sibling;
+               while (next && resource_overlaps(new, next)) {
+                       if (resource_contains(new, next)) {
+                               struct resource *_next = next->sibling;
+
+                               remove_resource(next);
+                               del_cxl_resource(next);
+                               next = _next;
+                       } else
+                               next->start = new->end + 1;
+               }
+       }
+       return 0;
+}
+
+static int pair_cxl_resource(struct device *dev, void *data)
+{
+       struct resource *cxl_res = data;
+       struct resource *p;
+
+       if (!is_root_decoder(dev))
+               return 0;
+
+       for (p = cxl_res->child; p; p = p->sibling) {
+               struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+               struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+               struct resource res = {
+                       .start = cxld->hpa_range.start,
+                       .end = cxld->hpa_range.end,
+                       .flags = IORESOURCE_MEM,
+               };
+
+               if (resource_contains(p, &res)) {
+                       cxlrd->res = cxl_get_public_resource(p);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 static int cxl_acpi_probe(struct platform_device *pdev)
 {
        int rc;
+       struct resource *cxl_res;
        struct cxl_port *root_port;
        struct device *host = &pdev->dev;
        struct acpi_device *adev = ACPI_COMPANION(host);
@@ -296,6 +455,14 @@ static int cxl_acpi_probe(struct platform_device *pdev)
        if (rc)
                return rc;
 
+       cxl_res = devm_kzalloc(host, sizeof(*cxl_res), GFP_KERNEL);
+       if (!cxl_res)
+               return -ENOMEM;
+       cxl_res->name = "CXL mem";
+       cxl_res->start = 0;
+       cxl_res->end = -1;
+       cxl_res->flags = IORESOURCE_MEM;
+
        root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
        if (IS_ERR(root_port))
                return PTR_ERR(root_port);
@@ -306,11 +473,28 @@ static int cxl_acpi_probe(struct platform_device *pdev)
        if (rc < 0)
                return rc;
 
+       rc = devm_add_action_or_reset(host, remove_cxl_resources, cxl_res);
+       if (rc)
+               return rc;
+
        ctx = (struct cxl_cfmws_context) {
                .dev = host,
                .root_port = root_port,
+               .cxl_res = cxl_res,
        };
-       acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx);
+       rc = acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx);
+       if (rc < 0)
+               return -ENXIO;
+
+       rc = add_cxl_resources(cxl_res);
+       if (rc)
+               return rc;
+
+       /*
+        * Populate the root decoders with their related iomem resource,
+        * if present
+        */
+       device_for_each_child(&root_port->dev, cxl_res, pair_cxl_resource);
 
        /*
         * Root level scanned with host-bridge as dports, now scan host-bridges
@@ -337,12 +521,19 @@ static const struct acpi_device_id cxl_acpi_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
 
+static const struct platform_device_id cxl_test_ids[] = {
+       { "cxl_acpi" },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, cxl_test_ids);
+
 static struct platform_driver cxl_acpi_driver = {
        .probe = cxl_acpi_probe,
        .driver = {
                .name = KBUILD_MODNAME,
                .acpi_match_table = cxl_acpi_ids,
        },
+       .id_table = cxl_test_ids,
 };
 
 module_platform_driver(cxl_acpi_driver);
index 9d35085..79c7257 100644 (file)
@@ -10,3 +10,4 @@ cxl_core-y += memdev.o
 cxl_core-y += mbox.o
 cxl_core-y += pci.o
 cxl_core-y += hdm.o
+cxl_core-$(CONFIG_CXL_REGION) += region.o
index 1a50c0f..1d8f87b 100644 (file)
@@ -9,6 +9,36 @@ extern const struct device_type cxl_nvdimm_type;
 
 extern struct attribute_group cxl_base_attribute_group;
 
+#ifdef CONFIG_CXL_REGION
+extern struct device_attribute dev_attr_create_pmem_region;
+extern struct device_attribute dev_attr_delete_region;
+extern struct device_attribute dev_attr_region;
+extern const struct device_type cxl_pmem_region_type;
+extern const struct device_type cxl_region_type;
+void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
+#define CXL_REGION_ATTR(x) (&dev_attr_##x.attr)
+#define CXL_REGION_TYPE(x) (&cxl_region_type)
+#define SET_CXL_REGION_ATTR(x) (&dev_attr_##x.attr),
+#define CXL_PMEM_REGION_TYPE(x) (&cxl_pmem_region_type)
+int cxl_region_init(void);
+void cxl_region_exit(void);
+#else
+static inline void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
+{
+}
+static inline int cxl_region_init(void)
+{
+       return 0;
+}
+static inline void cxl_region_exit(void)
+{
+}
+#define CXL_REGION_ATTR(x) NULL
+#define CXL_REGION_TYPE(x) NULL
+#define SET_CXL_REGION_ATTR(x)
+#define CXL_PMEM_REGION_TYPE(x) NULL
+#endif
+
 struct cxl_send_command;
 struct cxl_mem_query_commands;
 int cxl_query_cmd(struct cxl_memdev *cxlmd,
@@ -17,9 +47,28 @@ int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s);
 void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
                                   resource_size_t length);
 
+struct dentry *cxl_debugfs_create_dir(const char *dir);
+int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled,
+                    enum cxl_decoder_mode mode);
+int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size);
+int cxl_dpa_free(struct cxl_endpoint_decoder *cxled);
+resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled);
+resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled);
+extern struct rw_semaphore cxl_dpa_rwsem;
+
+bool is_switch_decoder(struct device *dev);
+struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev);
+static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
+                                        struct cxl_memdev *cxlmd)
+{
+       if (!port)
+               return NULL;
+
+       return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev);
+}
+
 int cxl_memdev_init(void);
 void cxl_memdev_exit(void);
 void cxl_mbox_init(void);
-void cxl_mbox_exit(void);
 
 #endif /* __CXL_CORE_H__ */
index bfc8ee8..d1d2cae 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */
 #include <linux/io-64-nonatomic-hi-lo.h>
+#include <linux/seq_file.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 
@@ -16,6 +17,8 @@
  * for enumerating these registers and capabilities.
  */
 
+DECLARE_RWSEM(cxl_dpa_rwsem);
+
 static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
                           int *target_map)
 {
@@ -46,20 +49,22 @@ static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
  */
 int devm_cxl_add_passthrough_decoder(struct cxl_port *port)
 {
-       struct cxl_decoder *cxld;
-       struct cxl_dport *dport;
+       struct cxl_switch_decoder *cxlsd;
+       struct cxl_dport *dport = NULL;
        int single_port_map[1];
+       unsigned long index;
 
-       cxld = cxl_switch_decoder_alloc(port, 1);
-       if (IS_ERR(cxld))
-               return PTR_ERR(cxld);
+       cxlsd = cxl_switch_decoder_alloc(port, 1);
+       if (IS_ERR(cxlsd))
+               return PTR_ERR(cxlsd);
 
        device_lock_assert(&port->dev);
 
-       dport = list_first_entry(&port->dports, typeof(*dport), list);
+       xa_for_each(&port->dports, index, dport)
+               break;
        single_port_map[0] = dport->port_id;
 
-       return add_hdm_decoder(port, cxld, single_port_map);
+       return add_hdm_decoder(port, &cxlsd->cxld, single_port_map);
 }
 EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, CXL);
 
@@ -124,47 +129,577 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
                return ERR_PTR(-ENXIO);
        }
 
+       dev_set_drvdata(dev, cxlhdm);
+
        return cxlhdm;
 }
 EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, CXL);
 
-static int to_interleave_granularity(u32 ctrl)
+static void __cxl_dpa_debug(struct seq_file *file, struct resource *r, int depth)
+{
+       unsigned long long start = r->start, end = r->end;
+
+       seq_printf(file, "%*s%08llx-%08llx : %s\n", depth * 2, "", start, end,
+                  r->name);
+}
+
+void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds)
+{
+       struct resource *p1, *p2;
+
+       down_read(&cxl_dpa_rwsem);
+       for (p1 = cxlds->dpa_res.child; p1; p1 = p1->sibling) {
+               __cxl_dpa_debug(file, p1, 0);
+               for (p2 = p1->child; p2; p2 = p2->sibling)
+                       __cxl_dpa_debug(file, p2, 1);
+       }
+       up_read(&cxl_dpa_rwsem);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_dpa_debug, CXL);
+
+/*
+ * Must be called in a context that synchronizes against this decoder's
+ * port ->remove() callback (like an endpoint decoder sysfs attribute)
+ */
+static void __cxl_dpa_release(struct cxl_endpoint_decoder *cxled)
+{
+       struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+       struct cxl_port *port = cxled_to_port(cxled);
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct resource *res = cxled->dpa_res;
+       resource_size_t skip_start;
+
+       lockdep_assert_held_write(&cxl_dpa_rwsem);
+
+       /* save @skip_start, before @res is released */
+       skip_start = res->start - cxled->skip;
+       __release_region(&cxlds->dpa_res, res->start, resource_size(res));
+       if (cxled->skip)
+               __release_region(&cxlds->dpa_res, skip_start, cxled->skip);
+       cxled->skip = 0;
+       cxled->dpa_res = NULL;
+       put_device(&cxled->cxld.dev);
+       port->hdm_end--;
+}
+
+static void cxl_dpa_release(void *cxled)
+{
+       down_write(&cxl_dpa_rwsem);
+       __cxl_dpa_release(cxled);
+       up_write(&cxl_dpa_rwsem);
+}
+
+/*
+ * Must be called from context that will not race port device
+ * unregistration, like decoder sysfs attribute methods
+ */
+static void devm_cxl_dpa_release(struct cxl_endpoint_decoder *cxled)
+{
+       struct cxl_port *port = cxled_to_port(cxled);
+
+       lockdep_assert_held_write(&cxl_dpa_rwsem);
+       devm_remove_action(&port->dev, cxl_dpa_release, cxled);
+       __cxl_dpa_release(cxled);
+}
+
+static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
+                            resource_size_t base, resource_size_t len,
+                            resource_size_t skipped)
+{
+       struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+       struct cxl_port *port = cxled_to_port(cxled);
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct device *dev = &port->dev;
+       struct resource *res;
+
+       lockdep_assert_held_write(&cxl_dpa_rwsem);
+
+       if (!len)
+               goto success;
+
+       if (cxled->dpa_res) {
+               dev_dbg(dev, "decoder%d.%d: existing allocation %pr assigned\n",
+                       port->id, cxled->cxld.id, cxled->dpa_res);
+               return -EBUSY;
+       }
+
+       if (port->hdm_end + 1 != cxled->cxld.id) {
+               /*
+                * Assumes alloc and commit order is always in hardware instance
+                * order per expectations from 8.2.5.12.20 Committing Decoder
+                * Programming that enforce decoder[m] committed before
+                * decoder[m+1] commit start.
+                */
+               dev_dbg(dev, "decoder%d.%d: expected decoder%d.%d\n", port->id,
+                       cxled->cxld.id, port->id, port->hdm_end + 1);
+               return -EBUSY;
+       }
+
+       if (skipped) {
+               res = __request_region(&cxlds->dpa_res, base - skipped, skipped,
+                                      dev_name(&cxled->cxld.dev), 0);
+               if (!res) {
+                       dev_dbg(dev,
+                               "decoder%d.%d: failed to reserve skipped space\n",
+                               port->id, cxled->cxld.id);
+                       return -EBUSY;
+               }
+       }
+       res = __request_region(&cxlds->dpa_res, base, len,
+                              dev_name(&cxled->cxld.dev), 0);
+       if (!res) {
+               dev_dbg(dev, "decoder%d.%d: failed to reserve allocation\n",
+                       port->id, cxled->cxld.id);
+               if (skipped)
+                       __release_region(&cxlds->dpa_res, base - skipped,
+                                        skipped);
+               return -EBUSY;
+       }
+       cxled->dpa_res = res;
+       cxled->skip = skipped;
+
+       if (resource_contains(&cxlds->pmem_res, res))
+               cxled->mode = CXL_DECODER_PMEM;
+       else if (resource_contains(&cxlds->ram_res, res))
+               cxled->mode = CXL_DECODER_RAM;
+       else {
+               dev_dbg(dev, "decoder%d.%d: %pr mixed\n", port->id,
+                       cxled->cxld.id, cxled->dpa_res);
+               cxled->mode = CXL_DECODER_MIXED;
+       }
+
+success:
+       port->hdm_end++;
+       get_device(&cxled->cxld.dev);
+       return 0;
+}
+
+static int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
+                               resource_size_t base, resource_size_t len,
+                               resource_size_t skipped)
 {
-       int val = FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl);
+       struct cxl_port *port = cxled_to_port(cxled);
+       int rc;
+
+       down_write(&cxl_dpa_rwsem);
+       rc = __cxl_dpa_reserve(cxled, base, len, skipped);
+       up_write(&cxl_dpa_rwsem);
+
+       if (rc)
+               return rc;
 
-       return 256 << val;
+       return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled);
 }
 
-static int to_interleave_ways(u32 ctrl)
+resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled)
 {
-       int val = FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl);
+       resource_size_t size = 0;
+
+       down_read(&cxl_dpa_rwsem);
+       if (cxled->dpa_res)
+               size = resource_size(cxled->dpa_res);
+       up_read(&cxl_dpa_rwsem);
 
-       switch (val) {
-       case 0 ... 4:
-               return 1 << val;
-       case 8 ... 10:
-               return 3 << (val - 8);
+       return size;
+}
+
+resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled)
+{
+       resource_size_t base = -1;
+
+       down_read(&cxl_dpa_rwsem);
+       if (cxled->dpa_res)
+               base = cxled->dpa_res->start;
+       up_read(&cxl_dpa_rwsem);
+
+       return base;
+}
+
+int cxl_dpa_free(struct cxl_endpoint_decoder *cxled)
+{
+       struct cxl_port *port = cxled_to_port(cxled);
+       struct device *dev = &cxled->cxld.dev;
+       int rc;
+
+       down_write(&cxl_dpa_rwsem);
+       if (!cxled->dpa_res) {
+               rc = 0;
+               goto out;
+       }
+       if (cxled->cxld.region) {
+               dev_dbg(dev, "decoder assigned to: %s\n",
+                       dev_name(&cxled->cxld.region->dev));
+               rc = -EBUSY;
+               goto out;
+       }
+       if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) {
+               dev_dbg(dev, "decoder enabled\n");
+               rc = -EBUSY;
+               goto out;
+       }
+       if (cxled->cxld.id != port->hdm_end) {
+               dev_dbg(dev, "expected decoder%d.%d\n", port->id,
+                       port->hdm_end);
+               rc = -EBUSY;
+               goto out;
+       }
+       devm_cxl_dpa_release(cxled);
+       rc = 0;
+out:
+       up_write(&cxl_dpa_rwsem);
+       return rc;
+}
+
+int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled,
+                    enum cxl_decoder_mode mode)
+{
+       struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct device *dev = &cxled->cxld.dev;
+       int rc;
+
+       switch (mode) {
+       case CXL_DECODER_RAM:
+       case CXL_DECODER_PMEM:
+               break;
        default:
+               dev_dbg(dev, "unsupported mode: %d\n", mode);
+               return -EINVAL;
+       }
+
+       down_write(&cxl_dpa_rwsem);
+       if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) {
+               rc = -EBUSY;
+               goto out;
+       }
+
+       /*
+        * Only allow modes that are supported by the current partition
+        * configuration
+        */
+       if (mode == CXL_DECODER_PMEM && !resource_size(&cxlds->pmem_res)) {
+               dev_dbg(dev, "no available pmem capacity\n");
+               rc = -ENXIO;
+               goto out;
+       }
+       if (mode == CXL_DECODER_RAM && !resource_size(&cxlds->ram_res)) {
+               dev_dbg(dev, "no available ram capacity\n");
+               rc = -ENXIO;
+               goto out;
+       }
+
+       cxled->mode = mode;
+       rc = 0;
+out:
+       up_write(&cxl_dpa_rwsem);
+
+       return rc;
+}
+
+int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size)
+{
+       struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+       resource_size_t free_ram_start, free_pmem_start;
+       struct cxl_port *port = cxled_to_port(cxled);
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct device *dev = &cxled->cxld.dev;
+       resource_size_t start, avail, skip;
+       struct resource *p, *last;
+       int rc;
+
+       down_write(&cxl_dpa_rwsem);
+       if (cxled->cxld.region) {
+               dev_dbg(dev, "decoder attached to %s\n",
+                       dev_name(&cxled->cxld.region->dev));
+               rc = -EBUSY;
+               goto out;
+       }
+
+       if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) {
+               dev_dbg(dev, "decoder enabled\n");
+               rc = -EBUSY;
+               goto out;
+       }
+
+       for (p = cxlds->ram_res.child, last = NULL; p; p = p->sibling)
+               last = p;
+       if (last)
+               free_ram_start = last->end + 1;
+       else
+               free_ram_start = cxlds->ram_res.start;
+
+       for (p = cxlds->pmem_res.child, last = NULL; p; p = p->sibling)
+               last = p;
+       if (last)
+               free_pmem_start = last->end + 1;
+       else
+               free_pmem_start = cxlds->pmem_res.start;
+
+       if (cxled->mode == CXL_DECODER_RAM) {
+               start = free_ram_start;
+               avail = cxlds->ram_res.end - start + 1;
+               skip = 0;
+       } else if (cxled->mode == CXL_DECODER_PMEM) {
+               resource_size_t skip_start, skip_end;
+
+               start = free_pmem_start;
+               avail = cxlds->pmem_res.end - start + 1;
+               skip_start = free_ram_start;
+
+               /*
+                * If some pmem is already allocated, then that allocation
+                * already handled the skip.
+                */
+               if (cxlds->pmem_res.child &&
+                   skip_start == cxlds->pmem_res.child->start)
+                       skip_end = skip_start - 1;
+               else
+                       skip_end = start - 1;
+               skip = skip_end - skip_start + 1;
+       } else {
+               dev_dbg(dev, "mode not set\n");
+               rc = -EINVAL;
+               goto out;
+       }
+
+       if (size > avail) {
+               dev_dbg(dev, "%pa exceeds available %s capacity: %pa\n", &size,
+                       cxled->mode == CXL_DECODER_RAM ? "ram" : "pmem",
+                       &avail);
+               rc = -ENOSPC;
+               goto out;
+       }
+
+       rc = __cxl_dpa_reserve(cxled, start, size, skip);
+out:
+       up_write(&cxl_dpa_rwsem);
+
+       if (rc)
+               return rc;
+
+       return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled);
+}
+
+static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl)
+{
+       u16 eig;
+       u8 eiw;
+
+       /*
+        * Input validation ensures these warns never fire, but otherwise
+        * suppress unititalized variable usage warnings.
+        */
+       if (WARN_ONCE(ways_to_cxl(cxld->interleave_ways, &eiw),
+                     "invalid interleave_ways: %d\n", cxld->interleave_ways))
+               return;
+       if (WARN_ONCE(granularity_to_cxl(cxld->interleave_granularity, &eig),
+                     "invalid interleave_granularity: %d\n",
+                     cxld->interleave_granularity))
+               return;
+
+       u32p_replace_bits(ctrl, eig, CXL_HDM_DECODER0_CTRL_IG_MASK);
+       u32p_replace_bits(ctrl, eiw, CXL_HDM_DECODER0_CTRL_IW_MASK);
+       *ctrl |= CXL_HDM_DECODER0_CTRL_COMMIT;
+}
+
+static void cxld_set_type(struct cxl_decoder *cxld, u32 *ctrl)
+{
+       u32p_replace_bits(ctrl, !!(cxld->target_type == 3),
+                         CXL_HDM_DECODER0_CTRL_TYPE);
+}
+
+static int cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt)
+{
+       struct cxl_dport **t = &cxlsd->target[0];
+       int ways = cxlsd->cxld.interleave_ways;
+
+       if (dev_WARN_ONCE(&cxlsd->cxld.dev,
+                         ways > 8 || ways > cxlsd->nr_targets,
+                         "ways: %d overflows targets: %d\n", ways,
+                         cxlsd->nr_targets))
+               return -ENXIO;
+
+       *tgt = FIELD_PREP(GENMASK(7, 0), t[0]->port_id);
+       if (ways > 1)
+               *tgt |= FIELD_PREP(GENMASK(15, 8), t[1]->port_id);
+       if (ways > 2)
+               *tgt |= FIELD_PREP(GENMASK(23, 16), t[2]->port_id);
+       if (ways > 3)
+               *tgt |= FIELD_PREP(GENMASK(31, 24), t[3]->port_id);
+       if (ways > 4)
+               *tgt |= FIELD_PREP(GENMASK_ULL(39, 32), t[4]->port_id);
+       if (ways > 5)
+               *tgt |= FIELD_PREP(GENMASK_ULL(47, 40), t[5]->port_id);
+       if (ways > 6)
+               *tgt |= FIELD_PREP(GENMASK_ULL(55, 48), t[6]->port_id);
+       if (ways > 7)
+               *tgt |= FIELD_PREP(GENMASK_ULL(63, 56), t[7]->port_id);
+
+       return 0;
+}
+
+/*
+ * Per CXL 2.0 8.2.5.12.20 Committing Decoder Programming, hardware must set
+ * committed or error within 10ms, but just be generous with 20ms to account for
+ * clock skew and other marginal behavior
+ */
+#define COMMIT_TIMEOUT_MS 20
+static int cxld_await_commit(void __iomem *hdm, int id)
+{
+       u32 ctrl;
+       int i;
+
+       for (i = 0; i < COMMIT_TIMEOUT_MS; i++) {
+               ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+               if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMIT_ERROR, ctrl)) {
+                       ctrl &= ~CXL_HDM_DECODER0_CTRL_COMMIT;
+                       writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+                       return -EIO;
+               }
+               if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
+                       return 0;
+               fsleep(1000);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int cxl_decoder_commit(struct cxl_decoder *cxld)
+{
+       struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+       struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+       void __iomem *hdm = cxlhdm->regs.hdm_decoder;
+       int id = cxld->id, rc;
+       u64 base, size;
+       u32 ctrl;
+
+       if (cxld->flags & CXL_DECODER_F_ENABLE)
+               return 0;
+
+       if (port->commit_end + 1 != id) {
+               dev_dbg(&port->dev,
+                       "%s: out of order commit, expected decoder%d.%d\n",
+                       dev_name(&cxld->dev), port->id, port->commit_end + 1);
+               return -EBUSY;
+       }
+
+       down_read(&cxl_dpa_rwsem);
+       /* common decoder settings */
+       ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(cxld->id));
+       cxld_set_interleave(cxld, &ctrl);
+       cxld_set_type(cxld, &ctrl);
+       base = cxld->hpa_range.start;
+       size = range_len(&cxld->hpa_range);
+
+       writel(upper_32_bits(base), hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id));
+       writel(lower_32_bits(base), hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id));
+       writel(upper_32_bits(size), hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(id));
+       writel(lower_32_bits(size), hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id));
+
+       if (is_switch_decoder(&cxld->dev)) {
+               struct cxl_switch_decoder *cxlsd =
+                       to_cxl_switch_decoder(&cxld->dev);
+               void __iomem *tl_hi = hdm + CXL_HDM_DECODER0_TL_HIGH(id);
+               void __iomem *tl_lo = hdm + CXL_HDM_DECODER0_TL_LOW(id);
+               u64 targets;
+
+               rc = cxlsd_set_targets(cxlsd, &targets);
+               if (rc) {
+                       dev_dbg(&port->dev, "%s: target configuration error\n",
+                               dev_name(&cxld->dev));
+                       goto err;
+               }
+
+               writel(upper_32_bits(targets), tl_hi);
+               writel(lower_32_bits(targets), tl_lo);
+       } else {
+               struct cxl_endpoint_decoder *cxled =
+                       to_cxl_endpoint_decoder(&cxld->dev);
+               void __iomem *sk_hi = hdm + CXL_HDM_DECODER0_SKIP_HIGH(id);
+               void __iomem *sk_lo = hdm + CXL_HDM_DECODER0_SKIP_LOW(id);
+
+               writel(upper_32_bits(cxled->skip), sk_hi);
+               writel(lower_32_bits(cxled->skip), sk_lo);
+       }
+
+       writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+       up_read(&cxl_dpa_rwsem);
+
+       port->commit_end++;
+       rc = cxld_await_commit(hdm, cxld->id);
+err:
+       if (rc) {
+               dev_dbg(&port->dev, "%s: error %d committing decoder\n",
+                       dev_name(&cxld->dev), rc);
+               cxld->reset(cxld);
+               return rc;
+       }
+       cxld->flags |= CXL_DECODER_F_ENABLE;
+
+       return 0;
+}
+
+static int cxl_decoder_reset(struct cxl_decoder *cxld)
+{
+       struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+       struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+       void __iomem *hdm = cxlhdm->regs.hdm_decoder;
+       int id = cxld->id;
+       u32 ctrl;
+
+       if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
                return 0;
+
+       if (port->commit_end != id) {
+               dev_dbg(&port->dev,
+                       "%s: out of order reset, expected decoder%d.%d\n",
+                       dev_name(&cxld->dev), port->id, port->commit_end);
+               return -EBUSY;
        }
+
+       down_read(&cxl_dpa_rwsem);
+       ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+       ctrl &= ~CXL_HDM_DECODER0_CTRL_COMMIT;
+       writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+
+       writel(0, hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(id));
+       writel(0, hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id));
+       writel(0, hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id));
+       writel(0, hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id));
+       up_read(&cxl_dpa_rwsem);
+
+       port->commit_end--;
+       cxld->flags &= ~CXL_DECODER_F_ENABLE;
+
+       return 0;
 }
 
 static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
-                           int *target_map, void __iomem *hdm, int which)
+                           int *target_map, void __iomem *hdm, int which,
+                           u64 *dpa_base)
 {
-       u64 size, base;
+       struct cxl_endpoint_decoder *cxled = NULL;
+       u64 size, base, skip, dpa_size;
+       bool committed;
+       u32 remainder;
+       int i, rc;
        u32 ctrl;
-       int i;
        union {
                u64 value;
                unsigned char target_id[8];
        } target_list;
 
+       if (is_endpoint_decoder(&cxld->dev))
+               cxled = to_cxl_endpoint_decoder(&cxld->dev);
+
        ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which));
        base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
        size = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which));
+       committed = !!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED);
+       cxld->commit = cxl_decoder_commit;
+       cxld->reset = cxl_decoder_reset;
 
-       if (!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED))
+       if (!committed)
                size = 0;
        if (base == U64_MAX || size == U64_MAX) {
                dev_warn(&port->dev, "decoder%d.%d: Invalid resource range\n",
@@ -172,39 +707,77 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
                return -ENXIO;
        }
 
-       cxld->decoder_range = (struct range) {
+       cxld->hpa_range = (struct range) {
                .start = base,
                .end = base + size - 1,
        };
 
-       /* switch decoders are always enabled if committed */
-       if (ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED) {
+       /* decoders are enabled if committed */
+       if (committed) {
                cxld->flags |= CXL_DECODER_F_ENABLE;
                if (ctrl & CXL_HDM_DECODER0_CTRL_LOCK)
                        cxld->flags |= CXL_DECODER_F_LOCK;
+               if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl))
+                       cxld->target_type = CXL_DECODER_EXPANDER;
+               else
+                       cxld->target_type = CXL_DECODER_ACCELERATOR;
+               if (cxld->id != port->commit_end + 1) {
+                       dev_warn(&port->dev,
+                                "decoder%d.%d: Committed out of order\n",
+                                port->id, cxld->id);
+                       return -ENXIO;
+               }
+               port->commit_end = cxld->id;
+       } else {
+               /* unless / until type-2 drivers arrive, assume type-3 */
+               if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl) == 0) {
+                       ctrl |= CXL_HDM_DECODER0_CTRL_TYPE;
+                       writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which));
+               }
+               cxld->target_type = CXL_DECODER_EXPANDER;
        }
-       cxld->interleave_ways = to_interleave_ways(ctrl);
-       if (!cxld->interleave_ways) {
+       rc = cxl_to_ways(FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl),
+                        &cxld->interleave_ways);
+       if (rc) {
                dev_warn(&port->dev,
                         "decoder%d.%d: Invalid interleave ways (ctrl: %#x)\n",
                         port->id, cxld->id, ctrl);
-               return -ENXIO;
+               return rc;
        }
-       cxld->interleave_granularity = to_interleave_granularity(ctrl);
+       rc = cxl_to_granularity(FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl),
+                               &cxld->interleave_granularity);
+       if (rc)
+               return rc;
 
-       if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl))
-               cxld->target_type = CXL_DECODER_EXPANDER;
-       else
-               cxld->target_type = CXL_DECODER_ACCELERATOR;
+       if (!cxled) {
+               target_list.value =
+                       ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
+               for (i = 0; i < cxld->interleave_ways; i++)
+                       target_map[i] = target_list.target_id[i];
 
-       if (is_endpoint_decoder(&cxld->dev))
                return 0;
+       }
 
-       target_list.value =
-               ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
-       for (i = 0; i < cxld->interleave_ways; i++)
-               target_map[i] = target_list.target_id[i];
+       if (!committed)
+               return 0;
 
+       dpa_size = div_u64_rem(size, cxld->interleave_ways, &remainder);
+       if (remainder) {
+               dev_err(&port->dev,
+                       "decoder%d.%d: invalid committed configuration size: %#llx ways: %d\n",
+                       port->id, cxld->id, size, cxld->interleave_ways);
+               return -ENXIO;
+       }
+       skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
+       rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip);
+       if (rc) {
+               dev_err(&port->dev,
+                       "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx\n (%d)",
+                       port->id, cxld->id, *dpa_base,
+                       *dpa_base + dpa_size + skip - 1, rc);
+               return rc;
+       }
+       *dpa_base += dpa_size + skip;
        return 0;
 }
 
@@ -216,7 +789,8 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
 {
        void __iomem *hdm = cxlhdm->regs.hdm_decoder;
        struct cxl_port *port = cxlhdm->port;
-       int i, committed, failed;
+       int i, committed;
+       u64 dpa_base = 0;
        u32 ctrl;
 
        /*
@@ -236,27 +810,37 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
        if (committed != cxlhdm->decoder_count)
                msleep(20);
 
-       for (i = 0, failed = 0; i < cxlhdm->decoder_count; i++) {
+       for (i = 0; i < cxlhdm->decoder_count; i++) {
                int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
                int rc, target_count = cxlhdm->target_count;
                struct cxl_decoder *cxld;
 
-               if (is_cxl_endpoint(port))
-                       cxld = cxl_endpoint_decoder_alloc(port);
-               else
-                       cxld = cxl_switch_decoder_alloc(port, target_count);
-               if (IS_ERR(cxld)) {
-                       dev_warn(&port->dev,
-                                "Failed to allocate the decoder\n");
-                       return PTR_ERR(cxld);
+               if (is_cxl_endpoint(port)) {
+                       struct cxl_endpoint_decoder *cxled;
+
+                       cxled = cxl_endpoint_decoder_alloc(port);
+                       if (IS_ERR(cxled)) {
+                               dev_warn(&port->dev,
+                                        "Failed to allocate the decoder\n");
+                               return PTR_ERR(cxled);
+                       }
+                       cxld = &cxled->cxld;
+               } else {
+                       struct cxl_switch_decoder *cxlsd;
+
+                       cxlsd = cxl_switch_decoder_alloc(port, target_count);
+                       if (IS_ERR(cxlsd)) {
+                               dev_warn(&port->dev,
+                                        "Failed to allocate the decoder\n");
+                               return PTR_ERR(cxlsd);
+                       }
+                       cxld = &cxlsd->cxld;
                }
 
-               rc = init_hdm_decoder(port, cxld, target_map,
-                                     cxlhdm->regs.hdm_decoder, i);
+               rc = init_hdm_decoder(port, cxld, target_map, hdm, i, &dpa_base);
                if (rc) {
                        put_device(&cxld->dev);
-                       failed++;
-                       continue;
+                       return rc;
                }
                rc = add_hdm_decoder(port, cxld, target_map);
                if (rc) {
@@ -266,11 +850,6 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
                }
        }
 
-       if (failed == cxlhdm->decoder_count) {
-               dev_err(&port->dev, "No valid decoders found\n");
-               return -ENXIO;
-       }
-
        return 0;
 }
 EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, CXL);
index cbf23be..16176b9 100644 (file)
@@ -718,12 +718,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL);
  */
 static int cxl_mem_get_partition_info(struct cxl_dev_state *cxlds)
 {
-       struct cxl_mbox_get_partition_info {
-               __le64 active_volatile_cap;
-               __le64 active_persistent_cap;
-               __le64 next_volatile_cap;
-               __le64 next_persistent_cap;
-       } __packed pi;
+       struct cxl_mbox_get_partition_info pi;
        int rc;
 
        rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_PARTITION_INFO, NULL, 0,
@@ -773,15 +768,6 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
        cxlds->partition_align_bytes =
                le64_to_cpu(id.partition_align) * CXL_CAPACITY_MULTIPLIER;
 
-       dev_dbg(cxlds->dev,
-               "Identify Memory Device\n"
-               "     total_bytes = %#llx\n"
-               "     volatile_only_bytes = %#llx\n"
-               "     persistent_only_bytes = %#llx\n"
-               "     partition_align_bytes = %#llx\n",
-               cxlds->total_bytes, cxlds->volatile_only_bytes,
-               cxlds->persistent_only_bytes, cxlds->partition_align_bytes);
-
        cxlds->lsa_size = le32_to_cpu(id.lsa_size);
        memcpy(cxlds->firmware_version, id.fw_revision, sizeof(id.fw_revision));
 
@@ -789,42 +775,63 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
 }
 EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);
 
-int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
+static int add_dpa_res(struct device *dev, struct resource *parent,
+                      struct resource *res, resource_size_t start,
+                      resource_size_t size, const char *type)
 {
        int rc;
 
-       if (cxlds->partition_align_bytes == 0) {
-               cxlds->ram_range.start = 0;
-               cxlds->ram_range.end = cxlds->volatile_only_bytes - 1;
-               cxlds->pmem_range.start = cxlds->volatile_only_bytes;
-               cxlds->pmem_range.end = cxlds->volatile_only_bytes +
-                                      cxlds->persistent_only_bytes - 1;
+       res->name = type;
+       res->start = start;
+       res->end = start + size - 1;
+       res->flags = IORESOURCE_MEM;
+       if (resource_size(res) == 0) {
+               dev_dbg(dev, "DPA(%s): no capacity\n", res->name);
                return 0;
        }
-
-       rc = cxl_mem_get_partition_info(cxlds);
+       rc = request_resource(parent, res);
        if (rc) {
-               dev_err(cxlds->dev, "Failed to query partition information\n");
+               dev_err(dev, "DPA(%s): failed to track %pr (%d)\n", res->name,
+                       res, rc);
                return rc;
        }
 
-       dev_dbg(cxlds->dev,
-               "Get Partition Info\n"
-               "     active_volatile_bytes = %#llx\n"
-               "     active_persistent_bytes = %#llx\n"
-               "     next_volatile_bytes = %#llx\n"
-               "     next_persistent_bytes = %#llx\n",
-               cxlds->active_volatile_bytes, cxlds->active_persistent_bytes,
-               cxlds->next_volatile_bytes, cxlds->next_persistent_bytes);
+       dev_dbg(dev, "DPA(%s): %pr\n", res->name, res);
+
+       return 0;
+}
 
-       cxlds->ram_range.start = 0;
-       cxlds->ram_range.end = cxlds->active_volatile_bytes - 1;
+int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
+{
+       struct device *dev = cxlds->dev;
+       int rc;
 
-       cxlds->pmem_range.start = cxlds->active_volatile_bytes;
-       cxlds->pmem_range.end =
-               cxlds->active_volatile_bytes + cxlds->active_persistent_bytes - 1;
+       cxlds->dpa_res =
+               (struct resource)DEFINE_RES_MEM(0, cxlds->total_bytes);
 
-       return 0;
+       if (cxlds->partition_align_bytes == 0) {
+               rc = add_dpa_res(dev, &cxlds->dpa_res, &cxlds->ram_res, 0,
+                                cxlds->volatile_only_bytes, "ram");
+               if (rc)
+                       return rc;
+               return add_dpa_res(dev, &cxlds->dpa_res, &cxlds->pmem_res,
+                                  cxlds->volatile_only_bytes,
+                                  cxlds->persistent_only_bytes, "pmem");
+       }
+
+       rc = cxl_mem_get_partition_info(cxlds);
+       if (rc) {
+               dev_err(dev, "Failed to query partition information\n");
+               return rc;
+       }
+
+       rc = add_dpa_res(dev, &cxlds->dpa_res, &cxlds->ram_res, 0,
+                        cxlds->active_volatile_bytes, "ram");
+       if (rc)
+               return rc;
+       return add_dpa_res(dev, &cxlds->dpa_res, &cxlds->pmem_res,
+                          cxlds->active_volatile_bytes,
+                          cxlds->active_persistent_bytes, "pmem");
 }
 EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL);
 
@@ -845,19 +852,11 @@ struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
 }
 EXPORT_SYMBOL_NS_GPL(cxl_dev_state_create, CXL);
 
-static struct dentry *cxl_debugfs;
-
 void __init cxl_mbox_init(void)
 {
        struct dentry *mbox_debugfs;
 
-       cxl_debugfs = debugfs_create_dir("cxl", NULL);
-       mbox_debugfs = debugfs_create_dir("mbox", cxl_debugfs);
+       mbox_debugfs = cxl_debugfs_create_dir("mbox");
        debugfs_create_bool("raw_allow_all", 0600, mbox_debugfs,
                            &cxl_raw_allow_all);
 }
-
-void cxl_mbox_exit(void)
-{
-       debugfs_remove_recursive(cxl_debugfs);
-}
index f7cdcd3..20ce488 100644 (file)
@@ -68,7 +68,7 @@ static ssize_t ram_size_show(struct device *dev, struct device_attribute *attr,
 {
        struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
-       unsigned long long len = range_len(&cxlds->ram_range);
+       unsigned long long len = resource_size(&cxlds->ram_res);
 
        return sysfs_emit(buf, "%#llx\n", len);
 }
@@ -81,7 +81,7 @@ static ssize_t pmem_size_show(struct device *dev, struct device_attribute *attr,
 {
        struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
-       unsigned long long len = range_len(&cxlds->pmem_range);
+       unsigned long long len = resource_size(&cxlds->pmem_res);
 
        return sysfs_emit(buf, "%#llx\n", len);
 }
index c4c99ff..9240df5 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <linux/pci-doe.h>
 #include <cxlpci.h>
 #include <cxlmem.h>
 #include <cxl.h>
@@ -225,7 +226,6 @@ static int dvsec_range_allowed(struct device *dev, void *arg)
 {
        struct range *dev_range = arg;
        struct cxl_decoder *cxld;
-       struct range root_range;
 
        if (!is_root_decoder(dev))
                return 0;
@@ -237,12 +237,7 @@ static int dvsec_range_allowed(struct device *dev, void *arg)
        if (!(cxld->flags & CXL_DECODER_F_RAM))
                return 0;
 
-       root_range = (struct range) {
-               .start = cxld->platform_res.start,
-               .end = cxld->platform_res.end,
-       };
-
-       return range_contains(&root_range, dev_range);
+       return range_contains(&cxld->hpa_range, dev_range);
 }
 
 static void disable_hdm(void *_cxlhdm)
@@ -458,3 +453,175 @@ hdm_init:
        return 0;
 }
 EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL);
+
+#define CXL_DOE_TABLE_ACCESS_REQ_CODE          0x000000ff
+#define   CXL_DOE_TABLE_ACCESS_REQ_CODE_READ   0
+#define CXL_DOE_TABLE_ACCESS_TABLE_TYPE                0x0000ff00
+#define   CXL_DOE_TABLE_ACCESS_TABLE_TYPE_CDATA        0
+#define CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE      0xffff0000
+#define CXL_DOE_TABLE_ACCESS_LAST_ENTRY                0xffff
+#define CXL_DOE_PROTOCOL_TABLE_ACCESS 2
+
+static struct pci_doe_mb *find_cdat_doe(struct device *uport)
+{
+       struct cxl_memdev *cxlmd;
+       struct cxl_dev_state *cxlds;
+       unsigned long index;
+       void *entry;
+
+       cxlmd = to_cxl_memdev(uport);
+       cxlds = cxlmd->cxlds;
+
+       xa_for_each(&cxlds->doe_mbs, index, entry) {
+               struct pci_doe_mb *cur = entry;
+
+               if (pci_doe_supports_prot(cur, PCI_DVSEC_VENDOR_ID_CXL,
+                                         CXL_DOE_PROTOCOL_TABLE_ACCESS))
+                       return cur;
+       }
+
+       return NULL;
+}
+
+#define CDAT_DOE_REQ(entry_handle)                                     \
+       (FIELD_PREP(CXL_DOE_TABLE_ACCESS_REQ_CODE,                      \
+                   CXL_DOE_TABLE_ACCESS_REQ_CODE_READ) |               \
+        FIELD_PREP(CXL_DOE_TABLE_ACCESS_TABLE_TYPE,                    \
+                   CXL_DOE_TABLE_ACCESS_TABLE_TYPE_CDATA) |            \
+        FIELD_PREP(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, (entry_handle)))
+
+static void cxl_doe_task_complete(struct pci_doe_task *task)
+{
+       complete(task->private);
+}
+
+struct cdat_doe_task {
+       u32 request_pl;
+       u32 response_pl[32];
+       struct completion c;
+       struct pci_doe_task task;
+};
+
+#define DECLARE_CDAT_DOE_TASK(req, cdt)                       \
+struct cdat_doe_task cdt = {                                  \
+       .c = COMPLETION_INITIALIZER_ONSTACK(cdt.c),           \
+       .request_pl = req,                                    \
+       .task = {                                             \
+               .prot.vid = PCI_DVSEC_VENDOR_ID_CXL,        \
+               .prot.type = CXL_DOE_PROTOCOL_TABLE_ACCESS, \
+               .request_pl = &cdt.request_pl,                \
+               .request_pl_sz = sizeof(cdt.request_pl),      \
+               .response_pl = cdt.response_pl,               \
+               .response_pl_sz = sizeof(cdt.response_pl),    \
+               .complete = cxl_doe_task_complete,            \
+               .private = &cdt.c,                            \
+       }                                                     \
+}
+
+static int cxl_cdat_get_length(struct device *dev,
+                              struct pci_doe_mb *cdat_doe,
+                              size_t *length)
+{
+       DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(0), t);
+       int rc;
+
+       rc = pci_doe_submit_task(cdat_doe, &t.task);
+       if (rc < 0) {
+               dev_err(dev, "DOE submit failed: %d", rc);
+               return rc;
+       }
+       wait_for_completion(&t.c);
+       if (t.task.rv < sizeof(u32))
+               return -EIO;
+
+       *length = t.response_pl[1];
+       dev_dbg(dev, "CDAT length %zu\n", *length);
+
+       return 0;
+}
+
+static int cxl_cdat_read_table(struct device *dev,
+                              struct pci_doe_mb *cdat_doe,
+                              struct cxl_cdat *cdat)
+{
+       size_t length = cdat->length;
+       u32 *data = cdat->table;
+       int entry_handle = 0;
+
+       do {
+               DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(entry_handle), t);
+               size_t entry_dw;
+               u32 *entry;
+               int rc;
+
+               rc = pci_doe_submit_task(cdat_doe, &t.task);
+               if (rc < 0) {
+                       dev_err(dev, "DOE submit failed: %d", rc);
+                       return rc;
+               }
+               wait_for_completion(&t.c);
+               /* 1 DW header + 1 DW data min */
+               if (t.task.rv < (2 * sizeof(u32)))
+                       return -EIO;
+
+               /* Get the CXL table access header entry handle */
+               entry_handle = FIELD_GET(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE,
+                                        t.response_pl[0]);
+               entry = t.response_pl + 1;
+               entry_dw = t.task.rv / sizeof(u32);
+               /* Skip Header */
+               entry_dw -= 1;
+               entry_dw = min(length / sizeof(u32), entry_dw);
+               /* Prevent length < 1 DW from causing a buffer overflow */
+               if (entry_dw) {
+                       memcpy(data, entry, entry_dw * sizeof(u32));
+                       length -= entry_dw * sizeof(u32);
+                       data += entry_dw;
+               }
+       } while (entry_handle != CXL_DOE_TABLE_ACCESS_LAST_ENTRY);
+
+       return 0;
+}
+
+/**
+ * read_cdat_data - Read the CDAT data on this port
+ * @port: Port to read data from
+ *
+ * This call will sleep waiting for responses from the DOE mailbox.
+ */
+void read_cdat_data(struct cxl_port *port)
+{
+       struct pci_doe_mb *cdat_doe;
+       struct device *dev = &port->dev;
+       struct device *uport = port->uport;
+       size_t cdat_length;
+       int rc;
+
+       cdat_doe = find_cdat_doe(uport);
+       if (!cdat_doe) {
+               dev_dbg(dev, "No CDAT mailbox\n");
+               return;
+       }
+
+       port->cdat_available = true;
+
+       if (cxl_cdat_get_length(dev, cdat_doe, &cdat_length)) {
+               dev_dbg(dev, "No CDAT length\n");
+               return;
+       }
+
+       port->cdat.table = devm_kzalloc(dev, cdat_length, GFP_KERNEL);
+       if (!port->cdat.table)
+               return;
+
+       port->cdat.length = cdat_length;
+       rc = cxl_cdat_read_table(dev, cdat_doe, &port->cdat);
+       if (rc) {
+               /* Don't leave table data allocated on error */
+               devm_kfree(dev, port->cdat.table);
+               port->cdat.table = NULL;
+               port->cdat.length = 0;
+               dev_err(dev, "CDAT data read error\n");
+       }
+}
+EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);
index bec7cfb..1d12a82 100644 (file)
@@ -62,9 +62,9 @@ static int match_nvdimm_bridge(struct device *dev, void *data)
        return is_cxl_nvdimm_bridge(dev);
 }
 
-struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd)
+struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start)
 {
-       struct cxl_port *port = find_cxl_root(&cxl_nvd->dev);
+       struct cxl_port *port = find_cxl_root(start);
        struct device *dev;
 
        if (!port)
index dbce99b..bffde86 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2020 Intel Corporation. All rights reserved. */
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/memregion.h>
 #include <linux/workqueue.h>
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -42,6 +44,8 @@ static int cxl_device_id(struct device *dev)
                return CXL_DEVICE_NVDIMM_BRIDGE;
        if (dev->type == &cxl_nvdimm_type)
                return CXL_DEVICE_NVDIMM;
+       if (dev->type == CXL_PMEM_REGION_TYPE())
+               return CXL_DEVICE_PMEM_REGION;
        if (is_cxl_port(dev)) {
                if (is_cxl_root(to_cxl_port(dev)))
                        return CXL_DEVICE_ROOT;
@@ -49,6 +53,8 @@ static int cxl_device_id(struct device *dev)
        }
        if (is_cxl_memdev(dev))
                return CXL_DEVICE_MEMORY_EXPANDER;
+       if (dev->type == CXL_REGION_TYPE())
+               return CXL_DEVICE_REGION;
        return 0;
 }
 
@@ -73,14 +79,8 @@ static ssize_t start_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
        struct cxl_decoder *cxld = to_cxl_decoder(dev);
-       u64 start;
 
-       if (is_root_decoder(dev))
-               start = cxld->platform_res.start;
-       else
-               start = cxld->decoder_range.start;
-
-       return sysfs_emit(buf, "%#llx\n", start);
+       return sysfs_emit(buf, "%#llx\n", cxld->hpa_range.start);
 }
 static DEVICE_ATTR_ADMIN_RO(start);
 
@@ -88,14 +88,8 @@ static ssize_t size_show(struct device *dev, struct device_attribute *attr,
                        char *buf)
 {
        struct cxl_decoder *cxld = to_cxl_decoder(dev);
-       u64 size;
-
-       if (is_root_decoder(dev))
-               size = resource_size(&cxld->platform_res);
-       else
-               size = range_len(&cxld->decoder_range);
 
-       return sysfs_emit(buf, "%#llx\n", size);
+       return sysfs_emit(buf, "%#llx\n", range_len(&cxld->hpa_range));
 }
 static DEVICE_ATTR_RO(size);
 
@@ -131,20 +125,21 @@ static ssize_t target_type_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(target_type);
 
-static ssize_t emit_target_list(struct cxl_decoder *cxld, char *buf)
+static ssize_t emit_target_list(struct cxl_switch_decoder *cxlsd, char *buf)
 {
+       struct cxl_decoder *cxld = &cxlsd->cxld;
        ssize_t offset = 0;
        int i, rc = 0;
 
        for (i = 0; i < cxld->interleave_ways; i++) {
-               struct cxl_dport *dport = cxld->target[i];
+               struct cxl_dport *dport = cxlsd->target[i];
                struct cxl_dport *next = NULL;
 
                if (!dport)
                        break;
 
                if (i + 1 < cxld->interleave_ways)
-                       next = cxld->target[i + 1];
+                       next = cxlsd->target[i + 1];
                rc = sysfs_emit_at(buf, offset, "%d%s", dport->port_id,
                                   next ? "," : "");
                if (rc < 0)
@@ -158,15 +153,15 @@ static ssize_t emit_target_list(struct cxl_decoder *cxld, char *buf)
 static ssize_t target_list_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct cxl_decoder *cxld = to_cxl_decoder(dev);
+       struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev);
        ssize_t offset;
        unsigned int seq;
        int rc;
 
        do {
-               seq = read_seqbegin(&cxld->target_lock);
-               rc = emit_target_list(cxld, buf);
-       } while (read_seqretry(&cxld->target_lock, seq));
+               seq = read_seqbegin(&cxlsd->target_lock);
+               rc = emit_target_list(cxlsd, buf);
+       } while (read_seqretry(&cxlsd->target_lock, seq));
 
        if (rc < 0)
                return rc;
@@ -180,10 +175,121 @@ static ssize_t target_list_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(target_list);
 
+static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+
+       switch (cxled->mode) {
+       case CXL_DECODER_RAM:
+               return sysfs_emit(buf, "ram\n");
+       case CXL_DECODER_PMEM:
+               return sysfs_emit(buf, "pmem\n");
+       case CXL_DECODER_NONE:
+               return sysfs_emit(buf, "none\n");
+       case CXL_DECODER_MIXED:
+       default:
+               return sysfs_emit(buf, "mixed\n");
+       }
+}
+
+static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t len)
+{
+       struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+       enum cxl_decoder_mode mode;
+       ssize_t rc;
+
+       if (sysfs_streq(buf, "pmem"))
+               mode = CXL_DECODER_PMEM;
+       else if (sysfs_streq(buf, "ram"))
+               mode = CXL_DECODER_RAM;
+       else
+               return -EINVAL;
+
+       rc = cxl_dpa_set_mode(cxled, mode);
+       if (rc)
+               return rc;
+
+       return len;
+}
+static DEVICE_ATTR_RW(mode);
+
+static ssize_t dpa_resource_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+       u64 base = cxl_dpa_resource_start(cxled);
+
+       return sysfs_emit(buf, "%#llx\n", base);
+}
+static DEVICE_ATTR_RO(dpa_resource);
+
+static ssize_t dpa_size_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+       resource_size_t size = cxl_dpa_size(cxled);
+
+       return sysfs_emit(buf, "%pa\n", &size);
+}
+
+static ssize_t dpa_size_store(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t len)
+{
+       struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+       unsigned long long size;
+       ssize_t rc;
+
+       rc = kstrtoull(buf, 0, &size);
+       if (rc)
+               return rc;
+
+       if (!IS_ALIGNED(size, SZ_256M))
+               return -EINVAL;
+
+       rc = cxl_dpa_free(cxled);
+       if (rc)
+               return rc;
+
+       if (size == 0)
+               return len;
+
+       rc = cxl_dpa_alloc(cxled, size);
+       if (rc)
+               return rc;
+
+       return len;
+}
+static DEVICE_ATTR_RW(dpa_size);
+
+static ssize_t interleave_granularity_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+       return sysfs_emit(buf, "%d\n", cxld->interleave_granularity);
+}
+
+static DEVICE_ATTR_RO(interleave_granularity);
+
+static ssize_t interleave_ways_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+       return sysfs_emit(buf, "%d\n", cxld->interleave_ways);
+}
+
+static DEVICE_ATTR_RO(interleave_ways);
+
 static struct attribute *cxl_decoder_base_attrs[] = {
        &dev_attr_start.attr,
        &dev_attr_size.attr,
        &dev_attr_locked.attr,
+       &dev_attr_interleave_granularity.attr,
+       &dev_attr_interleave_ways.attr,
        NULL,
 };
 
@@ -197,11 +303,35 @@ static struct attribute *cxl_decoder_root_attrs[] = {
        &dev_attr_cap_type2.attr,
        &dev_attr_cap_type3.attr,
        &dev_attr_target_list.attr,
+       SET_CXL_REGION_ATTR(create_pmem_region)
+       SET_CXL_REGION_ATTR(delete_region)
        NULL,
 };
 
+static bool can_create_pmem(struct cxl_root_decoder *cxlrd)
+{
+       unsigned long flags = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_PMEM;
+
+       return (cxlrd->cxlsd.cxld.flags & flags) == flags;
+}
+
+static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+
+       if (a == CXL_REGION_ATTR(create_pmem_region) && !can_create_pmem(cxlrd))
+               return 0;
+
+       if (a == CXL_REGION_ATTR(delete_region) && !can_create_pmem(cxlrd))
+               return 0;
+
+       return a->mode;
+}
+
 static struct attribute_group cxl_decoder_root_attribute_group = {
        .attrs = cxl_decoder_root_attrs,
+       .is_visible = cxl_root_decoder_visible,
 };
 
 static const struct attribute_group *cxl_decoder_root_attribute_groups[] = {
@@ -214,6 +344,7 @@ static const struct attribute_group *cxl_decoder_root_attribute_groups[] = {
 static struct attribute *cxl_decoder_switch_attrs[] = {
        &dev_attr_target_type.attr,
        &dev_attr_target_list.attr,
+       SET_CXL_REGION_ATTR(region)
        NULL,
 };
 
@@ -230,6 +361,10 @@ static const struct attribute_group *cxl_decoder_switch_attribute_groups[] = {
 
 static struct attribute *cxl_decoder_endpoint_attrs[] = {
        &dev_attr_target_type.attr,
+       &dev_attr_mode.attr,
+       &dev_attr_dpa_size.attr,
+       &dev_attr_dpa_resource.attr,
+       SET_CXL_REGION_ATTR(region)
        NULL,
 };
 
@@ -244,31 +379,64 @@ static const struct attribute_group *cxl_decoder_endpoint_attribute_groups[] = {
        NULL,
 };
 
-static void cxl_decoder_release(struct device *dev)
+static void __cxl_decoder_release(struct cxl_decoder *cxld)
 {
-       struct cxl_decoder *cxld = to_cxl_decoder(dev);
-       struct cxl_port *port = to_cxl_port(dev->parent);
+       struct cxl_port *port = to_cxl_port(cxld->dev.parent);
 
        ida_free(&port->decoder_ida, cxld->id);
-       kfree(cxld);
        put_device(&port->dev);
 }
 
+static void cxl_endpoint_decoder_release(struct device *dev)
+{
+       struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+
+       __cxl_decoder_release(&cxled->cxld);
+       kfree(cxled);
+}
+
+static void cxl_switch_decoder_release(struct device *dev)
+{
+       struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev);
+
+       __cxl_decoder_release(&cxlsd->cxld);
+       kfree(cxlsd);
+}
+
+struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev)
+{
+       if (dev_WARN_ONCE(dev, !is_root_decoder(dev),
+                         "not a cxl_root_decoder device\n"))
+               return NULL;
+       return container_of(dev, struct cxl_root_decoder, cxlsd.cxld.dev);
+}
+EXPORT_SYMBOL_NS_GPL(to_cxl_root_decoder, CXL);
+
+static void cxl_root_decoder_release(struct device *dev)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+
+       if (atomic_read(&cxlrd->region_id) >= 0)
+               memregion_free(atomic_read(&cxlrd->region_id));
+       __cxl_decoder_release(&cxlrd->cxlsd.cxld);
+       kfree(cxlrd);
+}
+
 static const struct device_type cxl_decoder_endpoint_type = {
        .name = "cxl_decoder_endpoint",
-       .release = cxl_decoder_release,
+       .release = cxl_endpoint_decoder_release,
        .groups = cxl_decoder_endpoint_attribute_groups,
 };
 
 static const struct device_type cxl_decoder_switch_type = {
        .name = "cxl_decoder_switch",
-       .release = cxl_decoder_release,
+       .release = cxl_switch_decoder_release,
        .groups = cxl_decoder_switch_attribute_groups,
 };
 
 static const struct device_type cxl_decoder_root_type = {
        .name = "cxl_decoder_root",
-       .release = cxl_decoder_release,
+       .release = cxl_root_decoder_release,
        .groups = cxl_decoder_root_attribute_groups,
 };
 
@@ -283,39 +451,63 @@ bool is_root_decoder(struct device *dev)
 }
 EXPORT_SYMBOL_NS_GPL(is_root_decoder, CXL);
 
-bool is_cxl_decoder(struct device *dev)
+bool is_switch_decoder(struct device *dev)
 {
-       return dev->type && dev->type->release == cxl_decoder_release;
+       return is_root_decoder(dev) || dev->type == &cxl_decoder_switch_type;
 }
-EXPORT_SYMBOL_NS_GPL(is_cxl_decoder, CXL);
 
 struct cxl_decoder *to_cxl_decoder(struct device *dev)
 {
-       if (dev_WARN_ONCE(dev, dev->type->release != cxl_decoder_release,
+       if (dev_WARN_ONCE(dev,
+                         !is_switch_decoder(dev) && !is_endpoint_decoder(dev),
                          "not a cxl_decoder device\n"))
                return NULL;
        return container_of(dev, struct cxl_decoder, dev);
 }
 EXPORT_SYMBOL_NS_GPL(to_cxl_decoder, CXL);
 
+struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev)
+{
+       if (dev_WARN_ONCE(dev, !is_endpoint_decoder(dev),
+                         "not a cxl_endpoint_decoder device\n"))
+               return NULL;
+       return container_of(dev, struct cxl_endpoint_decoder, cxld.dev);
+}
+EXPORT_SYMBOL_NS_GPL(to_cxl_endpoint_decoder, CXL);
+
+struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
+{
+       if (dev_WARN_ONCE(dev, !is_switch_decoder(dev),
+                         "not a cxl_switch_decoder device\n"))
+               return NULL;
+       return container_of(dev, struct cxl_switch_decoder, cxld.dev);
+}
+
 static void cxl_ep_release(struct cxl_ep *ep)
 {
-       if (!ep)
-               return;
-       list_del(&ep->list);
        put_device(ep->ep);
        kfree(ep);
 }
 
+static void cxl_ep_remove(struct cxl_port *port, struct cxl_ep *ep)
+{
+       if (!ep)
+               return;
+       xa_erase(&port->endpoints, (unsigned long) ep->ep);
+       cxl_ep_release(ep);
+}
+
 static void cxl_port_release(struct device *dev)
 {
        struct cxl_port *port = to_cxl_port(dev);
-       struct cxl_ep *ep, *_e;
+       unsigned long index;
+       struct cxl_ep *ep;
 
-       device_lock(dev);
-       list_for_each_entry_safe(ep, _e, &port->endpoints, list)
-               cxl_ep_release(ep);
-       device_unlock(dev);
+       xa_for_each(&port->endpoints, index, ep)
+               cxl_ep_remove(port, ep);
+       xa_destroy(&port->endpoints);
+       xa_destroy(&port->dports);
+       xa_destroy(&port->regions);
        ida_free(&cxl_port_ida, port->id);
        kfree(port);
 }
@@ -370,7 +562,7 @@ static void unregister_port(void *_port)
                lock_dev = &parent->dev;
 
        device_lock_assert(lock_dev);
-       port->uport = NULL;
+       port->dead = true;
        device_unregister(&port->dev);
 }
 
@@ -395,7 +587,7 @@ static struct lock_class_key cxl_port_key;
 
 static struct cxl_port *cxl_port_alloc(struct device *uport,
                                       resource_size_t component_reg_phys,
-                                      struct cxl_port *parent_port)
+                                      struct cxl_dport *parent_dport)
 {
        struct cxl_port *port;
        struct device *dev;
@@ -409,6 +601,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport,
        if (rc < 0)
                goto err;
        port->id = rc;
+       port->uport = uport;
 
        /*
         * The top-level cxl_port "cxl_root" does not have a cxl_port as
@@ -417,17 +610,37 @@ static struct cxl_port *cxl_port_alloc(struct device *uport,
         * description.
         */
        dev = &port->dev;
-       if (parent_port) {
+       if (parent_dport) {
+               struct cxl_port *parent_port = parent_dport->port;
+               struct cxl_port *iter;
+
                dev->parent = &parent_port->dev;
                port->depth = parent_port->depth + 1;
+               port->parent_dport = parent_dport;
+
+               /*
+                * walk to the host bridge, or the first ancestor that knows
+                * the host bridge
+                */
+               iter = port;
+               while (!iter->host_bridge &&
+                      !is_cxl_root(to_cxl_port(iter->dev.parent)))
+                       iter = to_cxl_port(iter->dev.parent);
+               if (iter->host_bridge)
+                       port->host_bridge = iter->host_bridge;
+               else
+                       port->host_bridge = iter->uport;
+               dev_dbg(uport, "host-bridge: %s\n", dev_name(port->host_bridge));
        } else
                dev->parent = uport;
 
-       port->uport = uport;
        port->component_reg_phys = component_reg_phys;
        ida_init(&port->decoder_ida);
-       INIT_LIST_HEAD(&port->dports);
-       INIT_LIST_HEAD(&port->endpoints);
+       port->hdm_end = -1;
+       port->commit_end = -1;
+       xa_init(&port->dports);
+       xa_init(&port->endpoints);
+       xa_init(&port->regions);
 
        device_initialize(dev);
        lockdep_set_class_and_subclass(&dev->mutex, &cxl_port_key, port->depth);
@@ -447,24 +660,24 @@ err:
  * @host: host device for devm operations
  * @uport: "physical" device implementing this upstream port
  * @component_reg_phys: (optional) for configurable cxl_port instances
- * @parent_port: next hop up in the CXL memory decode hierarchy
+ * @parent_dport: next hop up in the CXL memory decode hierarchy
  */
 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
                                   resource_size_t component_reg_phys,
-                                  struct cxl_port *parent_port)
+                                  struct cxl_dport *parent_dport)
 {
        struct cxl_port *port;
        struct device *dev;
        int rc;
 
-       port = cxl_port_alloc(uport, component_reg_phys, parent_port);
+       port = cxl_port_alloc(uport, component_reg_phys, parent_dport);
        if (IS_ERR(port))
                return port;
 
        dev = &port->dev;
        if (is_cxl_memdev(uport))
                rc = dev_set_name(dev, "endpoint%d", port->id);
-       else if (parent_port)
+       else if (parent_dport)
                rc = dev_set_name(dev, "port%d", port->id);
        else
                rc = dev_set_name(dev, "root%d", port->id);
@@ -556,17 +769,13 @@ static int match_root_child(struct device *dev, const void *match)
                return 0;
 
        port = to_cxl_port(dev);
-       device_lock(dev);
-       list_for_each_entry(dport, &port->dports, list) {
-               iter = match;
-               while (iter) {
-                       if (iter == dport->dport)
-                               goto out;
-                       iter = iter->parent;
-               }
+       iter = match;
+       while (iter) {
+               dport = cxl_find_dport_by_dev(port, iter);
+               if (dport)
+                       break;
+               iter = iter->parent;
        }
-out:
-       device_unlock(dev);
 
        return !!iter;
 }
@@ -590,9 +799,10 @@ EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL);
 static struct cxl_dport *find_dport(struct cxl_port *port, int id)
 {
        struct cxl_dport *dport;
+       unsigned long index;
 
        device_lock_assert(&port->dev);
-       list_for_each_entry (dport, &port->dports, list)
+       xa_for_each(&port->dports, index, dport)
                if (dport->port_id == id)
                        return dport;
        return NULL;
@@ -604,15 +814,15 @@ static int add_dport(struct cxl_port *port, struct cxl_dport *new)
 
        device_lock_assert(&port->dev);
        dup = find_dport(port, new->port_id);
-       if (dup)
+       if (dup) {
                dev_err(&port->dev,
                        "unable to add dport%d-%s non-unique port id (%s)\n",
                        new->port_id, dev_name(new->dport),
                        dev_name(dup->dport));
-       else
-               list_add_tail(&new->list, &port->dports);
-
-       return dup ? -EEXIST : 0;
+               return -EBUSY;
+       }
+       return xa_insert(&port->dports, (unsigned long)new->dport, new,
+                        GFP_KERNEL);
 }
 
 /*
@@ -639,10 +849,8 @@ static void cxl_dport_remove(void *data)
        struct cxl_dport *dport = data;
        struct cxl_port *port = dport->port;
 
+       xa_erase(&port->dports, (unsigned long) dport->dport);
        put_device(dport->dport);
-       cond_cxl_root_lock(port);
-       list_del(&dport->list);
-       cond_cxl_root_unlock(port);
 }
 
 static void cxl_dport_unlink(void *data)
@@ -694,7 +902,6 @@ struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
        if (!dport)
                return ERR_PTR(-ENOMEM);
 
-       INIT_LIST_HEAD(&dport->list);
        dport->dport = dport_dev;
        dport->port_id = port_id;
        dport->component_reg_phys = component_reg_phys;
@@ -723,44 +930,33 @@ struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
 }
 EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport, CXL);
 
-static struct cxl_ep *find_ep(struct cxl_port *port, struct device *ep_dev)
-{
-       struct cxl_ep *ep;
-
-       device_lock_assert(&port->dev);
-       list_for_each_entry(ep, &port->endpoints, list)
-               if (ep->ep == ep_dev)
-                       return ep;
-       return NULL;
-}
-
-static int add_ep(struct cxl_port *port, struct cxl_ep *new)
+static int add_ep(struct cxl_ep *new)
 {
-       struct cxl_ep *dup;
+       struct cxl_port *port = new->dport->port;
+       int rc;
 
        device_lock(&port->dev);
        if (port->dead) {
                device_unlock(&port->dev);
                return -ENXIO;
        }
-       dup = find_ep(port, new->ep);
-       if (!dup)
-               list_add_tail(&new->list, &port->endpoints);
+       rc = xa_insert(&port->endpoints, (unsigned long)new->ep, new,
+                      GFP_KERNEL);
        device_unlock(&port->dev);
 
-       return dup ? -EEXIST : 0;
+       return rc;
 }
 
 /**
  * cxl_add_ep - register an endpoint's interest in a port
- * @port: a port in the endpoint's topology ancestry
+ * @dport: the dport that routes to @ep_dev
  * @ep_dev: device representing the endpoint
  *
  * Intermediate CXL ports are scanned based on the arrival of endpoints.
  * When those endpoints depart the port can be destroyed once all
  * endpoints that care about that port have been removed.
  */
-static int cxl_add_ep(struct cxl_port *port, struct device *ep_dev)
+static int cxl_add_ep(struct cxl_dport *dport, struct device *ep_dev)
 {
        struct cxl_ep *ep;
        int rc;
@@ -769,10 +965,10 @@ static int cxl_add_ep(struct cxl_port *port, struct device *ep_dev)
        if (!ep)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&ep->list);
        ep->ep = get_device(ep_dev);
+       ep->dport = dport;
 
-       rc = add_ep(port, ep);
+       rc = add_ep(ep);
        if (rc)
                cxl_ep_release(ep);
        return rc;
@@ -781,11 +977,13 @@ static int cxl_add_ep(struct cxl_port *port, struct device *ep_dev)
 struct cxl_find_port_ctx {
        const struct device *dport_dev;
        const struct cxl_port *parent_port;
+       struct cxl_dport **dport;
 };
 
 static int match_port_by_dport(struct device *dev, const void *data)
 {
        const struct cxl_find_port_ctx *ctx = data;
+       struct cxl_dport *dport;
        struct cxl_port *port;
 
        if (!is_cxl_port(dev))
@@ -794,7 +992,10 @@ static int match_port_by_dport(struct device *dev, const void *data)
                return 0;
 
        port = to_cxl_port(dev);
-       return cxl_find_dport_by_dev(port, ctx->dport_dev) != NULL;
+       dport = cxl_find_dport_by_dev(port, ctx->dport_dev);
+       if (ctx->dport)
+               *ctx->dport = dport;
+       return dport != NULL;
 }
 
 static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
@@ -810,24 +1011,32 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
        return NULL;
 }
 
-static struct cxl_port *find_cxl_port(struct device *dport_dev)
+static struct cxl_port *find_cxl_port(struct device *dport_dev,
+                                     struct cxl_dport **dport)
 {
        struct cxl_find_port_ctx ctx = {
                .dport_dev = dport_dev,
+               .dport = dport,
        };
+       struct cxl_port *port;
 
-       return __find_cxl_port(&ctx);
+       port = __find_cxl_port(&ctx);
+       return port;
 }
 
 static struct cxl_port *find_cxl_port_at(struct cxl_port *parent_port,
-                                        struct device *dport_dev)
+                                        struct device *dport_dev,
+                                        struct cxl_dport **dport)
 {
        struct cxl_find_port_ctx ctx = {
                .dport_dev = dport_dev,
                .parent_port = parent_port,
+               .dport = dport,
        };
+       struct cxl_port *port;
 
-       return __find_cxl_port(&ctx);
+       port = __find_cxl_port(&ctx);
+       return port;
 }
 
 /*
@@ -851,13 +1060,13 @@ static void delete_endpoint(void *data)
        struct cxl_port *parent_port;
        struct device *parent;
 
-       parent_port = cxl_mem_find_port(cxlmd);
+       parent_port = cxl_mem_find_port(cxlmd, NULL);
        if (!parent_port)
                goto out;
        parent = &parent_port->dev;
 
        device_lock(parent);
-       if (parent->driver && endpoint->uport) {
+       if (parent->driver && !endpoint->dead) {
                devm_release_action(parent, cxl_unlink_uport, endpoint);
                devm_release_action(parent, unregister_port, endpoint);
        }
@@ -883,21 +1092,70 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, CXL);
  * for a port to be unregistered is when all memdevs beneath that port have gone
  * through ->remove(). This "bottom-up" removal selectively removes individual
  * child ports manually. This depends on devm_cxl_add_port() to not change is
- * devm action registration order.
+ * devm action registration order, and for dports to have already been
+ * destroyed by reap_dports().
  */
-static void delete_switch_port(struct cxl_port *port, struct list_head *dports)
+static void delete_switch_port(struct cxl_port *port)
+{
+       devm_release_action(port->dev.parent, cxl_unlink_uport, port);
+       devm_release_action(port->dev.parent, unregister_port, port);
+}
+
+static void reap_dports(struct cxl_port *port)
 {
-       struct cxl_dport *dport, *_d;
+       struct cxl_dport *dport;
+       unsigned long index;
+
+       device_lock_assert(&port->dev);
 
-       list_for_each_entry_safe(dport, _d, dports, list) {
+       xa_for_each(&port->dports, index, dport) {
                devm_release_action(&port->dev, cxl_dport_unlink, dport);
                devm_release_action(&port->dev, cxl_dport_remove, dport);
                devm_kfree(&port->dev, dport);
        }
-       devm_release_action(port->dev.parent, cxl_unlink_uport, port);
-       devm_release_action(port->dev.parent, unregister_port, port);
 }
 
+int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
+                         struct cxl_dport *parent_dport)
+{
+       struct cxl_port *parent_port = parent_dport->port;
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct cxl_port *endpoint, *iter, *down;
+       int rc;
+
+       /*
+        * Now that the path to the root is established record all the
+        * intervening ports in the chain.
+        */
+       for (iter = parent_port, down = NULL; !is_cxl_root(iter);
+            down = iter, iter = to_cxl_port(iter->dev.parent)) {
+               struct cxl_ep *ep;
+
+               ep = cxl_ep_load(iter, cxlmd);
+               ep->next = down;
+       }
+
+       endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
+                                    cxlds->component_reg_phys, parent_dport);
+       if (IS_ERR(endpoint))
+               return PTR_ERR(endpoint);
+
+       dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
+
+       rc = cxl_endpoint_autoremove(cxlmd, endpoint);
+       if (rc)
+               return rc;
+
+       if (!endpoint->dev.driver) {
+               dev_err(&cxlmd->dev, "%s failed probe\n",
+                       dev_name(&endpoint->dev));
+               return -ENXIO;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_add_endpoint, CXL);
+
 static void cxl_detach_ep(void *data)
 {
        struct cxl_memdev *cxlmd = data;
@@ -906,13 +1164,13 @@ static void cxl_detach_ep(void *data)
        for (iter = &cxlmd->dev; iter; iter = grandparent(iter)) {
                struct device *dport_dev = grandparent(iter);
                struct cxl_port *port, *parent_port;
-               LIST_HEAD(reap_dports);
                struct cxl_ep *ep;
+               bool died = false;
 
                if (!dport_dev)
                        break;
 
-               port = find_cxl_port(dport_dev);
+               port = find_cxl_port(dport_dev, NULL);
                if (!port)
                        continue;
 
@@ -936,26 +1194,27 @@ static void cxl_detach_ep(void *data)
                }
 
                device_lock(&port->dev);
-               ep = find_ep(port, &cxlmd->dev);
+               ep = cxl_ep_load(port, cxlmd);
                dev_dbg(&cxlmd->dev, "disconnect %s from %s\n",
                        ep ? dev_name(ep->ep) : "", dev_name(&port->dev));
-               cxl_ep_release(ep);
-               if (ep && !port->dead && list_empty(&port->endpoints) &&
+               cxl_ep_remove(port, ep);
+               if (ep && !port->dead && xa_empty(&port->endpoints) &&
                    !is_cxl_root(parent_port)) {
                        /*
                         * This was the last ep attached to a dynamically
                         * enumerated port. Block new cxl_add_ep() and garbage
                         * collect the port.
                         */
+                       died = true;
                        port->dead = true;
-                       list_splice_init(&port->dports, &reap_dports);
+                       reap_dports(port);
                }
                device_unlock(&port->dev);
 
-               if (!list_empty(&reap_dports)) {
+               if (died) {
                        dev_dbg(&cxlmd->dev, "delete %s\n",
                                dev_name(&port->dev));
-                       delete_switch_port(port, &reap_dports);
+                       delete_switch_port(port);
                }
                put_device(&port->dev);
                device_unlock(&parent_port->dev);
@@ -986,6 +1245,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
 {
        struct device *dparent = grandparent(dport_dev);
        struct cxl_port *port, *parent_port = NULL;
+       struct cxl_dport *dport, *parent_dport;
        resource_size_t component_reg_phys;
        int rc;
 
@@ -1000,7 +1260,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
                return -ENXIO;
        }
 
-       parent_port = find_cxl_port(dparent);
+       parent_port = find_cxl_port(dparent, &parent_dport);
        if (!parent_port) {
                /* iterate to create this parent_port */
                return -EAGAIN;
@@ -1015,13 +1275,14 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
                goto out;
        }
 
-       port = find_cxl_port_at(parent_port, dport_dev);
+       port = find_cxl_port_at(parent_port, dport_dev, &dport);
        if (!port) {
                component_reg_phys = find_component_registers(uport_dev);
                port = devm_cxl_add_port(&parent_port->dev, uport_dev,
-                                        component_reg_phys, parent_port);
+                                        component_reg_phys, parent_dport);
+               /* retry find to pick up the new dport information */
                if (!IS_ERR(port))
-                       get_device(&port->dev);
+                       port = find_cxl_port_at(parent_port, dport_dev, &dport);
        }
 out:
        device_unlock(&parent_port->dev);
@@ -1031,8 +1292,8 @@ out:
        else {
                dev_dbg(&cxlmd->dev, "add to new port %s:%s\n",
                        dev_name(&port->dev), dev_name(port->uport));
-               rc = cxl_add_ep(port, &cxlmd->dev);
-               if (rc == -EEXIST) {
+               rc = cxl_add_ep(dport, &cxlmd->dev);
+               if (rc == -EBUSY) {
                        /*
                         * "can't" happen, but this error code means
                         * something to the caller, so translate it.
@@ -1065,6 +1326,7 @@ retry:
        for (iter = dev; iter; iter = grandparent(iter)) {
                struct device *dport_dev = grandparent(iter);
                struct device *uport_dev;
+               struct cxl_dport *dport;
                struct cxl_port *port;
 
                if (!dport_dev)
@@ -1080,12 +1342,12 @@ retry:
                dev_dbg(dev, "scan: iter: %s dport_dev: %s parent: %s\n",
                        dev_name(iter), dev_name(dport_dev),
                        dev_name(uport_dev));
-               port = find_cxl_port(dport_dev);
+               port = find_cxl_port(dport_dev, &dport);
                if (port) {
                        dev_dbg(&cxlmd->dev,
                                "found already registered port %s:%s\n",
                                dev_name(&port->dev), dev_name(port->uport));
-                       rc = cxl_add_ep(port, &cxlmd->dev);
+                       rc = cxl_add_ep(dport, &cxlmd->dev);
 
                        /*
                         * If the endpoint already exists in the port's list,
@@ -1094,7 +1356,7 @@ retry:
                         * the parent_port lock as the current port may be being
                         * reaped.
                         */
-                       if (rc && rc != -EEXIST) {
+                       if (rc && rc != -EBUSY) {
                                put_device(&port->dev);
                                return rc;
                        }
@@ -1124,30 +1386,14 @@ retry:
 }
 EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, CXL);
 
-struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd)
+struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
+                                  struct cxl_dport **dport)
 {
-       return find_cxl_port(grandparent(&cxlmd->dev));
+       return find_cxl_port(grandparent(&cxlmd->dev), dport);
 }
 EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, CXL);
 
-struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port,
-                                       const struct device *dev)
-{
-       struct cxl_dport *dport;
-
-       device_lock(&port->dev);
-       list_for_each_entry(dport, &port->dports, list)
-               if (dport->dport == dev) {
-                       device_unlock(&port->dev);
-                       return dport;
-               }
-
-       device_unlock(&port->dev);
-       return NULL;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_find_dport_by_dev, CXL);
-
-static int decoder_populate_targets(struct cxl_decoder *cxld,
+static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd,
                                    struct cxl_port *port, int *target_map)
 {
        int i, rc = 0;
@@ -1157,88 +1403,92 @@ static int decoder_populate_targets(struct cxl_decoder *cxld,
 
        device_lock_assert(&port->dev);
 
-       if (list_empty(&port->dports))
+       if (xa_empty(&port->dports))
                return -EINVAL;
 
-       write_seqlock(&cxld->target_lock);
-       for (i = 0; i < cxld->nr_targets; i++) {
+       write_seqlock(&cxlsd->target_lock);
+       for (i = 0; i < cxlsd->nr_targets; i++) {
                struct cxl_dport *dport = find_dport(port, target_map[i]);
 
                if (!dport) {
                        rc = -ENXIO;
                        break;
                }
-               cxld->target[i] = dport;
+               cxlsd->target[i] = dport;
        }
-       write_sequnlock(&cxld->target_lock);
+       write_sequnlock(&cxlsd->target_lock);
 
        return rc;
 }
 
+static struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos)
+{
+       struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd;
+       struct cxl_decoder *cxld = &cxlsd->cxld;
+       int iw;
+
+       iw = cxld->interleave_ways;
+       if (dev_WARN_ONCE(&cxld->dev, iw != cxlsd->nr_targets,
+                         "misconfigured root decoder\n"))
+               return NULL;
+
+       return cxlrd->cxlsd.target[pos % iw];
+}
+
 static struct lock_class_key cxl_decoder_key;
 
 /**
- * cxl_decoder_alloc - Allocate a new CXL decoder
+ * cxl_decoder_init - Common decoder setup / initialization
  * @port: owning port of this decoder
- * @nr_targets: downstream targets accessible by this decoder. All upstream
- *             ports and root ports must have at least 1 target. Endpoint
- *             devices will have 0 targets. Callers wishing to register an
- *             endpoint device should specify 0.
- *
- * A port should contain one or more decoders. Each of those decoders enable
- * some address space for CXL.mem utilization. A decoder is expected to be
- * configured by the caller before registering.
+ * @cxld: common decoder properties to initialize
  *
- * Return: A new cxl decoder to be registered by cxl_decoder_add(). The decoder
- *        is initialized to be a "passthrough" decoder.
+ * A port may contain one or more decoders. Each of those decoders
+ * enable some address space for CXL.mem utilization. A decoder is
+ * expected to be configured by the caller before registering via
+ * cxl_decoder_add()
  */
-static struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port,
-                                            unsigned int nr_targets)
+static int cxl_decoder_init(struct cxl_port *port, struct cxl_decoder *cxld)
 {
-       struct cxl_decoder *cxld;
        struct device *dev;
-       int rc = 0;
-
-       if (nr_targets > CXL_DECODER_MAX_INTERLEAVE)
-               return ERR_PTR(-EINVAL);
-
-       cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL);
-       if (!cxld)
-               return ERR_PTR(-ENOMEM);
+       int rc;
 
        rc = ida_alloc(&port->decoder_ida, GFP_KERNEL);
        if (rc < 0)
-               goto err;
+               return rc;
 
        /* need parent to stick around to release the id */
        get_device(&port->dev);
        cxld->id = rc;
 
-       cxld->nr_targets = nr_targets;
-       seqlock_init(&cxld->target_lock);
        dev = &cxld->dev;
        device_initialize(dev);
        lockdep_set_class(&dev->mutex, &cxl_decoder_key);
        device_set_pm_not_required(dev);
        dev->parent = &port->dev;
        dev->bus = &cxl_bus_type;
-       if (is_cxl_root(port))
-               cxld->dev.type = &cxl_decoder_root_type;
-       else if (is_cxl_endpoint(port))
-               cxld->dev.type = &cxl_decoder_endpoint_type;
-       else
-               cxld->dev.type = &cxl_decoder_switch_type;
 
        /* Pre initialize an "empty" decoder */
        cxld->interleave_ways = 1;
        cxld->interleave_granularity = PAGE_SIZE;
        cxld->target_type = CXL_DECODER_EXPANDER;
-       cxld->platform_res = (struct resource)DEFINE_RES_MEM(0, 0);
+       cxld->hpa_range = (struct range) {
+               .start = 0,
+               .end = -1,
+       };
 
-       return cxld;
-err:
-       kfree(cxld);
-       return ERR_PTR(rc);
+       return 0;
+}
+
+static int cxl_switch_decoder_init(struct cxl_port *port,
+                                  struct cxl_switch_decoder *cxlsd,
+                                  int nr_targets)
+{
+       if (nr_targets > CXL_DECODER_MAX_INTERLEAVE)
+               return -EINVAL;
+
+       cxlsd->nr_targets = nr_targets;
+       seqlock_init(&cxlsd->target_lock);
+       return cxl_decoder_init(port, &cxlsd->cxld);
 }
 
 /**
@@ -1251,13 +1501,46 @@ err:
  * firmware description of CXL resources into a CXL standard decode
  * topology.
  */
-struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
-                                          unsigned int nr_targets)
+struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
+                                               unsigned int nr_targets)
 {
+       struct cxl_root_decoder *cxlrd;
+       struct cxl_switch_decoder *cxlsd;
+       struct cxl_decoder *cxld;
+       int rc;
+
        if (!is_cxl_root(port))
                return ERR_PTR(-EINVAL);
 
-       return cxl_decoder_alloc(port, nr_targets);
+       cxlrd = kzalloc(struct_size(cxlrd, cxlsd.target, nr_targets),
+                       GFP_KERNEL);
+       if (!cxlrd)
+               return ERR_PTR(-ENOMEM);
+
+       cxlsd = &cxlrd->cxlsd;
+       rc = cxl_switch_decoder_init(port, cxlsd, nr_targets);
+       if (rc) {
+               kfree(cxlrd);
+               return ERR_PTR(rc);
+       }
+
+       cxlrd->calc_hb = cxl_hb_modulo;
+
+       cxld = &cxlsd->cxld;
+       cxld->dev.type = &cxl_decoder_root_type;
+       /*
+        * cxl_root_decoder_release() special cases negative ids to
+        * detect memregion_alloc() failures.
+        */
+       atomic_set(&cxlrd->region_id, -1);
+       rc = memregion_alloc(GFP_KERNEL);
+       if (rc < 0) {
+               put_device(&cxld->dev);
+               return ERR_PTR(rc);
+       }
+
+       atomic_set(&cxlrd->region_id, rc);
+       return cxlrd;
 }
 EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL);
 
@@ -1272,13 +1555,29 @@ EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL);
  * that sit between Switch Upstream Ports / Switch Downstream Ports and
  * Host Bridges / Root Ports.
  */
-struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
-                                            unsigned int nr_targets)
+struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
+                                                   unsigned int nr_targets)
 {
+       struct cxl_switch_decoder *cxlsd;
+       struct cxl_decoder *cxld;
+       int rc;
+
        if (is_cxl_root(port) || is_cxl_endpoint(port))
                return ERR_PTR(-EINVAL);
 
-       return cxl_decoder_alloc(port, nr_targets);
+       cxlsd = kzalloc(struct_size(cxlsd, target, nr_targets), GFP_KERNEL);
+       if (!cxlsd)
+               return ERR_PTR(-ENOMEM);
+
+       rc = cxl_switch_decoder_init(port, cxlsd, nr_targets);
+       if (rc) {
+               kfree(cxlsd);
+               return ERR_PTR(rc);
+       }
+
+       cxld = &cxlsd->cxld;
+       cxld->dev.type = &cxl_decoder_switch_type;
+       return cxlsd;
 }
 EXPORT_SYMBOL_NS_GPL(cxl_switch_decoder_alloc, CXL);
 
@@ -1288,18 +1587,35 @@ EXPORT_SYMBOL_NS_GPL(cxl_switch_decoder_alloc, CXL);
  *
  * Return: A new cxl decoder to be registered by cxl_decoder_add()
  */
-struct cxl_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port)
+struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port)
 {
+       struct cxl_endpoint_decoder *cxled;
+       struct cxl_decoder *cxld;
+       int rc;
+
        if (!is_cxl_endpoint(port))
                return ERR_PTR(-EINVAL);
 
-       return cxl_decoder_alloc(port, 0);
+       cxled = kzalloc(sizeof(*cxled), GFP_KERNEL);
+       if (!cxled)
+               return ERR_PTR(-ENOMEM);
+
+       cxled->pos = -1;
+       cxld = &cxled->cxld;
+       rc = cxl_decoder_init(port, cxld);
+       if (rc)  {
+               kfree(cxled);
+               return ERR_PTR(rc);
+       }
+
+       cxld->dev.type = &cxl_decoder_endpoint_type;
+       return cxled;
 }
 EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, CXL);
 
 /**
  * cxl_decoder_add_locked - Add a decoder with targets
- * @cxld: The cxl decoder allocated by cxl_decoder_alloc()
+ * @cxld: The cxl decoder allocated by cxl_<type>_decoder_alloc()
  * @target_map: A list of downstream ports that this decoder can direct memory
  *              traffic to. These numbers should correspond with the port number
  *              in the PCIe Link Capabilities structure.
@@ -1335,7 +1651,9 @@ int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map)
 
        port = to_cxl_port(cxld->dev.parent);
        if (!is_endpoint_decoder(dev)) {
-               rc = decoder_populate_targets(cxld, port, target_map);
+               struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev);
+
+               rc = decoder_populate_targets(cxlsd, port, target_map);
                if (rc && (cxld->flags & CXL_DECODER_F_ENABLE)) {
                        dev_err(&port->dev,
                                "Failed to populate active decoder targets\n");
@@ -1347,20 +1665,13 @@ int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map)
        if (rc)
                return rc;
 
-       /*
-        * Platform decoder resources should show up with a reasonable name. All
-        * other resources are just sub ranges within the main decoder resource.
-        */
-       if (is_root_decoder(dev))
-               cxld->platform_res.name = dev_name(dev);
-
        return device_add(dev);
 }
 EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, CXL);
 
 /**
  * cxl_decoder_add - Add a decoder with targets
- * @cxld: The cxl decoder allocated by cxl_decoder_alloc()
+ * @cxld: The cxl decoder allocated by cxl_<type>_decoder_alloc()
  * @target_map: A list of downstream ports that this decoder can direct memory
  *              traffic to. These numbers should correspond with the port number
  *              in the PCIe Link Capabilities structure.
@@ -1394,6 +1705,13 @@ EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, CXL);
 
 static void cxld_unregister(void *dev)
 {
+       struct cxl_endpoint_decoder *cxled;
+
+       if (is_endpoint_decoder(dev)) {
+               cxled = to_cxl_endpoint_decoder(dev);
+               cxl_decoder_kill_region(cxled);
+       }
+
        device_unregister(dev);
 }
 
@@ -1521,10 +1839,20 @@ struct bus_type cxl_bus_type = {
 };
 EXPORT_SYMBOL_NS_GPL(cxl_bus_type, CXL);
 
+static struct dentry *cxl_debugfs;
+
+struct dentry *cxl_debugfs_create_dir(const char *dir)
+{
+       return debugfs_create_dir(dir, cxl_debugfs);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_debugfs_create_dir, CXL);
+
 static __init int cxl_core_init(void)
 {
        int rc;
 
+       cxl_debugfs = debugfs_create_dir("cxl", NULL);
+
        cxl_mbox_init();
 
        rc = cxl_memdev_init();
@@ -1541,22 +1869,28 @@ static __init int cxl_core_init(void)
        if (rc)
                goto err_bus;
 
+       rc = cxl_region_init();
+       if (rc)
+               goto err_region;
+
        return 0;
 
+err_region:
+       bus_unregister(&cxl_bus_type);
 err_bus:
        destroy_workqueue(cxl_bus_wq);
 err_wq:
        cxl_memdev_exit();
-       cxl_mbox_exit();
        return rc;
 }
 
 static void cxl_core_exit(void)
 {
+       cxl_region_exit();
        bus_unregister(&cxl_bus_type);
        destroy_workqueue(cxl_bus_wq);
        cxl_memdev_exit();
-       cxl_mbox_exit();
+       debugfs_remove_recursive(cxl_debugfs);
 }
 
 module_init(cxl_core_init);
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
new file mode 100644 (file)
index 0000000..4011480
--- /dev/null
@@ -0,0 +1,1896 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
+#include <linux/memregion.h>
+#include <linux/genalloc.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uuid.h>
+#include <linux/idr.h>
+#include <cxlmem.h>
+#include <cxl.h>
+#include "core.h"
+
+/**
+ * DOC: cxl core region
+ *
+ * CXL Regions represent mapped memory capacity in system physical address
+ * space. Whereas the CXL Root Decoders identify the bounds of potential CXL
+ * Memory ranges, Regions represent the active mapped capacity by the HDM
+ * Decoder Capability structures throughout the Host Bridges, Switches, and
+ * Endpoints in the topology.
+ *
+ * Region configuration has ordering constraints. UUID may be set at any time
+ * but is only visible for persistent regions.
+ * 1. Interleave granularity
+ * 2. Interleave size
+ * 3. Decoder targets
+ */
+
+/*
+ * All changes to the interleave configuration occur with this lock held
+ * for write.
+ */
+static DECLARE_RWSEM(cxl_region_rwsem);
+
+static struct cxl_region *to_cxl_region(struct device *dev);
+
+static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       ssize_t rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       rc = sysfs_emit(buf, "%pUb\n", &p->uuid);
+       up_read(&cxl_region_rwsem);
+
+       return rc;
+}
+
+static int is_dup(struct device *match, void *data)
+{
+       struct cxl_region_params *p;
+       struct cxl_region *cxlr;
+       uuid_t *uuid = data;
+
+       if (!is_cxl_region(match))
+               return 0;
+
+       lockdep_assert_held(&cxl_region_rwsem);
+       cxlr = to_cxl_region(match);
+       p = &cxlr->params;
+
+       if (uuid_equal(&p->uuid, uuid)) {
+               dev_dbg(match, "already has uuid: %pUb\n", uuid);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static ssize_t uuid_store(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t len)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       uuid_t temp;
+       ssize_t rc;
+
+       if (len != UUID_STRING_LEN + 1)
+               return -EINVAL;
+
+       rc = uuid_parse(buf, &temp);
+       if (rc)
+               return rc;
+
+       if (uuid_is_null(&temp))
+               return -EINVAL;
+
+       rc = down_write_killable(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+
+       if (uuid_equal(&p->uuid, &temp))
+               goto out;
+
+       rc = -EBUSY;
+       if (p->state >= CXL_CONFIG_ACTIVE)
+               goto out;
+
+       rc = bus_for_each_dev(&cxl_bus_type, NULL, &temp, is_dup);
+       if (rc < 0)
+               goto out;
+
+       uuid_copy(&p->uuid, &temp);
+out:
+       up_write(&cxl_region_rwsem);
+
+       if (rc)
+               return rc;
+       return len;
+}
+static DEVICE_ATTR_RW(uuid);
+
+static struct cxl_region_ref *cxl_rr_load(struct cxl_port *port,
+                                         struct cxl_region *cxlr)
+{
+       return xa_load(&port->regions, (unsigned long)cxlr);
+}
+
+static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
+{
+       struct cxl_region_params *p = &cxlr->params;
+       int i;
+
+       for (i = count - 1; i >= 0; i--) {
+               struct cxl_endpoint_decoder *cxled = p->targets[i];
+               struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+               struct cxl_port *iter = cxled_to_port(cxled);
+               struct cxl_ep *ep;
+               int rc;
+
+               while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
+                       iter = to_cxl_port(iter->dev.parent);
+
+               for (ep = cxl_ep_load(iter, cxlmd); iter;
+                    iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
+                       struct cxl_region_ref *cxl_rr;
+                       struct cxl_decoder *cxld;
+
+                       cxl_rr = cxl_rr_load(iter, cxlr);
+                       cxld = cxl_rr->decoder;
+                       rc = cxld->reset(cxld);
+                       if (rc)
+                               return rc;
+               }
+
+               rc = cxled->cxld.reset(&cxled->cxld);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static int cxl_region_decode_commit(struct cxl_region *cxlr)
+{
+       struct cxl_region_params *p = &cxlr->params;
+       int i, rc = 0;
+
+       for (i = 0; i < p->nr_targets; i++) {
+               struct cxl_endpoint_decoder *cxled = p->targets[i];
+               struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+               struct cxl_region_ref *cxl_rr;
+               struct cxl_decoder *cxld;
+               struct cxl_port *iter;
+               struct cxl_ep *ep;
+
+               /* commit bottom up */
+               for (iter = cxled_to_port(cxled); !is_cxl_root(iter);
+                    iter = to_cxl_port(iter->dev.parent)) {
+                       cxl_rr = cxl_rr_load(iter, cxlr);
+                       cxld = cxl_rr->decoder;
+                       rc = cxld->commit(cxld);
+                       if (rc)
+                               break;
+               }
+
+               if (rc) {
+                       /* programming @iter failed, teardown */
+                       for (ep = cxl_ep_load(iter, cxlmd); ep && iter;
+                            iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
+                               cxl_rr = cxl_rr_load(iter, cxlr);
+                               cxld = cxl_rr->decoder;
+                               cxld->reset(cxld);
+                       }
+
+                       cxled->cxld.reset(&cxled->cxld);
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       /* undo the targets that were successfully committed */
+       cxl_region_decode_reset(cxlr, i);
+       return rc;
+}
+
+static ssize_t commit_store(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t len)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       bool commit;
+       ssize_t rc;
+
+       rc = kstrtobool(buf, &commit);
+       if (rc)
+               return rc;
+
+       rc = down_write_killable(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+
+       /* Already in the requested state? */
+       if (commit && p->state >= CXL_CONFIG_COMMIT)
+               goto out;
+       if (!commit && p->state < CXL_CONFIG_COMMIT)
+               goto out;
+
+       /* Not ready to commit? */
+       if (commit && p->state < CXL_CONFIG_ACTIVE) {
+               rc = -ENXIO;
+               goto out;
+       }
+
+       if (commit)
+               rc = cxl_region_decode_commit(cxlr);
+       else {
+               p->state = CXL_CONFIG_RESET_PENDING;
+               up_write(&cxl_region_rwsem);
+               device_release_driver(&cxlr->dev);
+               down_write(&cxl_region_rwsem);
+
+               /*
+                * The lock was dropped, so need to revalidate that the reset is
+                * still pending.
+                */
+               if (p->state == CXL_CONFIG_RESET_PENDING)
+                       rc = cxl_region_decode_reset(cxlr, p->interleave_ways);
+       }
+
+       if (rc)
+               goto out;
+
+       if (commit)
+               p->state = CXL_CONFIG_COMMIT;
+       else if (p->state == CXL_CONFIG_RESET_PENDING)
+               p->state = CXL_CONFIG_ACTIVE;
+
+out:
+       up_write(&cxl_region_rwsem);
+
+       if (rc)
+               return rc;
+       return len;
+}
+
+static ssize_t commit_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       ssize_t rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       rc = sysfs_emit(buf, "%d\n", p->state >= CXL_CONFIG_COMMIT);
+       up_read(&cxl_region_rwsem);
+
+       return rc;
+}
+static DEVICE_ATTR_RW(commit);
+
+static umode_t cxl_region_visible(struct kobject *kobj, struct attribute *a,
+                                 int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct cxl_region *cxlr = to_cxl_region(dev);
+
+       if (a == &dev_attr_uuid.attr && cxlr->mode != CXL_DECODER_PMEM)
+               return 0;
+       return a->mode;
+}
+
+static ssize_t interleave_ways_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       ssize_t rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       rc = sysfs_emit(buf, "%d\n", p->interleave_ways);
+       up_read(&cxl_region_rwsem);
+
+       return rc;
+}
+
+static const struct attribute_group *get_cxl_region_target_group(void);
+
+static ssize_t interleave_ways_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t len)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev->parent);
+       struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       unsigned int val, save;
+       int rc;
+       u8 iw;
+
+       rc = kstrtouint(buf, 0, &val);
+       if (rc)
+               return rc;
+
+       rc = ways_to_cxl(val, &iw);
+       if (rc)
+               return rc;
+
+       /*
+        * Even for x3, x9, and x12 interleaves the region interleave must be a
+        * power of 2 multiple of the host bridge interleave.
+        */
+       if (!is_power_of_2(val / cxld->interleave_ways) ||
+           (val % cxld->interleave_ways)) {
+               dev_dbg(&cxlr->dev, "invalid interleave: %d\n", val);
+               return -EINVAL;
+       }
+
+       rc = down_write_killable(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) {
+               rc = -EBUSY;
+               goto out;
+       }
+
+       save = p->interleave_ways;
+       p->interleave_ways = val;
+       rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_target_group());
+       if (rc)
+               p->interleave_ways = save;
+out:
+       up_write(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       return len;
+}
+static DEVICE_ATTR_RW(interleave_ways);
+
+static ssize_t interleave_granularity_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       ssize_t rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       rc = sysfs_emit(buf, "%d\n", p->interleave_granularity);
+       up_read(&cxl_region_rwsem);
+
+       return rc;
+}
+
+static ssize_t interleave_granularity_store(struct device *dev,
+                                           struct device_attribute *attr,
+                                           const char *buf, size_t len)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev->parent);
+       struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       int rc, val;
+       u16 ig;
+
+       rc = kstrtoint(buf, 0, &val);
+       if (rc)
+               return rc;
+
+       rc = granularity_to_cxl(val, &ig);
+       if (rc)
+               return rc;
+
+       /*
+        * When the host-bridge is interleaved, disallow region granularity !=
+        * root granularity. Regions with a granularity less than the root
+        * interleave result in needing multiple endpoints to support a single
+        * slot in the interleave (possible to suport in the future). Regions
+        * with a granularity greater than the root interleave result in invalid
+        * DPA translations (invalid to support).
+        */
+       if (cxld->interleave_ways > 1 && val != cxld->interleave_granularity)
+               return -EINVAL;
+
+       rc = down_write_killable(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) {
+               rc = -EBUSY;
+               goto out;
+       }
+
+       p->interleave_granularity = val;
+out:
+       up_write(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       return len;
+}
+static DEVICE_ATTR_RW(interleave_granularity);
+
+static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       u64 resource = -1ULL;
+       ssize_t rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       if (p->res)
+               resource = p->res->start;
+       rc = sysfs_emit(buf, "%#llx\n", resource);
+       up_read(&cxl_region_rwsem);
+
+       return rc;
+}
+static DEVICE_ATTR_RO(resource);
+
+static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
+       struct cxl_region_params *p = &cxlr->params;
+       struct resource *res;
+       u32 remainder = 0;
+
+       lockdep_assert_held_write(&cxl_region_rwsem);
+
+       /* Nothing to do... */
+       if (p->res && resource_size(p->res) == size)
+               return 0;
+
+       /* To change size the old size must be freed first */
+       if (p->res)
+               return -EBUSY;
+
+       if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE)
+               return -EBUSY;
+
+       /* ways, granularity and uuid (if PMEM) need to be set before HPA */
+       if (!p->interleave_ways || !p->interleave_granularity ||
+           (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid)))
+               return -ENXIO;
+
+       div_u64_rem(size, SZ_256M * p->interleave_ways, &remainder);
+       if (remainder)
+               return -EINVAL;
+
+       res = alloc_free_mem_region(cxlrd->res, size, SZ_256M,
+                                   dev_name(&cxlr->dev));
+       if (IS_ERR(res)) {
+               dev_dbg(&cxlr->dev, "failed to allocate HPA: %ld\n",
+                       PTR_ERR(res));
+               return PTR_ERR(res);
+       }
+
+       p->res = res;
+       p->state = CXL_CONFIG_INTERLEAVE_ACTIVE;
+
+       return 0;
+}
+
+static void cxl_region_iomem_release(struct cxl_region *cxlr)
+{
+       struct cxl_region_params *p = &cxlr->params;
+
+       if (device_is_registered(&cxlr->dev))
+               lockdep_assert_held_write(&cxl_region_rwsem);
+       if (p->res) {
+               remove_resource(p->res);
+               kfree(p->res);
+               p->res = NULL;
+       }
+}
+
+static int free_hpa(struct cxl_region *cxlr)
+{
+       struct cxl_region_params *p = &cxlr->params;
+
+       lockdep_assert_held_write(&cxl_region_rwsem);
+
+       if (!p->res)
+               return 0;
+
+       if (p->state >= CXL_CONFIG_ACTIVE)
+               return -EBUSY;
+
+       cxl_region_iomem_release(cxlr);
+       p->state = CXL_CONFIG_IDLE;
+       return 0;
+}
+
+static ssize_t size_store(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t len)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       u64 val;
+       int rc;
+
+       rc = kstrtou64(buf, 0, &val);
+       if (rc)
+               return rc;
+
+       rc = down_write_killable(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+
+       if (val)
+               rc = alloc_hpa(cxlr, val);
+       else
+               rc = free_hpa(cxlr);
+       up_write(&cxl_region_rwsem);
+
+       if (rc)
+               return rc;
+
+       return len;
+}
+
+static ssize_t size_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       u64 size = 0;
+       ssize_t rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+       if (p->res)
+               size = resource_size(p->res);
+       rc = sysfs_emit(buf, "%#llx\n", size);
+       up_read(&cxl_region_rwsem);
+
+       return rc;
+}
+static DEVICE_ATTR_RW(size);
+
+static struct attribute *cxl_region_attrs[] = {
+       &dev_attr_uuid.attr,
+       &dev_attr_commit.attr,
+       &dev_attr_interleave_ways.attr,
+       &dev_attr_interleave_granularity.attr,
+       &dev_attr_resource.attr,
+       &dev_attr_size.attr,
+       NULL,
+};
+
+static const struct attribute_group cxl_region_group = {
+       .attrs = cxl_region_attrs,
+       .is_visible = cxl_region_visible,
+};
+
+static size_t show_targetN(struct cxl_region *cxlr, char *buf, int pos)
+{
+       struct cxl_region_params *p = &cxlr->params;
+       struct cxl_endpoint_decoder *cxled;
+       int rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+
+       if (pos >= p->interleave_ways) {
+               dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos,
+                       p->interleave_ways);
+               rc = -ENXIO;
+               goto out;
+       }
+
+       cxled = p->targets[pos];
+       if (!cxled)
+               rc = sysfs_emit(buf, "\n");
+       else
+               rc = sysfs_emit(buf, "%s\n", dev_name(&cxled->cxld.dev));
+out:
+       up_read(&cxl_region_rwsem);
+
+       return rc;
+}
+
+static int match_free_decoder(struct device *dev, void *data)
+{
+       struct cxl_decoder *cxld;
+       int *id = data;
+
+       if (!is_switch_decoder(dev))
+               return 0;
+
+       cxld = to_cxl_decoder(dev);
+
+       /* enforce ordered allocation */
+       if (cxld->id != *id)
+               return 0;
+
+       if (!cxld->region)
+               return 1;
+
+       (*id)++;
+
+       return 0;
+}
+
+static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port,
+                                                  struct cxl_region *cxlr)
+{
+       struct device *dev;
+       int id = 0;
+
+       dev = device_find_child(&port->dev, &id, match_free_decoder);
+       if (!dev)
+               return NULL;
+       /*
+        * This decoder is pinned registered as long as the endpoint decoder is
+        * registered, and endpoint decoder unregistration holds the
+        * cxl_region_rwsem over unregister events, so no need to hold on to
+        * this extra reference.
+        */
+       put_device(dev);
+       return to_cxl_decoder(dev);
+}
+
+static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port,
+                                              struct cxl_region *cxlr)
+{
+       struct cxl_region_params *p = &cxlr->params;
+       struct cxl_region_ref *cxl_rr, *iter;
+       unsigned long index;
+       int rc;
+
+       xa_for_each(&port->regions, index, iter) {
+               struct cxl_region_params *ip = &iter->region->params;
+
+               if (ip->res->start > p->res->start) {
+                       dev_dbg(&cxlr->dev,
+                               "%s: HPA order violation %s:%pr vs %pr\n",
+                               dev_name(&port->dev),
+                               dev_name(&iter->region->dev), ip->res, p->res);
+                       return ERR_PTR(-EBUSY);
+               }
+       }
+
+       cxl_rr = kzalloc(sizeof(*cxl_rr), GFP_KERNEL);
+       if (!cxl_rr)
+               return ERR_PTR(-ENOMEM);
+       cxl_rr->port = port;
+       cxl_rr->region = cxlr;
+       cxl_rr->nr_targets = 1;
+       xa_init(&cxl_rr->endpoints);
+
+       rc = xa_insert(&port->regions, (unsigned long)cxlr, cxl_rr, GFP_KERNEL);
+       if (rc) {
+               dev_dbg(&cxlr->dev,
+                       "%s: failed to track region reference: %d\n",
+                       dev_name(&port->dev), rc);
+               kfree(cxl_rr);
+               return ERR_PTR(rc);
+       }
+
+       return cxl_rr;
+}
+
+static void free_region_ref(struct cxl_region_ref *cxl_rr)
+{
+       struct cxl_port *port = cxl_rr->port;
+       struct cxl_region *cxlr = cxl_rr->region;
+       struct cxl_decoder *cxld = cxl_rr->decoder;
+
+       dev_WARN_ONCE(&cxlr->dev, cxld->region != cxlr, "region mismatch\n");
+       if (cxld->region == cxlr) {
+               cxld->region = NULL;
+               put_device(&cxlr->dev);
+       }
+
+       xa_erase(&port->regions, (unsigned long)cxlr);
+       xa_destroy(&cxl_rr->endpoints);
+       kfree(cxl_rr);
+}
+
+static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr,
+                        struct cxl_endpoint_decoder *cxled)
+{
+       int rc;
+       struct cxl_port *port = cxl_rr->port;
+       struct cxl_region *cxlr = cxl_rr->region;
+       struct cxl_decoder *cxld = cxl_rr->decoder;
+       struct cxl_ep *ep = cxl_ep_load(port, cxled_to_memdev(cxled));
+
+       if (ep) {
+               rc = xa_insert(&cxl_rr->endpoints, (unsigned long)cxled, ep,
+                              GFP_KERNEL);
+               if (rc)
+                       return rc;
+       }
+       cxl_rr->nr_eps++;
+
+       if (!cxld->region) {
+               cxld->region = cxlr;
+               get_device(&cxlr->dev);
+       }
+
+       return 0;
+}
+
+/**
+ * cxl_port_attach_region() - track a region's interest in a port by endpoint
+ * @port: port to add a new region reference 'struct cxl_region_ref'
+ * @cxlr: region to attach to @port
+ * @cxled: endpoint decoder used to create or further pin a region reference
+ * @pos: interleave position of @cxled in @cxlr
+ *
+ * The attach event is an opportunity to validate CXL decode setup
+ * constraints and record metadata needed for programming HDM decoders,
+ * in particular decoder target lists.
+ *
+ * The steps are:
+ *
+ * - validate that there are no other regions with a higher HPA already
+ *   associated with @port
+ * - establish a region reference if one is not already present
+ *
+ *   - additionally allocate a decoder instance that will host @cxlr on
+ *     @port
+ *
+ * - pin the region reference by the endpoint
+ * - account for how many entries in @port's target list are needed to
+ *   cover all of the added endpoints.
+ */
+static int cxl_port_attach_region(struct cxl_port *port,
+                                 struct cxl_region *cxlr,
+                                 struct cxl_endpoint_decoder *cxled, int pos)
+{
+       struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+       struct cxl_ep *ep = cxl_ep_load(port, cxlmd);
+       struct cxl_region_ref *cxl_rr;
+       bool nr_targets_inc = false;
+       struct cxl_decoder *cxld;
+       unsigned long index;
+       int rc = -EBUSY;
+
+       lockdep_assert_held_write(&cxl_region_rwsem);
+
+       cxl_rr = cxl_rr_load(port, cxlr);
+       if (cxl_rr) {
+               struct cxl_ep *ep_iter;
+               int found = 0;
+
+               /*
+                * Walk the existing endpoints that have been attached to
+                * @cxlr at @port and see if they share the same 'next' port
+                * in the downstream direction. I.e. endpoints that share common
+                * upstream switch.
+                */
+               xa_for_each(&cxl_rr->endpoints, index, ep_iter) {
+                       if (ep_iter == ep)
+                               continue;
+                       if (ep_iter->next == ep->next) {
+                               found++;
+                               break;
+                       }
+               }
+
+               /*
+                * New target port, or @port is an endpoint port that always
+                * accounts its own local decode as a target.
+                */
+               if (!found || !ep->next) {
+                       cxl_rr->nr_targets++;
+                       nr_targets_inc = true;
+               }
+
+               /*
+                * The decoder for @cxlr was allocated when the region was first
+                * attached to @port.
+                */
+               cxld = cxl_rr->decoder;
+       } else {
+               cxl_rr = alloc_region_ref(port, cxlr);
+               if (IS_ERR(cxl_rr)) {
+                       dev_dbg(&cxlr->dev,
+                               "%s: failed to allocate region reference\n",
+                               dev_name(&port->dev));
+                       return PTR_ERR(cxl_rr);
+               }
+               nr_targets_inc = true;
+
+               if (port == cxled_to_port(cxled))
+                       cxld = &cxled->cxld;
+               else
+                       cxld = cxl_region_find_decoder(port, cxlr);
+               if (!cxld) {
+                       dev_dbg(&cxlr->dev, "%s: no decoder available\n",
+                               dev_name(&port->dev));
+                       goto out_erase;
+               }
+
+               if (cxld->region) {
+                       dev_dbg(&cxlr->dev, "%s: %s already attached to %s\n",
+                               dev_name(&port->dev), dev_name(&cxld->dev),
+                               dev_name(&cxld->region->dev));
+                       rc = -EBUSY;
+                       goto out_erase;
+               }
+
+               cxl_rr->decoder = cxld;
+       }
+
+       rc = cxl_rr_ep_add(cxl_rr, cxled);
+       if (rc) {
+               dev_dbg(&cxlr->dev,
+                       "%s: failed to track endpoint %s:%s reference\n",
+                       dev_name(&port->dev), dev_name(&cxlmd->dev),
+                       dev_name(&cxld->dev));
+               goto out_erase;
+       }
+
+       dev_dbg(&cxlr->dev,
+               "%s:%s %s add: %s:%s @ %d next: %s nr_eps: %d nr_targets: %d\n",
+               dev_name(port->uport), dev_name(&port->dev),
+               dev_name(&cxld->dev), dev_name(&cxlmd->dev),
+               dev_name(&cxled->cxld.dev), pos,
+               ep ? ep->next ? dev_name(ep->next->uport) :
+                                     dev_name(&cxlmd->dev) :
+                          "none",
+               cxl_rr->nr_eps, cxl_rr->nr_targets);
+
+       return 0;
+out_erase:
+       if (nr_targets_inc)
+               cxl_rr->nr_targets--;
+       if (cxl_rr->nr_eps == 0)
+               free_region_ref(cxl_rr);
+       return rc;
+}
+
+static void cxl_port_detach_region(struct cxl_port *port,
+                                  struct cxl_region *cxlr,
+                                  struct cxl_endpoint_decoder *cxled)
+{
+       struct cxl_region_ref *cxl_rr;
+       struct cxl_ep *ep = NULL;
+
+       lockdep_assert_held_write(&cxl_region_rwsem);
+
+       cxl_rr = cxl_rr_load(port, cxlr);
+       if (!cxl_rr)
+               return;
+
+       /*
+        * Endpoint ports do not carry cxl_ep references, and they
+        * never target more than one endpoint by definition
+        */
+       if (cxl_rr->decoder == &cxled->cxld)
+               cxl_rr->nr_eps--;
+       else
+               ep = xa_erase(&cxl_rr->endpoints, (unsigned long)cxled);
+       if (ep) {
+               struct cxl_ep *ep_iter;
+               unsigned long index;
+               int found = 0;
+
+               cxl_rr->nr_eps--;
+               xa_for_each(&cxl_rr->endpoints, index, ep_iter) {
+                       if (ep_iter->next == ep->next) {
+                               found++;
+                               break;
+                       }
+               }
+               if (!found)
+                       cxl_rr->nr_targets--;
+       }
+
+       if (cxl_rr->nr_eps == 0)
+               free_region_ref(cxl_rr);
+}
+
+static int check_last_peer(struct cxl_endpoint_decoder *cxled,
+                          struct cxl_ep *ep, struct cxl_region_ref *cxl_rr,
+                          int distance)
+{
+       struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+       struct cxl_region *cxlr = cxl_rr->region;
+       struct cxl_region_params *p = &cxlr->params;
+       struct cxl_endpoint_decoder *cxled_peer;
+       struct cxl_port *port = cxl_rr->port;
+       struct cxl_memdev *cxlmd_peer;
+       struct cxl_ep *ep_peer;
+       int pos = cxled->pos;
+
+       /*
+        * If this position wants to share a dport with the last endpoint mapped
+        * then that endpoint, at index 'position - distance', must also be
+        * mapped by this dport.
+        */
+       if (pos < distance) {
+               dev_dbg(&cxlr->dev, "%s:%s: cannot host %s:%s at %d\n",
+                       dev_name(port->uport), dev_name(&port->dev),
+                       dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos);
+               return -ENXIO;
+       }
+       cxled_peer = p->targets[pos - distance];
+       cxlmd_peer = cxled_to_memdev(cxled_peer);
+       ep_peer = cxl_ep_load(port, cxlmd_peer);
+       if (ep->dport != ep_peer->dport) {
+               dev_dbg(&cxlr->dev,
+                       "%s:%s: %s:%s pos %d mismatched peer %s:%s\n",
+                       dev_name(port->uport), dev_name(&port->dev),
+                       dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos,
+                       dev_name(&cxlmd_peer->dev),
+                       dev_name(&cxled_peer->cxld.dev));
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int cxl_port_setup_targets(struct cxl_port *port,
+                                 struct cxl_region *cxlr,
+                                 struct cxl_endpoint_decoder *cxled)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
+       int parent_iw, parent_ig, ig, iw, rc, inc = 0, pos = cxled->pos;
+       struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
+       struct cxl_region_ref *cxl_rr = cxl_rr_load(port, cxlr);
+       struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+       struct cxl_ep *ep = cxl_ep_load(port, cxlmd);
+       struct cxl_region_params *p = &cxlr->params;
+       struct cxl_decoder *cxld = cxl_rr->decoder;
+       struct cxl_switch_decoder *cxlsd;
+       u16 eig, peig;
+       u8 eiw, peiw;
+
+       /*
+        * While root level decoders support x3, x6, x12, switch level
+        * decoders only support powers of 2 up to x16.
+        */
+       if (!is_power_of_2(cxl_rr->nr_targets)) {
+               dev_dbg(&cxlr->dev, "%s:%s: invalid target count %d\n",
+                       dev_name(port->uport), dev_name(&port->dev),
+                       cxl_rr->nr_targets);
+               return -EINVAL;
+       }
+
+       cxlsd = to_cxl_switch_decoder(&cxld->dev);
+       if (cxl_rr->nr_targets_set) {
+               int i, distance;
+
+               distance = p->nr_targets / cxl_rr->nr_targets;
+               for (i = 0; i < cxl_rr->nr_targets_set; i++)
+                       if (ep->dport == cxlsd->target[i]) {
+                               rc = check_last_peer(cxled, ep, cxl_rr,
+                                                    distance);
+                               if (rc)
+                                       return rc;
+                               goto out_target_set;
+                       }
+               goto add_target;
+       }
+
+       if (is_cxl_root(parent_port)) {
+               parent_ig = cxlrd->cxlsd.cxld.interleave_granularity;
+               parent_iw = cxlrd->cxlsd.cxld.interleave_ways;
+               /*
+                * For purposes of address bit routing, use power-of-2 math for
+                * switch ports.
+                */
+               if (!is_power_of_2(parent_iw))
+                       parent_iw /= 3;
+       } else {
+               struct cxl_region_ref *parent_rr;
+               struct cxl_decoder *parent_cxld;
+
+               parent_rr = cxl_rr_load(parent_port, cxlr);
+               parent_cxld = parent_rr->decoder;
+               parent_ig = parent_cxld->interleave_granularity;
+               parent_iw = parent_cxld->interleave_ways;
+       }
+
+       rc = granularity_to_cxl(parent_ig, &peig);
+       if (rc) {
+               dev_dbg(&cxlr->dev, "%s:%s: invalid parent granularity: %d\n",
+                       dev_name(parent_port->uport),
+                       dev_name(&parent_port->dev), parent_ig);
+               return rc;
+       }
+
+       rc = ways_to_cxl(parent_iw, &peiw);
+       if (rc) {
+               dev_dbg(&cxlr->dev, "%s:%s: invalid parent interleave: %d\n",
+                       dev_name(parent_port->uport),
+                       dev_name(&parent_port->dev), parent_iw);
+               return rc;
+       }
+
+       iw = cxl_rr->nr_targets;
+       rc = ways_to_cxl(iw, &eiw);
+       if (rc) {
+               dev_dbg(&cxlr->dev, "%s:%s: invalid port interleave: %d\n",
+                       dev_name(port->uport), dev_name(&port->dev), iw);
+               return rc;
+       }
+
+       /*
+        * If @parent_port is masking address bits, pick the next unused address
+        * bit to route @port's targets.
+        */
+       if (parent_iw > 1 && cxl_rr->nr_targets > 1) {
+               u32 address_bit = max(peig + peiw, eiw + peig);
+
+               eig = address_bit - eiw + 1;
+       } else {
+               eiw = peiw;
+               eig = peig;
+       }
+
+       rc = cxl_to_granularity(eig, &ig);
+       if (rc) {
+               dev_dbg(&cxlr->dev, "%s:%s: invalid interleave: %d\n",
+                       dev_name(port->uport), dev_name(&port->dev),
+                       256 << eig);
+               return rc;
+       }
+
+       cxld->interleave_ways = iw;
+       cxld->interleave_granularity = ig;
+       cxld->hpa_range = (struct range) {
+               .start = p->res->start,
+               .end = p->res->end,
+       };
+       dev_dbg(&cxlr->dev, "%s:%s iw: %d ig: %d\n", dev_name(port->uport),
+               dev_name(&port->dev), iw, ig);
+add_target:
+       if (cxl_rr->nr_targets_set == cxl_rr->nr_targets) {
+               dev_dbg(&cxlr->dev,
+                       "%s:%s: targets full trying to add %s:%s at %d\n",
+                       dev_name(port->uport), dev_name(&port->dev),
+                       dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos);
+               return -ENXIO;
+       }
+       cxlsd->target[cxl_rr->nr_targets_set] = ep->dport;
+       inc = 1;
+out_target_set:
+       cxl_rr->nr_targets_set += inc;
+       dev_dbg(&cxlr->dev, "%s:%s target[%d] = %s for %s:%s @ %d\n",
+               dev_name(port->uport), dev_name(&port->dev),
+               cxl_rr->nr_targets_set - 1, dev_name(ep->dport->dport),
+               dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos);
+
+       return 0;
+}
+
+static void cxl_port_reset_targets(struct cxl_port *port,
+                                  struct cxl_region *cxlr)
+{
+       struct cxl_region_ref *cxl_rr = cxl_rr_load(port, cxlr);
+       struct cxl_decoder *cxld;
+
+       /*
+        * After the last endpoint has been detached the entire cxl_rr may now
+        * be gone.
+        */
+       if (!cxl_rr)
+               return;
+       cxl_rr->nr_targets_set = 0;
+
+       cxld = cxl_rr->decoder;
+       cxld->hpa_range = (struct range) {
+               .start = 0,
+               .end = -1,
+       };
+}
+
+static void cxl_region_teardown_targets(struct cxl_region *cxlr)
+{
+       struct cxl_region_params *p = &cxlr->params;
+       struct cxl_endpoint_decoder *cxled;
+       struct cxl_memdev *cxlmd;
+       struct cxl_port *iter;
+       struct cxl_ep *ep;
+       int i;
+
+       for (i = 0; i < p->nr_targets; i++) {
+               cxled = p->targets[i];
+               cxlmd = cxled_to_memdev(cxled);
+
+               iter = cxled_to_port(cxled);
+               while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
+                       iter = to_cxl_port(iter->dev.parent);
+
+               for (ep = cxl_ep_load(iter, cxlmd); iter;
+                    iter = ep->next, ep = cxl_ep_load(iter, cxlmd))
+                       cxl_port_reset_targets(iter, cxlr);
+       }
+}
+
+static int cxl_region_setup_targets(struct cxl_region *cxlr)
+{
+       struct cxl_region_params *p = &cxlr->params;
+       struct cxl_endpoint_decoder *cxled;
+       struct cxl_memdev *cxlmd;
+       struct cxl_port *iter;
+       struct cxl_ep *ep;
+       int i, rc;
+
+       for (i = 0; i < p->nr_targets; i++) {
+               cxled = p->targets[i];
+               cxlmd = cxled_to_memdev(cxled);
+
+               iter = cxled_to_port(cxled);
+               while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
+                       iter = to_cxl_port(iter->dev.parent);
+
+               /*
+                * Descend the topology tree programming targets while
+                * looking for conflicts.
+                */
+               for (ep = cxl_ep_load(iter, cxlmd); iter;
+                    iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
+                       rc = cxl_port_setup_targets(iter, cxlr, cxled);
+                       if (rc) {
+                               cxl_region_teardown_targets(cxlr);
+                               return rc;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int cxl_region_attach(struct cxl_region *cxlr,
+                            struct cxl_endpoint_decoder *cxled, int pos)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
+       struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+       struct cxl_port *ep_port, *root_port, *iter;
+       struct cxl_region_params *p = &cxlr->params;
+       struct cxl_dport *dport;
+       int i, rc = -ENXIO;
+
+       if (cxled->mode == CXL_DECODER_DEAD) {
+               dev_dbg(&cxlr->dev, "%s dead\n", dev_name(&cxled->cxld.dev));
+               return -ENODEV;
+       }
+
+       /* all full of members, or interleave config not established? */
+       if (p->state > CXL_CONFIG_INTERLEAVE_ACTIVE) {
+               dev_dbg(&cxlr->dev, "region already active\n");
+               return -EBUSY;
+       } else if (p->state < CXL_CONFIG_INTERLEAVE_ACTIVE) {
+               dev_dbg(&cxlr->dev, "interleave config missing\n");
+               return -ENXIO;
+       }
+
+       if (pos < 0 || pos >= p->interleave_ways) {
+               dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos,
+                       p->interleave_ways);
+               return -ENXIO;
+       }
+
+       if (p->targets[pos] == cxled)
+               return 0;
+
+       if (p->targets[pos]) {
+               struct cxl_endpoint_decoder *cxled_target = p->targets[pos];
+               struct cxl_memdev *cxlmd_target = cxled_to_memdev(cxled_target);
+
+               dev_dbg(&cxlr->dev, "position %d already assigned to %s:%s\n",
+                       pos, dev_name(&cxlmd_target->dev),
+                       dev_name(&cxled_target->cxld.dev));
+               return -EBUSY;
+       }
+
+       for (i = 0; i < p->interleave_ways; i++) {
+               struct cxl_endpoint_decoder *cxled_target;
+               struct cxl_memdev *cxlmd_target;
+
+               cxled_target = p->targets[pos];
+               if (!cxled_target)
+                       continue;
+
+               cxlmd_target = cxled_to_memdev(cxled_target);
+               if (cxlmd_target == cxlmd) {
+                       dev_dbg(&cxlr->dev,
+                               "%s already specified at position %d via: %s\n",
+                               dev_name(&cxlmd->dev), pos,
+                               dev_name(&cxled_target->cxld.dev));
+                       return -EBUSY;
+               }
+       }
+
+       ep_port = cxled_to_port(cxled);
+       root_port = cxlrd_to_port(cxlrd);
+       dport = cxl_find_dport_by_dev(root_port, ep_port->host_bridge);
+       if (!dport) {
+               dev_dbg(&cxlr->dev, "%s:%s invalid target for %s\n",
+                       dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+                       dev_name(cxlr->dev.parent));
+               return -ENXIO;
+       }
+
+       if (cxlrd->calc_hb(cxlrd, pos) != dport) {
+               dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n",
+                       dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+                       dev_name(&cxlrd->cxlsd.cxld.dev));
+               return -ENXIO;
+       }
+
+       if (cxled->cxld.target_type != cxlr->type) {
+               dev_dbg(&cxlr->dev, "%s:%s type mismatch: %d vs %d\n",
+                       dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+                       cxled->cxld.target_type, cxlr->type);
+               return -ENXIO;
+       }
+
+       if (!cxled->dpa_res) {
+               dev_dbg(&cxlr->dev, "%s:%s: missing DPA allocation.\n",
+                       dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev));
+               return -ENXIO;
+       }
+
+       if (resource_size(cxled->dpa_res) * p->interleave_ways !=
+           resource_size(p->res)) {
+               dev_dbg(&cxlr->dev,
+                       "%s:%s: decoder-size-%#llx * ways-%d != region-size-%#llx\n",
+                       dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+                       (u64)resource_size(cxled->dpa_res), p->interleave_ways,
+                       (u64)resource_size(p->res));
+               return -EINVAL;
+       }
+
+       for (iter = ep_port; !is_cxl_root(iter);
+            iter = to_cxl_port(iter->dev.parent)) {
+               rc = cxl_port_attach_region(iter, cxlr, cxled, pos);
+               if (rc)
+                       goto err;
+       }
+
+       p->targets[pos] = cxled;
+       cxled->pos = pos;
+       p->nr_targets++;
+
+       if (p->nr_targets == p->interleave_ways) {
+               rc = cxl_region_setup_targets(cxlr);
+               if (rc)
+                       goto err_decrement;
+               p->state = CXL_CONFIG_ACTIVE;
+       }
+
+       cxled->cxld.interleave_ways = p->interleave_ways;
+       cxled->cxld.interleave_granularity = p->interleave_granularity;
+       cxled->cxld.hpa_range = (struct range) {
+               .start = p->res->start,
+               .end = p->res->end,
+       };
+
+       return 0;
+
+err_decrement:
+       p->nr_targets--;
+err:
+       for (iter = ep_port; !is_cxl_root(iter);
+            iter = to_cxl_port(iter->dev.parent))
+               cxl_port_detach_region(iter, cxlr, cxled);
+       return rc;
+}
+
+static int cxl_region_detach(struct cxl_endpoint_decoder *cxled)
+{
+       struct cxl_port *iter, *ep_port = cxled_to_port(cxled);
+       struct cxl_region *cxlr = cxled->cxld.region;
+       struct cxl_region_params *p;
+       int rc = 0;
+
+       lockdep_assert_held_write(&cxl_region_rwsem);
+
+       if (!cxlr)
+               return 0;
+
+       p = &cxlr->params;
+       get_device(&cxlr->dev);
+
+       if (p->state > CXL_CONFIG_ACTIVE) {
+               /*
+                * TODO: tear down all impacted regions if a device is
+                * removed out of order
+                */
+               rc = cxl_region_decode_reset(cxlr, p->interleave_ways);
+               if (rc)
+                       goto out;
+               p->state = CXL_CONFIG_ACTIVE;
+       }
+
+       for (iter = ep_port; !is_cxl_root(iter);
+            iter = to_cxl_port(iter->dev.parent))
+               cxl_port_detach_region(iter, cxlr, cxled);
+
+       if (cxled->pos < 0 || cxled->pos >= p->interleave_ways ||
+           p->targets[cxled->pos] != cxled) {
+               struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+
+               dev_WARN_ONCE(&cxlr->dev, 1, "expected %s:%s at position %d\n",
+                             dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+                             cxled->pos);
+               goto out;
+       }
+
+       if (p->state == CXL_CONFIG_ACTIVE) {
+               p->state = CXL_CONFIG_INTERLEAVE_ACTIVE;
+               cxl_region_teardown_targets(cxlr);
+       }
+       p->targets[cxled->pos] = NULL;
+       p->nr_targets--;
+       cxled->cxld.hpa_range = (struct range) {
+               .start = 0,
+               .end = -1,
+       };
+
+       /* notify the region driver that one of its targets has departed */
+       up_write(&cxl_region_rwsem);
+       device_release_driver(&cxlr->dev);
+       down_write(&cxl_region_rwsem);
+out:
+       put_device(&cxlr->dev);
+       return rc;
+}
+
+void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
+{
+       down_write(&cxl_region_rwsem);
+       cxled->mode = CXL_DECODER_DEAD;
+       cxl_region_detach(cxled);
+       up_write(&cxl_region_rwsem);
+}
+
+static int attach_target(struct cxl_region *cxlr, const char *decoder, int pos)
+{
+       struct device *dev;
+       int rc;
+
+       dev = bus_find_device_by_name(&cxl_bus_type, NULL, decoder);
+       if (!dev)
+               return -ENODEV;
+
+       if (!is_endpoint_decoder(dev)) {
+               put_device(dev);
+               return -EINVAL;
+       }
+
+       rc = down_write_killable(&cxl_region_rwsem);
+       if (rc)
+               goto out;
+       down_read(&cxl_dpa_rwsem);
+       rc = cxl_region_attach(cxlr, to_cxl_endpoint_decoder(dev), pos);
+       up_read(&cxl_dpa_rwsem);
+       up_write(&cxl_region_rwsem);
+out:
+       put_device(dev);
+       return rc;
+}
+
+static int detach_target(struct cxl_region *cxlr, int pos)
+{
+       struct cxl_region_params *p = &cxlr->params;
+       int rc;
+
+       rc = down_write_killable(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+
+       if (pos >= p->interleave_ways) {
+               dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos,
+                       p->interleave_ways);
+               rc = -ENXIO;
+               goto out;
+       }
+
+       if (!p->targets[pos]) {
+               rc = 0;
+               goto out;
+       }
+
+       rc = cxl_region_detach(p->targets[pos]);
+out:
+       up_write(&cxl_region_rwsem);
+       return rc;
+}
+
+static size_t store_targetN(struct cxl_region *cxlr, const char *buf, int pos,
+                           size_t len)
+{
+       int rc;
+
+       if (sysfs_streq(buf, "\n"))
+               rc = detach_target(cxlr, pos);
+       else
+               rc = attach_target(cxlr, buf, pos);
+
+       if (rc < 0)
+               return rc;
+       return len;
+}
+
+#define TARGET_ATTR_RW(n)                                              \
+static ssize_t target##n##_show(                                       \
+       struct device *dev, struct device_attribute *attr, char *buf)  \
+{                                                                      \
+       return show_targetN(to_cxl_region(dev), buf, (n));             \
+}                                                                      \
+static ssize_t target##n##_store(struct device *dev,                   \
+                                struct device_attribute *attr,        \
+                                const char *buf, size_t len)          \
+{                                                                      \
+       return store_targetN(to_cxl_region(dev), buf, (n), len);       \
+}                                                                      \
+static DEVICE_ATTR_RW(target##n)
+
+TARGET_ATTR_RW(0);
+TARGET_ATTR_RW(1);
+TARGET_ATTR_RW(2);
+TARGET_ATTR_RW(3);
+TARGET_ATTR_RW(4);
+TARGET_ATTR_RW(5);
+TARGET_ATTR_RW(6);
+TARGET_ATTR_RW(7);
+TARGET_ATTR_RW(8);
+TARGET_ATTR_RW(9);
+TARGET_ATTR_RW(10);
+TARGET_ATTR_RW(11);
+TARGET_ATTR_RW(12);
+TARGET_ATTR_RW(13);
+TARGET_ATTR_RW(14);
+TARGET_ATTR_RW(15);
+
+static struct attribute *target_attrs[] = {
+       &dev_attr_target0.attr,
+       &dev_attr_target1.attr,
+       &dev_attr_target2.attr,
+       &dev_attr_target3.attr,
+       &dev_attr_target4.attr,
+       &dev_attr_target5.attr,
+       &dev_attr_target6.attr,
+       &dev_attr_target7.attr,
+       &dev_attr_target8.attr,
+       &dev_attr_target9.attr,
+       &dev_attr_target10.attr,
+       &dev_attr_target11.attr,
+       &dev_attr_target12.attr,
+       &dev_attr_target13.attr,
+       &dev_attr_target14.attr,
+       &dev_attr_target15.attr,
+       NULL,
+};
+
+static umode_t cxl_region_target_visible(struct kobject *kobj,
+                                        struct attribute *a, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+
+       if (n < p->interleave_ways)
+               return a->mode;
+       return 0;
+}
+
+static const struct attribute_group cxl_region_target_group = {
+       .attrs = target_attrs,
+       .is_visible = cxl_region_target_visible,
+};
+
+static const struct attribute_group *get_cxl_region_target_group(void)
+{
+       return &cxl_region_target_group;
+}
+
+static const struct attribute_group *region_groups[] = {
+       &cxl_base_attribute_group,
+       &cxl_region_group,
+       &cxl_region_target_group,
+       NULL,
+};
+
+static void cxl_region_release(struct device *dev)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+
+       memregion_free(cxlr->id);
+       kfree(cxlr);
+}
+
+const struct device_type cxl_region_type = {
+       .name = "cxl_region",
+       .release = cxl_region_release,
+       .groups = region_groups
+};
+
+bool is_cxl_region(struct device *dev)
+{
+       return dev->type == &cxl_region_type;
+}
+EXPORT_SYMBOL_NS_GPL(is_cxl_region, CXL);
+
+static struct cxl_region *to_cxl_region(struct device *dev)
+{
+       if (dev_WARN_ONCE(dev, dev->type != &cxl_region_type,
+                         "not a cxl_region device\n"))
+               return NULL;
+
+       return container_of(dev, struct cxl_region, dev);
+}
+
+static void unregister_region(void *dev)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+
+       device_del(dev);
+       cxl_region_iomem_release(cxlr);
+       put_device(dev);
+}
+
+static struct lock_class_key cxl_region_key;
+
+static struct cxl_region *cxl_region_alloc(struct cxl_root_decoder *cxlrd, int id)
+{
+       struct cxl_region *cxlr;
+       struct device *dev;
+
+       cxlr = kzalloc(sizeof(*cxlr), GFP_KERNEL);
+       if (!cxlr) {
+               memregion_free(id);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       dev = &cxlr->dev;
+       device_initialize(dev);
+       lockdep_set_class(&dev->mutex, &cxl_region_key);
+       dev->parent = &cxlrd->cxlsd.cxld.dev;
+       device_set_pm_not_required(dev);
+       dev->bus = &cxl_bus_type;
+       dev->type = &cxl_region_type;
+       cxlr->id = id;
+
+       return cxlr;
+}
+
+/**
+ * devm_cxl_add_region - Adds a region to a decoder
+ * @cxlrd: root decoder
+ * @id: memregion id to create, or memregion_free() on failure
+ * @mode: mode for the endpoint decoders of this region
+ * @type: select whether this is an expander or accelerator (type-2 or type-3)
+ *
+ * This is the second step of region initialization. Regions exist within an
+ * address space which is mapped by a @cxlrd.
+ *
+ * Return: 0 if the region was added to the @cxlrd, else returns negative error
+ * code. The region will be named "regionZ" where Z is the unique region number.
+ */
+static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
+                                             int id,
+                                             enum cxl_decoder_mode mode,
+                                             enum cxl_decoder_type type)
+{
+       struct cxl_port *port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
+       struct cxl_region *cxlr;
+       struct device *dev;
+       int rc;
+
+       cxlr = cxl_region_alloc(cxlrd, id);
+       if (IS_ERR(cxlr))
+               return cxlr;
+       cxlr->mode = mode;
+       cxlr->type = type;
+
+       dev = &cxlr->dev;
+       rc = dev_set_name(dev, "region%d", id);
+       if (rc)
+               goto err;
+
+       rc = device_add(dev);
+       if (rc)
+               goto err;
+
+       rc = devm_add_action_or_reset(port->uport, unregister_region, cxlr);
+       if (rc)
+               return ERR_PTR(rc);
+
+       dev_dbg(port->uport, "%s: created %s\n",
+               dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
+       return cxlr;
+
+err:
+       put_device(dev);
+       return ERR_PTR(rc);
+}
+
+static ssize_t create_pmem_region_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+
+       return sysfs_emit(buf, "region%u\n", atomic_read(&cxlrd->region_id));
+}
+
+static ssize_t create_pmem_region_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t len)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+       struct cxl_region *cxlr;
+       int id, rc;
+
+       rc = sscanf(buf, "region%d\n", &id);
+       if (rc != 1)
+               return -EINVAL;
+
+       rc = memregion_alloc(GFP_KERNEL);
+       if (rc < 0)
+               return rc;
+
+       if (atomic_cmpxchg(&cxlrd->region_id, id, rc) != id) {
+               memregion_free(rc);
+               return -EBUSY;
+       }
+
+       cxlr = devm_cxl_add_region(cxlrd, id, CXL_DECODER_PMEM,
+                                  CXL_DECODER_EXPANDER);
+       if (IS_ERR(cxlr))
+               return PTR_ERR(cxlr);
+
+       return len;
+}
+DEVICE_ATTR_RW(create_pmem_region);
+
+static ssize_t region_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct cxl_decoder *cxld = to_cxl_decoder(dev);
+       ssize_t rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc)
+               return rc;
+
+       if (cxld->region)
+               rc = sysfs_emit(buf, "%s\n", dev_name(&cxld->region->dev));
+       else
+               rc = sysfs_emit(buf, "\n");
+       up_read(&cxl_region_rwsem);
+
+       return rc;
+}
+DEVICE_ATTR_RO(region);
+
+static struct cxl_region *
+cxl_find_region_by_name(struct cxl_root_decoder *cxlrd, const char *name)
+{
+       struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+       struct device *region_dev;
+
+       region_dev = device_find_child_by_name(&cxld->dev, name);
+       if (!region_dev)
+               return ERR_PTR(-ENODEV);
+
+       return to_cxl_region(region_dev);
+}
+
+static ssize_t delete_region_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t len)
+{
+       struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+       struct cxl_port *port = to_cxl_port(dev->parent);
+       struct cxl_region *cxlr;
+
+       cxlr = cxl_find_region_by_name(cxlrd, buf);
+       if (IS_ERR(cxlr))
+               return PTR_ERR(cxlr);
+
+       devm_release_action(port->uport, unregister_region, cxlr);
+       put_device(&cxlr->dev);
+
+       return len;
+}
+DEVICE_ATTR_WO(delete_region);
+
+static void cxl_pmem_region_release(struct device *dev)
+{
+       struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+       int i;
+
+       for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+               struct cxl_memdev *cxlmd = cxlr_pmem->mapping[i].cxlmd;
+
+               put_device(&cxlmd->dev);
+       }
+
+       kfree(cxlr_pmem);
+}
+
+static const struct attribute_group *cxl_pmem_region_attribute_groups[] = {
+       &cxl_base_attribute_group,
+       NULL,
+};
+
+const struct device_type cxl_pmem_region_type = {
+       .name = "cxl_pmem_region",
+       .release = cxl_pmem_region_release,
+       .groups = cxl_pmem_region_attribute_groups,
+};
+
+bool is_cxl_pmem_region(struct device *dev)
+{
+       return dev->type == &cxl_pmem_region_type;
+}
+EXPORT_SYMBOL_NS_GPL(is_cxl_pmem_region, CXL);
+
+struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
+{
+       if (dev_WARN_ONCE(dev, !is_cxl_pmem_region(dev),
+                         "not a cxl_pmem_region device\n"))
+               return NULL;
+       return container_of(dev, struct cxl_pmem_region, dev);
+}
+EXPORT_SYMBOL_NS_GPL(to_cxl_pmem_region, CXL);
+
+static struct lock_class_key cxl_pmem_region_key;
+
+static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
+{
+       struct cxl_region_params *p = &cxlr->params;
+       struct cxl_pmem_region *cxlr_pmem;
+       struct device *dev;
+       int i;
+
+       down_read(&cxl_region_rwsem);
+       if (p->state != CXL_CONFIG_COMMIT) {
+               cxlr_pmem = ERR_PTR(-ENXIO);
+               goto out;
+       }
+
+       cxlr_pmem = kzalloc(struct_size(cxlr_pmem, mapping, p->nr_targets),
+                           GFP_KERNEL);
+       if (!cxlr_pmem) {
+               cxlr_pmem = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       cxlr_pmem->hpa_range.start = p->res->start;
+       cxlr_pmem->hpa_range.end = p->res->end;
+
+       /* Snapshot the region configuration underneath the cxl_region_rwsem */
+       cxlr_pmem->nr_mappings = p->nr_targets;
+       for (i = 0; i < p->nr_targets; i++) {
+               struct cxl_endpoint_decoder *cxled = p->targets[i];
+               struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+               struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+
+               m->cxlmd = cxlmd;
+               get_device(&cxlmd->dev);
+               m->start = cxled->dpa_res->start;
+               m->size = resource_size(cxled->dpa_res);
+               m->position = i;
+       }
+
+       dev = &cxlr_pmem->dev;
+       cxlr_pmem->cxlr = cxlr;
+       device_initialize(dev);
+       lockdep_set_class(&dev->mutex, &cxl_pmem_region_key);
+       device_set_pm_not_required(dev);
+       dev->parent = &cxlr->dev;
+       dev->bus = &cxl_bus_type;
+       dev->type = &cxl_pmem_region_type;
+out:
+       up_read(&cxl_region_rwsem);
+
+       return cxlr_pmem;
+}
+
+static void cxlr_pmem_unregister(void *dev)
+{
+       device_unregister(dev);
+}
+
+/**
+ * devm_cxl_add_pmem_region() - add a cxl_region-to-nd_region bridge
+ * @cxlr: parent CXL region for this pmem region bridge device
+ *
+ * Return: 0 on success negative error code on failure.
+ */
+static int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
+{
+       struct cxl_pmem_region *cxlr_pmem;
+       struct device *dev;
+       int rc;
+
+       cxlr_pmem = cxl_pmem_region_alloc(cxlr);
+       if (IS_ERR(cxlr_pmem))
+               return PTR_ERR(cxlr_pmem);
+
+       dev = &cxlr_pmem->dev;
+       rc = dev_set_name(dev, "pmem_region%d", cxlr->id);
+       if (rc)
+               goto err;
+
+       rc = device_add(dev);
+       if (rc)
+               goto err;
+
+       dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent),
+               dev_name(dev));
+
+       return devm_add_action_or_reset(&cxlr->dev, cxlr_pmem_unregister, dev);
+
+err:
+       put_device(dev);
+       return rc;
+}
+
+static int cxl_region_probe(struct device *dev)
+{
+       struct cxl_region *cxlr = to_cxl_region(dev);
+       struct cxl_region_params *p = &cxlr->params;
+       int rc;
+
+       rc = down_read_interruptible(&cxl_region_rwsem);
+       if (rc) {
+               dev_dbg(&cxlr->dev, "probe interrupted\n");
+               return rc;
+       }
+
+       if (p->state < CXL_CONFIG_COMMIT) {
+               dev_dbg(&cxlr->dev, "config state: %d\n", p->state);
+               rc = -ENXIO;
+       }
+
+       /*
+        * From this point on any path that changes the region's state away from
+        * CXL_CONFIG_COMMIT is also responsible for releasing the driver.
+        */
+       up_read(&cxl_region_rwsem);
+
+       switch (cxlr->mode) {
+       case CXL_DECODER_PMEM:
+               return devm_cxl_add_pmem_region(cxlr);
+       default:
+               dev_dbg(&cxlr->dev, "unsupported region mode: %d\n",
+                       cxlr->mode);
+               return -ENXIO;
+       }
+}
+
+static struct cxl_driver cxl_region_driver = {
+       .name = "cxl_region",
+       .probe = cxl_region_probe,
+       .id = CXL_DEVICE_REGION,
+};
+
+int cxl_region_init(void)
+{
+       return cxl_driver_register(&cxl_region_driver);
+}
+
+void cxl_region_exit(void)
+{
+       cxl_driver_unregister(&cxl_region_driver);
+}
+
+MODULE_IMPORT_NS(CXL);
+MODULE_ALIAS_CXL(CXL_DEVICE_REGION);
index 6799b27..f680450 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/libnvdimm.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
+#include <linux/log2.h>
 #include <linux/io.h>
 
 /**
 #define   CXL_HDM_DECODER0_CTRL_LOCK BIT(8)
 #define   CXL_HDM_DECODER0_CTRL_COMMIT BIT(9)
 #define   CXL_HDM_DECODER0_CTRL_COMMITTED BIT(10)
+#define   CXL_HDM_DECODER0_CTRL_COMMIT_ERROR BIT(11)
 #define   CXL_HDM_DECODER0_CTRL_TYPE BIT(12)
 #define CXL_HDM_DECODER0_TL_LOW(i) (0x20 * (i) + 0x24)
 #define CXL_HDM_DECODER0_TL_HIGH(i) (0x20 * (i) + 0x28)
+#define CXL_HDM_DECODER0_SKIP_LOW(i) CXL_HDM_DECODER0_TL_LOW(i)
+#define CXL_HDM_DECODER0_SKIP_HIGH(i) CXL_HDM_DECODER0_TL_HIGH(i)
 
 static inline int cxl_hdm_decoder_count(u32 cap_hdr)
 {
@@ -64,6 +68,57 @@ static inline int cxl_hdm_decoder_count(u32 cap_hdr)
        return val ? val * 2 : 1;
 }
 
+/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
+static inline int cxl_to_granularity(u16 ig, unsigned int *val)
+{
+       if (ig > 6)
+               return -EINVAL;
+       *val = 256 << ig;
+       return 0;
+}
+
+/* Encode defined in CXL ECN "3, 6, 12 and 16-way memory Interleaving" */
+static inline int cxl_to_ways(u8 eniw, unsigned int *val)
+{
+       switch (eniw) {
+       case 0 ... 4:
+               *val = 1 << eniw;
+               break;
+       case 8 ... 10:
+               *val = 3 << (eniw - 8);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static inline int granularity_to_cxl(int g, u16 *ig)
+{
+       if (g > SZ_16K || g < 256 || !is_power_of_2(g))
+               return -EINVAL;
+       *ig = ilog2(g) - 8;
+       return 0;
+}
+
+static inline int ways_to_cxl(unsigned int ways, u8 *iw)
+{
+       if (ways > 16)
+               return -EINVAL;
+       if (is_power_of_2(ways)) {
+               *iw = ilog2(ways);
+               return 0;
+       }
+       if (ways % 3)
+               return -EINVAL;
+       ways /= 3;
+       if (!is_power_of_2(ways))
+               return -EINVAL;
+       *iw = ilog2(ways) + 8;
+       return 0;
+}
+
 /* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
 #define CXLDEV_CAP_ARRAY_OFFSET 0x0
 #define   CXLDEV_CAP_ARRAY_CAP_ID 0
@@ -193,37 +248,153 @@ enum cxl_decoder_type {
  */
 #define CXL_DECODER_MAX_INTERLEAVE 16
 
+#define CXL_DECODER_MIN_GRANULARITY 256
+
 /**
- * struct cxl_decoder - CXL address range decode configuration
+ * struct cxl_decoder - Common CXL HDM Decoder Attributes
  * @dev: this decoder's device
  * @id: kernel device name id
- * @platform_res: address space resources considered by root decoder
- * @decoder_range: address space resources considered by midlevel decoder
+ * @hpa_range: Host physical address range mapped by this decoder
  * @interleave_ways: number of cxl_dports in this decode
  * @interleave_granularity: data stride per dport
  * @target_type: accelerator vs expander (type2 vs type3) selector
+ * @region: currently assigned region for this decoder
  * @flags: memory type capabilities and locking
- * @target_lock: coordinate coherent reads of the target list
- * @nr_targets: number of elements in @target
- * @target: active ordered target list in current decoder configuration
- */
+ * @commit: device/decoder-type specific callback to commit settings to hw
+ * @reset: device/decoder-type specific callback to reset hw settings
+*/
 struct cxl_decoder {
        struct device dev;
        int id;
-       union {
-               struct resource platform_res;
-               struct range decoder_range;
-       };
+       struct range hpa_range;
        int interleave_ways;
        int interleave_granularity;
        enum cxl_decoder_type target_type;
+       struct cxl_region *region;
        unsigned long flags;
+       int (*commit)(struct cxl_decoder *cxld);
+       int (*reset)(struct cxl_decoder *cxld);
+};
+
+/*
+ * CXL_DECODER_DEAD prevents endpoints from being reattached to regions
+ * while cxld_unregister() is running
+ */
+enum cxl_decoder_mode {
+       CXL_DECODER_NONE,
+       CXL_DECODER_RAM,
+       CXL_DECODER_PMEM,
+       CXL_DECODER_MIXED,
+       CXL_DECODER_DEAD,
+};
+
+/**
+ * struct cxl_endpoint_decoder - Endpoint  / SPA to DPA decoder
+ * @cxld: base cxl_decoder_object
+ * @dpa_res: actively claimed DPA span of this decoder
+ * @skip: offset into @dpa_res where @cxld.hpa_range maps
+ * @mode: which memory type / access-mode-partition this decoder targets
+ * @pos: interleave position in @cxld.region
+ */
+struct cxl_endpoint_decoder {
+       struct cxl_decoder cxld;
+       struct resource *dpa_res;
+       resource_size_t skip;
+       enum cxl_decoder_mode mode;
+       int pos;
+};
+
+/**
+ * struct cxl_switch_decoder - Switch specific CXL HDM Decoder
+ * @cxld: base cxl_decoder object
+ * @target_lock: coordinate coherent reads of the target list
+ * @nr_targets: number of elements in @target
+ * @target: active ordered target list in current decoder configuration
+ *
+ * The 'switch' decoder type represents the decoder instances of cxl_port's that
+ * route from the root of a CXL memory decode topology to the endpoints. They
+ * come in two flavors, root-level decoders, statically defined by platform
+ * firmware, and mid-level decoders, where interleave-granularity,
+ * interleave-width, and the target list are mutable.
+ */
+struct cxl_switch_decoder {
+       struct cxl_decoder cxld;
        seqlock_t target_lock;
        int nr_targets;
        struct cxl_dport *target[];
 };
 
 
+/**
+ * struct cxl_root_decoder - Static platform CXL address decoder
+ * @res: host / parent resource for region allocations
+ * @region_id: region id for next region provisioning event
+ * @calc_hb: which host bridge covers the n'th position by granularity
+ * @cxlsd: base cxl switch decoder
+ */
+struct cxl_root_decoder {
+       struct resource *res;
+       atomic_t region_id;
+       struct cxl_dport *(*calc_hb)(struct cxl_root_decoder *cxlrd, int pos);
+       struct cxl_switch_decoder cxlsd;
+};
+
+/*
+ * enum cxl_config_state - State machine for region configuration
+ * @CXL_CONFIG_IDLE: Any sysfs attribute can be written freely
+ * @CXL_CONFIG_INTERLEAVE_ACTIVE: region size has been set, no more
+ * changes to interleave_ways or interleave_granularity
+ * @CXL_CONFIG_ACTIVE: All targets have been added the region is now
+ * active
+ * @CXL_CONFIG_RESET_PENDING: see commit_store()
+ * @CXL_CONFIG_COMMIT: Soft-config has been committed to hardware
+ */
+enum cxl_config_state {
+       CXL_CONFIG_IDLE,
+       CXL_CONFIG_INTERLEAVE_ACTIVE,
+       CXL_CONFIG_ACTIVE,
+       CXL_CONFIG_RESET_PENDING,
+       CXL_CONFIG_COMMIT,
+};
+
+/**
+ * struct cxl_region_params - region settings
+ * @state: allow the driver to lockdown further parameter changes
+ * @uuid: unique id for persistent regions
+ * @interleave_ways: number of endpoints in the region
+ * @interleave_granularity: capacity each endpoint contributes to a stripe
+ * @res: allocated iomem capacity for this region
+ * @targets: active ordered targets in current decoder configuration
+ * @nr_targets: number of targets
+ *
+ * State transitions are protected by the cxl_region_rwsem
+ */
+struct cxl_region_params {
+       enum cxl_config_state state;
+       uuid_t uuid;
+       int interleave_ways;
+       int interleave_granularity;
+       struct resource *res;
+       struct cxl_endpoint_decoder *targets[CXL_DECODER_MAX_INTERLEAVE];
+       int nr_targets;
+};
+
+/**
+ * struct cxl_region - CXL region
+ * @dev: This region's device
+ * @id: This region's id. Id is globally unique across all regions
+ * @mode: Endpoint decoder allocation / access mode
+ * @type: Endpoint decoder target type
+ * @params: active + config params for the region
+ */
+struct cxl_region {
+       struct device dev;
+       int id;
+       enum cxl_decoder_mode mode;
+       enum cxl_decoder_type type;
+       struct cxl_region_params params;
+};
+
 /**
  * enum cxl_nvdimm_brige_state - state machine for managing bus rescans
  * @CXL_NVB_NEW: Set at bridge create and after cxl_pmem_wq is destroyed
@@ -251,7 +422,26 @@ struct cxl_nvdimm_bridge {
 struct cxl_nvdimm {
        struct device dev;
        struct cxl_memdev *cxlmd;
-       struct nvdimm *nvdimm;
+       struct cxl_nvdimm_bridge *bridge;
+       struct cxl_pmem_region *region;
+};
+
+struct cxl_pmem_region_mapping {
+       struct cxl_memdev *cxlmd;
+       struct cxl_nvdimm *cxl_nvd;
+       u64 start;
+       u64 size;
+       int position;
+};
+
+struct cxl_pmem_region {
+       struct device dev;
+       struct cxl_region *cxlr;
+       struct nd_region *nd_region;
+       struct cxl_nvdimm_bridge *bridge;
+       struct range hpa_range;
+       int nr_mappings;
+       struct cxl_pmem_region_mapping mapping[];
 };
 
 /**
@@ -260,50 +450,94 @@ struct cxl_nvdimm {
  *                  decode hierarchy.
  * @dev: this port's device
  * @uport: PCI or platform device implementing the upstream port capability
+ * @host_bridge: Shortcut to the platform attach point for this port
  * @id: id for port device-name
  * @dports: cxl_dport instances referenced by decoders
  * @endpoints: cxl_ep instances, endpoints that are a descendant of this port
+ * @regions: cxl_region_ref instances, regions mapped by this port
+ * @parent_dport: dport that points to this port in the parent
  * @decoder_ida: allocator for decoder ids
+ * @hdm_end: track last allocated HDM decoder instance for allocation ordering
+ * @commit_end: cursor to track highest committed decoder for commit ordering
  * @component_reg_phys: component register capability base address (optional)
  * @dead: last ep has been removed, force port re-creation
  * @depth: How deep this port is relative to the root. depth 0 is the root.
+ * @cdat: Cached CDAT data
+ * @cdat_available: Should a CDAT attribute be available in sysfs
  */
 struct cxl_port {
        struct device dev;
        struct device *uport;
+       struct device *host_bridge;
        int id;
-       struct list_head dports;
-       struct list_head endpoints;
+       struct xarray dports;
+       struct xarray endpoints;
+       struct xarray regions;
+       struct cxl_dport *parent_dport;
        struct ida decoder_ida;
+       int hdm_end;
+       int commit_end;
        resource_size_t component_reg_phys;
        bool dead;
        unsigned int depth;
+       struct cxl_cdat {
+               void *table;
+               size_t length;
+       } cdat;
+       bool cdat_available;
 };
 
+static inline struct cxl_dport *
+cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
+{
+       return xa_load(&port->dports, (unsigned long)dport_dev);
+}
+
 /**
  * struct cxl_dport - CXL downstream port
  * @dport: PCI bridge or firmware device representing the downstream link
  * @port_id: unique hardware identifier for dport in decoder target list
  * @component_reg_phys: downstream port component registers
  * @port: reference to cxl_port that contains this downstream port
- * @list: node for a cxl_port's list of cxl_dport instances
  */
 struct cxl_dport {
        struct device *dport;
        int port_id;
        resource_size_t component_reg_phys;
        struct cxl_port *port;
-       struct list_head list;
 };
 
 /**
  * struct cxl_ep - track an endpoint's interest in a port
  * @ep: device that hosts a generic CXL endpoint (expander or accelerator)
- * @list: node on port->endpoints list
+ * @dport: which dport routes to this endpoint on @port
+ * @next: cxl switch port across the link attached to @dport NULL if
+ *       attached to an endpoint
  */
 struct cxl_ep {
        struct device *ep;
-       struct list_head list;
+       struct cxl_dport *dport;
+       struct cxl_port *next;
+};
+
+/**
+ * struct cxl_region_ref - track a region's interest in a port
+ * @port: point in topology to install this reference
+ * @decoder: decoder assigned for @region in @port
+ * @region: region for this reference
+ * @endpoints: cxl_ep references for region members beneath @port
+ * @nr_targets_set: track how many targets have been programmed during setup
+ * @nr_eps: number of endpoints beneath @port
+ * @nr_targets: number of distinct targets needed to reach @nr_eps
+ */
+struct cxl_region_ref {
+       struct cxl_port *port;
+       struct cxl_decoder *decoder;
+       struct cxl_region *region;
+       struct xarray endpoints;
+       int nr_targets_set;
+       int nr_eps;
+       int nr_targets;
 };
 
 /*
@@ -325,29 +559,31 @@ int devm_cxl_register_pci_bus(struct device *host, struct device *uport,
 struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
                                   resource_size_t component_reg_phys,
-                                  struct cxl_port *parent_port);
+                                  struct cxl_dport *parent_dport);
+int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
+                         struct cxl_dport *parent_dport);
 struct cxl_port *find_cxl_root(struct device *dev);
 int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
 int cxl_bus_rescan(void);
-struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd);
+struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
+                                  struct cxl_dport **dport);
 bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd);
 
 struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
                                     struct device *dport, int port_id,
                                     resource_size_t component_reg_phys);
-struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port,
-                                       const struct device *dev);
 
 struct cxl_decoder *to_cxl_decoder(struct device *dev);
+struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev);
+struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev);
 bool is_root_decoder(struct device *dev);
 bool is_endpoint_decoder(struct device *dev);
-bool is_cxl_decoder(struct device *dev);
-struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
-                                          unsigned int nr_targets);
-struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
-                                            unsigned int nr_targets);
+struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
+                                               unsigned int nr_targets);
+struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
+                                                   unsigned int nr_targets);
 int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map);
-struct cxl_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port);
+struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port);
 int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map);
 int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);
 int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
@@ -357,6 +593,8 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port);
 int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm);
 int devm_cxl_add_passthrough_decoder(struct cxl_port *port);
 
+bool is_cxl_region(struct device *dev);
+
 extern struct bus_type cxl_bus_type;
 
 struct cxl_driver {
@@ -385,6 +623,8 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);
 #define CXL_DEVICE_PORT                        3
 #define CXL_DEVICE_ROOT                        4
 #define CXL_DEVICE_MEMORY_EXPANDER     5
+#define CXL_DEVICE_REGION              6
+#define CXL_DEVICE_PMEM_REGION         7
 
 #define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
 #define CXL_MODALIAS_FMT "cxl:t%d"
@@ -396,7 +636,21 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
 bool is_cxl_nvdimm(struct device *dev);
 bool is_cxl_nvdimm_bridge(struct device *dev);
 int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
-struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd);
+struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
+
+#ifdef CONFIG_CXL_REGION
+bool is_cxl_pmem_region(struct device *dev);
+struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
+#else
+static inline bool is_cxl_pmem_region(struct device *dev)
+{
+       return false;
+}
+static inline struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
+{
+       return NULL;
+}
+#endif
 
 /*
  * Unit test builds overrides this to __weak, find the 'strong' version
index 7df0b05..88e3a8e 100644 (file)
@@ -50,6 +50,24 @@ static inline struct cxl_memdev *to_cxl_memdev(struct device *dev)
        return container_of(dev, struct cxl_memdev, dev);
 }
 
+static inline struct cxl_port *cxled_to_port(struct cxl_endpoint_decoder *cxled)
+{
+       return to_cxl_port(cxled->cxld.dev.parent);
+}
+
+static inline struct cxl_port *cxlrd_to_port(struct cxl_root_decoder *cxlrd)
+{
+       return to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
+}
+
+static inline struct cxl_memdev *
+cxled_to_memdev(struct cxl_endpoint_decoder *cxled)
+{
+       struct cxl_port *port = to_cxl_port(cxled->cxld.dev.parent);
+
+       return to_cxl_memdev(port->uport);
+}
+
 bool is_cxl_memdev(struct device *dev);
 static inline bool is_cxl_endpoint(struct cxl_port *port)
 {
@@ -178,8 +196,9 @@ struct cxl_endpoint_dvsec_info {
  * @firmware_version: Firmware version for the memory device.
  * @enabled_cmds: Hardware commands found enabled in CEL.
  * @exclusive_cmds: Commands that are kernel-internal only
- * @pmem_range: Active Persistent memory capacity configuration
- * @ram_range: Active Volatile memory capacity configuration
+ * @dpa_res: Overall DPA resource tree for the device
+ * @pmem_res: Active Persistent memory capacity configuration
+ * @ram_res: Active Volatile memory capacity configuration
  * @total_bytes: sum of all possible capacities
  * @volatile_only_bytes: hard volatile capacity
  * @persistent_only_bytes: hard persistent capacity
@@ -191,6 +210,7 @@ struct cxl_endpoint_dvsec_info {
  * @component_reg_phys: register base of component registers
  * @info: Cached DVSEC information about the device.
  * @serial: PCIe Device Serial Number
+ * @doe_mbs: PCI DOE mailbox array
  * @mbox_send: @dev specific transport for transmitting mailbox commands
  *
  * See section 8.2.9.5.2 Capacity Configuration and Label Storage for
@@ -209,8 +229,9 @@ struct cxl_dev_state {
        DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX);
        DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
 
-       struct range pmem_range;
-       struct range ram_range;
+       struct resource dpa_res;
+       struct resource pmem_res;
+       struct resource ram_res;
        u64 total_bytes;
        u64 volatile_only_bytes;
        u64 persistent_only_bytes;
@@ -224,6 +245,8 @@ struct cxl_dev_state {
        resource_size_t component_reg_phys;
        u64 serial;
 
+       struct xarray doe_mbs;
+
        int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
 };
 
@@ -299,6 +322,13 @@ struct cxl_mbox_identify {
        u8 qos_telemetry_caps;
 } __packed;
 
+struct cxl_mbox_get_partition_info {
+       __le64 active_volatile_cap;
+       __le64 active_persistent_cap;
+       __le64 next_volatile_cap;
+       __le64 next_persistent_cap;
+} __packed;
+
 struct cxl_mbox_get_lsa {
        __le32 offset;
        __le32 length;
@@ -370,4 +400,8 @@ struct cxl_hdm {
        unsigned int interleave_mask;
        struct cxl_port *port;
 };
+
+struct seq_file;
+struct dentry *cxl_debugfs_create_dir(const char *dir);
+void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds);
 #endif /* __CXL_MEM_H__ */
index fce1c11..eec597d 100644 (file)
@@ -74,4 +74,5 @@ static inline resource_size_t cxl_regmap_to_base(struct pci_dev *pdev,
 int devm_cxl_port_enumerate_dports(struct cxl_port *port);
 struct cxl_dev_state;
 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm);
+void read_cdat_data(struct cxl_port *port);
 #endif /* __CXL_PCI_H__ */
index a979d0b..64ccf05 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/pci.h>
  * in higher level operations.
  */
 
-static int create_endpoint(struct cxl_memdev *cxlmd,
-                          struct cxl_port *parent_port)
+static void enable_suspend(void *data)
 {
-       struct cxl_dev_state *cxlds = cxlmd->cxlds;
-       struct cxl_port *endpoint;
-       int rc;
+       cxl_mem_active_dec();
+}
 
-       endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
-                                    cxlds->component_reg_phys, parent_port);
-       if (IS_ERR(endpoint))
-               return PTR_ERR(endpoint);
+static void remove_debugfs(void *dentry)
+{
+       debugfs_remove_recursive(dentry);
+}
 
-       dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
+static int cxl_mem_dpa_show(struct seq_file *file, void *data)
+{
+       struct device *dev = file->private;
+       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
 
-       rc = cxl_endpoint_autoremove(cxlmd, endpoint);
-       if (rc)
-               return rc;
-
-       if (!endpoint->dev.driver) {
-               dev_err(&cxlmd->dev, "%s failed probe\n",
-                       dev_name(&endpoint->dev));
-               return -ENXIO;
-       }
+       cxl_dpa_debug(file, cxlmd->cxlds);
 
        return 0;
 }
 
-static void enable_suspend(void *data)
-{
-       cxl_mem_active_dec();
-}
-
 static int cxl_mem_probe(struct device *dev)
 {
        struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
        struct cxl_port *parent_port;
+       struct cxl_dport *dport;
+       struct dentry *dentry;
        int rc;
 
        /*
@@ -73,11 +64,17 @@ static int cxl_mem_probe(struct device *dev)
        if (work_pending(&cxlmd->detach_work))
                return -EBUSY;
 
+       dentry = cxl_debugfs_create_dir(dev_name(dev));
+       debugfs_create_devm_seqfile(dev, "dpamem", dentry, cxl_mem_dpa_show);
+       rc = devm_add_action_or_reset(dev, remove_debugfs, dentry);
+       if (rc)
+               return rc;
+
        rc = devm_cxl_enumerate_ports(cxlmd);
        if (rc)
                return rc;
 
-       parent_port = cxl_mem_find_port(cxlmd);
+       parent_port = cxl_mem_find_port(cxlmd, &dport);
        if (!parent_port) {
                dev_err(dev, "CXL port topology not found\n");
                return -ENXIO;
@@ -91,7 +88,7 @@ static int cxl_mem_probe(struct device *dev)
                goto unlock;
        }
 
-       rc = create_endpoint(cxlmd, parent_port);
+       rc = devm_cxl_add_endpoint(cxlmd, dport);
 unlock:
        device_unlock(&parent_port->dev);
        put_device(&parent_port->dev);
index 5a0ae46..faeb5d9 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/pci.h>
+#include <linux/pci-doe.h>
 #include <linux/io.h>
 #include "cxlmem.h"
 #include "cxlpci.h"
@@ -386,6 +387,47 @@ static int cxl_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
        return rc;
 }
 
+static void cxl_pci_destroy_doe(void *mbs)
+{
+       xa_destroy(mbs);
+}
+
+static void devm_cxl_pci_create_doe(struct cxl_dev_state *cxlds)
+{
+       struct device *dev = cxlds->dev;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       u16 off = 0;
+
+       xa_init(&cxlds->doe_mbs);
+       if (devm_add_action(&pdev->dev, cxl_pci_destroy_doe, &cxlds->doe_mbs)) {
+               dev_err(dev, "Failed to create XArray for DOE's\n");
+               return;
+       }
+
+       /*
+        * Mailbox creation is best effort.  Higher layers must determine if
+        * the lack of a mailbox for their protocol is a device failure or not.
+        */
+       pci_doe_for_each_off(pdev, off) {
+               struct pci_doe_mb *doe_mb;
+
+               doe_mb = pcim_doe_create_mb(pdev, off);
+               if (IS_ERR(doe_mb)) {
+                       dev_err(dev, "Failed to create MB object for MB @ %x\n",
+                               off);
+                       continue;
+               }
+
+               if (xa_insert(&cxlds->doe_mbs, off, doe_mb, GFP_KERNEL)) {
+                       dev_err(dev, "xa_insert failed to insert MB @ %x\n",
+                               off);
+                       continue;
+               }
+
+               dev_dbg(dev, "Created DOE mailbox @%x\n", off);
+       }
+}
+
 static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct cxl_register_map map;
@@ -434,6 +476,8 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        cxlds->component_reg_phys = cxl_regmap_to_base(pdev, &map);
 
+       devm_cxl_pci_create_doe(cxlds);
+
        rc = cxl_pci_setup_mailbox(cxlds);
        if (rc)
                return rc;
@@ -454,7 +498,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (IS_ERR(cxlmd))
                return PTR_ERR(cxlmd);
 
-       if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
+       if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM))
                rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd);
 
        return rc;
index 0aaa70b..7dc0a2f 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/ndctl.h>
 #include <linux/async.h>
 #include <linux/slab.h>
+#include <linux/nd.h>
 #include "cxlmem.h"
 #include "cxl.h"
 
@@ -26,7 +27,23 @@ static void clear_exclusive(void *cxlds)
 
 static void unregister_nvdimm(void *nvdimm)
 {
+       struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+       struct cxl_nvdimm_bridge *cxl_nvb = cxl_nvd->bridge;
+       struct cxl_pmem_region *cxlr_pmem;
+
+       device_lock(&cxl_nvb->dev);
+       cxlr_pmem = cxl_nvd->region;
+       dev_set_drvdata(&cxl_nvd->dev, NULL);
+       cxl_nvd->region = NULL;
+       device_unlock(&cxl_nvb->dev);
+
+       if (cxlr_pmem) {
+               device_release_driver(&cxlr_pmem->dev);
+               put_device(&cxlr_pmem->dev);
+       }
+
        nvdimm_delete(nvdimm);
+       cxl_nvd->bridge = NULL;
 }
 
 static int cxl_nvdimm_probe(struct device *dev)
@@ -39,7 +56,7 @@ static int cxl_nvdimm_probe(struct device *dev)
        struct nvdimm *nvdimm;
        int rc;
 
-       cxl_nvb = cxl_find_nvdimm_bridge(cxl_nvd);
+       cxl_nvb = cxl_find_nvdimm_bridge(dev);
        if (!cxl_nvb)
                return -ENXIO;
 
@@ -66,6 +83,7 @@ static int cxl_nvdimm_probe(struct device *dev)
        }
 
        dev_set_drvdata(dev, nvdimm);
+       cxl_nvd->bridge = cxl_nvb;
        rc = devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
 out:
        device_unlock(&cxl_nvb->dev);
@@ -204,15 +222,38 @@ static bool online_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb)
        return cxl_nvb->nvdimm_bus != NULL;
 }
 
-static int cxl_nvdimm_release_driver(struct device *dev, void *data)
+static int cxl_nvdimm_release_driver(struct device *dev, void *cxl_nvb)
 {
+       struct cxl_nvdimm *cxl_nvd;
+
        if (!is_cxl_nvdimm(dev))
                return 0;
+
+       cxl_nvd = to_cxl_nvdimm(dev);
+       if (cxl_nvd->bridge != cxl_nvb)
+               return 0;
+
        device_release_driver(dev);
        return 0;
 }
 
-static void offline_nvdimm_bus(struct nvdimm_bus *nvdimm_bus)
+static int cxl_pmem_region_release_driver(struct device *dev, void *cxl_nvb)
+{
+       struct cxl_pmem_region *cxlr_pmem;
+
+       if (!is_cxl_pmem_region(dev))
+               return 0;
+
+       cxlr_pmem = to_cxl_pmem_region(dev);
+       if (cxlr_pmem->bridge != cxl_nvb)
+               return 0;
+
+       device_release_driver(dev);
+       return 0;
+}
+
+static void offline_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb,
+                              struct nvdimm_bus *nvdimm_bus)
 {
        if (!nvdimm_bus)
                return;
@@ -222,7 +263,10 @@ static void offline_nvdimm_bus(struct nvdimm_bus *nvdimm_bus)
         * nvdimm_bus_unregister() rips the nvdimm objects out from
         * underneath them.
         */
-       bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_nvdimm_release_driver);
+       bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
+                        cxl_pmem_region_release_driver);
+       bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
+                        cxl_nvdimm_release_driver);
        nvdimm_bus_unregister(nvdimm_bus);
 }
 
@@ -260,7 +304,7 @@ static void cxl_nvb_update_state(struct work_struct *work)
 
                dev_dbg(&cxl_nvb->dev, "rescan: %d\n", rc);
        }
-       offline_nvdimm_bus(victim_bus);
+       offline_nvdimm_bus(cxl_nvb, victim_bus);
 
        put_device(&cxl_nvb->dev);
 }
@@ -315,6 +359,203 @@ static struct cxl_driver cxl_nvdimm_bridge_driver = {
        .id = CXL_DEVICE_NVDIMM_BRIDGE,
 };
 
+static int match_cxl_nvdimm(struct device *dev, void *data)
+{
+       return is_cxl_nvdimm(dev);
+}
+
+static void unregister_nvdimm_region(void *nd_region)
+{
+       struct cxl_nvdimm_bridge *cxl_nvb;
+       struct cxl_pmem_region *cxlr_pmem;
+       int i;
+
+       cxlr_pmem = nd_region_provider_data(nd_region);
+       cxl_nvb = cxlr_pmem->bridge;
+       device_lock(&cxl_nvb->dev);
+       for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+               struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+               struct cxl_nvdimm *cxl_nvd = m->cxl_nvd;
+
+               if (cxl_nvd->region) {
+                       put_device(&cxlr_pmem->dev);
+                       cxl_nvd->region = NULL;
+               }
+       }
+       device_unlock(&cxl_nvb->dev);
+
+       nvdimm_region_delete(nd_region);
+}
+
+static void cxlr_pmem_remove_resource(void *res)
+{
+       remove_resource(res);
+}
+
+struct cxl_pmem_region_info {
+       u64 offset;
+       u64 serial;
+};
+
+static int cxl_pmem_region_probe(struct device *dev)
+{
+       struct nd_mapping_desc mappings[CXL_DECODER_MAX_INTERLEAVE];
+       struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+       struct cxl_region *cxlr = cxlr_pmem->cxlr;
+       struct cxl_pmem_region_info *info = NULL;
+       struct cxl_nvdimm_bridge *cxl_nvb;
+       struct nd_interleave_set *nd_set;
+       struct nd_region_desc ndr_desc;
+       struct cxl_nvdimm *cxl_nvd;
+       struct nvdimm *nvdimm;
+       struct resource *res;
+       int rc, i = 0;
+
+       cxl_nvb = cxl_find_nvdimm_bridge(&cxlr_pmem->mapping[0].cxlmd->dev);
+       if (!cxl_nvb) {
+               dev_dbg(dev, "bridge not found\n");
+               return -ENXIO;
+       }
+       cxlr_pmem->bridge = cxl_nvb;
+
+       device_lock(&cxl_nvb->dev);
+       if (!cxl_nvb->nvdimm_bus) {
+               dev_dbg(dev, "nvdimm bus not found\n");
+               rc = -ENXIO;
+               goto err;
+       }
+
+       memset(&mappings, 0, sizeof(mappings));
+       memset(&ndr_desc, 0, sizeof(ndr_desc));
+
+       res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+       if (!res) {
+               rc = -ENOMEM;
+               goto err;
+       }
+
+       res->name = "Persistent Memory";
+       res->start = cxlr_pmem->hpa_range.start;
+       res->end = cxlr_pmem->hpa_range.end;
+       res->flags = IORESOURCE_MEM;
+       res->desc = IORES_DESC_PERSISTENT_MEMORY;
+
+       rc = insert_resource(&iomem_resource, res);
+       if (rc)
+               goto err;
+
+       rc = devm_add_action_or_reset(dev, cxlr_pmem_remove_resource, res);
+       if (rc)
+               goto err;
+
+       ndr_desc.res = res;
+       ndr_desc.provider_data = cxlr_pmem;
+
+       ndr_desc.numa_node = memory_add_physaddr_to_nid(res->start);
+       ndr_desc.target_node = phys_to_target_node(res->start);
+       if (ndr_desc.target_node == NUMA_NO_NODE) {
+               ndr_desc.target_node = ndr_desc.numa_node;
+               dev_dbg(&cxlr->dev, "changing target node from %d to %d",
+                       NUMA_NO_NODE, ndr_desc.target_node);
+       }
+
+       nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
+       if (!nd_set) {
+               rc = -ENOMEM;
+               goto err;
+       }
+
+       ndr_desc.memregion = cxlr->id;
+       set_bit(ND_REGION_CXL, &ndr_desc.flags);
+       set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc.flags);
+
+       info = kmalloc_array(cxlr_pmem->nr_mappings, sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               rc = -ENOMEM;
+               goto err;
+       }
+
+       for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+               struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+               struct cxl_memdev *cxlmd = m->cxlmd;
+               struct cxl_dev_state *cxlds = cxlmd->cxlds;
+               struct device *d;
+
+               d = device_find_child(&cxlmd->dev, NULL, match_cxl_nvdimm);
+               if (!d) {
+                       dev_dbg(dev, "[%d]: %s: no cxl_nvdimm found\n", i,
+                               dev_name(&cxlmd->dev));
+                       rc = -ENODEV;
+                       goto err;
+               }
+
+               /* safe to drop ref now with bridge lock held */
+               put_device(d);
+
+               cxl_nvd = to_cxl_nvdimm(d);
+               nvdimm = dev_get_drvdata(&cxl_nvd->dev);
+               if (!nvdimm) {
+                       dev_dbg(dev, "[%d]: %s: no nvdimm found\n", i,
+                               dev_name(&cxlmd->dev));
+                       rc = -ENODEV;
+                       goto err;
+               }
+               cxl_nvd->region = cxlr_pmem;
+               get_device(&cxlr_pmem->dev);
+               m->cxl_nvd = cxl_nvd;
+               mappings[i] = (struct nd_mapping_desc) {
+                       .nvdimm = nvdimm,
+                       .start = m->start,
+                       .size = m->size,
+                       .position = i,
+               };
+               info[i].offset = m->start;
+               info[i].serial = cxlds->serial;
+       }
+       ndr_desc.num_mappings = cxlr_pmem->nr_mappings;
+       ndr_desc.mapping = mappings;
+
+       /*
+        * TODO enable CXL labels which skip the need for 'interleave-set cookie'
+        */
+       nd_set->cookie1 =
+               nd_fletcher64(info, sizeof(*info) * cxlr_pmem->nr_mappings, 0);
+       nd_set->cookie2 = nd_set->cookie1;
+       ndr_desc.nd_set = nd_set;
+
+       cxlr_pmem->nd_region =
+               nvdimm_pmem_region_create(cxl_nvb->nvdimm_bus, &ndr_desc);
+       if (!cxlr_pmem->nd_region) {
+               rc = -ENOMEM;
+               goto err;
+       }
+
+       rc = devm_add_action_or_reset(dev, unregister_nvdimm_region,
+                                     cxlr_pmem->nd_region);
+out:
+       kfree(info);
+       device_unlock(&cxl_nvb->dev);
+       put_device(&cxl_nvb->dev);
+
+       return rc;
+
+err:
+       dev_dbg(dev, "failed to create nvdimm region\n");
+       for (i--; i >= 0; i--) {
+               nvdimm = mappings[i].nvdimm;
+               cxl_nvd = nvdimm_provider_data(nvdimm);
+               put_device(&cxl_nvd->region->dev);
+               cxl_nvd->region = NULL;
+       }
+       goto out;
+}
+
+static struct cxl_driver cxl_pmem_region_driver = {
+       .name = "cxl_pmem_region",
+       .probe = cxl_pmem_region_probe,
+       .id = CXL_DEVICE_PMEM_REGION,
+};
+
 /*
  * Return all bridges to the CXL_NVB_NEW state to invalidate any
  * ->state_work referring to the now destroyed cxl_pmem_wq.
@@ -359,8 +600,14 @@ static __init int cxl_pmem_init(void)
        if (rc)
                goto err_nvdimm;
 
+       rc = cxl_driver_register(&cxl_pmem_region_driver);
+       if (rc)
+               goto err_region;
+
        return 0;
 
+err_region:
+       cxl_driver_unregister(&cxl_nvdimm_driver);
 err_nvdimm:
        cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
 err_bridge:
@@ -370,6 +617,7 @@ err_bridge:
 
 static __exit void cxl_pmem_exit(void)
 {
+       cxl_driver_unregister(&cxl_pmem_region_driver);
        cxl_driver_unregister(&cxl_nvdimm_driver);
        cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
        destroy_cxl_pmem_wq();
@@ -381,3 +629,4 @@ module_exit(cxl_pmem_exit);
 MODULE_IMPORT_NS(CXL);
 MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE);
 MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM);
+MODULE_ALIAS_CXL(CXL_DEVICE_PMEM_REGION);
index 3cf308f..5453771 100644 (file)
@@ -53,6 +53,9 @@ static int cxl_port_probe(struct device *dev)
                struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport);
                struct cxl_dev_state *cxlds = cxlmd->cxlds;
 
+               /* Cache the data early to ensure is_visible() works */
+               read_cdat_data(port);
+
                get_device(&cxlmd->dev);
                rc = devm_add_action_or_reset(dev, schedule_detach, cxlmd);
                if (rc)
@@ -78,10 +81,60 @@ static int cxl_port_probe(struct device *dev)
        return 0;
 }
 
+static ssize_t CDAT_read(struct file *filp, struct kobject *kobj,
+                        struct bin_attribute *bin_attr, char *buf,
+                        loff_t offset, size_t count)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct cxl_port *port = to_cxl_port(dev);
+
+       if (!port->cdat_available)
+               return -ENXIO;
+
+       if (!port->cdat.table)
+               return 0;
+
+       return memory_read_from_buffer(buf, count, &offset,
+                                      port->cdat.table,
+                                      port->cdat.length);
+}
+
+static BIN_ATTR_ADMIN_RO(CDAT, 0);
+
+static umode_t cxl_port_bin_attr_is_visible(struct kobject *kobj,
+                                           struct bin_attribute *attr, int i)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct cxl_port *port = to_cxl_port(dev);
+
+       if ((attr == &bin_attr_CDAT) && port->cdat_available)
+               return attr->attr.mode;
+
+       return 0;
+}
+
+static struct bin_attribute *cxl_cdat_bin_attributes[] = {
+       &bin_attr_CDAT,
+       NULL,
+};
+
+static struct attribute_group cxl_cdat_attribute_group = {
+       .bin_attrs = cxl_cdat_bin_attributes,
+       .is_bin_visible = cxl_port_bin_attr_is_visible,
+};
+
+static const struct attribute_group *cxl_port_attribute_groups[] = {
+       &cxl_cdat_attribute_group,
+       NULL,
+};
+
 static struct cxl_driver cxl_port_driver = {
        .name = "cxl_port",
        .probe = cxl_port_probe,
        .id = CXL_DEVICE_PORT,
+       .drv = {
+               .dev_groups = cxl_port_attribute_groups,
+       },
 };
 
 module_cxl_driver(cxl_port_driver);
index f7dcc44..027e8f3 100644 (file)
@@ -33,7 +33,7 @@ struct exynos_bus {
 
        unsigned long curr_freq;
 
-       struct opp_table *opp_table;
+       int opp_token;
        struct clk *clk;
        unsigned int ratio;
 };
@@ -161,8 +161,7 @@ static void exynos_bus_exit(struct device *dev)
 
        dev_pm_opp_of_remove_table(dev);
        clk_disable_unprepare(bus->clk);
-       dev_pm_opp_put_regulators(bus->opp_table);
-       bus->opp_table = NULL;
+       dev_pm_opp_put_regulators(bus->opp_token);
 }
 
 static void exynos_bus_passive_exit(struct device *dev)
@@ -179,18 +178,16 @@ static int exynos_bus_parent_parse_of(struct device_node *np,
                                        struct exynos_bus *bus)
 {
        struct device *dev = bus->dev;
-       struct opp_table *opp_table;
-       const char *vdd = "vdd";
+       const char *supplies[] = { "vdd", NULL };
        int i, ret, count, size;
 
-       opp_table = dev_pm_opp_set_regulators(dev, &vdd, 1);
-       if (IS_ERR(opp_table)) {
-               ret = PTR_ERR(opp_table);
+       ret = dev_pm_opp_set_regulators(dev, supplies);
+       if (ret < 0) {
                dev_err(dev, "failed to set regulators %d\n", ret);
                return ret;
        }
 
-       bus->opp_table = opp_table;
+       bus->opp_token = ret;
 
        /*
         * Get the devfreq-event devices to get the current utilization of
@@ -236,8 +233,7 @@ static int exynos_bus_parent_parse_of(struct device_node *np,
        return 0;
 
 err_regulator:
-       dev_pm_opp_put_regulators(bus->opp_table);
-       bus->opp_table = NULL;
+       dev_pm_opp_put_regulators(bus->opp_token);
 
        return ret;
 }
@@ -459,8 +455,7 @@ err:
        dev_pm_opp_of_remove_table(dev);
        clk_disable_unprepare(bus->clk);
 err_reg:
-       dev_pm_opp_put_regulators(bus->opp_table);
-       bus->opp_table = NULL;
+       dev_pm_opp_put_regulators(bus->opp_token);
 
        return ret;
 }
index 585a95f..503376b 100644 (file)
@@ -821,6 +821,15 @@ static int devm_tegra_devfreq_init_hw(struct device *dev,
        return err;
 }
 
+static int tegra_devfreq_config_clks_nop(struct device *dev,
+                                        struct opp_table *opp_table,
+                                        struct dev_pm_opp *opp, void *data,
+                                        bool scaling_down)
+{
+       /* We want to skip clk configuration via dev_pm_opp_set_opp() */
+       return 0;
+}
+
 static int tegra_devfreq_probe(struct platform_device *pdev)
 {
        u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
@@ -830,6 +839,13 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
        unsigned int i;
        long rate;
        int err;
+       const char *clk_names[] = { "actmon", NULL };
+       struct dev_pm_opp_config config = {
+               .supported_hw = &hw_version,
+               .supported_hw_count = 1,
+               .clk_names = clk_names,
+               .config_clks = tegra_devfreq_config_clks_nop,
+       };
 
        tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
        if (!tegra)
@@ -874,13 +890,13 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
                return err;
        }
 
-       err = devm_pm_opp_set_supported_hw(&pdev->dev, &hw_version, 1);
+       err = devm_pm_opp_set_config(&pdev->dev, &config);
        if (err) {
-               dev_err(&pdev->dev, "Failed to set supported HW: %d\n", err);
+               dev_err(&pdev->dev, "Failed to set OPP config: %d\n", err);
                return err;
        }
 
-       err = devm_pm_opp_of_add_table_noclk(&pdev->dev, 0);
+       err = devm_pm_opp_of_add_table_indexed(&pdev->dev, 0);
        if (err) {
                dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err);
                return err;
index 8989e21..011be7f 100644 (file)
@@ -111,6 +111,12 @@ int lima_devfreq_init(struct lima_device *ldev)
        struct dev_pm_opp *opp;
        unsigned long cur_freq;
        int ret;
+       const char *regulator_names[] = { "mali", NULL };
+       const char *clk_names[] = { "core", NULL };
+       struct dev_pm_opp_config config = {
+               .regulator_names = regulator_names,
+               .clk_names = clk_names,
+       };
 
        if (!device_property_present(dev, "operating-points-v2"))
                /* Optional, continue without devfreq */
@@ -118,11 +124,7 @@ int lima_devfreq_init(struct lima_device *ldev)
 
        spin_lock_init(&ldevfreq->lock);
 
-       ret = devm_pm_opp_set_clkname(dev, "core");
-       if (ret)
-               return ret;
-
-       ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1);
+       ret = devm_pm_opp_set_config(dev, &config);
        if (ret) {
                /* Continue if the optional regulator is missing */
                if (ret != -ENODEV)
index 194af7f..5110cd9 100644 (file)
@@ -101,8 +101,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
                return 0;
        }
 
-       ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
-                                        pfdev->comp->num_supplies);
+       ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names);
        if (ret) {
                /* Continue if the optional regulator is missing */
                if (ret != -ENODEV) {
index 2d870cf..2fa5afe 100644 (file)
@@ -626,24 +626,29 @@ static int panfrost_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const char * const default_supplies[] = { "mali" };
+/*
+ * The OPP core wants the supply names to be NULL terminated, but we need the
+ * correct num_supplies value for regulator core. Hence, we NULL terminate here
+ * and then initialize num_supplies with ARRAY_SIZE - 1.
+ */
+static const char * const default_supplies[] = { "mali", NULL };
 static const struct panfrost_compatible default_data = {
-       .num_supplies = ARRAY_SIZE(default_supplies),
+       .num_supplies = ARRAY_SIZE(default_supplies) - 1,
        .supply_names = default_supplies,
        .num_pm_domains = 1, /* optional */
        .pm_domain_names = NULL,
 };
 
 static const struct panfrost_compatible amlogic_data = {
-       .num_supplies = ARRAY_SIZE(default_supplies),
+       .num_supplies = ARRAY_SIZE(default_supplies) - 1,
        .supply_names = default_supplies,
        .vendor_quirk = panfrost_gpu_amlogic_quirk,
 };
 
-static const char * const mediatek_mt8183_supplies[] = { "mali", "sram" };
+static const char * const mediatek_mt8183_supplies[] = { "mali", "sram", NULL };
 static const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
 static const struct panfrost_compatible mediatek_mt8183_data = {
-       .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies),
+       .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies) - 1,
        .supply_names = mediatek_mt8183_supplies,
        .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
        .pm_domain_names = mediatek_mt8183_pm_domains,
index cb48c5f..c93d290 100644 (file)
@@ -875,7 +875,7 @@ static int vcodec_domains_get(struct venus_core *core)
        }
 
 skip_pmdomains:
-       if (!core->has_opp_table)
+       if (!core->res->opp_pmdomain)
                return 0;
 
        /* Attach the power domain for setting performance state */
@@ -1007,6 +1007,10 @@ static int core_get_v4(struct venus_core *core)
        if (ret)
                return ret;
 
+       ret = vcodec_domains_get(core);
+       if (ret)
+               return ret;
+
        if (core->res->opp_pmdomain) {
                ret = devm_pm_opp_of_add_table(dev);
                if (!ret) {
@@ -1017,10 +1021,6 @@ static int core_get_v4(struct venus_core *core)
                }
        }
 
-       ret = vcodec_domains_get(core);
-       if (ret)
-               return ret;
-
        return 0;
 }
 
index 908f8d5..85bc936 100644 (file)
@@ -1395,15 +1395,14 @@ err_msg:
 static int tegra_emc_opp_table_init(struct tegra_emc *emc)
 {
        u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
-       struct opp_table *hw_opp_table;
-       int err;
+       int opp_token, err;
 
-       hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
-       err = PTR_ERR_OR_ZERO(hw_opp_table);
-       if (err) {
+       err = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
+       if (err < 0) {
                dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err);
                return err;
        }
+       opp_token = err;
 
        err = dev_pm_opp_of_add_table(emc->dev);
        if (err) {
@@ -1430,7 +1429,7 @@ static int tegra_emc_opp_table_init(struct tegra_emc *emc)
 remove_table:
        dev_pm_opp_of_remove_table(emc->dev);
 put_hw_table:
-       dev_pm_opp_put_supported_hw(hw_opp_table);
+       dev_pm_opp_put_supported_hw(opp_token);
 
        return err;
 }
index d976260..473a71b 100644 (file)
@@ -133,7 +133,8 @@ static void nd_region_release(struct device *dev)
                put_device(&nvdimm->dev);
        }
        free_percpu(nd_region->lane);
-       memregion_free(nd_region->id);
+       if (!test_bit(ND_REGION_CXL, &nd_region->flags))
+               memregion_free(nd_region->id);
        kfree(nd_region);
 }
 
@@ -982,9 +983,14 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
 
        if (!nd_region)
                return NULL;
-       nd_region->id = memregion_alloc(GFP_KERNEL);
-       if (nd_region->id < 0)
-               goto err_id;
+       /* CXL pre-assigns memregion ids before creating nvdimm regions */
+       if (test_bit(ND_REGION_CXL, &ndr_desc->flags)) {
+               nd_region->id = ndr_desc->memregion;
+       } else {
+               nd_region->id = memregion_alloc(GFP_KERNEL);
+               if (nd_region->id < 0)
+                       goto err_id;
+       }
 
        nd_region->lane = alloc_percpu(struct nd_percpu_lane);
        if (!nd_region->lane)
@@ -1043,9 +1049,10 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
 
        return nd_region;
 
- err_percpu:
-       memregion_free(nd_region->id);
- err_id:
+err_percpu:
+       if (!test_bit(ND_REGION_CXL, &ndr_desc->flags))
+               memregion_free(nd_region->id);
+err_id:
        kfree(nd_region);
        return NULL;
 }
@@ -1068,6 +1075,13 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
 }
 EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
 
+void nvdimm_region_delete(struct nd_region *nd_region)
+{
+       if (nd_region)
+               nd_device_unregister(&nd_region->dev, ND_SYNC);
+}
+EXPORT_SYMBOL_GPL(nvdimm_region_delete);
+
 int nvdimm_flush(struct nd_region *nd_region, struct bio *bio)
 {
        int rc = 0;
index 84063ea..77d1ba3 100644 (file)
 #include <linux/clk.h>
 #include <linux/errno.h>
 #include <linux/err.h>
-#include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/export.h>
 #include <linux/pm_domain.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/xarray.h>
 
 #include "opp.h"
 
@@ -36,6 +37,9 @@ DEFINE_MUTEX(opp_table_lock);
 /* Flag indicating that opp_tables list is being updated at the moment */
 static bool opp_tables_busy;
 
+/* OPP ID allocator */
+static DEFINE_XARRAY_ALLOC1(opp_configs);
+
 static bool _find_opp_dev(const struct device *dev, struct opp_table *opp_table)
 {
        struct opp_device *opp_dev;
@@ -93,6 +97,18 @@ struct opp_table *_find_opp_table(struct device *dev)
        return opp_table;
 }
 
+/*
+ * Returns true if multiple clocks aren't there, else returns false with WARN.
+ *
+ * We don't force clk_count == 1 here as there are users who don't have a clock
+ * representation in the OPP table and manage the clock configuration themselves
+ * in an platform specific way.
+ */
+static bool assert_single_clk(struct opp_table *opp_table)
+{
+       return !WARN_ON(opp_table->clk_count > 1);
+}
+
 /**
  * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an opp
  * @opp:       opp for which voltage has to be returned for
@@ -113,6 +129,31 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
 
+/**
+ * dev_pm_opp_get_supplies() - Gets the supply information corresponding to an opp
+ * @opp:       opp for which voltage has to be returned for
+ * @supplies:  Placeholder for copying the supply information.
+ *
+ * Return: negative error number on failure, 0 otherwise on success after
+ * setting @supplies.
+ *
+ * This can be used for devices with any number of power supplies. The caller
+ * must ensure the @supplies array must contain space for each regulator.
+ */
+int dev_pm_opp_get_supplies(struct dev_pm_opp *opp,
+                           struct dev_pm_opp_supply *supplies)
+{
+       if (IS_ERR_OR_NULL(opp) || !supplies) {
+               pr_err("%s: Invalid parameters\n", __func__);
+               return -EINVAL;
+       }
+
+       memcpy(supplies, opp->supplies,
+              sizeof(*supplies) * opp->opp_table->regulator_count);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_supplies);
+
 /**
  * dev_pm_opp_get_power() - Gets the power corresponding to an opp
  * @opp:       opp for which power has to be returned for
@@ -152,7 +193,10 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
                return 0;
        }
 
-       return opp->rate;
+       if (!assert_single_clk(opp->opp_table))
+               return 0;
+
+       return opp->rates[0];
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
 
@@ -398,6 +442,154 @@ int dev_pm_opp_get_opp_count(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
 
+/* Helpers to read keys */
+static unsigned long _read_freq(struct dev_pm_opp *opp, int index)
+{
+       return opp->rates[0];
+}
+
+static unsigned long _read_level(struct dev_pm_opp *opp, int index)
+{
+       return opp->level;
+}
+
+static unsigned long _read_bw(struct dev_pm_opp *opp, int index)
+{
+       return opp->bandwidth[index].peak;
+}
+
+/* Generic comparison helpers */
+static bool _compare_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+                          unsigned long opp_key, unsigned long key)
+{
+       if (opp_key == key) {
+               *opp = temp_opp;
+               return true;
+       }
+
+       return false;
+}
+
+static bool _compare_ceil(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+                         unsigned long opp_key, unsigned long key)
+{
+       if (opp_key >= key) {
+               *opp = temp_opp;
+               return true;
+       }
+
+       return false;
+}
+
+static bool _compare_floor(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+                          unsigned long opp_key, unsigned long key)
+{
+       if (opp_key > key)
+               return true;
+
+       *opp = temp_opp;
+       return false;
+}
+
+/* Generic key finding helpers */
+static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
+               unsigned long *key, int index, bool available,
+               unsigned long (*read)(struct dev_pm_opp *opp, int index),
+               bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+                               unsigned long opp_key, unsigned long key),
+               bool (*assert)(struct opp_table *opp_table))
+{
+       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
+
+       /* Assert that the requirement is met */
+       if (assert && !assert(opp_table))
+               return ERR_PTR(-EINVAL);
+
+       mutex_lock(&opp_table->lock);
+
+       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
+               if (temp_opp->available == available) {
+                       if (compare(&opp, temp_opp, read(temp_opp, index), *key))
+                               break;
+               }
+       }
+
+       /* Increment the reference count of OPP */
+       if (!IS_ERR(opp)) {
+               *key = read(opp, index);
+               dev_pm_opp_get(opp);
+       }
+
+       mutex_unlock(&opp_table->lock);
+
+       return opp;
+}
+
+static struct dev_pm_opp *
+_find_key(struct device *dev, unsigned long *key, int index, bool available,
+         unsigned long (*read)(struct dev_pm_opp *opp, int index),
+         bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+                         unsigned long opp_key, unsigned long key),
+         bool (*assert)(struct opp_table *opp_table))
+{
+       struct opp_table *opp_table;
+       struct dev_pm_opp *opp;
+
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
+                       PTR_ERR(opp_table));
+               return ERR_CAST(opp_table);
+       }
+
+       opp = _opp_table_find_key(opp_table, key, index, available, read,
+                                 compare, assert);
+
+       dev_pm_opp_put_opp_table(opp_table);
+
+       return opp;
+}
+
+static struct dev_pm_opp *_find_key_exact(struct device *dev,
+               unsigned long key, int index, bool available,
+               unsigned long (*read)(struct dev_pm_opp *opp, int index),
+               bool (*assert)(struct opp_table *opp_table))
+{
+       /*
+        * The value of key will be updated here, but will be ignored as the
+        * caller doesn't need it.
+        */
+       return _find_key(dev, &key, index, available, read, _compare_exact,
+                        assert);
+}
+
+static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
+               unsigned long *key, int index, bool available,
+               unsigned long (*read)(struct dev_pm_opp *opp, int index),
+               bool (*assert)(struct opp_table *opp_table))
+{
+       return _opp_table_find_key(opp_table, key, index, available, read,
+                                  _compare_ceil, assert);
+}
+
+static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
+               int index, bool available,
+               unsigned long (*read)(struct dev_pm_opp *opp, int index),
+               bool (*assert)(struct opp_table *opp_table))
+{
+       return _find_key(dev, key, index, available, read, _compare_ceil,
+                        assert);
+}
+
+static struct dev_pm_opp *_find_key_floor(struct device *dev,
+               unsigned long *key, int index, bool available,
+               unsigned long (*read)(struct dev_pm_opp *opp, int index),
+               bool (*assert)(struct opp_table *opp_table))
+{
+       return _find_key(dev, key, index, available, read, _compare_floor,
+                        assert);
+}
+
 /**
  * dev_pm_opp_find_freq_exact() - search for an exact frequency
  * @dev:               device for which we do this operation
@@ -422,61 +614,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
  * use.
  */
 struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
-                                             unsigned long freq,
-                                             bool available)
+               unsigned long freq, bool available)
 {
-       struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               int r = PTR_ERR(opp_table);
-
-               dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
-               return ERR_PTR(r);
-       }
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available == available &&
-                               temp_opp->rate == freq) {
-                       opp = temp_opp;
-
-                       /* Increment the reference count of OPP */
-                       dev_pm_opp_get(opp);
-                       break;
-               }
-       }
-
-       mutex_unlock(&opp_table->lock);
-       dev_pm_opp_put_opp_table(opp_table);
-
-       return opp;
+       return _find_key_exact(dev, freq, 0, available, _read_freq,
+                              assert_single_clk);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
 
 static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
                                                   unsigned long *freq)
 {
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available && temp_opp->rate >= *freq) {
-                       opp = temp_opp;
-                       *freq = opp->rate;
-
-                       /* Increment the reference count of OPP */
-                       dev_pm_opp_get(opp);
-                       break;
-               }
-       }
-
-       mutex_unlock(&opp_table->lock);
-
-       return opp;
+       return _opp_table_find_key_ceil(opp_table, freq, 0, true, _read_freq,
+                                       assert_single_clk);
 }
 
 /**
@@ -500,23 +649,7 @@ static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
 struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
                                             unsigned long *freq)
 {
-       struct opp_table *opp_table;
-       struct dev_pm_opp *opp;
-
-       if (!dev || !freq) {
-               dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
-               return ERR_PTR(-EINVAL);
-       }
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table))
-               return ERR_CAST(opp_table);
-
-       opp = _find_freq_ceil(opp_table, freq);
-
-       dev_pm_opp_put_opp_table(opp_table);
-
-       return opp;
+       return _find_key_ceil(dev, freq, 0, true, _read_freq, assert_single_clk);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
 
@@ -541,97 +674,10 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
 struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
                                              unsigned long *freq)
 {
-       struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
-       if (!dev || !freq) {
-               dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
-               return ERR_PTR(-EINVAL);
-       }
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table))
-               return ERR_CAST(opp_table);
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available) {
-                       /* go to the next node, before choosing prev */
-                       if (temp_opp->rate > *freq)
-                               break;
-                       else
-                               opp = temp_opp;
-               }
-       }
-
-       /* Increment the reference count of OPP */
-       if (!IS_ERR(opp))
-               dev_pm_opp_get(opp);
-       mutex_unlock(&opp_table->lock);
-       dev_pm_opp_put_opp_table(opp_table);
-
-       if (!IS_ERR(opp))
-               *freq = opp->rate;
-
-       return opp;
+       return _find_key_floor(dev, freq, 0, true, _read_freq, assert_single_clk);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
 
-/**
- * dev_pm_opp_find_freq_ceil_by_volt() - Find OPP with highest frequency for
- *                                      target voltage.
- * @dev:       Device for which we do this operation.
- * @u_volt:    Target voltage.
- *
- * Search for OPP with highest (ceil) frequency and has voltage <= u_volt.
- *
- * Return: matching *opp, else returns ERR_PTR in case of error which should be
- * handled using IS_ERR.
- *
- * Error return values can be:
- * EINVAL:     bad parameters
- *
- * The callers are required to call dev_pm_opp_put() for the returned OPP after
- * use.
- */
-struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
-                                                    unsigned long u_volt)
-{
-       struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
-       if (!dev || !u_volt) {
-               dev_err(dev, "%s: Invalid argument volt=%lu\n", __func__,
-                       u_volt);
-               return ERR_PTR(-EINVAL);
-       }
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table))
-               return ERR_CAST(opp_table);
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available) {
-                       if (temp_opp->supplies[0].u_volt > u_volt)
-                               break;
-                       opp = temp_opp;
-               }
-       }
-
-       /* Increment the reference count of OPP */
-       if (!IS_ERR(opp))
-               dev_pm_opp_get(opp);
-
-       mutex_unlock(&opp_table->lock);
-       dev_pm_opp_put_opp_table(opp_table);
-
-       return opp;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_by_volt);
-
 /**
  * dev_pm_opp_find_level_exact() - search for an exact level
  * @dev:               device for which we do this operation
@@ -650,33 +696,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_by_volt);
 struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
                                               unsigned int level)
 {
-       struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               int r = PTR_ERR(opp_table);
-
-               dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
-               return ERR_PTR(r);
-       }
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->level == level) {
-                       opp = temp_opp;
-
-                       /* Increment the reference count of OPP */
-                       dev_pm_opp_get(opp);
-                       break;
-               }
-       }
-
-       mutex_unlock(&opp_table->lock);
-       dev_pm_opp_put_opp_table(opp_table);
-
-       return opp;
+       return _find_key_exact(dev, level, 0, true, _read_level, NULL);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_exact);
 
@@ -698,33 +718,11 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_exact);
 struct dev_pm_opp *dev_pm_opp_find_level_ceil(struct device *dev,
                                              unsigned int *level)
 {
-       struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               int r = PTR_ERR(opp_table);
-
-               dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
-               return ERR_PTR(r);
-       }
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available && temp_opp->level >= *level) {
-                       opp = temp_opp;
-                       *level = opp->level;
-
-                       /* Increment the reference count of OPP */
-                       dev_pm_opp_get(opp);
-                       break;
-               }
-       }
-
-       mutex_unlock(&opp_table->lock);
-       dev_pm_opp_put_opp_table(opp_table);
+       unsigned long temp = *level;
+       struct dev_pm_opp *opp;
 
+       opp = _find_key_ceil(dev, &temp, 0, true, _read_level, NULL);
+       *level = temp;
        return opp;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_ceil);
@@ -732,7 +730,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_ceil);
 /**
  * dev_pm_opp_find_bw_ceil() - Search for a rounded ceil bandwidth
  * @dev:       device for which we do this operation
- * @freq:      start bandwidth
+ * @bw:        start bandwidth
  * @index:     which bandwidth to compare, in case of OPPs with several values
  *
  * Search for the matching floor *available* OPP from a starting bandwidth
@@ -748,50 +746,22 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_ceil);
  * The callers are required to call dev_pm_opp_put() for the returned OPP after
  * use.
  */
-struct dev_pm_opp *dev_pm_opp_find_bw_ceil(struct device *dev,
-                                          unsigned int *bw, int index)
+struct dev_pm_opp *dev_pm_opp_find_bw_ceil(struct device *dev, unsigned int *bw,
+                                          int index)
 {
-       struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
+       unsigned long temp = *bw;
+       struct dev_pm_opp *opp;
 
-       if (!dev || !bw) {
-               dev_err(dev, "%s: Invalid argument bw=%p\n", __func__, bw);
-               return ERR_PTR(-EINVAL);
-       }
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table))
-               return ERR_CAST(opp_table);
-
-       if (index >= opp_table->path_count)
-               return ERR_PTR(-EINVAL);
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available && temp_opp->bandwidth) {
-                       if (temp_opp->bandwidth[index].peak >= *bw) {
-                               opp = temp_opp;
-                               *bw = opp->bandwidth[index].peak;
-
-                               /* Increment the reference count of OPP */
-                               dev_pm_opp_get(opp);
-                               break;
-                       }
-               }
-       }
-
-       mutex_unlock(&opp_table->lock);
-       dev_pm_opp_put_opp_table(opp_table);
-
-       return opp;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_ceil);
+       opp = _find_key_ceil(dev, &temp, index, true, _read_bw, NULL);
+       *bw = temp;
+       return opp;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_ceil);
 
 /**
  * dev_pm_opp_find_bw_floor() - Search for a rounded floor bandwidth
  * @dev:       device for which we do this operation
- * @freq:      start bandwidth
+ * @bw:        start bandwidth
  * @index:     which bandwidth to compare, in case of OPPs with several values
  *
  * Search for the matching floor *available* OPP from a starting bandwidth
@@ -810,41 +780,11 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_ceil);
 struct dev_pm_opp *dev_pm_opp_find_bw_floor(struct device *dev,
                                            unsigned int *bw, int index)
 {
-       struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
-       if (!dev || !bw) {
-               dev_err(dev, "%s: Invalid argument bw=%p\n", __func__, bw);
-               return ERR_PTR(-EINVAL);
-       }
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table))
-               return ERR_CAST(opp_table);
-
-       if (index >= opp_table->path_count)
-               return ERR_PTR(-EINVAL);
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available && temp_opp->bandwidth) {
-                       /* go to the next node, before choosing prev */
-                       if (temp_opp->bandwidth[index].peak > *bw)
-                               break;
-                       opp = temp_opp;
-               }
-       }
-
-       /* Increment the reference count of OPP */
-       if (!IS_ERR(opp))
-               dev_pm_opp_get(opp);
-       mutex_unlock(&opp_table->lock);
-       dev_pm_opp_put_opp_table(opp_table);
-
-       if (!IS_ERR(opp))
-               *bw = opp->bandwidth[index].peak;
+       unsigned long temp = *bw;
+       struct dev_pm_opp *opp;
 
+       opp = _find_key_floor(dev, &temp, index, true, _read_bw, NULL);
+       *bw = temp;
        return opp;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_floor);
@@ -874,80 +814,97 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
        return ret;
 }
 
-static inline int _generic_set_opp_clk_only(struct device *dev, struct clk *clk,
-                                           unsigned long freq)
+static int
+_opp_config_clk_single(struct device *dev, struct opp_table *opp_table,
+                      struct dev_pm_opp *opp, void *data, bool scaling_down)
 {
+       unsigned long *target = data;
+       unsigned long freq;
        int ret;
 
-       /* We may reach here for devices which don't change frequency */
-       if (IS_ERR(clk))
-               return 0;
+       /* One of target and opp must be available */
+       if (target) {
+               freq = *target;
+       } else if (opp) {
+               freq = opp->rates[0];
+       } else {
+               WARN_ON(1);
+               return -EINVAL;
+       }
 
-       ret = clk_set_rate(clk, freq);
+       ret = clk_set_rate(opp_table->clk, freq);
        if (ret) {
                dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
                        ret);
+       } else {
+               opp_table->rate_clk_single = freq;
        }
 
        return ret;
 }
 
-static int _generic_set_opp_regulator(struct opp_table *opp_table,
-                                     struct device *dev,
-                                     struct dev_pm_opp *opp,
-                                     unsigned long freq,
-                                     int scaling_down)
+/*
+ * Simple implementation for configuring multiple clocks. Configure clocks in
+ * the order in which they are present in the array while scaling up.
+ */
+int dev_pm_opp_config_clks_simple(struct device *dev,
+               struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
+               bool scaling_down)
 {
-       struct regulator *reg = opp_table->regulators[0];
-       struct dev_pm_opp *old_opp = opp_table->current_opp;
+       int ret, i;
+
+       if (scaling_down) {
+               for (i = opp_table->clk_count - 1; i >= 0; i--) {
+                       ret = clk_set_rate(opp_table->clks[i], opp->rates[i]);
+                       if (ret) {
+                               dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+                                       ret);
+                               return ret;
+                       }
+               }
+       } else {
+               for (i = 0; i < opp_table->clk_count; i++) {
+                       ret = clk_set_rate(opp_table->clks[i], opp->rates[i]);
+                       if (ret) {
+                               dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+                                       ret);
+                               return ret;
+                       }
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_config_clks_simple);
+
+static int _opp_config_regulator_single(struct device *dev,
+                       struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
+                       struct regulator **regulators, unsigned int count)
+{
+       struct regulator *reg = regulators[0];
        int ret;
 
        /* This function only supports single regulator per device */
-       if (WARN_ON(opp_table->regulator_count > 1)) {
+       if (WARN_ON(count > 1)) {
                dev_err(dev, "multiple regulators are not supported\n");
                return -EINVAL;
        }
 
-       /* Scaling up? Scale voltage before frequency */
-       if (!scaling_down) {
-               ret = _set_opp_voltage(dev, reg, opp->supplies);
-               if (ret)
-                       goto restore_voltage;
-       }
-
-       /* Change frequency */
-       ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq);
+       ret = _set_opp_voltage(dev, reg, new_opp->supplies);
        if (ret)
-               goto restore_voltage;
-
-       /* Scaling down? Scale voltage after frequency */
-       if (scaling_down) {
-               ret = _set_opp_voltage(dev, reg, opp->supplies);
-               if (ret)
-                       goto restore_freq;
-       }
+               return ret;
 
        /*
         * Enable the regulator after setting its voltages, otherwise it breaks
         * some boot-enabled regulators.
         */
-       if (unlikely(!opp_table->enabled)) {
+       if (unlikely(!new_opp->opp_table->enabled)) {
                ret = regulator_enable(reg);
                if (ret < 0)
                        dev_warn(dev, "Failed to enable regulator: %d", ret);
        }
 
        return 0;
-
-restore_freq:
-       if (_generic_set_opp_clk_only(dev, opp_table->clk, old_opp->rate))
-               dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
-                       __func__, old_opp->rate);
-restore_voltage:
-       /* This shouldn't harm even if the voltages weren't updated earlier */
-       _set_opp_voltage(dev, reg, old_opp->supplies);
-
-       return ret;
 }
 
 static int _set_opp_bw(const struct opp_table *opp_table,
@@ -978,36 +935,6 @@ static int _set_opp_bw(const struct opp_table *opp_table,
        return 0;
 }
 
-static int _set_opp_custom(const struct opp_table *opp_table,
-                          struct device *dev, struct dev_pm_opp *opp,
-                          unsigned long freq)
-{
-       struct dev_pm_set_opp_data *data = opp_table->set_opp_data;
-       struct dev_pm_opp *old_opp = opp_table->current_opp;
-       int size;
-
-       /*
-        * We support this only if dev_pm_opp_set_regulators() was called
-        * earlier.
-        */
-       if (opp_table->sod_supplies) {
-               size = sizeof(*old_opp->supplies) * opp_table->regulator_count;
-               memcpy(data->old_opp.supplies, old_opp->supplies, size);
-               memcpy(data->new_opp.supplies, opp->supplies, size);
-               data->regulator_count = opp_table->regulator_count;
-       } else {
-               data->regulator_count = 0;
-       }
-
-       data->regulators = opp_table->regulators;
-       data->clk = opp_table->clk;
-       data->dev = dev;
-       data->old_opp.rate = old_opp->rate;
-       data->new_opp.rate = freq;
-
-       return opp_table->set_opp(data);
-}
-
 static int _set_required_opp(struct device *dev, struct device *pd_dev,
                             struct dev_pm_opp *opp, int i)
 {
@@ -1019,7 +946,7 @@ static int _set_required_opp(struct device *dev, struct device *pd_dev,
 
        ret = dev_pm_genpd_set_performance_state(pd_dev, pstate);
        if (ret) {
-               dev_err(dev, "Failed to set performance rate of %s: %d (%d)\n",
+               dev_err(dev, "Failed to set performance state of %s: %d (%d)\n",
                        dev_name(pd_dev), pstate, ret);
        }
 
@@ -1138,7 +1065,7 @@ static int _disable_opp_table(struct device *dev, struct opp_table *opp_table)
 }
 
 static int _set_opp(struct device *dev, struct opp_table *opp_table,
-                   struct dev_pm_opp *opp, unsigned long freq)
+                   struct dev_pm_opp *opp, void *clk_data, bool forced)
 {
        struct dev_pm_opp *old_opp;
        int scaling_down, ret;
@@ -1153,18 +1080,17 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
        old_opp = opp_table->current_opp;
 
        /* Return early if nothing to do */
-       if (old_opp == opp && opp_table->current_rate == freq &&
-           opp_table->enabled) {
+       if (!forced && old_opp == opp && opp_table->enabled) {
                dev_dbg(dev, "%s: OPPs are same, nothing to do\n", __func__);
                return 0;
        }
 
        dev_dbg(dev, "%s: switching OPP: Freq %lu -> %lu Hz, Level %u -> %u, Bw %u -> %u\n",
-               __func__, opp_table->current_rate, freq, old_opp->level,
+               __func__, old_opp->rates[0], opp->rates[0], old_opp->level,
                opp->level, old_opp->bandwidth ? old_opp->bandwidth[0].peak : 0,
                opp->bandwidth ? opp->bandwidth[0].peak : 0);
 
-       scaling_down = _opp_compare_key(old_opp, opp);
+       scaling_down = _opp_compare_key(opp_table, old_opp, opp);
        if (scaling_down == -1)
                scaling_down = 0;
 
@@ -1181,23 +1107,38 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
                        dev_err(dev, "Failed to set bw: %d\n", ret);
                        return ret;
                }
-       }
 
-       if (opp_table->set_opp) {
-               ret = _set_opp_custom(opp_table, dev, opp, freq);
-       } else if (opp_table->regulators) {
-               ret = _generic_set_opp_regulator(opp_table, dev, opp, freq,
-                                                scaling_down);
-       } else {
-               /* Only frequency scaling */
-               ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq);
+               if (opp_table->config_regulators) {
+                       ret = opp_table->config_regulators(dev, old_opp, opp,
+                                                          opp_table->regulators,
+                                                          opp_table->regulator_count);
+                       if (ret) {
+                               dev_err(dev, "Failed to set regulator voltages: %d\n",
+                                       ret);
+                               return ret;
+                       }
+               }
        }
 
-       if (ret)
-               return ret;
+       if (opp_table->config_clks) {
+               ret = opp_table->config_clks(dev, opp_table, opp, clk_data, scaling_down);
+               if (ret)
+                       return ret;
+       }
 
        /* Scaling down? Configure required OPPs after frequency */
        if (scaling_down) {
+               if (opp_table->config_regulators) {
+                       ret = opp_table->config_regulators(dev, old_opp, opp,
+                                                          opp_table->regulators,
+                                                          opp_table->regulator_count);
+                       if (ret) {
+                               dev_err(dev, "Failed to set regulator voltages: %d\n",
+                                       ret);
+                               return ret;
+                       }
+               }
+
                ret = _set_opp_bw(opp_table, opp, dev);
                if (ret) {
                        dev_err(dev, "Failed to set bw: %d\n", ret);
@@ -1217,7 +1158,6 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
        /* Make sure current_opp doesn't get freed */
        dev_pm_opp_get(opp);
        opp_table->current_opp = opp;
-       opp_table->current_rate = freq;
 
        return ret;
 }
@@ -1238,6 +1178,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
        struct opp_table *opp_table;
        unsigned long freq = 0, temp_freq;
        struct dev_pm_opp *opp = NULL;
+       bool forced = false;
        int ret;
 
        opp_table = _find_opp_table(dev);
@@ -1255,7 +1196,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                 * equivalent to a clk_set_rate()
                 */
                if (!_get_opp_count(opp_table)) {
-                       ret = _generic_set_opp_clk_only(dev, opp_table->clk, target_freq);
+                       ret = opp_table->config_clks(dev, opp_table, NULL,
+                                                    &target_freq, false);
                        goto put_opp_table;
                }
 
@@ -1276,12 +1218,22 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                                __func__, freq, ret);
                        goto put_opp_table;
                }
+
+               /*
+                * An OPP entry specifies the highest frequency at which other
+                * properties of the OPP entry apply. Even if the new OPP is
+                * same as the old one, we may still reach here for a different
+                * value of the frequency. In such a case, do not abort but
+                * configure the hardware to the desired frequency forcefully.
+                */
+               forced = opp_table->rate_clk_single != target_freq;
        }
 
-       ret = _set_opp(dev, opp_table, opp, freq);
+       ret = _set_opp(dev, opp_table, opp, &target_freq, forced);
 
        if (target_freq)
                dev_pm_opp_put(opp);
+
 put_opp_table:
        dev_pm_opp_put_opp_table(opp_table);
        return ret;
@@ -1309,7 +1261,7 @@ int dev_pm_opp_set_opp(struct device *dev, struct dev_pm_opp *opp)
                return PTR_ERR(opp_table);
        }
 
-       ret = _set_opp(dev, opp_table, opp, opp ? opp->rate : 0);
+       ret = _set_opp(dev, opp_table, opp, NULL, false);
        dev_pm_opp_put_opp_table(opp_table);
 
        return ret;
@@ -1366,6 +1318,8 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
        INIT_LIST_HEAD(&opp_table->dev_list);
        INIT_LIST_HEAD(&opp_table->lazy);
 
+       opp_table->clk = ERR_PTR(-ENODEV);
+
        /* Mark regulator count uninitialized */
        opp_table->regulator_count = -1;
 
@@ -1412,20 +1366,38 @@ static struct opp_table *_update_opp_table_clk(struct device *dev,
        int ret;
 
        /*
-        * Return early if we don't need to get clk or we have already tried it
+        * Return early if we don't need to get clk or we have already done it
         * earlier.
         */
-       if (!getclk || IS_ERR(opp_table) || opp_table->clk)
+       if (!getclk || IS_ERR(opp_table) || !IS_ERR(opp_table->clk) ||
+           opp_table->clks)
                return opp_table;
 
        /* Find clk for the device */
        opp_table->clk = clk_get(dev, NULL);
 
        ret = PTR_ERR_OR_ZERO(opp_table->clk);
-       if (!ret)
+       if (!ret) {
+               opp_table->config_clks = _opp_config_clk_single;
+               opp_table->clk_count = 1;
                return opp_table;
+       }
 
        if (ret == -ENOENT) {
+               /*
+                * There are few platforms which don't want the OPP core to
+                * manage device's clock settings. In such cases neither the
+                * platform provides the clks explicitly to us, nor the DT
+                * contains a valid clk entry. The OPP nodes in DT may still
+                * contain "opp-hz" property though, which we need to parse and
+                * allow the platform to find an OPP based on freq later on.
+                *
+                * This is a simple solution to take care of such corner cases,
+                * i.e. make the clk_count 1, which lets us allocate space for
+                * frequency in opp->rates and also parse the entries in DT.
+                */
+               opp_table->clk_count = 1;
+
                dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
                return opp_table;
        }
@@ -1528,7 +1500,7 @@ static void _opp_table_kref_release(struct kref *kref)
 
        _of_clear_opp_table(opp_table);
 
-       /* Release clk */
+       /* Release automatically acquired single clk */
        if (!IS_ERR(opp_table->clk))
                clk_put(opp_table->clk);
 
@@ -1581,7 +1553,7 @@ static void _opp_kref_release(struct kref *kref)
         * frequency/voltage list.
         */
        blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_REMOVE, opp);
-       _of_opp_free_required_opps(opp_table, opp);
+       _of_clear_opp(opp_table, opp);
        opp_debug_remove_one(opp);
        kfree(opp);
 }
@@ -1613,10 +1585,13 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
        if (IS_ERR(opp_table))
                return;
 
+       if (!assert_single_clk(opp_table))
+               goto put_table;
+
        mutex_lock(&opp_table->lock);
 
        list_for_each_entry(iter, &opp_table->opp_list, node) {
-               if (iter->rate == freq) {
+               if (iter->rates[0] == freq) {
                        opp = iter;
                        break;
                }
@@ -1634,6 +1609,7 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
                         __func__, freq);
        }
 
+put_table:
        /* Drop the reference taken by _find_opp_table() */
        dev_pm_opp_put_opp_table(opp_table);
 }
@@ -1720,26 +1696,31 @@ void dev_pm_opp_remove_all_dynamic(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic);
 
-struct dev_pm_opp *_opp_allocate(struct opp_table *table)
+struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table)
 {
        struct dev_pm_opp *opp;
-       int supply_count, supply_size, icc_size;
+       int supply_count, supply_size, icc_size, clk_size;
 
        /* Allocate space for at least one supply */
-       supply_count = table->regulator_count > 0 ? table->regulator_count : 1;
+       supply_count = opp_table->regulator_count > 0 ?
+                       opp_table->regulator_count : 1;
        supply_size = sizeof(*opp->supplies) * supply_count;
-       icc_size = sizeof(*opp->bandwidth) * table->path_count;
+       clk_size = sizeof(*opp->rates) * opp_table->clk_count;
+       icc_size = sizeof(*opp->bandwidth) * opp_table->path_count;
 
        /* allocate new OPP node and supplies structures */
-       opp = kzalloc(sizeof(*opp) + supply_size + icc_size, GFP_KERNEL);
-
+       opp = kzalloc(sizeof(*opp) + supply_size + clk_size + icc_size, GFP_KERNEL);
        if (!opp)
                return NULL;
 
-       /* Put the supplies at the end of the OPP structure as an empty array */
+       /* Put the supplies, bw and clock at the end of the OPP structure */
        opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
+
+       opp->rates = (unsigned long *)(opp->supplies + supply_count);
+
        if (icc_size)
-               opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->supplies + supply_count);
+               opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->rates + opp_table->clk_count);
+
        INIT_LIST_HEAD(&opp->node);
 
        return opp;
@@ -1770,15 +1751,57 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
        return true;
 }
 
-int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)
+static int _opp_compare_rate(struct opp_table *opp_table,
+                            struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)
 {
-       if (opp1->rate != opp2->rate)
-               return opp1->rate < opp2->rate ? -1 : 1;
-       if (opp1->bandwidth && opp2->bandwidth &&
-           opp1->bandwidth[0].peak != opp2->bandwidth[0].peak)
-               return opp1->bandwidth[0].peak < opp2->bandwidth[0].peak ? -1 : 1;
+       int i;
+
+       for (i = 0; i < opp_table->clk_count; i++) {
+               if (opp1->rates[i] != opp2->rates[i])
+                       return opp1->rates[i] < opp2->rates[i] ? -1 : 1;
+       }
+
+       /* Same rates for both OPPs */
+       return 0;
+}
+
+static int _opp_compare_bw(struct opp_table *opp_table, struct dev_pm_opp *opp1,
+                          struct dev_pm_opp *opp2)
+{
+       int i;
+
+       for (i = 0; i < opp_table->path_count; i++) {
+               if (opp1->bandwidth[i].peak != opp2->bandwidth[i].peak)
+                       return opp1->bandwidth[i].peak < opp2->bandwidth[i].peak ? -1 : 1;
+       }
+
+       /* Same bw for both OPPs */
+       return 0;
+}
+
+/*
+ * Returns
+ * 0: opp1 == opp2
+ * 1: opp1 > opp2
+ * -1: opp1 < opp2
+ */
+int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1,
+                    struct dev_pm_opp *opp2)
+{
+       int ret;
+
+       ret = _opp_compare_rate(opp_table, opp1, opp2);
+       if (ret)
+               return ret;
+
+       ret = _opp_compare_bw(opp_table, opp1, opp2);
+       if (ret)
+               return ret;
+
        if (opp1->level != opp2->level)
                return opp1->level < opp2->level ? -1 : 1;
+
+       /* Duplicate OPPs */
        return 0;
 }
 
@@ -1798,7 +1821,7 @@ static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,
         * loop.
         */
        list_for_each_entry(opp, &opp_table->opp_list, node) {
-               opp_cmp = _opp_compare_key(new_opp, opp);
+               opp_cmp = _opp_compare_key(opp_table, new_opp, opp);
                if (opp_cmp > 0) {
                        *head = &opp->node;
                        continue;
@@ -1809,8 +1832,8 @@ static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,
 
                /* Duplicate OPPs */
                dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
-                        __func__, opp->rate, opp->supplies[0].u_volt,
-                        opp->available, new_opp->rate,
+                        __func__, opp->rates[0], opp->supplies[0].u_volt,
+                        opp->available, new_opp->rates[0],
                         new_opp->supplies[0].u_volt, new_opp->available);
 
                /* Should we compare voltages for all regulators here ? */
@@ -1831,7 +1854,7 @@ void _required_opps_available(struct dev_pm_opp *opp, int count)
 
                opp->available = false;
                pr_warn("%s: OPP not supported by required OPP %pOF (%lu)\n",
-                        __func__, opp->required_opps[i]->np, opp->rate);
+                        __func__, opp->required_opps[i]->np, opp->rates[0]);
                return;
        }
 }
@@ -1847,7 +1870,7 @@ void _required_opps_available(struct dev_pm_opp *opp, int count)
  *  should be considered an error by the callers of _opp_add().
  */
 int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
-            struct opp_table *opp_table, bool rate_not_available)
+            struct opp_table *opp_table)
 {
        struct list_head *head;
        int ret;
@@ -1872,7 +1895,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
        if (!_opp_supported_by_regulators(new_opp, opp_table)) {
                new_opp->available = false;
                dev_warn(dev, "%s: OPP not supported by regulators (%lu)\n",
-                        __func__, new_opp->rate);
+                        __func__, new_opp->rates[0]);
        }
 
        /* required-opps not fully initialized yet */
@@ -1913,12 +1936,15 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
        unsigned long tol;
        int ret;
 
+       if (!assert_single_clk(opp_table))
+               return -EINVAL;
+
        new_opp = _opp_allocate(opp_table);
        if (!new_opp)
                return -ENOMEM;
 
        /* populate the opp table */
-       new_opp->rate = freq;
+       new_opp->rates[0] = freq;
        tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
        new_opp->supplies[0].u_volt = u_volt;
        new_opp->supplies[0].u_volt_min = u_volt - tol;
@@ -1926,7 +1952,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
        new_opp->available = true;
        new_opp->dynamic = dynamic;
 
-       ret = _opp_add(dev, new_opp, opp_table, false);
+       ret = _opp_add(dev, new_opp, opp_table);
        if (ret) {
                /* Don't return error for duplicate OPPs */
                if (ret == -EBUSY)
@@ -1948,7 +1974,7 @@ free_opp:
 }
 
 /**
- * dev_pm_opp_set_supported_hw() - Set supported platforms
+ * _opp_set_supported_hw() - Set supported platforms
  * @dev: Device for which supported-hw has to be set.
  * @versions: Array of hierarchy of versions to match.
  * @count: Number of elements in the array.
@@ -1958,87 +1984,42 @@ free_opp:
  * OPPs, which are available for those versions, based on its 'opp-supported-hw'
  * property.
  */
-struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
-                       const u32 *versions, unsigned int count)
+static int _opp_set_supported_hw(struct opp_table *opp_table,
+                                const u32 *versions, unsigned int count)
 {
-       struct opp_table *opp_table;
-
-       opp_table = _add_opp_table(dev, false);
-       if (IS_ERR(opp_table))
-               return opp_table;
-
-       /* Make sure there are no concurrent readers while updating opp_table */
-       WARN_ON(!list_empty(&opp_table->opp_list));
-
        /* Another CPU that shares the OPP table has set the property ? */
        if (opp_table->supported_hw)
-               return opp_table;
+               return 0;
 
        opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions),
                                        GFP_KERNEL);
-       if (!opp_table->supported_hw) {
-               dev_pm_opp_put_opp_table(opp_table);
-               return ERR_PTR(-ENOMEM);
-       }
+       if (!opp_table->supported_hw)
+               return -ENOMEM;
 
        opp_table->supported_hw_count = count;
 
-       return opp_table;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw);
 
 /**
- * dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw
- * @opp_table: OPP table returned by dev_pm_opp_set_supported_hw().
+ * _opp_put_supported_hw() - Releases resources blocked for supported hw
+ * @opp_table: OPP table returned by _opp_set_supported_hw().
  *
  * This is required only for the V2 bindings, and is called for a matching
- * dev_pm_opp_set_supported_hw(). Until this is called, the opp_table structure
+ * _opp_set_supported_hw(). Until this is called, the opp_table structure
  * will not be freed.
  */
-void dev_pm_opp_put_supported_hw(struct opp_table *opp_table)
-{
-       if (unlikely(!opp_table))
-               return;
-
-       kfree(opp_table->supported_hw);
-       opp_table->supported_hw = NULL;
-       opp_table->supported_hw_count = 0;
-
-       dev_pm_opp_put_opp_table(opp_table);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
-
-static void devm_pm_opp_supported_hw_release(void *data)
-{
-       dev_pm_opp_put_supported_hw(data);
-}
-
-/**
- * devm_pm_opp_set_supported_hw() - Set supported platforms
- * @dev: Device for which supported-hw has to be set.
- * @versions: Array of hierarchy of versions to match.
- * @count: Number of elements in the array.
- *
- * This is a resource-managed variant of dev_pm_opp_set_supported_hw().
- *
- * Return: 0 on success and errorno otherwise.
- */
-int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
-                                unsigned int count)
+static void _opp_put_supported_hw(struct opp_table *opp_table)
 {
-       struct opp_table *opp_table;
-
-       opp_table = dev_pm_opp_set_supported_hw(dev, versions, count);
-       if (IS_ERR(opp_table))
-               return PTR_ERR(opp_table);
-
-       return devm_add_action_or_reset(dev, devm_pm_opp_supported_hw_release,
-                                       opp_table);
+       if (opp_table->supported_hw) {
+               kfree(opp_table->supported_hw);
+               opp_table->supported_hw = NULL;
+               opp_table->supported_hw_count = 0;
+       }
 }
-EXPORT_SYMBOL_GPL(devm_pm_opp_set_supported_hw);
 
 /**
- * dev_pm_opp_set_prop_name() - Set prop-extn name
+ * _opp_set_prop_name() - Set prop-extn name
  * @dev: Device for which the prop-name has to be set.
  * @name: name to postfix to properties.
  *
@@ -2047,53 +2028,36 @@ EXPORT_SYMBOL_GPL(devm_pm_opp_set_supported_hw);
  * which the extension will apply are opp-microvolt and opp-microamp. OPP core
  * should postfix the property name with -<name> while looking for them.
  */
-struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+static int _opp_set_prop_name(struct opp_table *opp_table, const char *name)
 {
-       struct opp_table *opp_table;
-
-       opp_table = _add_opp_table(dev, false);
-       if (IS_ERR(opp_table))
-               return opp_table;
-
-       /* Make sure there are no concurrent readers while updating opp_table */
-       WARN_ON(!list_empty(&opp_table->opp_list));
-
        /* Another CPU that shares the OPP table has set the property ? */
-       if (opp_table->prop_name)
-               return opp_table;
-
-       opp_table->prop_name = kstrdup(name, GFP_KERNEL);
        if (!opp_table->prop_name) {
-               dev_pm_opp_put_opp_table(opp_table);
-               return ERR_PTR(-ENOMEM);
+               opp_table->prop_name = kstrdup(name, GFP_KERNEL);
+               if (!opp_table->prop_name)
+                       return -ENOMEM;
        }
 
-       return opp_table;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name);
 
 /**
- * dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name
- * @opp_table: OPP table returned by dev_pm_opp_set_prop_name().
+ * _opp_put_prop_name() - Releases resources blocked for prop-name
+ * @opp_table: OPP table returned by _opp_set_prop_name().
  *
  * This is required only for the V2 bindings, and is called for a matching
- * dev_pm_opp_set_prop_name(). Until this is called, the opp_table structure
+ * _opp_set_prop_name(). Until this is called, the opp_table structure
  * will not be freed.
  */
-void dev_pm_opp_put_prop_name(struct opp_table *opp_table)
+static void _opp_put_prop_name(struct opp_table *opp_table)
 {
-       if (unlikely(!opp_table))
-               return;
-
-       kfree(opp_table->prop_name);
-       opp_table->prop_name = NULL;
-
-       dev_pm_opp_put_opp_table(opp_table);
+       if (opp_table->prop_name) {
+               kfree(opp_table->prop_name);
+               opp_table->prop_name = NULL;
+       }
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
 
 /**
- * dev_pm_opp_set_regulators() - Set regulator names for the device
+ * _opp_set_regulators() - Set regulator names for the device
  * @dev: Device for which regulator name is being set.
  * @names: Array of pointers to the names of the regulator.
  * @count: Number of regulators.
@@ -2104,36 +2068,29 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
  *
  * This must be called before any OPPs are initialized for the device.
  */
-struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
-                                           const char * const names[],
-                                           unsigned int count)
+static int _opp_set_regulators(struct opp_table *opp_table, struct device *dev,
+                              const char * const names[])
 {
-       struct dev_pm_opp_supply *supplies;
-       struct opp_table *opp_table;
+       const char * const *temp = names;
        struct regulator *reg;
-       int ret, i;
+       int count = 0, ret, i;
 
-       opp_table = _add_opp_table(dev, false);
-       if (IS_ERR(opp_table))
-               return opp_table;
+       /* Count number of regulators */
+       while (*temp++)
+               count++;
 
-       /* This should be called before OPPs are initialized */
-       if (WARN_ON(!list_empty(&opp_table->opp_list))) {
-               ret = -EBUSY;
-               goto err;
-       }
+       if (!count)
+               return -EINVAL;
 
        /* Another CPU that shares the OPP table has set the regulators ? */
        if (opp_table->regulators)
-               return opp_table;
+               return 0;
 
        opp_table->regulators = kmalloc_array(count,
                                              sizeof(*opp_table->regulators),
                                              GFP_KERNEL);
-       if (!opp_table->regulators) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!opp_table->regulators)
+               return -ENOMEM;
 
        for (i = 0; i < count; i++) {
                reg = regulator_get_optional(dev, names[i]);
@@ -2149,21 +2106,11 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
 
        opp_table->regulator_count = count;
 
-       supplies = kmalloc_array(count * 2, sizeof(*supplies), GFP_KERNEL);
-       if (!supplies) {
-               ret = -ENOMEM;
-               goto free_regulators;
-       }
-
-       mutex_lock(&opp_table->lock);
-       opp_table->sod_supplies = supplies;
-       if (opp_table->set_opp_data) {
-               opp_table->set_opp_data->old_opp.supplies = supplies;
-               opp_table->set_opp_data->new_opp.supplies = supplies + count;
-       }
-       mutex_unlock(&opp_table->lock);
+       /* Set generic config_regulators() for single regulators here */
+       if (count == 1)
+               opp_table->config_regulators = _opp_config_regulator_single;
 
-       return opp_table;
+       return 0;
 
 free_regulators:
        while (i != 0)
@@ -2172,26 +2119,20 @@ free_regulators:
        kfree(opp_table->regulators);
        opp_table->regulators = NULL;
        opp_table->regulator_count = -1;
-err:
-       dev_pm_opp_put_opp_table(opp_table);
 
-       return ERR_PTR(ret);
+       return ret;
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
 
 /**
- * dev_pm_opp_put_regulators() - Releases resources blocked for regulator
- * @opp_table: OPP table returned from dev_pm_opp_set_regulators().
+ * _opp_put_regulators() - Releases resources blocked for regulator
+ * @opp_table: OPP table returned from _opp_set_regulators().
  */
-void dev_pm_opp_put_regulators(struct opp_table *opp_table)
+static void _opp_put_regulators(struct opp_table *opp_table)
 {
        int i;
 
-       if (unlikely(!opp_table))
-               return;
-
        if (!opp_table->regulators)
-               goto put_opp_table;
+               return;
 
        if (opp_table->enabled) {
                for (i = opp_table->regulator_count - 1; i >= 0; i--)
@@ -2201,252 +2142,158 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table)
        for (i = opp_table->regulator_count - 1; i >= 0; i--)
                regulator_put(opp_table->regulators[i]);
 
-       mutex_lock(&opp_table->lock);
-       if (opp_table->set_opp_data) {
-               opp_table->set_opp_data->old_opp.supplies = NULL;
-               opp_table->set_opp_data->new_opp.supplies = NULL;
-       }
-
-       kfree(opp_table->sod_supplies);
-       opp_table->sod_supplies = NULL;
-       mutex_unlock(&opp_table->lock);
-
        kfree(opp_table->regulators);
        opp_table->regulators = NULL;
        opp_table->regulator_count = -1;
-
-put_opp_table:
-       dev_pm_opp_put_opp_table(opp_table);
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
 
-static void devm_pm_opp_regulators_release(void *data)
-{
-       dev_pm_opp_put_regulators(data);
-}
-
-/**
- * devm_pm_opp_set_regulators() - Set regulator names for the device
- * @dev: Device for which regulator name is being set.
- * @names: Array of pointers to the names of the regulator.
- * @count: Number of regulators.
- *
- * This is a resource-managed variant of dev_pm_opp_set_regulators().
- *
- * Return: 0 on success and errorno otherwise.
- */
-int devm_pm_opp_set_regulators(struct device *dev,
-                              const char * const names[],
-                              unsigned int count)
+static void _put_clks(struct opp_table *opp_table, int count)
 {
-       struct opp_table *opp_table;
+       int i;
 
-       opp_table = dev_pm_opp_set_regulators(dev, names, count);
-       if (IS_ERR(opp_table))
-               return PTR_ERR(opp_table);
+       for (i = count - 1; i >= 0; i--)
+               clk_put(opp_table->clks[i]);
 
-       return devm_add_action_or_reset(dev, devm_pm_opp_regulators_release,
-                                       opp_table);
+       kfree(opp_table->clks);
+       opp_table->clks = NULL;
 }
-EXPORT_SYMBOL_GPL(devm_pm_opp_set_regulators);
 
 /**
- * dev_pm_opp_set_clkname() - Set clk name for the device
- * @dev: Device for which clk name is being set.
- * @name: Clk name.
- *
- * In order to support OPP switching, OPP layer needs to get pointer to the
- * clock for the device. Simple cases work fine without using this routine (i.e.
- * by passing connection-id as NULL), but for a device with multiple clocks
- * available, the OPP core needs to know the exact name of the clk to use.
+ * _opp_set_clknames() - Set clk names for the device
+ * @dev: Device for which clk names is being set.
+ * @names: Clk names.
+ *
+ * In order to support OPP switching, OPP layer needs to get pointers to the
+ * clocks for the device. Simple cases work fine without using this routine
+ * (i.e. by passing connection-id as NULL), but for a device with multiple
+ * clocks available, the OPP core needs to know the exact names of the clks to
+ * use.
  *
  * This must be called before any OPPs are initialized for the device.
  */
-struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
+static int _opp_set_clknames(struct opp_table *opp_table, struct device *dev,
+                            const char * const names[],
+                            config_clks_t config_clks)
 {
-       struct opp_table *opp_table;
-       int ret;
+       const char * const *temp = names;
+       int count = 0, ret, i;
+       struct clk *clk;
 
-       opp_table = _add_opp_table(dev, false);
-       if (IS_ERR(opp_table))
-               return opp_table;
+       /* Count number of clks */
+       while (*temp++)
+               count++;
 
-       /* This should be called before OPPs are initialized */
-       if (WARN_ON(!list_empty(&opp_table->opp_list))) {
-               ret = -EBUSY;
-               goto err;
-       }
+       /*
+        * This is a special case where we have a single clock, whose connection
+        * id name is NULL, i.e. first two entries are NULL in the array.
+        */
+       if (!count && !names[1])
+               count = 1;
 
-       /* clk shouldn't be initialized at this point */
-       if (WARN_ON(opp_table->clk)) {
-               ret = -EBUSY;
-               goto err;
-       }
+       /* Fail early for invalid configurations */
+       if (!count || (!config_clks && count > 1))
+               return -EINVAL;
 
-       /* Find clk for the device */
-       opp_table->clk = clk_get(dev, name);
-       if (IS_ERR(opp_table->clk)) {
-               ret = dev_err_probe(dev, PTR_ERR(opp_table->clk),
-                                   "%s: Couldn't find clock\n", __func__);
-               goto err;
-       }
+       /* Another CPU that shares the OPP table has set the clkname ? */
+       if (opp_table->clks)
+               return 0;
 
-       return opp_table;
+       opp_table->clks = kmalloc_array(count, sizeof(*opp_table->clks),
+                                       GFP_KERNEL);
+       if (!opp_table->clks)
+               return -ENOMEM;
 
-err:
-       dev_pm_opp_put_opp_table(opp_table);
+       /* Find clks for the device */
+       for (i = 0; i < count; i++) {
+               clk = clk_get(dev, names[i]);
+               if (IS_ERR(clk)) {
+                       ret = dev_err_probe(dev, PTR_ERR(clk),
+                                           "%s: Couldn't find clock with name: %s\n",
+                                           __func__, names[i]);
+                       goto free_clks;
+               }
 
-       return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_clkname);
+               opp_table->clks[i] = clk;
+       }
 
-/**
- * dev_pm_opp_put_clkname() - Releases resources blocked for clk.
- * @opp_table: OPP table returned from dev_pm_opp_set_clkname().
- */
-void dev_pm_opp_put_clkname(struct opp_table *opp_table)
-{
-       if (unlikely(!opp_table))
-               return;
+       opp_table->clk_count = count;
+       opp_table->config_clks = config_clks;
 
-       clk_put(opp_table->clk);
-       opp_table->clk = ERR_PTR(-EINVAL);
+       /* Set generic single clk set here */
+       if (count == 1) {
+               if (!opp_table->config_clks)
+                       opp_table->config_clks = _opp_config_clk_single;
 
-       dev_pm_opp_put_opp_table(opp_table);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_clkname);
+               /*
+                * We could have just dropped the "clk" field and used "clks"
+                * everywhere. Instead we kept the "clk" field around for
+                * following reasons:
+                *
+                * - avoiding clks[0] everywhere else.
+                * - not running single clk helpers for multiple clk usecase by
+                *   mistake.
+                *
+                * Since this is single-clk case, just update the clk pointer
+                * too.
+                */
+               opp_table->clk = opp_table->clks[0];
+       }
 
-static void devm_pm_opp_clkname_release(void *data)
-{
-       dev_pm_opp_put_clkname(data);
+       return 0;
+
+free_clks:
+       _put_clks(opp_table, i);
+       return ret;
 }
 
 /**
- * devm_pm_opp_set_clkname() - Set clk name for the device
- * @dev: Device for which clk name is being set.
- * @name: Clk name.
- *
- * This is a resource-managed variant of dev_pm_opp_set_clkname().
- *
- * Return: 0 on success and errorno otherwise.
+ * _opp_put_clknames() - Releases resources blocked for clks.
+ * @opp_table: OPP table returned from _opp_set_clknames().
  */
-int devm_pm_opp_set_clkname(struct device *dev, const char *name)
+static void _opp_put_clknames(struct opp_table *opp_table)
 {
-       struct opp_table *opp_table;
+       if (!opp_table->clks)
+               return;
 
-       opp_table = dev_pm_opp_set_clkname(dev, name);
-       if (IS_ERR(opp_table))
-               return PTR_ERR(opp_table);
+       opp_table->config_clks = NULL;
+       opp_table->clk = ERR_PTR(-ENODEV);
 
-       return devm_add_action_or_reset(dev, devm_pm_opp_clkname_release,
-                                       opp_table);
+       _put_clks(opp_table, opp_table->clk_count);
 }
-EXPORT_SYMBOL_GPL(devm_pm_opp_set_clkname);
 
 /**
- * dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper
+ * _opp_set_config_regulators_helper() - Register custom set regulator helper.
  * @dev: Device for which the helper is getting registered.
- * @set_opp: Custom set OPP helper.
+ * @config_regulators: Custom set regulator helper.
  *
- * This is useful to support complex platforms (like platforms with multiple
- * regulators per device), instead of the generic OPP set rate helper.
+ * This is useful to support platforms with multiple regulators per device.
  *
  * This must be called before any OPPs are initialized for the device.
  */
-struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
-                       int (*set_opp)(struct dev_pm_set_opp_data *data))
+static int _opp_set_config_regulators_helper(struct opp_table *opp_table,
+               struct device *dev, config_regulators_t config_regulators)
 {
-       struct dev_pm_set_opp_data *data;
-       struct opp_table *opp_table;
-
-       if (!set_opp)
-               return ERR_PTR(-EINVAL);
-
-       opp_table = _add_opp_table(dev, false);
-       if (IS_ERR(opp_table))
-               return opp_table;
-
-       /* This should be called before OPPs are initialized */
-       if (WARN_ON(!list_empty(&opp_table->opp_list))) {
-               dev_pm_opp_put_opp_table(opp_table);
-               return ERR_PTR(-EBUSY);
-       }
-
        /* Another CPU that shares the OPP table has set the helper ? */
-       if (opp_table->set_opp)
-               return opp_table;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return ERR_PTR(-ENOMEM);
-
-       mutex_lock(&opp_table->lock);
-       opp_table->set_opp_data = data;
-       if (opp_table->sod_supplies) {
-               data->old_opp.supplies = opp_table->sod_supplies;
-               data->new_opp.supplies = opp_table->sod_supplies +
-                                        opp_table->regulator_count;
-       }
-       mutex_unlock(&opp_table->lock);
-
-       opp_table->set_opp = set_opp;
-
-       return opp_table;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper);
-
-/**
- * dev_pm_opp_unregister_set_opp_helper() - Releases resources blocked for
- *                                        set_opp helper
- * @opp_table: OPP table returned from dev_pm_opp_register_set_opp_helper().
- *
- * Release resources blocked for platform specific set_opp helper.
- */
-void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table)
-{
-       if (unlikely(!opp_table))
-               return;
-
-       opp_table->set_opp = NULL;
+       if (!opp_table->config_regulators)
+               opp_table->config_regulators = config_regulators;
 
-       mutex_lock(&opp_table->lock);
-       kfree(opp_table->set_opp_data);
-       opp_table->set_opp_data = NULL;
-       mutex_unlock(&opp_table->lock);
-
-       dev_pm_opp_put_opp_table(opp_table);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper);
-
-static void devm_pm_opp_unregister_set_opp_helper(void *data)
-{
-       dev_pm_opp_unregister_set_opp_helper(data);
+       return 0;
 }
 
 /**
- * devm_pm_opp_register_set_opp_helper() - Register custom set OPP helper
- * @dev: Device for which the helper is getting registered.
- * @set_opp: Custom set OPP helper.
- *
- * This is a resource-managed version of dev_pm_opp_register_set_opp_helper().
+ * _opp_put_config_regulators_helper() - Releases resources blocked for
+ *                                      config_regulators helper.
+ * @opp_table: OPP table returned from _opp_set_config_regulators_helper().
  *
- * Return: 0 on success and errorno otherwise.
+ * Release resources blocked for platform specific config_regulators helper.
  */
-int devm_pm_opp_register_set_opp_helper(struct device *dev,
-                                       int (*set_opp)(struct dev_pm_set_opp_data *data))
+static void _opp_put_config_regulators_helper(struct opp_table *opp_table)
 {
-       struct opp_table *opp_table;
-
-       opp_table = dev_pm_opp_register_set_opp_helper(dev, set_opp);
-       if (IS_ERR(opp_table))
-               return PTR_ERR(opp_table);
-
-       return devm_add_action_or_reset(dev, devm_pm_opp_unregister_set_opp_helper,
-                                       opp_table);
+       if (opp_table->config_regulators)
+               opp_table->config_regulators = NULL;
 }
-EXPORT_SYMBOL_GPL(devm_pm_opp_register_set_opp_helper);
 
-static void _opp_detach_genpd(struct opp_table *opp_table)
+static void _detach_genpd(struct opp_table *opp_table)
 {
        int index;
 
@@ -2466,7 +2313,7 @@ static void _opp_detach_genpd(struct opp_table *opp_table)
 }
 
 /**
- * dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
+ * _opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
  * @dev: Consumer device for which the genpd is getting attached.
  * @names: Null terminated array of pointers containing names of genpd to attach.
  * @virt_devs: Pointer to return the array of virtual devices.
@@ -2487,30 +2334,23 @@ static void _opp_detach_genpd(struct opp_table *opp_table)
  * The order of entries in the names array must match the order in which
  * "required-opps" are added in DT.
  */
-struct opp_table *dev_pm_opp_attach_genpd(struct device *dev,
-               const char * const *names, struct device ***virt_devs)
+static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
+                       const char * const *names, struct device ***virt_devs)
 {
-       struct opp_table *opp_table;
        struct device *virt_dev;
        int index = 0, ret = -EINVAL;
        const char * const *name = names;
 
-       opp_table = _add_opp_table(dev, false);
-       if (IS_ERR(opp_table))
-               return opp_table;
-
        if (opp_table->genpd_virt_devs)
-               return opp_table;
+               return 0;
 
        /*
         * If the genpd's OPP table isn't already initialized, parsing of the
         * required-opps fail for dev. We should retry this after genpd's OPP
         * table is added.
         */
-       if (!opp_table->required_opp_count) {
-               ret = -EPROBE_DEFER;
-               goto put_table;
-       }
+       if (!opp_table->required_opp_count)
+               return -EPROBE_DEFER;
 
        mutex_lock(&opp_table->genpd_virt_dev_lock);
 
@@ -2528,8 +2368,8 @@ struct opp_table *dev_pm_opp_attach_genpd(struct device *dev,
                }
 
                virt_dev = dev_pm_domain_attach_by_name(dev, *name);
-               if (IS_ERR(virt_dev)) {
-                       ret = PTR_ERR(virt_dev);
+               if (IS_ERR_OR_NULL(virt_dev)) {
+                       ret = PTR_ERR(virt_dev) ? : -ENODEV;
                        dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret);
                        goto err;
                }
@@ -2543,73 +2383,230 @@ struct opp_table *dev_pm_opp_attach_genpd(struct device *dev,
                *virt_devs = opp_table->genpd_virt_devs;
        mutex_unlock(&opp_table->genpd_virt_dev_lock);
 
-       return opp_table;
+       return 0;
 
 err:
-       _opp_detach_genpd(opp_table);
+       _detach_genpd(opp_table);
 unlock:
        mutex_unlock(&opp_table->genpd_virt_dev_lock);
+       return ret;
 
-put_table:
-       dev_pm_opp_put_opp_table(opp_table);
-
-       return ERR_PTR(ret);
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_attach_genpd);
 
 /**
- * dev_pm_opp_detach_genpd() - Detach genpd(s) from the device.
- * @opp_table: OPP table returned by dev_pm_opp_attach_genpd().
+ * _opp_detach_genpd() - Detach genpd(s) from the device.
+ * @opp_table: OPP table returned by _opp_attach_genpd().
  *
  * This detaches the genpd(s), resets the virtual device pointers, and puts the
  * OPP table.
  */
-void dev_pm_opp_detach_genpd(struct opp_table *opp_table)
+static void _opp_detach_genpd(struct opp_table *opp_table)
 {
-       if (unlikely(!opp_table))
-               return;
-
        /*
         * Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting
         * used in parallel.
         */
        mutex_lock(&opp_table->genpd_virt_dev_lock);
-       _opp_detach_genpd(opp_table);
+       _detach_genpd(opp_table);
        mutex_unlock(&opp_table->genpd_virt_dev_lock);
-
-       dev_pm_opp_put_opp_table(opp_table);
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_detach_genpd);
 
-static void devm_pm_opp_detach_genpd(void *data)
+static void _opp_clear_config(struct opp_config_data *data)
 {
-       dev_pm_opp_detach_genpd(data);
+       if (data->flags & OPP_CONFIG_GENPD)
+               _opp_detach_genpd(data->opp_table);
+       if (data->flags & OPP_CONFIG_REGULATOR)
+               _opp_put_regulators(data->opp_table);
+       if (data->flags & OPP_CONFIG_SUPPORTED_HW)
+               _opp_put_supported_hw(data->opp_table);
+       if (data->flags & OPP_CONFIG_REGULATOR_HELPER)
+               _opp_put_config_regulators_helper(data->opp_table);
+       if (data->flags & OPP_CONFIG_PROP_NAME)
+               _opp_put_prop_name(data->opp_table);
+       if (data->flags & OPP_CONFIG_CLK)
+               _opp_put_clknames(data->opp_table);
+
+       dev_pm_opp_put_opp_table(data->opp_table);
+       kfree(data);
 }
 
 /**
- * devm_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual
- *                           device pointer
- * @dev: Consumer device for which the genpd is getting attached.
- * @names: Null terminated array of pointers containing names of genpd to attach.
- * @virt_devs: Pointer to return the array of virtual devices.
+ * dev_pm_opp_set_config() - Set OPP configuration for the device.
+ * @dev: Device for which configuration is being set.
+ * @config: OPP configuration.
  *
- * This is a resource-managed version of dev_pm_opp_attach_genpd().
+ * This allows all device OPP configurations to be performed at once.
  *
- * Return: 0 on success and errorno otherwise.
+ * This must be called before any OPPs are initialized for the device. This may
+ * be called multiple times for the same OPP table, for example once for each
+ * CPU that share the same table. This must be balanced by the same number of
+ * calls to dev_pm_opp_clear_config() in order to free the OPP table properly.
+ *
+ * This returns a token to the caller, which must be passed to
+ * dev_pm_opp_clear_config() to free the resources later. The value of the
+ * returned token will be >= 1 for success and negative for errors. The minimum
+ * value of 1 is chosen here to make it easy for callers to manage the resource.
  */
-int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names,
-                            struct device ***virt_devs)
+int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
 {
        struct opp_table *opp_table;
+       struct opp_config_data *data;
+       unsigned int id;
+       int ret;
 
-       opp_table = dev_pm_opp_attach_genpd(dev, names, virt_devs);
-       if (IS_ERR(opp_table))
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       opp_table = _add_opp_table(dev, false);
+       if (IS_ERR(opp_table)) {
+               kfree(data);
                return PTR_ERR(opp_table);
+       }
+
+       data->opp_table = opp_table;
+       data->flags = 0;
+
+       /* This should be called before OPPs are initialized */
+       if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+               ret = -EBUSY;
+               goto err;
+       }
+
+       /* Configure clocks */
+       if (config->clk_names) {
+               ret = _opp_set_clknames(opp_table, dev, config->clk_names,
+                                       config->config_clks);
+               if (ret)
+                       goto err;
+
+               data->flags |= OPP_CONFIG_CLK;
+       } else if (config->config_clks) {
+               /* Don't allow config callback without clocks */
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* Configure property names */
+       if (config->prop_name) {
+               ret = _opp_set_prop_name(opp_table, config->prop_name);
+               if (ret)
+                       goto err;
+
+               data->flags |= OPP_CONFIG_PROP_NAME;
+       }
+
+       /* Configure config_regulators helper */
+       if (config->config_regulators) {
+               ret = _opp_set_config_regulators_helper(opp_table, dev,
+                                               config->config_regulators);
+               if (ret)
+                       goto err;
+
+               data->flags |= OPP_CONFIG_REGULATOR_HELPER;
+       }
+
+       /* Configure supported hardware */
+       if (config->supported_hw) {
+               ret = _opp_set_supported_hw(opp_table, config->supported_hw,
+                                           config->supported_hw_count);
+               if (ret)
+                       goto err;
+
+               data->flags |= OPP_CONFIG_SUPPORTED_HW;
+       }
+
+       /* Configure supplies */
+       if (config->regulator_names) {
+               ret = _opp_set_regulators(opp_table, dev,
+                                         config->regulator_names);
+               if (ret)
+                       goto err;
+
+               data->flags |= OPP_CONFIG_REGULATOR;
+       }
+
+       /* Attach genpds */
+       if (config->genpd_names) {
+               ret = _opp_attach_genpd(opp_table, dev, config->genpd_names,
+                                       config->virt_devs);
+               if (ret)
+                       goto err;
+
+               data->flags |= OPP_CONFIG_GENPD;
+       }
+
+       ret = xa_alloc(&opp_configs, &id, data, XA_LIMIT(1, INT_MAX),
+                      GFP_KERNEL);
+       if (ret)
+               goto err;
+
+       return id;
+
+err:
+       _opp_clear_config(data);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_config);
+
+/**
+ * dev_pm_opp_clear_config() - Releases resources blocked for OPP configuration.
+ * @opp_table: OPP table returned from dev_pm_opp_set_config().
+ *
+ * This allows all device OPP configurations to be cleared at once. This must be
+ * called once for each call made to dev_pm_opp_set_config(), in order to free
+ * the OPPs properly.
+ *
+ * Currently the first call itself ends up freeing all the OPP configurations,
+ * while the later ones only drop the OPP table reference. This works well for
+ * now as we would never want to use an half initialized OPP table and want to
+ * remove the configurations together.
+ */
+void dev_pm_opp_clear_config(int token)
+{
+       struct opp_config_data *data;
+
+       /*
+        * This lets the callers call this unconditionally and keep their code
+        * simple.
+        */
+       if (unlikely(token <= 0))
+               return;
+
+       data = xa_erase(&opp_configs, token);
+       if (WARN_ON(!data))
+               return;
+
+       _opp_clear_config(data);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_clear_config);
+
+static void devm_pm_opp_config_release(void *token)
+{
+       dev_pm_opp_clear_config((unsigned long)token);
+}
+
+/**
+ * devm_pm_opp_set_config() - Set OPP configuration for the device.
+ * @dev: Device for which configuration is being set.
+ * @config: OPP configuration.
+ *
+ * This allows all device OPP configurations to be performed at once.
+ * This is a resource-managed variant of dev_pm_opp_set_config().
+ *
+ * Return: 0 on success and errorno otherwise.
+ */
+int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
+{
+       int token = dev_pm_opp_set_config(dev, config);
 
-       return devm_add_action_or_reset(dev, devm_pm_opp_detach_genpd,
-                                       opp_table);
+       if (token < 0)
+               return token;
+
+       return devm_add_action_or_reset(dev, devm_pm_opp_config_release,
+                                       (void *) ((unsigned long) token));
 }
-EXPORT_SYMBOL_GPL(devm_pm_opp_attach_genpd);
+EXPORT_SYMBOL_GPL(devm_pm_opp_set_config);
 
 /**
  * dev_pm_opp_xlate_required_opp() - Find required OPP for @src_table OPP.
@@ -2795,11 +2792,16 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
                return r;
        }
 
+       if (!assert_single_clk(opp_table)) {
+               r = -EINVAL;
+               goto put_table;
+       }
+
        mutex_lock(&opp_table->lock);
 
        /* Do we have the frequency? */
        list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
-               if (tmp_opp->rate == freq) {
+               if (tmp_opp->rates[0] == freq) {
                        opp = tmp_opp;
                        break;
                }
@@ -2866,11 +2868,16 @@ int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
                return r;
        }
 
+       if (!assert_single_clk(opp_table)) {
+               r = -EINVAL;
+               goto put_table;
+       }
+
        mutex_lock(&opp_table->lock);
 
        /* Do we have the frequency? */
        list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
-               if (tmp_opp->rate == freq) {
+               if (tmp_opp->rates[0] == freq) {
                        opp = tmp_opp;
                        break;
                }
@@ -2897,11 +2904,11 @@ int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
                                     opp);
 
        dev_pm_opp_put(opp);
-       goto adjust_put_table;
+       goto put_table;
 
 adjust_unlock:
        mutex_unlock(&opp_table->lock);
-adjust_put_table:
+put_table:
        dev_pm_opp_put_opp_table(opp_table);
        return r;
 }
index 5004335..3c35060 100644 (file)
@@ -41,7 +41,7 @@
  * the table if any of the mentioned functions have been invoked in the interim.
  */
 int dev_pm_opp_init_cpufreq_table(struct device *dev,
-                                 struct cpufreq_frequency_table **table)
+                                 struct cpufreq_frequency_table **opp_table)
 {
        struct dev_pm_opp *opp;
        struct cpufreq_frequency_table *freq_table = NULL;
@@ -76,7 +76,7 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
        freq_table[i].driver_data = i;
        freq_table[i].frequency = CPUFREQ_TABLE_END;
 
-       *table = &freq_table[0];
+       *opp_table = &freq_table[0];
 
 out:
        if (ret)
@@ -94,13 +94,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
  * Free up the table allocated by dev_pm_opp_init_cpufreq_table
  */
 void dev_pm_opp_free_cpufreq_table(struct device *dev,
-                                  struct cpufreq_frequency_table **table)
+                                  struct cpufreq_frequency_table **opp_table)
 {
-       if (!table)
+       if (!opp_table)
                return;
 
-       kfree(*table);
-       *table = NULL;
+       kfree(*opp_table);
+       *opp_table = NULL;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
 #endif /* CONFIG_CPU_FREQ */
index 1b6e5c5..96a30a0 100644 (file)
@@ -74,6 +74,24 @@ static void opp_debug_create_bw(struct dev_pm_opp *opp,
        }
 }
 
+static void opp_debug_create_clks(struct dev_pm_opp *opp,
+                                 struct opp_table *opp_table,
+                                 struct dentry *pdentry)
+{
+       char name[12];
+       int i;
+
+       if (opp_table->clk_count == 1) {
+               debugfs_create_ulong("rate_hz", S_IRUGO, pdentry, &opp->rates[0]);
+               return;
+       }
+
+       for (i = 0; i < opp_table->clk_count; i++) {
+               snprintf(name, sizeof(name), "rate_hz_%d", i);
+               debugfs_create_ulong(name, S_IRUGO, pdentry, &opp->rates[i]);
+       }
+}
+
 static void opp_debug_create_supplies(struct dev_pm_opp *opp,
                                      struct opp_table *opp_table,
                                      struct dentry *pdentry)
@@ -117,10 +135,11 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
         * Get directory name for OPP.
         *
         * - Normally rate is unique to each OPP, use it to get unique opp-name.
-        * - For some devices rate isn't available, use index instead.
+        * - For some devices rate isn't available or there are multiple, use
+        *   index instead for them.
         */
-       if (likely(opp->rate))
-               id = opp->rate;
+       if (likely(opp_table->clk_count == 1 && opp->rates[0]))
+               id = opp->rates[0];
        else
                id = _get_opp_count(opp_table);
 
@@ -134,7 +153,6 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
        debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo);
        debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend);
        debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate);
-       debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate);
        debugfs_create_u32("level", S_IRUGO, d, &opp->level);
        debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
                             &opp->clock_latency_ns);
@@ -142,6 +160,7 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
        opp->of_name = of_node_full_name(opp->np);
        debugfs_create_str("of_name", S_IRUGO, d, (char **)&opp->of_name);
 
+       opp_debug_create_clks(opp, opp_table, d);
        opp_debug_create_supplies(opp, opp_table, d);
        opp_debug_create_bw(opp, opp_table, d);
 
index eb89c9a..605d686 100644 (file)
@@ -242,20 +242,20 @@ void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
        opp_table->np = opp_np;
 
        _opp_table_alloc_required_tables(opp_table, dev, opp_np);
-       of_node_put(opp_np);
 }
 
 void _of_clear_opp_table(struct opp_table *opp_table)
 {
        _opp_table_free_required_tables(opp_table);
+       of_node_put(opp_table->np);
 }
 
 /*
  * Release all resources previously acquired with a call to
  * _of_opp_alloc_required_opps().
  */
-void _of_opp_free_required_opps(struct opp_table *opp_table,
-                               struct dev_pm_opp *opp)
+static void _of_opp_free_required_opps(struct opp_table *opp_table,
+                                      struct dev_pm_opp *opp)
 {
        struct dev_pm_opp **required_opps = opp->required_opps;
        int i;
@@ -275,6 +275,12 @@ void _of_opp_free_required_opps(struct opp_table *opp_table,
        kfree(required_opps);
 }
 
+void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp)
+{
+       _of_opp_free_required_opps(opp_table, opp);
+       of_node_put(opp->np);
+}
+
 /* Populate all required OPPs which are part of "required-opps" list */
 static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
                                       struct dev_pm_opp *opp)
@@ -767,7 +773,51 @@ void dev_pm_opp_of_remove_table(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
 
-static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table,
+static int _read_rate(struct dev_pm_opp *new_opp, struct opp_table *opp_table,
+                     struct device_node *np)
+{
+       struct property *prop;
+       int i, count, ret;
+       u64 *rates;
+
+       prop = of_find_property(np, "opp-hz", NULL);
+       if (!prop)
+               return -ENODEV;
+
+       count = prop->length / sizeof(u64);
+       if (opp_table->clk_count != count) {
+               pr_err("%s: Count mismatch between opp-hz and clk_count (%d %d)\n",
+                      __func__, count, opp_table->clk_count);
+               return -EINVAL;
+       }
+
+       rates = kmalloc_array(count, sizeof(*rates), GFP_KERNEL);
+       if (!rates)
+               return -ENOMEM;
+
+       ret = of_property_read_u64_array(np, "opp-hz", rates, count);
+       if (ret) {
+               pr_err("%s: Error parsing opp-hz: %d\n", __func__, ret);
+       } else {
+               /*
+                * Rate is defined as an unsigned long in clk API, and so
+                * casting explicitly to its type. Must be fixed once rate is 64
+                * bit guaranteed in clk API.
+                */
+               for (i = 0; i < count; i++) {
+                       new_opp->rates[i] = (unsigned long)rates[i];
+
+                       /* This will happen for frequencies > 4.29 GHz */
+                       WARN_ON(new_opp->rates[i] != rates[i]);
+               }
+       }
+
+       kfree(rates);
+
+       return ret;
+}
+
+static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *opp_table,
                    struct device_node *np, bool peak)
 {
        const char *name = peak ? "opp-peak-kBps" : "opp-avg-kBps";
@@ -780,9 +830,9 @@ static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table,
                return -ENODEV;
 
        count = prop->length / sizeof(u32);
-       if (table->path_count != count) {
+       if (opp_table->path_count != count) {
                pr_err("%s: Mismatch between %s and paths (%d %d)\n",
-                               __func__, name, count, table->path_count);
+                               __func__, name, count, opp_table->path_count);
                return -EINVAL;
        }
 
@@ -808,34 +858,27 @@ out:
        return ret;
 }
 
-static int _read_opp_key(struct dev_pm_opp *new_opp, struct opp_table *table,
-                        struct device_node *np, bool *rate_not_available)
+static int _read_opp_key(struct dev_pm_opp *new_opp,
+                        struct opp_table *opp_table, struct device_node *np)
 {
        bool found = false;
-       u64 rate;
        int ret;
 
-       ret = of_property_read_u64(np, "opp-hz", &rate);
-       if (!ret) {
-               /*
-                * Rate is defined as an unsigned long in clk API, and so
-                * casting explicitly to its type. Must be fixed once rate is 64
-                * bit guaranteed in clk API.
-                */
-               new_opp->rate = (unsigned long)rate;
+       ret = _read_rate(new_opp, opp_table, np);
+       if (!ret)
                found = true;
-       }
-       *rate_not_available = !!ret;
+       else if (ret != -ENODEV)
+               return ret;
 
        /*
         * Bandwidth consists of peak and average (optional) values:
         * opp-peak-kBps = <path1_value path2_value>;
         * opp-avg-kBps = <path1_value path2_value>;
         */
-       ret = _read_bw(new_opp, table, np, true);
+       ret = _read_bw(new_opp, opp_table, np, true);
        if (!ret) {
                found = true;
-               ret = _read_bw(new_opp, table, np, false);
+               ret = _read_bw(new_opp, opp_table, np, false);
        }
 
        /* The properties were found but we failed to parse them */
@@ -881,13 +924,12 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
        struct dev_pm_opp *new_opp;
        u32 val;
        int ret;
-       bool rate_not_available = false;
 
        new_opp = _opp_allocate(opp_table);
        if (!new_opp)
                return ERR_PTR(-ENOMEM);
 
-       ret = _read_opp_key(new_opp, opp_table, np, &rate_not_available);
+       ret = _read_opp_key(new_opp, opp_table, np);
        if (ret < 0) {
                dev_err(dev, "%s: opp key field not found\n", __func__);
                goto free_opp;
@@ -895,14 +937,14 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
 
        /* Check if the OPP supports hardware's hierarchy of versions or not */
        if (!_opp_is_supported(dev, opp_table, np)) {
-               dev_dbg(dev, "OPP not supported by hardware: %lu\n",
-                       new_opp->rate);
+               dev_dbg(dev, "OPP not supported by hardware: %s\n",
+                       of_node_full_name(np));
                goto free_opp;
        }
 
        new_opp->turbo = of_property_read_bool(np, "turbo-mode");
 
-       new_opp->np = np;
+       new_opp->np = of_node_get(np);
        new_opp->dynamic = false;
        new_opp->available = true;
 
@@ -920,7 +962,7 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
        if (opp_table->is_genpd)
                new_opp->pstate = pm_genpd_opp_to_performance_state(dev, new_opp);
 
-       ret = _opp_add(dev, new_opp, opp_table, rate_not_available);
+       ret = _opp_add(dev, new_opp, opp_table);
        if (ret) {
                /* Don't return error for duplicate OPPs */
                if (ret == -EBUSY)
@@ -931,8 +973,8 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
        /* OPP to select on device suspend */
        if (of_property_read_bool(np, "opp-suspend")) {
                if (opp_table->suspend_opp) {
-                       /* Pick the OPP with higher rate as suspend OPP */
-                       if (new_opp->rate > opp_table->suspend_opp->rate) {
+                       /* Pick the OPP with higher rate/bw/level as suspend OPP */
+                       if (_opp_compare_key(opp_table, new_opp, opp_table->suspend_opp) == 1) {
                                opp_table->suspend_opp->suspend = false;
                                new_opp->suspend = true;
                                opp_table->suspend_opp = new_opp;
@@ -947,7 +989,7 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
                opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
 
        pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu level:%u\n",
-                __func__, new_opp->turbo, new_opp->rate,
+                __func__, new_opp->turbo, new_opp->rates[0],
                 new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
                 new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns,
                 new_opp->level);
@@ -1084,7 +1126,7 @@ remove_static_opp:
        return ret;
 }
 
-static int _of_add_table_indexed(struct device *dev, int index, bool getclk)
+static int _of_add_table_indexed(struct device *dev, int index)
 {
        struct opp_table *opp_table;
        int ret, count;
@@ -1100,7 +1142,7 @@ static int _of_add_table_indexed(struct device *dev, int index, bool getclk)
                        index = 0;
        }
 
-       opp_table = _add_opp_table_indexed(dev, index, getclk);
+       opp_table = _add_opp_table_indexed(dev, index, true);
        if (IS_ERR(opp_table))
                return PTR_ERR(opp_table);
 
@@ -1124,11 +1166,11 @@ static void devm_pm_opp_of_table_release(void *data)
        dev_pm_opp_of_remove_table(data);
 }
 
-static int _devm_of_add_table_indexed(struct device *dev, int index, bool getclk)
+static int _devm_of_add_table_indexed(struct device *dev, int index)
 {
        int ret;
 
-       ret = _of_add_table_indexed(dev, index, getclk);
+       ret = _of_add_table_indexed(dev, index);
        if (ret)
                return ret;
 
@@ -1156,7 +1198,7 @@ static int _devm_of_add_table_indexed(struct device *dev, int index, bool getclk
  */
 int devm_pm_opp_of_add_table(struct device *dev)
 {
-       return _devm_of_add_table_indexed(dev, 0, true);
+       return _devm_of_add_table_indexed(dev, 0);
 }
 EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table);
 
@@ -1179,7 +1221,7 @@ EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table);
  */
 int dev_pm_opp_of_add_table(struct device *dev)
 {
-       return _of_add_table_indexed(dev, 0, true);
+       return _of_add_table_indexed(dev, 0);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
 
@@ -1195,7 +1237,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
  */
 int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
 {
-       return _of_add_table_indexed(dev, index, true);
+       return _of_add_table_indexed(dev, index);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
 
@@ -1208,42 +1250,10 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
  */
 int devm_pm_opp_of_add_table_indexed(struct device *dev, int index)
 {
-       return _devm_of_add_table_indexed(dev, index, true);
+       return _devm_of_add_table_indexed(dev, index);
 }
 EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_indexed);
 
-/**
- * dev_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device
- *             tree without getting clk for device.
- * @dev:       device pointer used to lookup OPP table.
- * @index:     Index number.
- *
- * Register the initial OPP table with the OPP library for given device only
- * using the "operating-points-v2" property. Do not try to get the clk for the
- * device.
- *
- * Return: Refer to dev_pm_opp_of_add_table() for return values.
- */
-int dev_pm_opp_of_add_table_noclk(struct device *dev, int index)
-{
-       return _of_add_table_indexed(dev, index, false);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_noclk);
-
-/**
- * devm_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device
- *             tree without getting clk for device.
- * @dev:       device pointer used to lookup OPP table.
- * @index:     Index number.
- *
- * This is a resource-managed variant of dev_pm_opp_of_add_table_noclk().
- */
-int devm_pm_opp_of_add_table_noclk(struct device *dev, int index)
-{
-       return _devm_of_add_table_indexed(dev, index, false);
-}
-EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_noclk);
-
 /* CPU device specific helpers */
 
 /**
index 45e3a55..3a6e077 100644 (file)
@@ -28,6 +28,27 @@ extern struct mutex opp_table_lock;
 
 extern struct list_head opp_tables, lazy_opp_tables;
 
+/* OPP Config flags */
+#define OPP_CONFIG_CLK                 BIT(0)
+#define OPP_CONFIG_REGULATOR           BIT(1)
+#define OPP_CONFIG_REGULATOR_HELPER    BIT(2)
+#define OPP_CONFIG_PROP_NAME           BIT(3)
+#define OPP_CONFIG_SUPPORTED_HW                BIT(4)
+#define OPP_CONFIG_GENPD               BIT(5)
+
+/**
+ * struct opp_config_data - data for set config operations
+ * @opp_table: OPP table
+ * @flags: OPP config flags
+ *
+ * This structure stores the OPP config information for each OPP table
+ * configuration by the callers.
+ */
+struct opp_config_data {
+       struct opp_table *opp_table;
+       unsigned int flags;
+};
+
 /*
  * Internal data structure organization with the OPP layer library is as
  * follows:
@@ -58,7 +79,7 @@ extern struct list_head opp_tables, lazy_opp_tables;
  * @suspend:   true if suspend OPP
  * @removed:   flag indicating that OPP's reference is dropped by OPP core.
  * @pstate: Device's power domain's performance state.
- * @rate:      Frequency in hertz
+ * @rates:     Frequencies in hertz
  * @level:     Performance level
  * @supplies:  Power supplies voltage/current values
  * @bandwidth: Interconnect bandwidth values
@@ -81,7 +102,7 @@ struct dev_pm_opp {
        bool suspend;
        bool removed;
        unsigned int pstate;
-       unsigned long rate;
+       unsigned long *rates;
        unsigned int level;
 
        struct dev_pm_opp_supply *supplies;
@@ -138,7 +159,7 @@ enum opp_table_access {
  * @clock_latency_ns_max: Max clock latency in nanoseconds.
  * @parsed_static_opps: Count of devices for which OPPs are initialized from DT.
  * @shared_opp: OPP is shared between multiple devices.
- * @current_rate: Currently configured frequency.
+ * @rate_clk_single: Currently configured frequency for single clk.
  * @current_opp: Currently configured OPP for the table.
  * @suspend_opp: Pointer to OPP to be used during device suspend.
  * @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers.
@@ -149,7 +170,11 @@ enum opp_table_access {
  * @supported_hw: Array of version number to support.
  * @supported_hw_count: Number of elements in supported_hw array.
  * @prop_name: A name to postfix to many DT properties, while parsing them.
- * @clk: Device's clock handle
+ * @config_clks: Platform specific config_clks() callback.
+ * @clks: Device's clock handles, for multiple clocks.
+ * @clk: Device's clock handle, for single clock.
+ * @clk_count: Number of clocks.
+ * @config_regulators: Platform specific config_regulators() callback.
  * @regulators: Supply regulators
  * @regulator_count: Number of power supply regulators. Its value can be -1
  * (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt
@@ -159,9 +184,6 @@ enum opp_table_access {
  * @enabled: Set to true if the device's resources are enabled/configured.
  * @genpd_performance_state: Device's power domain support performance state.
  * @is_genpd: Marks if the OPP table belongs to a genpd.
- * @set_opp: Platform specific set_opp callback
- * @sod_supplies: Set opp data supplies
- * @set_opp_data: Data to be passed to set_opp callback
  * @dentry:    debugfs dentry pointer of the real device directory (not links).
  * @dentry_name: Name of the real dentry.
  *
@@ -188,7 +210,7 @@ struct opp_table {
 
        unsigned int parsed_static_opps;
        enum opp_table_access shared_opp;
-       unsigned long current_rate;
+       unsigned long rate_clk_single;
        struct dev_pm_opp *current_opp;
        struct dev_pm_opp *suspend_opp;
 
@@ -200,7 +222,11 @@ struct opp_table {
        unsigned int *supported_hw;
        unsigned int supported_hw_count;
        const char *prop_name;
+       config_clks_t config_clks;
+       struct clk **clks;
        struct clk *clk;
+       int clk_count;
+       config_regulators_t config_regulators;
        struct regulator **regulators;
        int regulator_count;
        struct icc_path **paths;
@@ -209,10 +235,6 @@ struct opp_table {
        bool genpd_performance_state;
        bool is_genpd;
 
-       int (*set_opp)(struct dev_pm_set_opp_data *data);
-       struct dev_pm_opp_supply *sod_supplies;
-       struct dev_pm_set_opp_data *set_opp_data;
-
 #ifdef CONFIG_DEBUG_FS
        struct dentry *dentry;
        char dentry_name[NAME_MAX];
@@ -228,8 +250,8 @@ struct opp_table *_find_opp_table(struct device *dev);
 struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
 struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
 void _opp_free(struct dev_pm_opp *opp);
-int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
-int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
+int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
+int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
 int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
 void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);
 struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);
@@ -245,14 +267,12 @@ static inline bool lazy_linking_pending(struct opp_table *opp_table)
 void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);
 void _of_clear_opp_table(struct opp_table *opp_table);
 struct opp_table *_managed_opp(struct device *dev, int index);
-void _of_opp_free_required_opps(struct opp_table *opp_table,
-                               struct dev_pm_opp *opp);
+void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp);
 #else
 static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {}
 static inline void _of_clear_opp_table(struct opp_table *opp_table) {}
 static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; }
-static inline void _of_opp_free_required_opps(struct opp_table *opp_table,
-                                             struct dev_pm_opp *opp) {}
+static inline void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp) {}
 #endif
 
 #ifdef CONFIG_DEBUG_FS
index bd4771f..8f3f13f 100644 (file)
@@ -36,11 +36,15 @@ struct ti_opp_supply_optimum_voltage_table {
  * @vdd_table: Optimized voltage mapping table
  * @num_vdd_table: number of entries in vdd_table
  * @vdd_absolute_max_voltage_uv: absolute maximum voltage in UV for the supply
+ * @old_supplies: Placeholder for supplies information for old OPP.
+ * @new_supplies: Placeholder for supplies information for new OPP.
  */
 struct ti_opp_supply_data {
        struct ti_opp_supply_optimum_voltage_table *vdd_table;
        u32 num_vdd_table;
        u32 vdd_absolute_max_voltage_uv;
+       struct dev_pm_opp_supply old_supplies[2];
+       struct dev_pm_opp_supply new_supplies[2];
 };
 
 static struct ti_opp_supply_data opp_data;
@@ -266,27 +270,32 @@ static int _opp_set_voltage(struct device *dev,
        return 0;
 }
 
-/**
- * ti_opp_supply_set_opp() - do the opp supply transition
- * @data:      information on regulators and new and old opps provided by
- *             opp core to use in transition
- *
- * Return: If successful, 0, else appropriate error value.
- */
-static int ti_opp_supply_set_opp(struct dev_pm_set_opp_data *data)
+/* Do the opp supply transition */
+static int ti_opp_config_regulators(struct device *dev,
+                       struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
+                       struct regulator **regulators, unsigned int count)
 {
-       struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
-       struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1];
-       struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
-       struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1];
-       struct device *dev = data->dev;
-       unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
-       struct clk *clk = data->clk;
-       struct regulator *vdd_reg = data->regulators[0];
-       struct regulator *vbb_reg = data->regulators[1];
+       struct dev_pm_opp_supply *old_supply_vdd = &opp_data.old_supplies[0];
+       struct dev_pm_opp_supply *old_supply_vbb = &opp_data.old_supplies[1];
+       struct dev_pm_opp_supply *new_supply_vdd = &opp_data.new_supplies[0];
+       struct dev_pm_opp_supply *new_supply_vbb = &opp_data.new_supplies[1];
+       struct regulator *vdd_reg = regulators[0];
+       struct regulator *vbb_reg = regulators[1];
+       unsigned long old_freq, freq;
        int vdd_uv;
        int ret;
 
+       /* We must have two regulators here */
+       WARN_ON(count != 2);
+
+       /* Fetch supplies and freq information from OPP core */
+       ret = dev_pm_opp_get_supplies(new_opp, opp_data.new_supplies);
+       WARN_ON(ret);
+
+       old_freq = dev_pm_opp_get_freq(old_opp);
+       freq = dev_pm_opp_get_freq(new_opp);
+       WARN_ON(!old_freq || !freq);
+
        vdd_uv = _get_optimal_vdd_voltage(dev, &opp_data,
                                          new_supply_vdd->u_volt);
 
@@ -303,39 +312,24 @@ static int ti_opp_supply_set_opp(struct dev_pm_set_opp_data *data)
                ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
                if (ret)
                        goto restore_voltage;
-       }
-
-       /* Change frequency */
-       dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
-               __func__, old_freq, freq);
-
-       ret = clk_set_rate(clk, freq);
-       if (ret) {
-               dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
-                       ret);
-               goto restore_voltage;
-       }
-
-       /* Scaling down? Scale voltage after frequency */
-       if (freq < old_freq) {
+       } else {
                ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
                if (ret)
-                       goto restore_freq;
+                       goto restore_voltage;
 
                ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
                                       "vdd");
                if (ret)
-                       goto restore_freq;
+                       goto restore_voltage;
        }
 
        return 0;
 
-restore_freq:
-       ret = clk_set_rate(clk, old_freq);
-       if (ret)
-               dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
-                       __func__, old_freq);
 restore_voltage:
+       /* Fetch old supplies information only if required */
+       ret = dev_pm_opp_get_supplies(old_opp, opp_data.old_supplies);
+       WARN_ON(ret);
+
        /* This shouldn't harm even if the voltages weren't updated earlier */
        if (old_supply_vdd->u_volt) {
                ret = _opp_set_voltage(dev, old_supply_vbb, 0, vbb_reg, "vbb");
@@ -405,9 +399,8 @@ static int ti_opp_supply_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       ret = PTR_ERR_OR_ZERO(dev_pm_opp_register_set_opp_helper(cpu_dev,
-                                                                ti_opp_supply_set_opp));
-       if (ret)
+       ret = dev_pm_opp_set_config_regulators(cpu_dev, ti_opp_config_regulators);
+       if (ret < 0)
                _free_optimized_voltages(dev, &opp_data);
 
        return ret;
index 5cc7cba..55c028a 100644 (file)
@@ -121,6 +121,9 @@ config XEN_PCIDEV_FRONTEND
 config PCI_ATS
        bool
 
+config PCI_DOE
+       bool
+
 config PCI_ECAM
        bool
 
index 0da6b1e..2680e4c 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_PCI_ECAM)                += ecam.o
 obj-$(CONFIG_PCI_P2PDMA)       += p2pdma.o
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
 obj-$(CONFIG_VGA_ARB)          += vgaarb.o
+obj-$(CONFIG_PCI_DOE)          += doe.o
 
 # Endpoint library must be initialized before its users
 obj-$(CONFIG_PCI_ENDPOINT)     += endpoint/
diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c
new file mode 100644 (file)
index 0000000..e402f05
--- /dev/null
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Data Object Exchange
+ *     PCIe r6.0, sec 6.30 DOE
+ *
+ * Copyright (C) 2021 Huawei
+ *     Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ *
+ * Copyright (C) 2022 Intel Corporation
+ *     Ira Weiny <ira.weiny@intel.com>
+ */
+
+#define dev_fmt(fmt) "DOE: " fmt
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/pci-doe.h>
+#include <linux/workqueue.h>
+
+#define PCI_DOE_PROTOCOL_DISCOVERY 0
+
+/* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */
+#define PCI_DOE_TIMEOUT HZ
+#define PCI_DOE_POLL_INTERVAL  (PCI_DOE_TIMEOUT / 128)
+
+#define PCI_DOE_FLAG_CANCEL    0
+#define PCI_DOE_FLAG_DEAD      1
+
+/**
+ * struct pci_doe_mb - State for a single DOE mailbox
+ *
+ * This state is used to manage a single DOE mailbox capability.  All fields
+ * should be considered opaque to the consumers and the structure passed into
+ * the helpers below after being created by devm_pci_doe_create()
+ *
+ * @pdev: PCI device this mailbox belongs to
+ * @cap_offset: Capability offset
+ * @prots: Array of protocols supported (encoded as long values)
+ * @wq: Wait queue for work item
+ * @work_queue: Queue of pci_doe_work items
+ * @flags: Bit array of PCI_DOE_FLAG_* flags
+ */
+struct pci_doe_mb {
+       struct pci_dev *pdev;
+       u16 cap_offset;
+       struct xarray prots;
+
+       wait_queue_head_t wq;
+       struct workqueue_struct *work_queue;
+       unsigned long flags;
+};
+
+static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout)
+{
+       if (wait_event_timeout(doe_mb->wq,
+                              test_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags),
+                              timeout))
+               return -EIO;
+       return 0;
+}
+
+static void pci_doe_write_ctrl(struct pci_doe_mb *doe_mb, u32 val)
+{
+       struct pci_dev *pdev = doe_mb->pdev;
+       int offset = doe_mb->cap_offset;
+
+       pci_write_config_dword(pdev, offset + PCI_DOE_CTRL, val);
+}
+
+static int pci_doe_abort(struct pci_doe_mb *doe_mb)
+{
+       struct pci_dev *pdev = doe_mb->pdev;
+       int offset = doe_mb->cap_offset;
+       unsigned long timeout_jiffies;
+
+       pci_dbg(pdev, "[%x] Issuing Abort\n", offset);
+
+       timeout_jiffies = jiffies + PCI_DOE_TIMEOUT;
+       pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_ABORT);
+
+       do {
+               int rc;
+               u32 val;
+
+               rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL);
+               if (rc)
+                       return rc;
+               pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+
+               /* Abort success! */
+               if (!FIELD_GET(PCI_DOE_STATUS_ERROR, val) &&
+                   !FIELD_GET(PCI_DOE_STATUS_BUSY, val))
+                       return 0;
+
+       } while (!time_after(jiffies, timeout_jiffies));
+
+       /* Abort has timed out and the MB is dead */
+       pci_err(pdev, "[%x] ABORT timed out\n", offset);
+       return -EIO;
+}
+
+static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
+                           struct pci_doe_task *task)
+{
+       struct pci_dev *pdev = doe_mb->pdev;
+       int offset = doe_mb->cap_offset;
+       u32 val;
+       int i;
+
+       /*
+        * Check the DOE busy bit is not set. If it is set, this could indicate
+        * someone other than Linux (e.g. firmware) is using the mailbox. Note
+        * it is expected that firmware and OS will negotiate access rights via
+        * an, as yet to be defined, method.
+        */
+       pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+       if (FIELD_GET(PCI_DOE_STATUS_BUSY, val))
+               return -EBUSY;
+
+       if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
+               return -EIO;
+
+       /* Write DOE Header */
+       val = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_VID, task->prot.vid) |
+               FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, task->prot.type);
+       pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val);
+       /* Length is 2 DW of header + length of payload in DW */
+       pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
+                              FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH,
+                                         2 + task->request_pl_sz /
+                                               sizeof(u32)));
+       for (i = 0; i < task->request_pl_sz / sizeof(u32); i++)
+               pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
+                                      task->request_pl[i]);
+
+       pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO);
+
+       return 0;
+}
+
+static bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb)
+{
+       struct pci_dev *pdev = doe_mb->pdev;
+       int offset = doe_mb->cap_offset;
+       u32 val;
+
+       pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+       if (FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val))
+               return true;
+       return false;
+}
+
+static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task)
+{
+       struct pci_dev *pdev = doe_mb->pdev;
+       int offset = doe_mb->cap_offset;
+       size_t length, payload_length;
+       u32 val;
+       int i;
+
+       /* Read the first dword to get the protocol */
+       pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
+       if ((FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val) != task->prot.vid) ||
+           (FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val) != task->prot.type)) {
+               dev_err_ratelimited(&pdev->dev, "[%x] expected [VID, Protocol] = [%04x, %02x], got [%04x, %02x]\n",
+                                   doe_mb->cap_offset, task->prot.vid, task->prot.type,
+                                   FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val),
+                                   FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val));
+               return -EIO;
+       }
+
+       pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
+       /* Read the second dword to get the length */
+       pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
+       pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
+
+       length = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, val);
+       if (length > SZ_1M || length < 2)
+               return -EIO;
+
+       /* First 2 dwords have already been read */
+       length -= 2;
+       payload_length = min(length, task->response_pl_sz / sizeof(u32));
+       /* Read the rest of the response payload */
+       for (i = 0; i < payload_length; i++) {
+               pci_read_config_dword(pdev, offset + PCI_DOE_READ,
+                                     &task->response_pl[i]);
+               /* Prior to the last ack, ensure Data Object Ready */
+               if (i == (payload_length - 1) && !pci_doe_data_obj_ready(doe_mb))
+                       return -EIO;
+               pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
+       }
+
+       /* Flush excess length */
+       for (; i < length; i++) {
+               pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
+               pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
+       }
+
+       /* Final error check to pick up on any since Data Object Ready */
+       pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+       if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
+               return -EIO;
+
+       return min(length, task->response_pl_sz / sizeof(u32)) * sizeof(u32);
+}
+
+static void signal_task_complete(struct pci_doe_task *task, int rv)
+{
+       task->rv = rv;
+       task->complete(task);
+}
+
+static void signal_task_abort(struct pci_doe_task *task, int rv)
+{
+       struct pci_doe_mb *doe_mb = task->doe_mb;
+       struct pci_dev *pdev = doe_mb->pdev;
+
+       if (pci_doe_abort(doe_mb)) {
+               /*
+                * If the device can't process an abort; set the mailbox dead
+                *      - no more submissions
+                */
+               pci_err(pdev, "[%x] Abort failed marking mailbox dead\n",
+                       doe_mb->cap_offset);
+               set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags);
+       }
+       signal_task_complete(task, rv);
+}
+
+static void doe_statemachine_work(struct work_struct *work)
+{
+       struct pci_doe_task *task = container_of(work, struct pci_doe_task,
+                                                work);
+       struct pci_doe_mb *doe_mb = task->doe_mb;
+       struct pci_dev *pdev = doe_mb->pdev;
+       int offset = doe_mb->cap_offset;
+       unsigned long timeout_jiffies;
+       u32 val;
+       int rc;
+
+       if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) {
+               signal_task_complete(task, -EIO);
+               return;
+       }
+
+       /* Send request */
+       rc = pci_doe_send_req(doe_mb, task);
+       if (rc) {
+               /*
+                * The specification does not provide any guidance on how to
+                * resolve conflicting requests from other entities.
+                * Furthermore, it is likely that busy will not be detected
+                * most of the time.  Flag any detection of status busy with an
+                * error.
+                */
+               if (rc == -EBUSY)
+                       dev_err_ratelimited(&pdev->dev, "[%x] busy detected; another entity is sending conflicting requests\n",
+                                           offset);
+               signal_task_abort(task, rc);
+               return;
+       }
+
+       timeout_jiffies = jiffies + PCI_DOE_TIMEOUT;
+       /* Poll for response */
+retry_resp:
+       pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+       if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) {
+               signal_task_abort(task, -EIO);
+               return;
+       }
+
+       if (!FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val)) {
+               if (time_after(jiffies, timeout_jiffies)) {
+                       signal_task_abort(task, -EIO);
+                       return;
+               }
+               rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL);
+               if (rc) {
+                       signal_task_abort(task, rc);
+                       return;
+               }
+               goto retry_resp;
+       }
+
+       rc  = pci_doe_recv_resp(doe_mb, task);
+       if (rc < 0) {
+               signal_task_abort(task, rc);
+               return;
+       }
+
+       signal_task_complete(task, rc);
+}
+
+static void pci_doe_task_complete(struct pci_doe_task *task)
+{
+       complete(task->private);
+}
+
+static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid,
+                            u8 *protocol)
+{
+       u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX,
+                                   *index);
+       u32 response_pl;
+       DECLARE_COMPLETION_ONSTACK(c);
+       struct pci_doe_task task = {
+               .prot.vid = PCI_VENDOR_ID_PCI_SIG,
+               .prot.type = PCI_DOE_PROTOCOL_DISCOVERY,
+               .request_pl = &request_pl,
+               .request_pl_sz = sizeof(request_pl),
+               .response_pl = &response_pl,
+               .response_pl_sz = sizeof(response_pl),
+               .complete = pci_doe_task_complete,
+               .private = &c,
+       };
+       int rc;
+
+       rc = pci_doe_submit_task(doe_mb, &task);
+       if (rc < 0)
+               return rc;
+
+       wait_for_completion(&c);
+
+       if (task.rv != sizeof(response_pl))
+               return -EIO;
+
+       *vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl);
+       *protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL,
+                             response_pl);
+       *index = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX,
+                          response_pl);
+
+       return 0;
+}
+
+static void *pci_doe_xa_prot_entry(u16 vid, u8 prot)
+{
+       return xa_mk_value((vid << 8) | prot);
+}
+
+static int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb)
+{
+       u8 index = 0;
+       u8 xa_idx = 0;
+
+       do {
+               int rc;
+               u16 vid;
+               u8 prot;
+
+               rc = pci_doe_discovery(doe_mb, &index, &vid, &prot);
+               if (rc)
+                       return rc;
+
+               pci_dbg(doe_mb->pdev,
+                       "[%x] Found protocol %d vid: %x prot: %x\n",
+                       doe_mb->cap_offset, xa_idx, vid, prot);
+
+               rc = xa_insert(&doe_mb->prots, xa_idx++,
+                              pci_doe_xa_prot_entry(vid, prot), GFP_KERNEL);
+               if (rc)
+                       return rc;
+       } while (index);
+
+       return 0;
+}
+
+static void pci_doe_xa_destroy(void *mb)
+{
+       struct pci_doe_mb *doe_mb = mb;
+
+       xa_destroy(&doe_mb->prots);
+}
+
+static void pci_doe_destroy_workqueue(void *mb)
+{
+       struct pci_doe_mb *doe_mb = mb;
+
+       destroy_workqueue(doe_mb->work_queue);
+}
+
+static void pci_doe_flush_mb(void *mb)
+{
+       struct pci_doe_mb *doe_mb = mb;
+
+       /* Stop all pending work items from starting */
+       set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags);
+
+       /* Cancel an in progress work item, if necessary */
+       set_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags);
+       wake_up(&doe_mb->wq);
+
+       /* Flush all work items */
+       flush_workqueue(doe_mb->work_queue);
+}
+
+/**
+ * pcim_doe_create_mb() - Create a DOE mailbox object
+ *
+ * @pdev: PCI device to create the DOE mailbox for
+ * @cap_offset: Offset of the DOE mailbox
+ *
+ * Create a single mailbox object to manage the mailbox protocol at the
+ * cap_offset specified.
+ *
+ * RETURNS: created mailbox object on success
+ *         ERR_PTR(-errno) on failure
+ */
+struct pci_doe_mb *pcim_doe_create_mb(struct pci_dev *pdev, u16 cap_offset)
+{
+       struct pci_doe_mb *doe_mb;
+       struct device *dev = &pdev->dev;
+       int rc;
+
+       doe_mb = devm_kzalloc(dev, sizeof(*doe_mb), GFP_KERNEL);
+       if (!doe_mb)
+               return ERR_PTR(-ENOMEM);
+
+       doe_mb->pdev = pdev;
+       doe_mb->cap_offset = cap_offset;
+       init_waitqueue_head(&doe_mb->wq);
+
+       xa_init(&doe_mb->prots);
+       rc = devm_add_action(dev, pci_doe_xa_destroy, doe_mb);
+       if (rc)
+               return ERR_PTR(rc);
+
+       doe_mb->work_queue = alloc_ordered_workqueue("%s %s DOE [%x]", 0,
+                                               dev_driver_string(&pdev->dev),
+                                               pci_name(pdev),
+                                               doe_mb->cap_offset);
+       if (!doe_mb->work_queue) {
+               pci_err(pdev, "[%x] failed to allocate work queue\n",
+                       doe_mb->cap_offset);
+               return ERR_PTR(-ENOMEM);
+       }
+       rc = devm_add_action_or_reset(dev, pci_doe_destroy_workqueue, doe_mb);
+       if (rc)
+               return ERR_PTR(rc);
+
+       /* Reset the mailbox by issuing an abort */
+       rc = pci_doe_abort(doe_mb);
+       if (rc) {
+               pci_err(pdev, "[%x] failed to reset mailbox with abort command : %d\n",
+                       doe_mb->cap_offset, rc);
+               return ERR_PTR(rc);
+       }
+
+       /*
+        * The state machine and the mailbox should be in sync now;
+        * Set up mailbox flush prior to using the mailbox to query protocols.
+        */
+       rc = devm_add_action_or_reset(dev, pci_doe_flush_mb, doe_mb);
+       if (rc)
+               return ERR_PTR(rc);
+
+       rc = pci_doe_cache_protocols(doe_mb);
+       if (rc) {
+               pci_err(pdev, "[%x] failed to cache protocols : %d\n",
+                       doe_mb->cap_offset, rc);
+               return ERR_PTR(rc);
+       }
+
+       return doe_mb;
+}
+EXPORT_SYMBOL_GPL(pcim_doe_create_mb);
+
+/**
+ * pci_doe_supports_prot() - Return if the DOE instance supports the given
+ *                          protocol
+ * @doe_mb: DOE mailbox capability to query
+ * @vid: Protocol Vendor ID
+ * @type: Protocol type
+ *
+ * RETURNS: True if the DOE mailbox supports the protocol specified
+ */
+bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type)
+{
+       unsigned long index;
+       void *entry;
+
+       /* The discovery protocol must always be supported */
+       if (vid == PCI_VENDOR_ID_PCI_SIG && type == PCI_DOE_PROTOCOL_DISCOVERY)
+               return true;
+
+       xa_for_each(&doe_mb->prots, index, entry)
+               if (entry == pci_doe_xa_prot_entry(vid, type))
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(pci_doe_supports_prot);
+
+/**
+ * pci_doe_submit_task() - Submit a task to be processed by the state machine
+ *
+ * @doe_mb: DOE mailbox capability to submit to
+ * @task: task to be queued
+ *
+ * Submit a DOE task (request/response) to the DOE mailbox to be processed.
+ * Returns upon queueing the task object.  If the queue is full this function
+ * will sleep until there is room in the queue.
+ *
+ * task->complete will be called when the state machine is done processing this
+ * task.
+ *
+ * Excess data will be discarded.
+ *
+ * RETURNS: 0 when task has been successfully queued, -ERRNO on error
+ */
+int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task)
+{
+       if (!pci_doe_supports_prot(doe_mb, task->prot.vid, task->prot.type))
+               return -EINVAL;
+
+       /*
+        * DOE requests must be a whole number of DW and the response needs to
+        * be big enough for at least 1 DW
+        */
+       if (task->request_pl_sz % sizeof(u32) ||
+           task->response_pl_sz < sizeof(u32))
+               return -EINVAL;
+
+       if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags))
+               return -EIO;
+
+       task->doe_mb = doe_mb;
+       INIT_WORK(&task->work, doe_statemachine_work);
+       queue_work(doe_mb->work_queue, &task->work);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pci_doe_submit_task);
index 9884d8b..c5286b0 100644 (file)
@@ -2315,7 +2315,7 @@ EXPORT_SYMBOL(pci_alloc_dev);
 
 static bool pci_bus_crs_vendor_id(u32 l)
 {
-       return (l & 0xffff) == 0x0001;
+       return (l & 0xffff) == PCI_VENDOR_ID_PCI_SIG;
 }
 
 static bool pci_bus_wait_crs(struct pci_bus *bus, int devfn, u32 *l,
index bff144c..1cf74b0 100644 (file)
@@ -311,7 +311,7 @@ config PINCTRL_MICROCHIP_SGPIO
          LED controller.
 
 config PINCTRL_OCELOT
-       bool "Pinctrl driver for the Microsemi Ocelot and Jaguar2 SoCs"
+       tristate "Pinctrl driver for the Microsemi Ocelot and Jaguar2 SoCs"
        depends on OF
        depends on HAS_IOMEM
        select GPIOLIB
index 4d75486..aaa78a6 100644 (file)
@@ -632,7 +632,7 @@ struct aspeed_pin_desc {
        SIG_EXPR_LIST_ALIAS(pin, sig, group)
 
 /**
- * Similar to the above, but for pins with a dual expressions (DE) and
+ * Similar to the above, but for pins with a dual expressions (DE)
  * and a single group (SG) of pins.
  *
  * @pin: The pin the signal will be routed to
index dad4530..7857e61 100644 (file)
@@ -507,7 +507,7 @@ static void bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
        }
 }
 
-static void bcm2835_gpio_irq_enable(struct irq_data *data)
+static void bcm2835_gpio_irq_unmask(struct irq_data *data)
 {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
@@ -516,13 +516,15 @@ static void bcm2835_gpio_irq_enable(struct irq_data *data)
        unsigned bank = GPIO_REG_OFFSET(gpio);
        unsigned long flags;
 
+       gpiochip_enable_irq(chip, gpio);
+
        raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
        set_bit(offset, &pc->enabled_irq_map[bank]);
        bcm2835_gpio_irq_config(pc, gpio, true);
        raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
 }
 
-static void bcm2835_gpio_irq_disable(struct irq_data *data)
+static void bcm2835_gpio_irq_mask(struct irq_data *data)
 {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
@@ -537,6 +539,8 @@ static void bcm2835_gpio_irq_disable(struct irq_data *data)
        bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
        clear_bit(offset, &pc->enabled_irq_map[bank]);
        raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
+
+       gpiochip_disable_irq(chip, gpio);
 }
 
 static int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc,
@@ -693,16 +697,15 @@ static int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
        return ret;
 }
 
-static struct irq_chip bcm2835_gpio_irq_chip = {
+static const struct irq_chip bcm2835_gpio_irq_chip = {
        .name = MODULE_NAME,
-       .irq_enable = bcm2835_gpio_irq_enable,
-       .irq_disable = bcm2835_gpio_irq_disable,
        .irq_set_type = bcm2835_gpio_irq_set_type,
        .irq_ack = bcm2835_gpio_irq_ack,
-       .irq_mask = bcm2835_gpio_irq_disable,
-       .irq_unmask = bcm2835_gpio_irq_enable,
+       .irq_mask = bcm2835_gpio_irq_mask,
+       .irq_unmask = bcm2835_gpio_irq_unmask,
        .irq_set_wake = bcm2835_gpio_irq_set_wake,
-       .flags = IRQCHIP_MASK_ON_SUSPEND,
+       .flags = (IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE),
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
 static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev)
@@ -1280,7 +1283,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
        pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
 
        girq = &pc->gpio_chip.irq;
-       girq->chip = &bcm2835_gpio_irq_chip;
+       gpio_irq_chip_set_chip(girq, &bcm2835_gpio_irq_chip);
        girq->parent_handler = bcm2835_gpio_irq_handler;
        girq->num_parents = BCM2835_NUM_IRQS;
        girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
index ffe3933..9e57f4c 100644 (file)
@@ -126,7 +126,7 @@ struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
        mutex_lock(&pinctrldev_list_mutex);
 
        list_for_each_entry(pctldev, &pinctrldev_list, node)
-               if (pctldev->dev->of_node == np) {
+               if (device_match_of_node(pctldev->dev, np)) {
                        mutex_unlock(&pinctrldev_list_mutex);
                        return pctldev;
                }
index 417e41b..91b3ee1 100644 (file)
@@ -247,6 +247,7 @@ static const struct of_device_id imx93_pinctrl_of_match[] = {
        { .compatible = "fsl,imx93-iomuxc", },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, imx93_pinctrl_of_match);
 
 static int imx93_pinctrl_probe(struct platform_device *pdev)
 {
index e5ec8b8..078eec8 100644 (file)
@@ -151,6 +151,14 @@ config PINCTRL_LEWISBURG
          This pinctrl driver provides an interface that allows configuring
          of Intel Lewisburg pins and using them as GPIOs.
 
+config PINCTRL_METEORLAKE
+       tristate "Intel Meteor Lake pinctrl and GPIO driver"
+       depends on ACPI
+       select PINCTRL_INTEL
+       help
+         This pinctrl driver provides an interface that allows configuring
+         of Intel Meteor Lake pins and using them as GPIOs.
+
 config PINCTRL_SUNRISEPOINT
        tristate "Intel Sunrisepoint pinctrl and GPIO driver"
        depends on ACPI
index 181ffcf..bb87e7b 100644 (file)
@@ -18,5 +18,6 @@ obj-$(CONFIG_PINCTRL_ICELAKE)         += pinctrl-icelake.o
 obj-$(CONFIG_PINCTRL_JASPERLAKE)       += pinctrl-jasperlake.o
 obj-$(CONFIG_PINCTRL_LAKEFIELD)                += pinctrl-lakefield.o
 obj-$(CONFIG_PINCTRL_LEWISBURG)                += pinctrl-lewisburg.o
+obj-$(CONFIG_PINCTRL_METEORLAKE)       += pinctrl-meteorlake.o
 obj-$(CONFIG_PINCTRL_SUNRISEPOINT)     += pinctrl-sunrisepoint.o
 obj-$(CONFIG_PINCTRL_TIGERLAKE)                += pinctrl-tigerlake.o
index 31f8f27..67db79f 100644 (file)
@@ -603,7 +603,7 @@ static const char *byt_get_group_name(struct pinctrl_dev *pctldev,
 {
        struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctldev);
 
-       return vg->soc->groups[selector].name;
+       return vg->soc->groups[selector].grp.name;
 }
 
 static int byt_get_group_pins(struct pinctrl_dev *pctldev,
@@ -613,8 +613,8 @@ static int byt_get_group_pins(struct pinctrl_dev *pctldev,
 {
        struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctldev);
 
-       *pins           = vg->soc->groups[selector].pins;
-       *num_pins       = vg->soc->groups[selector].npins;
+       *pins           = vg->soc->groups[selector].grp.pins;
+       *num_pins       = vg->soc->groups[selector].grp.npins;
 
        return 0;
 }
@@ -662,15 +662,15 @@ static void byt_set_group_simple_mux(struct intel_pinctrl *vg,
 
        raw_spin_lock_irqsave(&byt_lock, flags);
 
-       for (i = 0; i < group.npins; i++) {
+       for (i = 0; i < group.grp.npins; i++) {
                void __iomem *padcfg0;
                u32 value;
 
-               padcfg0 = byt_gpio_reg(vg, group.pins[i], BYT_CONF0_REG);
+               padcfg0 = byt_gpio_reg(vg, group.grp.pins[i], BYT_CONF0_REG);
                if (!padcfg0) {
                        dev_warn(vg->dev,
                                 "Group %s, pin %i not muxed (no padcfg0)\n",
-                                group.name, i);
+                                group.grp.name, i);
                        continue;
                }
 
@@ -692,15 +692,15 @@ static void byt_set_group_mixed_mux(struct intel_pinctrl *vg,
 
        raw_spin_lock_irqsave(&byt_lock, flags);
 
-       for (i = 0; i < group.npins; i++) {
+       for (i = 0; i < group.grp.npins; i++) {
                void __iomem *padcfg0;
                u32 value;
 
-               padcfg0 = byt_gpio_reg(vg, group.pins[i], BYT_CONF0_REG);
+               padcfg0 = byt_gpio_reg(vg, group.grp.pins[i], BYT_CONF0_REG);
                if (!padcfg0) {
                        dev_warn(vg->dev,
                                 "Group %s, pin %i not muxed (no padcfg0)\n",
-                                group.name, i);
+                                group.grp.name, i);
                        continue;
                }
 
index 26b2a42..5c4fd16 100644 (file)
@@ -627,7 +627,7 @@ static const char *chv_get_group_name(struct pinctrl_dev *pctldev,
 {
        struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
 
-       return pctrl->soc->groups[group].name;
+       return pctrl->soc->groups[group].grp.name;
 }
 
 static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
@@ -635,8 +635,8 @@ static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
 {
        struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
 
-       *pins = pctrl->soc->groups[group].pins;
-       *npins = pctrl->soc->groups[group].npins;
+       *pins = pctrl->soc->groups[group].grp.pins;
+       *npins = pctrl->soc->groups[group].grp.npins;
        return 0;
 }
 
@@ -721,16 +721,16 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
        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])) {
+       for (i = 0; i < grp->grp.npins; i++) {
+               if (chv_pad_locked(pctrl, grp->grp.pins[i])) {
                        raw_spin_unlock_irqrestore(&chv_lock, flags);
-                       dev_warn(dev, "unable to set mode for locked pin %u\n", grp->pins[i]);
+                       dev_warn(dev, "unable to set mode for locked pin %u\n", grp->grp.pins[i]);
                        return -EBUSY;
                }
        }
 
-       for (i = 0; i < grp->npins; i++) {
-               int pin = grp->pins[i];
+       for (i = 0; i < grp->grp.npins; i++) {
+               int pin = grp->grp.pins[i];
                unsigned int mode;
                bool invert_oe;
                u32 value;
index fd093e3..52ecd66 100644 (file)
@@ -279,7 +279,7 @@ static const char *intel_get_group_name(struct pinctrl_dev *pctldev,
 {
        struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
 
-       return pctrl->soc->groups[group].name;
+       return pctrl->soc->groups[group].grp.name;
 }
 
 static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
@@ -287,8 +287,8 @@ static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
 {
        struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
 
-       *pins = pctrl->soc->groups[group].pins;
-       *npins = pctrl->soc->groups[group].npins;
+       *pins = pctrl->soc->groups[group].grp.pins;
+       *npins = pctrl->soc->groups[group].grp.npins;
        return 0;
 }
 
@@ -391,19 +391,19 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev,
         * 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 (!intel_pad_usable(pctrl, grp->pins[i])) {
+       for (i = 0; i < grp->grp.npins; i++) {
+               if (!intel_pad_usable(pctrl, grp->grp.pins[i])) {
                        raw_spin_unlock_irqrestore(&pctrl->lock, flags);
                        return -EBUSY;
                }
        }
 
        /* Now enable the mux setting for each pin in the group */
-       for (i = 0; i < grp->npins; i++) {
+       for (i = 0; i < grp->grp.npins; i++) {
                void __iomem *padcfg0;
                u32 value;
 
-               padcfg0 = intel_get_padcfg(pctrl, grp->pins[i], PADCFG0);
+               padcfg0 = intel_get_padcfg(pctrl, grp->grp.pins[i], PADCFG0);
                value = readl(padcfg0);
 
                value &= ~PADCFG0_PMODE_MASK;
index 710341b..6562842 100644 (file)
@@ -24,17 +24,12 @@ struct device;
 
 /**
  * struct intel_pingroup - Description about group of pins
- * @name: Name of the groups
- * @pins: All pins in this group
- * @npins: Number of pins in this groups
- * @mode: Native mode in which the group is muxed out @pins. Used if @modes
- *        is %NULL.
+ * @grp: Generic data of the pin group (name and pins)
+ * @mode: Native mode in which the group is muxed out @pins. Used if @modes is %NULL.
  * @modes: If not %NULL this will hold mode for each pin in @pins
  */
 struct intel_pingroup {
-       const char *name;
-       const unsigned int *pins;
-       size_t npins;
+       struct pingroup grp;
        unsigned short mode;
        const unsigned int *modes;
 };
@@ -156,15 +151,11 @@ struct intel_community {
  *     a single integer or an array of integers in which case mode is per
  *     pin.
  */
-#define PIN_GROUP(n, p, m)                                     \
-       {                                                       \
-               .name = (n),                                    \
-               .pins = (p),                                    \
-               .npins = ARRAY_SIZE((p)),                       \
-               .mode = __builtin_choose_expr(                  \
-                       __builtin_constant_p((m)), (m), 0),     \
-               .modes = __builtin_choose_expr(                 \
-                       __builtin_constant_p((m)), NULL, (m)),  \
+#define PIN_GROUP(n, p, m)                                                             \
+       {                                                                               \
+               .grp = PINCTRL_PINGROUP((n), (p), ARRAY_SIZE((p))),                     \
+               .mode = __builtin_choose_expr(__builtin_constant_p((m)), (m), 0),       \
+               .modes = __builtin_choose_expr(__builtin_constant_p((m)), NULL, (m)),   \
        }
 
 #define FUNCTION(n, g)                         \
index 4fb39eb..5d1abee 100644 (file)
@@ -282,7 +282,7 @@ static const char *lp_get_group_name(struct pinctrl_dev *pctldev,
 {
        struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
 
-       return lg->soc->groups[selector].name;
+       return lg->soc->groups[selector].grp.name;
 }
 
 static int lp_get_group_pins(struct pinctrl_dev *pctldev,
@@ -292,8 +292,8 @@ static int lp_get_group_pins(struct pinctrl_dev *pctldev,
 {
        struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
 
-       *pins           = lg->soc->groups[selector].pins;
-       *num_pins       = lg->soc->groups[selector].npins;
+       *pins           = lg->soc->groups[selector].grp.pins;
+       *num_pins       = lg->soc->groups[selector].grp.npins;
 
        return 0;
 }
@@ -366,8 +366,8 @@ static int lp_pinmux_set_mux(struct pinctrl_dev *pctldev,
        raw_spin_lock_irqsave(&lg->lock, flags);
 
        /* Now enable the mux setting for each pin in the group */
-       for (i = 0; i < grp->npins; i++) {
-               void __iomem *reg = lp_gpio_reg(&lg->chip, grp->pins[i], LP_CONFIG1);
+       for (i = 0; i < grp->grp.npins; i++) {
+               void __iomem *reg = lp_gpio_reg(&lg->chip, grp->grp.pins[i], LP_CONFIG1);
                u32 value;
 
                value = ioread32(reg);
index 3ae141e..5e75281 100644 (file)
@@ -520,7 +520,7 @@ static const char *mrfld_get_group_name(struct pinctrl_dev *pctldev,
 {
        struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
 
-       return mp->groups[group].name;
+       return mp->groups[group].grp.name;
 }
 
 static int mrfld_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
@@ -528,8 +528,8 @@ static int mrfld_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
 {
        struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
 
-       *pins = mp->groups[group].pins;
-       *npins = mp->groups[group].npins;
+       *pins = mp->groups[group].grp.pins;
+       *npins = mp->groups[group].grp.npins;
        return 0;
 }
 
@@ -604,15 +604,15 @@ static int mrfld_pinmux_set_mux(struct pinctrl_dev *pctldev,
         * 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]))
+       for (i = 0; i < grp->grp.npins; i++) {
+               if (!mrfld_buf_available(mp, grp->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);
+       for (i = 0; i < grp->grp.npins; i++)
+               mrfld_update_bufcfg(mp, grp->grp.pins[i], bits, mask);
        raw_spin_unlock_irqrestore(&mp->lock, flags);
 
        return 0;
diff --git a/drivers/pinctrl/intel/pinctrl-meteorlake.c b/drivers/pinctrl/intel/pinctrl-meteorlake.c
new file mode 100644 (file)
index 0000000..9576dcd
--- /dev/null
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Meteor Lake PCH pinctrl/GPIO driver
+ *
+ * Copyright (C) 2022, Intel Corporation
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-intel.h"
+
+#define MTL_PAD_OWN    0x0b0
+#define MTL_PADCFGLOCK 0x110
+#define MTL_HOSTSW_OWN 0x140
+#define MTL_GPI_IS     0x200
+#define MTL_GPI_IE     0x210
+
+#define MTL_GPP(r, s, e, g)                            \
+       {                                               \
+               .reg_num = (r),                         \
+               .base = (s),                            \
+               .size = ((e) - (s) + 1),                \
+               .gpio_base = (g),                       \
+       }
+
+#define MTL_COMMUNITY(b, s, e, g)                      \
+       {                                               \
+               .barno = (b),                           \
+               .padown_offset = MTL_PAD_OWN,           \
+               .padcfglock_offset = MTL_PADCFGLOCK,    \
+               .hostown_offset = MTL_HOSTSW_OWN,       \
+               .is_offset = MTL_GPI_IS,                \
+               .ie_offset = MTL_GPI_IE,                \
+               .pin_base = (s),                        \
+               .npins = ((e) - (s) + 1),               \
+               .gpps = (g),                            \
+               .ngpps = ARRAY_SIZE(g),                 \
+       }
+
+/* Meteor Lake-P */
+static const struct pinctrl_pin_desc mtlp_pins[] = {
+       /* CPU */
+       PINCTRL_PIN(0, "PECI"),
+       PINCTRL_PIN(1, "UFS_RESET_B"),
+       PINCTRL_PIN(2, "VIDSOUT"),
+       PINCTRL_PIN(3, "VIDSCK"),
+       PINCTRL_PIN(4, "VIDALERT_B"),
+       /* GPP_V */
+       PINCTRL_PIN(5, "BATLOW_B"),
+       PINCTRL_PIN(6, "AC_PRESENT"),
+       PINCTRL_PIN(7, "SOC_WAKE_B"),
+       PINCTRL_PIN(8, "PWRBTN_B"),
+       PINCTRL_PIN(9, "SLP_S3_B"),
+       PINCTRL_PIN(10, "SLP_S4_B"),
+       PINCTRL_PIN(11, "SLP_A_B"),
+       PINCTRL_PIN(12, "GPP_V_7"),
+       PINCTRL_PIN(13, "SUSCLK"),
+       PINCTRL_PIN(14, "SLP_WLAN_B"),
+       PINCTRL_PIN(15, "SLP_S5_B"),
+       PINCTRL_PIN(16, "LANPHYPC"),
+       PINCTRL_PIN(17, "SLP_LAN_B"),
+       PINCTRL_PIN(18, "GPP_V_13"),
+       PINCTRL_PIN(19, "WAKE_B"),
+       PINCTRL_PIN(20, "GPP_V_15"),
+       PINCTRL_PIN(21, "GPP_V_16"),
+       PINCTRL_PIN(22, "GPP_V_17"),
+       PINCTRL_PIN(23, "GPP_V_18"),
+       PINCTRL_PIN(24, "CATERR_B"),
+       PINCTRL_PIN(25, "PROCHOT_B"),
+       PINCTRL_PIN(26, "THERMTRIP_B"),
+       PINCTRL_PIN(27, "DSI_DE_TE_2_GENLOCK_REF"),
+       PINCTRL_PIN(28, "DSI_DE_TE_1_DISP_UTILS"),
+       /* GPP_C */
+       PINCTRL_PIN(29, "SMBCLK"),
+       PINCTRL_PIN(30, "SMBDATA"),
+       PINCTRL_PIN(31, "SMBALERT_B"),
+       PINCTRL_PIN(32, "SML0CLK"),
+       PINCTRL_PIN(33, "SML0DATA"),
+       PINCTRL_PIN(34, "GPP_C_5"),
+       PINCTRL_PIN(35, "GPP_C_6"),
+       PINCTRL_PIN(36, "GPP_C_7"),
+       PINCTRL_PIN(37, "GPP_C_8"),
+       PINCTRL_PIN(38, "GPP_C_9"),
+       PINCTRL_PIN(39, "GPP_C_10"),
+       PINCTRL_PIN(40, "GPP_C_11"),
+       PINCTRL_PIN(41, "GPP_C_12"),
+       PINCTRL_PIN(42, "GPP_C_13"),
+       PINCTRL_PIN(43, "GPP_C_14"),
+       PINCTRL_PIN(44, "GPP_C_15"),
+       PINCTRL_PIN(45, "GPP_C_16"),
+       PINCTRL_PIN(46, "GPP_C_17"),
+       PINCTRL_PIN(47, "GPP_C_18"),
+       PINCTRL_PIN(48, "GPP_C_19"),
+       PINCTRL_PIN(49, "GPP_C_20"),
+       PINCTRL_PIN(50, "GPP_C_21"),
+       PINCTRL_PIN(51, "GPP_C_22"),
+       PINCTRL_PIN(52, "GPP_C_23"),
+       /* GPP_A */
+       PINCTRL_PIN(53, "ESPI_IO_0"),
+       PINCTRL_PIN(54, "ESPI_IO_1"),
+       PINCTRL_PIN(55, "ESPI_IO_2"),
+       PINCTRL_PIN(56, "ESPI_IO_3"),
+       PINCTRL_PIN(57, "ESPI_CS0_B"),
+       PINCTRL_PIN(58, "ESPI_CLK"),
+       PINCTRL_PIN(59, "ESPI_RESET_B"),
+       PINCTRL_PIN(60, "GPP_A_7"),
+       PINCTRL_PIN(61, "GPP_A_8"),
+       PINCTRL_PIN(62, "GPP_A_9"),
+       PINCTRL_PIN(63, "GPP_A_10"),
+       PINCTRL_PIN(64, "GPP_A_11"),
+       PINCTRL_PIN(65, "GPP_A_12"),
+       PINCTRL_PIN(66, "ESPI_CS1_B"),
+       PINCTRL_PIN(67, "ESPI_CS2_B"),
+       PINCTRL_PIN(68, "ESPI_CS3_B"),
+       PINCTRL_PIN(69, "ESPI_ALERT0_B"),
+       PINCTRL_PIN(70, "ESPI_ALERT1_B"),
+       PINCTRL_PIN(71, "ESPI_ALERT2_B"),
+       PINCTRL_PIN(72, "ESPI_ALERT3_B"),
+       PINCTRL_PIN(73, "GPP_A_20"),
+       PINCTRL_PIN(74, "GPP_A_21"),
+       PINCTRL_PIN(75, "GPP_A_22"),
+       PINCTRL_PIN(76, "GPP_A_23"),
+       PINCTRL_PIN(77, "ESPI_CLK_LOOPBK"),
+       /* GPP_E */
+       PINCTRL_PIN(78, "GPP_E_0"),
+       PINCTRL_PIN(79, "GPP_E_1"),
+       PINCTRL_PIN(80, "GPP_E_2"),
+       PINCTRL_PIN(81, "GPP_E_3"),
+       PINCTRL_PIN(82, "GPP_E_4"),
+       PINCTRL_PIN(83, "GPP_E_5"),
+       PINCTRL_PIN(84, "GPP_E_6"),
+       PINCTRL_PIN(85, "GPP_E_7"),
+       PINCTRL_PIN(86, "GPP_E_8"),
+       PINCTRL_PIN(87, "GPP_E_9"),
+       PINCTRL_PIN(88, "GPP_E_10"),
+       PINCTRL_PIN(89, "GPP_E_11"),
+       PINCTRL_PIN(90, "GPP_E_12"),
+       PINCTRL_PIN(91, "GPP_E_13"),
+       PINCTRL_PIN(92, "GPP_E_14"),
+       PINCTRL_PIN(93, "SLP_DRAM_B"),
+       PINCTRL_PIN(94, "GPP_E_16"),
+       PINCTRL_PIN(95, "GPP_E_17"),
+       PINCTRL_PIN(96, "GPP_E_18"),
+       PINCTRL_PIN(97, "GPP_E_19"),
+       PINCTRL_PIN(98, "GPP_E_20"),
+       PINCTRL_PIN(99, "GPP_E_21"),
+       PINCTRL_PIN(100, "DNX_FORCE_RELOAD"),
+       PINCTRL_PIN(101, "GPP_E_23"),
+       PINCTRL_PIN(102, "THC0_GSPI0_CLK_LOOPBK"),
+       /* GPP_H */
+       PINCTRL_PIN(103, "GPP_H_0"),
+       PINCTRL_PIN(104, "GPP_H_1"),
+       PINCTRL_PIN(105, "GPP_H_2"),
+       PINCTRL_PIN(106, "GPP_H_3"),
+       PINCTRL_PIN(107, "GPP_H_4"),
+       PINCTRL_PIN(108, "GPP_H_5"),
+       PINCTRL_PIN(109, "GPP_H_6"),
+       PINCTRL_PIN(110, "GPP_H_7"),
+       PINCTRL_PIN(111, "GPP_H_8"),
+       PINCTRL_PIN(112, "GPP_H_9"),
+       PINCTRL_PIN(113, "GPP_H_10"),
+       PINCTRL_PIN(114, "GPP_H_11"),
+       PINCTRL_PIN(115, "GPP_H_12"),
+       PINCTRL_PIN(116, "CPU_C10_GATE_B"),
+       PINCTRL_PIN(117, "GPP_H_14"),
+       PINCTRL_PIN(118, "GPP_H_15"),
+       PINCTRL_PIN(119, "GPP_H_16"),
+       PINCTRL_PIN(120, "GPP_H_17"),
+       PINCTRL_PIN(121, "GPP_H_18"),
+       PINCTRL_PIN(122, "GPP_H_19"),
+       PINCTRL_PIN(123, "GPP_H_20"),
+       PINCTRL_PIN(124, "GPP_H_21"),
+       PINCTRL_PIN(125, "GPP_H_22"),
+       PINCTRL_PIN(126, "GPP_H_23"),
+       PINCTRL_PIN(127, "LPI3C1_CLK_LOOPBK"),
+       PINCTRL_PIN(128, "I3C0_CLK_LOOPBK"),
+       /* GPP_F */
+       PINCTRL_PIN(129, "CNV_BRI_DT"),
+       PINCTRL_PIN(130, "CNV_BRI_RSP"),
+       PINCTRL_PIN(131, "CNV_RGI_DT"),
+       PINCTRL_PIN(132, "CNV_RGI_RSP"),
+       PINCTRL_PIN(133, "CNV_RF_RESET_B"),
+       PINCTRL_PIN(134, "CRF_CLKREQ"),
+       PINCTRL_PIN(135, "GPP_F_6"),
+       PINCTRL_PIN(136, "FUSA_DIAGTEST_EN"),
+       PINCTRL_PIN(137, "FUSA_DIAGTEST_MODE"),
+       PINCTRL_PIN(138, "BOOTMPC"),
+       PINCTRL_PIN(139, "GPP_F_10"),
+       PINCTRL_PIN(140, "GPP_F_11"),
+       PINCTRL_PIN(141, "GSXDOUT"),
+       PINCTRL_PIN(142, "GSXSLOAD"),
+       PINCTRL_PIN(143, "GSXDIN"),
+       PINCTRL_PIN(144, "GSXSRESETB"),
+       PINCTRL_PIN(145, "GSXCLK"),
+       PINCTRL_PIN(146, "GMII_MDC_0"),
+       PINCTRL_PIN(147, "GMII_MDIO_0"),
+       PINCTRL_PIN(148, "GPP_F_19"),
+       PINCTRL_PIN(149, "GPP_F_20"),
+       PINCTRL_PIN(150, "GPP_F_21"),
+       PINCTRL_PIN(151, "GPP_F_22"),
+       PINCTRL_PIN(152, "GPP_F_23"),
+       PINCTRL_PIN(153, "THC1_GSPI1_CLK_LOOPBK"),
+       PINCTRL_PIN(154, "GSPI0A_CLK_LOOPBK"),
+       /* SPI0 */
+       PINCTRL_PIN(155, "SPI0_IO_2"),
+       PINCTRL_PIN(156, "SPI0_IO_3"),
+       PINCTRL_PIN(157, "SPI0_MOSI_IO_0"),
+       PINCTRL_PIN(158, "SPI0_MISO_IO_1"),
+       PINCTRL_PIN(159, "SPI0_TPM_CS_B"),
+       PINCTRL_PIN(160, "SPI0_FLASH_0_CS_B"),
+       PINCTRL_PIN(161, "SPI0_FLASH_1_CS_B"),
+       PINCTRL_PIN(162, "SPI0_CLK"),
+       PINCTRL_PIN(163, "L_BKLTEN"),
+       PINCTRL_PIN(164, "L_BKLTCTL"),
+       PINCTRL_PIN(165, "L_VDDEN"),
+       PINCTRL_PIN(166, "SYS_PWROK"),
+       PINCTRL_PIN(167, "SYS_RESET_B"),
+       PINCTRL_PIN(168, "MLK_RST_B"),
+       PINCTRL_PIN(169, "SPI0_CLK_LOOPBK"),
+       /* vGPIO_3 */
+       PINCTRL_PIN(170, "ESPI_USB_OCB_0"),
+       PINCTRL_PIN(171, "ESPI_USB_OCB_1"),
+       PINCTRL_PIN(172, "ESPI_USB_OCB_2"),
+       PINCTRL_PIN(173, "ESPI_USB_OCB_3"),
+       PINCTRL_PIN(174, "USB_CPU_OCB_0"),
+       PINCTRL_PIN(175, "USB_CPU_OCB_1"),
+       PINCTRL_PIN(176, "USB_CPU_OCB_2"),
+       PINCTRL_PIN(177, "USB_CPU_OCB_3"),
+       PINCTRL_PIN(178, "TS0_IN_INT"),
+       PINCTRL_PIN(179, "TS1_IN_INT"),
+       PINCTRL_PIN(180, "THC0_WOT_INT"),
+       PINCTRL_PIN(181, "THC1_WOT_INT"),
+       PINCTRL_PIN(182, "THC0_WHC_INT"),
+       PINCTRL_PIN(183, "THC1_WHC_INT"),
+       /* GPP_S */
+       PINCTRL_PIN(184, "GPP_S_0"),
+       PINCTRL_PIN(185, "GPP_S_1"),
+       PINCTRL_PIN(186, "GPP_S_2"),
+       PINCTRL_PIN(187, "GPP_S_3"),
+       PINCTRL_PIN(188, "GPP_S_4"),
+       PINCTRL_PIN(189, "GPP_S_5"),
+       PINCTRL_PIN(190, "GPP_S_6"),
+       PINCTRL_PIN(191, "GPP_S_7"),
+       /* JTAG */
+       PINCTRL_PIN(192, "JTAG_MBPB0"),
+       PINCTRL_PIN(193, "JTAG_MBPB1"),
+       PINCTRL_PIN(194, "JTAG_MBPB2"),
+       PINCTRL_PIN(195, "JTAG_MBPB3"),
+       PINCTRL_PIN(196, "JTAG_TDO"),
+       PINCTRL_PIN(197, "PRDY_B"),
+       PINCTRL_PIN(198, "PREQ_B"),
+       PINCTRL_PIN(199, "JTAG_TDI"),
+       PINCTRL_PIN(200, "JTAG_TMS"),
+       PINCTRL_PIN(201, "JTAG_TCK"),
+       PINCTRL_PIN(202, "DBG_PMODE"),
+       PINCTRL_PIN(203, "JTAG_TRST_B"),
+       /* GPP_B */
+       PINCTRL_PIN(204, "ADM_VID_0"),
+       PINCTRL_PIN(205, "ADM_VID_1"),
+       PINCTRL_PIN(206, "GPP_B_2"),
+       PINCTRL_PIN(207, "GPP_B_3"),
+       PINCTRL_PIN(208, "GPP_B_4"),
+       PINCTRL_PIN(209, "GPP_B_5"),
+       PINCTRL_PIN(210, "GPP_B_6"),
+       PINCTRL_PIN(211, "GPP_B_7"),
+       PINCTRL_PIN(212, "GPP_B_8"),
+       PINCTRL_PIN(213, "GPP_B_9"),
+       PINCTRL_PIN(214, "GPP_B_10"),
+       PINCTRL_PIN(215, "GPP_B_11"),
+       PINCTRL_PIN(216, "SLP_S0_B"),
+       PINCTRL_PIN(217, "PLTRST_B"),
+       PINCTRL_PIN(218, "GPP_B_14"),
+       PINCTRL_PIN(219, "GPP_B_15"),
+       PINCTRL_PIN(220, "GPP_B_16"),
+       PINCTRL_PIN(221, "GPP_B_17"),
+       PINCTRL_PIN(222, "GPP_B_18"),
+       PINCTRL_PIN(223, "GPP_B_19"),
+       PINCTRL_PIN(224, "GPP_B_20"),
+       PINCTRL_PIN(225, "GPP_B_21"),
+       PINCTRL_PIN(226, "GPP_B_22"),
+       PINCTRL_PIN(227, "GPP_B_23"),
+       PINCTRL_PIN(228, "ISH_I3C0_CLK_LOOPBK"),
+       /* GPP_D */
+       PINCTRL_PIN(229, "GPP_D_0"),
+       PINCTRL_PIN(230, "GPP_D_1"),
+       PINCTRL_PIN(231, "GPP_D_2"),
+       PINCTRL_PIN(232, "GPP_D_3"),
+       PINCTRL_PIN(233, "GPP_D_4"),
+       PINCTRL_PIN(234, "GPP_D_5"),
+       PINCTRL_PIN(235, "GPP_D_6"),
+       PINCTRL_PIN(236, "GPP_D_7"),
+       PINCTRL_PIN(237, "GPP_D_8"),
+       PINCTRL_PIN(238, "GPP_D_9"),
+       PINCTRL_PIN(239, "HDA_BCLK"),
+       PINCTRL_PIN(240, "HDA_SYNC"),
+       PINCTRL_PIN(241, "HDA_SDO"),
+       PINCTRL_PIN(242, "HDA_SDI_0"),
+       PINCTRL_PIN(243, "GPP_D_14"),
+       PINCTRL_PIN(244, "GPP_D_15"),
+       PINCTRL_PIN(245, "GPP_D_16"),
+       PINCTRL_PIN(246, "HDA_RST_B"),
+       PINCTRL_PIN(247, "GPP_D_18"),
+       PINCTRL_PIN(248, "GPP_D_19"),
+       PINCTRL_PIN(249, "GPP_D_20"),
+       PINCTRL_PIN(250, "UFS_REFCLK"),
+       PINCTRL_PIN(251, "BPKI3C_SDA"),
+       PINCTRL_PIN(252, "BPKI3C_SCL"),
+       PINCTRL_PIN(253, "BOOTHALT_B"),
+       /* vGPIO */
+       PINCTRL_PIN(254, "CNV_BTEN"),
+       PINCTRL_PIN(255, "CNV_BT_HOST_WAKEB"),
+       PINCTRL_PIN(256, "CNV_BT_IF_SELECT"),
+       PINCTRL_PIN(257, "vCNV_BT_UART_TXD"),
+       PINCTRL_PIN(258, "vCNV_BT_UART_RXD"),
+       PINCTRL_PIN(259, "vCNV_BT_UART_CTS_B"),
+       PINCTRL_PIN(260, "vCNV_BT_UART_RTS_B"),
+       PINCTRL_PIN(261, "vCNV_MFUART1_TXD"),
+       PINCTRL_PIN(262, "vCNV_MFUART1_RXD"),
+       PINCTRL_PIN(263, "vCNV_MFUART1_CTS_B"),
+       PINCTRL_PIN(264, "vCNV_MFUART1_RTS_B"),
+       PINCTRL_PIN(265, "vUART0_TXD"),
+       PINCTRL_PIN(266, "vUART0_RXD"),
+       PINCTRL_PIN(267, "vUART0_CTS_B"),
+       PINCTRL_PIN(268, "vUART0_RTS_B"),
+       PINCTRL_PIN(269, "vISH_UART0_TXD"),
+       PINCTRL_PIN(270, "vISH_UART0_RXD"),
+       PINCTRL_PIN(271, "vISH_UART0_CTS_B"),
+       PINCTRL_PIN(272, "vISH_UART0_RTS_B"),
+       PINCTRL_PIN(273, "vCNV_BT_I2S_BCLK"),
+       PINCTRL_PIN(274, "vCNV_BT_I2S_WS_SYNC"),
+       PINCTRL_PIN(275, "vCNV_BT_I2S_SDO"),
+       PINCTRL_PIN(276, "vCNV_BT_I2S_SDI"),
+       PINCTRL_PIN(277, "vI2S2_SCLK"),
+       PINCTRL_PIN(278, "vI2S2_SFRM"),
+       PINCTRL_PIN(279, "vI2S2_TXD"),
+       PINCTRL_PIN(280, "vI2S2_RXD"),
+       PINCTRL_PIN(281, "vCNV_BT_I2S_BCLK_2"),
+       PINCTRL_PIN(282, "vCNV_BT_I2S_WS_SYNC_2"),
+       PINCTRL_PIN(283, "vCNV_BT_I2S_SDO_2"),
+       PINCTRL_PIN(284, "vCNV_BT_I2S_SDI_2"),
+       PINCTRL_PIN(285, "vI2S2_SCLK_2"),
+       PINCTRL_PIN(286, "vI2S2_SFRM_2"),
+       PINCTRL_PIN(287, "vI2S2_TXD_2"),
+       PINCTRL_PIN(288, "vI2S2_RXD_2"),
+};
+
+static const struct intel_padgroup mtlp_community0_gpps[] = {
+       MTL_GPP(0, 0, 4, 0),            /* CPU */
+       MTL_GPP(1, 5, 28, 32),          /* GPP_V */
+       MTL_GPP(2, 29, 52, 64),         /* GPP_C */
+};
+
+static const struct intel_padgroup mtlp_community1_gpps[] = {
+       MTL_GPP(0, 53, 77, 96),         /* GPP_A */
+       MTL_GPP(1, 78, 102, 128),       /* GPP_E */
+};
+
+static const struct intel_padgroup mtlp_community3_gpps[] = {
+       MTL_GPP(0, 103, 128, 160),      /* GPP_H */
+       MTL_GPP(1, 129, 154, 192),      /* GPP_F */
+       MTL_GPP(2, 155, 169, 224),      /* SPI0 */
+       MTL_GPP(3, 170, 183, 256),      /* vGPIO_3 */
+};
+
+static const struct intel_padgroup mtlp_community4_gpps[] = {
+       MTL_GPP(0, 184, 191, 288),      /* GPP_S */
+       MTL_GPP(1, 192, 203, 320),      /* JTAG */
+};
+
+static const struct intel_padgroup mtlp_community5_gpps[] = {
+       MTL_GPP(0, 204, 228, 352),      /* GPP_B */
+       MTL_GPP(1, 229, 253, 384),      /* GPP_D */
+       MTL_GPP(2, 254, 285, 416),      /* vGPIO_0 */
+       MTL_GPP(3, 286, 288, 448),      /* vGPIO_1 */
+};
+
+static const struct intel_community mtlp_communities[] = {
+       MTL_COMMUNITY(0, 0, 52, mtlp_community0_gpps),
+       MTL_COMMUNITY(1, 53, 102, mtlp_community1_gpps),
+       MTL_COMMUNITY(2, 103, 183, mtlp_community3_gpps),
+       MTL_COMMUNITY(3, 184, 203, mtlp_community4_gpps),
+       MTL_COMMUNITY(4, 204, 288, mtlp_community5_gpps),
+};
+
+static const struct intel_pinctrl_soc_data mtlp_soc_data = {
+       .pins = mtlp_pins,
+       .npins = ARRAY_SIZE(mtlp_pins),
+       .communities = mtlp_communities,
+       .ncommunities = ARRAY_SIZE(mtlp_communities),
+};
+
+static const struct acpi_device_id mtl_pinctrl_acpi_match[] = {
+       { "INTC1083", (kernel_ulong_t)&mtlp_soc_data },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, mtl_pinctrl_acpi_match);
+
+static INTEL_PINCTRL_PM_OPS(mtl_pinctrl_pm_ops);
+
+static struct platform_driver mtl_pinctrl_driver = {
+       .probe = intel_pinctrl_probe_by_hid,
+       .driver = {
+               .name = "meteorlake-pinctrl",
+               .acpi_match_table = mtl_pinctrl_acpi_match,
+               .pm = &mtl_pinctrl_pm_ops,
+       },
+};
+module_platform_driver(mtl_pinctrl_driver);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Meteor Lake PCH pinctrl/GPIO driver");
+MODULE_LICENSE("GPL v2");
index acccde9..78c02b7 100644 (file)
@@ -1107,24 +1107,10 @@ static const struct mtk_pin_field_calc mt8192_pin_pupd_range[] = {
        PIN_FIELD_BASE(54, 54, 1, 0x0060, 0x10, 2, 1),
        PIN_FIELD_BASE(55, 55, 1, 0x0060, 0x10, 4, 1),
        PIN_FIELD_BASE(56, 56, 1, 0x0060, 0x10, 3, 1),
-       PIN_FIELD_BASE(118, 118, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(119, 119, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(120, 120, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(121, 121, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(122, 122, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(123, 123, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(124, 124, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(125, 125, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(139, 139, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(140, 140, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(141, 141, 4, 0x00e0, 0x10, 31, 1),
-       PIN_FIELD_BASE(142, 142, 4, 0x00e0, 0x10, 31, 1),
        PIN_FIELD_BASE(152, 152, 7, 0x0090, 0x10, 3, 1),
        PIN_FIELD_BASE(153, 153, 7, 0x0090, 0x10, 2, 1),
        PIN_FIELD_BASE(154, 154, 7, 0x0090, 0x10, 0, 1),
        PIN_FIELD_BASE(155, 155, 7, 0x0090, 0x10, 1, 1),
-       PIN_FIELD_BASE(160, 160, 7, 0x00f0, 0x10, 31, 1),
-       PIN_FIELD_BASE(161, 161, 7, 0x00f0, 0x10, 31, 1),
        PIN_FIELD_BASE(183, 183, 9, 0x0030, 0x10, 1, 1),
        PIN_FIELD_BASE(184, 184, 9, 0x0030, 0x10, 2, 1),
        PIN_FIELD_BASE(185, 185, 9, 0x0030, 0x10, 4, 1),
@@ -1137,12 +1123,6 @@ static const struct mtk_pin_field_calc mt8192_pin_pupd_range[] = {
        PIN_FIELD_BASE(192, 192, 9, 0x0030, 0x10, 0, 1),
        PIN_FIELD_BASE(193, 193, 9, 0x0030, 0x10, 5, 1),
        PIN_FIELD_BASE(194, 194, 9, 0x0030, 0x10, 11, 1),
-       PIN_FIELD_BASE(200, 200, 8, 0x0070, 0x10, 31, 1),
-       PIN_FIELD_BASE(201, 201, 8, 0x0070, 0x10, 31, 1),
-       PIN_FIELD_BASE(202, 202, 5, 0x0070, 0x10, 31, 1),
-       PIN_FIELD_BASE(203, 203, 5, 0x0070, 0x10, 31, 1),
-       PIN_FIELD_BASE(204, 204, 8, 0x0070, 0x10, 31, 1),
-       PIN_FIELD_BASE(205, 205, 8, 0x0070, 0x10, 31, 1),
 };
 
 static const struct mtk_pin_field_calc mt8192_pin_r0_range[] = {
@@ -1164,24 +1144,10 @@ static const struct mtk_pin_field_calc mt8192_pin_r0_range[] = {
        PIN_FIELD_BASE(54, 54, 1, 0x0080, 0x10, 2, 1),
        PIN_FIELD_BASE(55, 55, 1, 0x0080, 0x10, 4, 1),
        PIN_FIELD_BASE(56, 56, 1, 0x0080, 0x10, 3, 1),
-       PIN_FIELD_BASE(118, 118, 4, 0x00e0, 0x10, 0, 1),
-       PIN_FIELD_BASE(119, 119, 4, 0x00e0, 0x10, 12, 1),
-       PIN_FIELD_BASE(120, 120, 4, 0x00e0, 0x10, 10, 1),
-       PIN_FIELD_BASE(121, 121, 4, 0x00e0, 0x10, 22, 1),
-       PIN_FIELD_BASE(122, 122, 4, 0x00e0, 0x10, 8, 1),
-       PIN_FIELD_BASE(123, 123, 4, 0x00e0, 0x10, 20, 1),
-       PIN_FIELD_BASE(124, 124, 4, 0x00e0, 0x10, 6, 1),
-       PIN_FIELD_BASE(125, 125, 4, 0x00e0, 0x10, 18, 1),
-       PIN_FIELD_BASE(139, 139, 4, 0x00e0, 0x10, 4, 1),
-       PIN_FIELD_BASE(140, 140, 4, 0x00e0, 0x10, 16, 1),
-       PIN_FIELD_BASE(141, 141, 4, 0x00e0, 0x10, 2, 1),
-       PIN_FIELD_BASE(142, 142, 4, 0x00e0, 0x10, 14, 1),
        PIN_FIELD_BASE(152, 152, 7, 0x00c0, 0x10, 3, 1),
        PIN_FIELD_BASE(153, 153, 7, 0x00c0, 0x10, 2, 1),
        PIN_FIELD_BASE(154, 154, 7, 0x00c0, 0x10, 0, 1),
        PIN_FIELD_BASE(155, 155, 7, 0x00c0, 0x10, 1, 1),
-       PIN_FIELD_BASE(160, 160, 7, 0x00f0, 0x10, 0, 1),
-       PIN_FIELD_BASE(161, 161, 7, 0x00f0, 0x10, 2, 1),
        PIN_FIELD_BASE(183, 183, 9, 0x0040, 0x10, 1, 1),
        PIN_FIELD_BASE(184, 184, 9, 0x0040, 0x10, 2, 1),
        PIN_FIELD_BASE(185, 185, 9, 0x0040, 0x10, 4, 1),
@@ -1194,12 +1160,6 @@ static const struct mtk_pin_field_calc mt8192_pin_r0_range[] = {
        PIN_FIELD_BASE(192, 192, 9, 0x0040, 0x10, 0, 1),
        PIN_FIELD_BASE(193, 193, 9, 0x0040, 0x10, 5, 1),
        PIN_FIELD_BASE(194, 194, 9, 0x0040, 0x10, 11, 1),
-       PIN_FIELD_BASE(200, 200, 8, 0x0070, 0x10, 2, 1),
-       PIN_FIELD_BASE(201, 201, 8, 0x0070, 0x10, 6, 1),
-       PIN_FIELD_BASE(202, 202, 5, 0x0070, 0x10, 0, 1),
-       PIN_FIELD_BASE(203, 203, 5, 0x0070, 0x10, 2, 1),
-       PIN_FIELD_BASE(204, 204, 8, 0x0070, 0x10, 0, 1),
-       PIN_FIELD_BASE(205, 205, 8, 0x0070, 0x10, 4, 1),
 };
 
 static const struct mtk_pin_field_calc mt8192_pin_r1_range[] = {
@@ -1221,24 +1181,10 @@ static const struct mtk_pin_field_calc mt8192_pin_r1_range[] = {
        PIN_FIELD_BASE(54, 54, 1, 0x0090, 0x10, 2, 1),
        PIN_FIELD_BASE(55, 55, 1, 0x0090, 0x10, 4, 1),
        PIN_FIELD_BASE(56, 56, 1, 0x0090, 0x10, 3, 1),
-       PIN_FIELD_BASE(118, 118, 4, 0x00e0, 0x10, 1, 1),
-       PIN_FIELD_BASE(119, 119, 4, 0x00e0, 0x10, 13, 1),
-       PIN_FIELD_BASE(120, 120, 4, 0x00e0, 0x10, 11, 1),
-       PIN_FIELD_BASE(121, 121, 4, 0x00e0, 0x10, 23, 1),
-       PIN_FIELD_BASE(122, 122, 4, 0x00e0, 0x10, 9, 1),
-       PIN_FIELD_BASE(123, 123, 4, 0x00e0, 0x10, 21, 1),
-       PIN_FIELD_BASE(124, 124, 4, 0x00e0, 0x10, 7, 1),
-       PIN_FIELD_BASE(125, 125, 4, 0x00e0, 0x10, 19, 1),
-       PIN_FIELD_BASE(139, 139, 4, 0x00e0, 0x10, 5, 1),
-       PIN_FIELD_BASE(140, 140, 4, 0x00e0, 0x10, 17, 1),
-       PIN_FIELD_BASE(141, 141, 4, 0x00e0, 0x10, 3, 1),
-       PIN_FIELD_BASE(142, 142, 4, 0x00e0, 0x10, 15, 1),
        PIN_FIELD_BASE(152, 152, 7, 0x00d0, 0x10, 3, 1),
        PIN_FIELD_BASE(153, 153, 7, 0x00d0, 0x10, 2, 1),
        PIN_FIELD_BASE(154, 154, 7, 0x00d0, 0x10, 0, 1),
        PIN_FIELD_BASE(155, 155, 7, 0x00d0, 0x10, 1, 1),
-       PIN_FIELD_BASE(160, 160, 7, 0x00f0, 0x10, 1, 1),
-       PIN_FIELD_BASE(161, 161, 7, 0x00f0, 0x10, 3, 1),
        PIN_FIELD_BASE(183, 183, 9, 0x0050, 0x10, 1, 1),
        PIN_FIELD_BASE(184, 184, 9, 0x0050, 0x10, 2, 1),
        PIN_FIELD_BASE(185, 185, 9, 0x0050, 0x10, 4, 1),
@@ -1251,83 +1197,169 @@ static const struct mtk_pin_field_calc mt8192_pin_r1_range[] = {
        PIN_FIELD_BASE(192, 192, 9, 0x0050, 0x10, 0, 1),
        PIN_FIELD_BASE(193, 193, 9, 0x0050, 0x10, 5, 1),
        PIN_FIELD_BASE(194, 194, 9, 0x0050, 0x10, 11, 1),
-       PIN_FIELD_BASE(200, 200, 8, 0x0070, 0x10, 3, 1),
-       PIN_FIELD_BASE(201, 201, 8, 0x0070, 0x10, 7, 1),
-       PIN_FIELD_BASE(202, 202, 5, 0x0070, 0x10, 1, 1),
-       PIN_FIELD_BASE(203, 203, 5, 0x0070, 0x10, 3, 1),
-       PIN_FIELD_BASE(204, 204, 8, 0x0070, 0x10, 1, 1),
-       PIN_FIELD_BASE(205, 205, 8, 0x0070, 0x10, 5, 1),
 };
 
-static const struct mtk_pin_field_calc mt8192_pin_e1e0en_range[] = {
-       PIN_FIELD_BASE(118, 118, 4, 0x0040, 0x10, 0, 1),
-       PIN_FIELD_BASE(119, 119, 4, 0x0040, 0x10, 18, 1),
-       PIN_FIELD_BASE(120, 120, 4, 0x0040, 0x10, 15, 1),
-       PIN_FIELD_BASE(121, 121, 4, 0x0050, 0x10, 3, 1),
-       PIN_FIELD_BASE(122, 122, 4, 0x0040, 0x10, 12, 1),
-       PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 0, 1),
-       PIN_FIELD_BASE(124, 124, 4, 0x0040, 0x10, 9, 1),
-       PIN_FIELD_BASE(125, 125, 4, 0x0040, 0x10, 27, 1),
-       PIN_FIELD_BASE(139, 139, 4, 0x0040, 0x10, 6, 1),
-       PIN_FIELD_BASE(140, 140, 4, 0x0040, 0x10, 24, 1),
-       PIN_FIELD_BASE(141, 141, 4, 0x0040, 0x10, 3, 1),
-       PIN_FIELD_BASE(142, 142, 4, 0x0040, 0x10, 21, 1),
-       PIN_FIELD_BASE(160, 160, 7, 0x0030, 0x10, 0, 1),
-       PIN_FIELD_BASE(161, 161, 7, 0x0030, 0x10, 3, 1),
-       PIN_FIELD_BASE(200, 200, 8, 0x0010, 0x10, 3, 1),
-       PIN_FIELD_BASE(201, 201, 8, 0x0010, 0x10, 9, 1),
-       PIN_FIELD_BASE(202, 202, 5, 0x0020, 0x10, 0, 1),
-       PIN_FIELD_BASE(203, 203, 5, 0x0020, 0x10, 3, 1),
-       PIN_FIELD_BASE(204, 204, 8, 0x0010, 0x10, 0, 1),
-       PIN_FIELD_BASE(205, 205, 8, 0x0010, 0x10, 6, 1),
-};
+static const struct mtk_pin_field_calc mt8192_pin_drv_adv_range[] = {
+       PIN_FIELD_BASE(89, 89, 2, 0x0040, 0x10, 0, 5),
+       PIN_FIELD_BASE(90, 90, 2, 0x0040, 0x10, 5, 5),
 
-static const struct mtk_pin_field_calc mt8192_pin_e0_range[] = {
-       PIN_FIELD_BASE(118, 118, 4, 0x0040, 0x10, 1, 1),
-       PIN_FIELD_BASE(119, 119, 4, 0x0040, 0x10, 19, 1),
-       PIN_FIELD_BASE(120, 120, 4, 0x0040, 0x10, 16, 1),
-       PIN_FIELD_BASE(121, 121, 4, 0x0050, 0x10, 4, 1),
-       PIN_FIELD_BASE(122, 122, 4, 0x0040, 0x10, 13, 1),
-       PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 1, 1),
-       PIN_FIELD_BASE(124, 124, 4, 0x0040, 0x10, 10, 1),
-       PIN_FIELD_BASE(125, 125, 4, 0x0040, 0x10, 28, 1),
-       PIN_FIELD_BASE(139, 139, 4, 0x0040, 0x10, 7, 1),
-       PIN_FIELD_BASE(140, 140, 4, 0x0040, 0x10, 25, 1),
-       PIN_FIELD_BASE(141, 141, 4, 0x0040, 0x10, 4, 1),
-       PIN_FIELD_BASE(142, 142, 4, 0x0040, 0x10, 22, 1),
-       PIN_FIELD_BASE(160, 160, 7, 0x0030, 0x10, 1, 1),
-       PIN_FIELD_BASE(161, 161, 7, 0x0030, 0x10, 4, 1),
-       PIN_FIELD_BASE(200, 200, 8, 0x0010, 0x10, 4, 1),
-       PIN_FIELD_BASE(201, 201, 8, 0x0010, 0x10, 10, 1),
-       PIN_FIELD_BASE(202, 202, 5, 0x0020, 0x10, 1, 1),
-       PIN_FIELD_BASE(203, 203, 5, 0x0020, 0x10, 4, 1),
-       PIN_FIELD_BASE(204, 204, 8, 0x0010, 0x10, 1, 1),
-       PIN_FIELD_BASE(205, 205, 8, 0x0010, 0x10, 7, 1),
+       PIN_FIELD_BASE(118, 118, 4, 0x0040, 0x10, 0, 3),
+       PIN_FIELD_BASE(119, 119, 4, 0x0040, 0x10, 18, 3),
+       PIN_FIELD_BASE(120, 120, 4, 0x0040, 0x10, 15, 3),
+       PIN_FIELD_BASE(121, 121, 4, 0x0050, 0x10, 3, 3),
+       PIN_FIELD_BASE(122, 122, 4, 0x0040, 0x10, 12, 3),
+       PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 0, 3),
+       PIN_FIELD_BASE(124, 124, 4, 0x0040, 0x10, 9, 3),
+       PIN_FIELD_BASE(125, 125, 4, 0x0040, 0x10, 27, 3),
+       PIN_FIELD_BASE(139, 139, 4, 0x0040, 0x10, 6, 3),
+       PIN_FIELD_BASE(140, 140, 4, 0x0040, 0x10, 24, 3),
+       PIN_FIELD_BASE(141, 141, 4, 0x0040, 0x10, 3, 3),
+       PIN_FIELD_BASE(142, 142, 4, 0x0040, 0x10, 21, 3),
+       PIN_FIELD_BASE(160, 160, 7, 0x0030, 0x10, 0, 3),
+       PIN_FIELD_BASE(161, 161, 7, 0x0030, 0x10, 3, 3),
+       PIN_FIELD_BASE(200, 200, 8, 0x0010, 0x10, 3, 3),
+       PIN_FIELD_BASE(201, 201, 8, 0x0010, 0x10, 9, 3),
+       PIN_FIELD_BASE(202, 202, 5, 0x0020, 0x10, 0, 3),
+       PIN_FIELD_BASE(203, 203, 5, 0x0020, 0x10, 3, 3),
+       PIN_FIELD_BASE(204, 204, 8, 0x0010, 0x10, 0, 3),
+       PIN_FIELD_BASE(205, 205, 8, 0x0010, 0x10, 6, 3),
 };
 
-static const struct mtk_pin_field_calc mt8192_pin_e1_range[] = {
-       PIN_FIELD_BASE(118, 118, 4, 0x0040, 0x10, 2, 1),
-       PIN_FIELD_BASE(119, 119, 4, 0x0040, 0x10, 20, 1),
-       PIN_FIELD_BASE(120, 120, 4, 0x0040, 0x10, 17, 1),
-       PIN_FIELD_BASE(121, 121, 4, 0x0050, 0x10, 5, 1),
-       PIN_FIELD_BASE(122, 122, 4, 0x0040, 0x10, 14, 1),
-       PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 2, 1),
-       PIN_FIELD_BASE(124, 124, 4, 0x0040, 0x10, 11, 1),
-       PIN_FIELD_BASE(125, 125, 4, 0x0040, 0x10, 29, 1),
-       PIN_FIELD_BASE(139, 139, 4, 0x0040, 0x10, 8, 1),
-       PIN_FIELD_BASE(140, 140, 4, 0x0040, 0x10, 26, 1),
-       PIN_FIELD_BASE(141, 141, 4, 0x0040, 0x10, 5, 1),
-       PIN_FIELD_BASE(142, 142, 4, 0x0040, 0x10, 23, 1),
-       PIN_FIELD_BASE(160, 160, 7, 0x0030, 0x10, 2, 1),
-       PIN_FIELD_BASE(161, 161, 7, 0x0030, 0x10, 5, 1),
-       PIN_FIELD_BASE(200, 200, 8, 0x0010, 0x10, 5, 1),
-       PIN_FIELD_BASE(201, 201, 8, 0x0010, 0x10, 11, 1),
-       PIN_FIELD_BASE(202, 202, 5, 0x0020, 0x10, 2, 1),
-       PIN_FIELD_BASE(203, 203, 5, 0x0020, 0x10, 5, 1),
-       PIN_FIELD_BASE(204, 204, 8, 0x0010, 0x10, 2, 1),
-       PIN_FIELD_BASE(205, 205, 8, 0x0010, 0x10, 8, 1),
+static const struct mtk_pin_field_calc mt8192_pin_rsel_range[] = {
+       PIN_FIELD_BASE(118, 118, 4, 0x00e0, 0x10, 0, 2),
+       PIN_FIELD_BASE(119, 119, 4, 0x00e0, 0x10, 12, 2),
+       PIN_FIELD_BASE(120, 120, 4, 0x00e0, 0x10, 10, 2),
+       PIN_FIELD_BASE(121, 121, 4, 0x00e0, 0x10, 22, 2),
+       PIN_FIELD_BASE(122, 122, 4, 0x00e0, 0x10, 8, 2),
+       PIN_FIELD_BASE(123, 123, 4, 0x00e0, 0x10, 20, 2),
+       PIN_FIELD_BASE(124, 124, 4, 0x00e0, 0x10, 6, 2),
+       PIN_FIELD_BASE(125, 125, 4, 0x00e0, 0x10, 18, 2),
+       PIN_FIELD_BASE(139, 139, 4, 0x00e0, 0x10, 4, 2),
+       PIN_FIELD_BASE(140, 140, 4, 0x00e0, 0x10, 16, 2),
+       PIN_FIELD_BASE(141, 141, 4, 0x00e0, 0x10, 2, 2),
+       PIN_FIELD_BASE(142, 142, 4, 0x00e0, 0x10, 14, 2),
+       PIN_FIELD_BASE(160, 160, 7, 0x00f0, 0x10, 0, 2),
+       PIN_FIELD_BASE(161, 161, 7, 0x00f0, 0x10, 2, 2),
+       PIN_FIELD_BASE(200, 200, 8, 0x0070, 0x10, 2, 2),
+       PIN_FIELD_BASE(201, 201, 8, 0x0070, 0x10, 6, 2),
+       PIN_FIELD_BASE(202, 202, 5, 0x0070, 0x10, 0, 2),
+       PIN_FIELD_BASE(203, 203, 5, 0x0070, 0x10, 2, 2),
+       PIN_FIELD_BASE(204, 204, 8, 0x0070, 0x10, 0, 2),
+       PIN_FIELD_BASE(205, 205, 8, 0x0070, 0x10, 4, 2),
 };
 
+static const unsigned int mt8192_pull_type[] = {
+       MTK_PULL_PU_PD_TYPE,/*0*/ MTK_PULL_PU_PD_TYPE,/*1*/
+       MTK_PULL_PU_PD_TYPE,/*2*/ MTK_PULL_PU_PD_TYPE,/*3*/
+       MTK_PULL_PU_PD_TYPE,/*4*/ MTK_PULL_PU_PD_TYPE,/*5*/
+       MTK_PULL_PU_PD_TYPE,/*6*/ MTK_PULL_PU_PD_TYPE,/*7*/
+       MTK_PULL_PU_PD_TYPE,/*8*/ MTK_PULL_PU_PD_TYPE,/*9*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PUPD_R1R0_TYPE,/*13*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*14*/ MTK_PULL_PUPD_R1R0_TYPE,/*15*/
+       MTK_PULL_PU_PD_TYPE,/*16*/ MTK_PULL_PU_PD_TYPE,/*17*/
+       MTK_PULL_PU_PD_TYPE,/*18*/ MTK_PULL_PU_PD_TYPE,/*19*/
+       MTK_PULL_PU_PD_TYPE,/*20*/ MTK_PULL_PU_PD_TYPE,/*21*/
+       MTK_PULL_PU_PD_TYPE,/*22*/ MTK_PULL_PU_PD_TYPE,/*23*/
+       MTK_PULL_PU_PD_TYPE,/*24*/ MTK_PULL_PU_PD_TYPE,/*25*/
+       MTK_PULL_PU_PD_TYPE,/*26*/ MTK_PULL_PU_PD_TYPE,/*27*/
+       MTK_PULL_PU_PD_TYPE,/*28*/ MTK_PULL_PU_PD_TYPE,/*29*/
+       MTK_PULL_PU_PD_TYPE,/*30*/ MTK_PULL_PU_PD_TYPE,/*31*/
+       MTK_PULL_PU_PD_TYPE,/*32*/ MTK_PULL_PU_PD_TYPE,/*33*/
+       MTK_PULL_PU_PD_TYPE,/*34*/ MTK_PULL_PU_PD_TYPE,/*35*/
+       MTK_PULL_PU_PD_TYPE,/*36*/ MTK_PULL_PU_PD_TYPE,/*37*/
+       MTK_PULL_PU_PD_TYPE,/*38*/ MTK_PULL_PU_PD_TYPE,/*39*/
+       MTK_PULL_PU_PD_TYPE,/*40*/ MTK_PULL_PU_PD_TYPE,/*41*/
+       MTK_PULL_PU_PD_TYPE,/*42*/ MTK_PULL_PU_PD_TYPE,/*43*/
+       MTK_PULL_PU_PD_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PU_PD_TYPE,/*57*/
+       MTK_PULL_PU_PD_TYPE,/*58*/ MTK_PULL_PU_PD_TYPE,/*59*/
+       MTK_PULL_PU_PD_TYPE,/*60*/ MTK_PULL_PU_PD_TYPE,/*61*/
+       MTK_PULL_PU_PD_TYPE,/*62*/ MTK_PULL_PU_PD_TYPE,/*63*/
+       MTK_PULL_PU_PD_TYPE,/*64*/ MTK_PULL_PU_PD_TYPE,/*65*/
+       MTK_PULL_PU_PD_TYPE,/*66*/ MTK_PULL_PU_PD_TYPE,/*67*/
+       MTK_PULL_PU_PD_TYPE,/*68*/ MTK_PULL_PU_PD_TYPE,/*69*/
+       MTK_PULL_PU_PD_TYPE,/*70*/ MTK_PULL_PU_PD_TYPE,/*71*/
+       MTK_PULL_PU_PD_TYPE,/*72*/ MTK_PULL_PU_PD_TYPE,/*73*/
+       MTK_PULL_PU_PD_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE,/*75*/
+       MTK_PULL_PU_PD_TYPE,/*76*/ MTK_PULL_PU_PD_TYPE,/*77*/
+       MTK_PULL_PU_PD_TYPE,/*78*/ MTK_PULL_PU_PD_TYPE,/*79*/
+       MTK_PULL_PU_PD_TYPE,/*80*/ MTK_PULL_PU_PD_TYPE,/*81*/
+       MTK_PULL_PU_PD_TYPE,/*82*/ MTK_PULL_PU_PD_TYPE,/*83*/
+       MTK_PULL_PU_PD_TYPE,/*84*/ MTK_PULL_PU_PD_TYPE,/*85*/
+       MTK_PULL_PU_PD_TYPE,/*86*/ MTK_PULL_PU_PD_TYPE,/*87*/
+       MTK_PULL_PU_PD_TYPE,/*88*/ MTK_PULL_PU_PD_TYPE,/*89*/
+       MTK_PULL_PU_PD_TYPE,/*90*/ MTK_PULL_PU_PD_TYPE,/*91*/
+       MTK_PULL_PU_PD_TYPE,/*92*/ MTK_PULL_PU_PD_TYPE,/*93*/
+       MTK_PULL_PU_PD_TYPE,/*94*/ MTK_PULL_PU_PD_TYPE,/*95*/
+       MTK_PULL_PU_PD_TYPE,/*96*/ MTK_PULL_PU_PD_TYPE,/*97*/
+       MTK_PULL_PU_PD_TYPE,/*98*/ MTK_PULL_PU_PD_TYPE,/*99*/
+       MTK_PULL_PU_PD_TYPE,/*100*/ MTK_PULL_PU_PD_TYPE,/*101*/
+       MTK_PULL_PU_PD_TYPE,/*102*/ MTK_PULL_PU_PD_TYPE,/*103*/
+       MTK_PULL_PU_PD_TYPE,/*104*/ MTK_PULL_PU_PD_TYPE,/*105*/
+       MTK_PULL_PU_PD_TYPE,/*106*/ MTK_PULL_PU_PD_TYPE,/*107*/
+       MTK_PULL_PU_PD_TYPE,/*108*/ MTK_PULL_PU_PD_TYPE,/*109*/
+       MTK_PULL_PU_PD_TYPE,/*110*/ MTK_PULL_PU_PD_TYPE,/*111*/
+       MTK_PULL_PU_PD_TYPE,/*112*/ MTK_PULL_PU_PD_TYPE,/*113*/
+       MTK_PULL_PU_PD_TYPE,/*114*/ MTK_PULL_PU_PD_TYPE,/*115*/
+       MTK_PULL_PU_PD_TYPE,/*116*/ MTK_PULL_PU_PD_TYPE,/*117*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*118*/ MTK_PULL_PU_PD_RSEL_TYPE,/*119*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*120*/ MTK_PULL_PU_PD_RSEL_TYPE,/*121*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*122*/ MTK_PULL_PU_PD_RSEL_TYPE,/*123*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*124*/ MTK_PULL_PU_PD_RSEL_TYPE,/*125*/
+       MTK_PULL_PU_PD_TYPE,/*126*/ MTK_PULL_PU_PD_TYPE,/*127*/
+       MTK_PULL_PU_PD_TYPE,/*128*/ MTK_PULL_PU_PD_TYPE,/*129*/
+       MTK_PULL_PU_PD_TYPE,/*130*/ MTK_PULL_PU_PD_TYPE,/*131*/
+       MTK_PULL_PU_PD_TYPE,/*132*/ MTK_PULL_PU_PD_TYPE,/*133*/
+       MTK_PULL_PU_PD_TYPE,/*134*/ MTK_PULL_PU_PD_TYPE,/*135*/
+       MTK_PULL_PU_PD_TYPE,/*136*/ MTK_PULL_PU_PD_TYPE,/*137*/
+       MTK_PULL_PU_PD_TYPE,/*138*/ MTK_PULL_PU_PD_RSEL_TYPE,/*139*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*140*/ MTK_PULL_PU_PD_RSEL_TYPE,/*141*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*142*/ MTK_PULL_PU_PD_TYPE,/*143*/
+       MTK_PULL_PU_PD_TYPE,/*144*/ MTK_PULL_PU_PD_TYPE,/*145*/
+       MTK_PULL_PU_PD_TYPE,/*146*/ MTK_PULL_PU_PD_TYPE,/*147*/
+       MTK_PULL_PU_PD_TYPE,/*148*/ MTK_PULL_PU_PD_TYPE,/*149*/
+       MTK_PULL_PU_PD_TYPE,/*150*/ MTK_PULL_PU_PD_TYPE,/*151*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*152*/ MTK_PULL_PUPD_R1R0_TYPE,/*153*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*154*/ MTK_PULL_PUPD_R1R0_TYPE,/*155*/
+       MTK_PULL_PU_PD_TYPE,/*156*/ MTK_PULL_PU_PD_TYPE,/*157*/
+       MTK_PULL_PU_PD_TYPE,/*158*/ MTK_PULL_PU_PD_TYPE,/*159*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*160*/ MTK_PULL_PU_PD_RSEL_TYPE,/*161*/
+       MTK_PULL_PU_PD_TYPE,/*162*/ MTK_PULL_PU_PD_TYPE,/*163*/
+       MTK_PULL_PU_PD_TYPE,/*164*/ MTK_PULL_PU_PD_TYPE,/*165*/
+       MTK_PULL_PU_PD_TYPE,/*166*/ MTK_PULL_PU_PD_TYPE,/*167*/
+       MTK_PULL_PU_PD_TYPE,/*168*/ MTK_PULL_PU_PD_TYPE,/*169*/
+       MTK_PULL_PU_PD_TYPE,/*170*/ MTK_PULL_PU_PD_TYPE,/*171*/
+       MTK_PULL_PU_PD_TYPE,/*172*/ MTK_PULL_PU_PD_TYPE,/*173*/
+       MTK_PULL_PU_PD_TYPE,/*174*/ MTK_PULL_PU_PD_TYPE,/*175*/
+       MTK_PULL_PU_PD_TYPE,/*176*/ MTK_PULL_PU_PD_TYPE,/*177*/
+       MTK_PULL_PU_PD_TYPE,/*178*/ MTK_PULL_PU_PD_TYPE,/*179*/
+       MTK_PULL_PU_PD_TYPE,/*180*/ MTK_PULL_PU_PD_TYPE,/*181*/
+       MTK_PULL_PU_PD_TYPE,/*182*/ MTK_PULL_PUPD_R1R0_TYPE,/*183*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*184*/ MTK_PULL_PUPD_R1R0_TYPE,/*185*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*186*/ MTK_PULL_PUPD_R1R0_TYPE,/*187*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*188*/ MTK_PULL_PUPD_R1R0_TYPE,/*189*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*190*/ MTK_PULL_PUPD_R1R0_TYPE,/*191*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*192*/ MTK_PULL_PUPD_R1R0_TYPE,/*193*/
+       MTK_PULL_PUPD_R1R0_TYPE,/*194*/ MTK_PULL_PU_PD_TYPE,/*195*/
+       MTK_PULL_PU_PD_TYPE,/*196*/ MTK_PULL_PU_PD_TYPE,/*197*/
+       MTK_PULL_PU_PD_TYPE,/*198*/ MTK_PULL_PU_PD_TYPE,/*199*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*200*/ MTK_PULL_PU_PD_RSEL_TYPE,/*201*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*202*/ MTK_PULL_PU_PD_RSEL_TYPE,/*203*/
+       MTK_PULL_PU_PD_RSEL_TYPE,/*204*/ MTK_PULL_PU_PD_RSEL_TYPE,/*205*/
+       MTK_PULL_PU_PD_TYPE,/*206*/ MTK_PULL_PU_PD_TYPE,/*207*/
+       MTK_PULL_PU_PD_TYPE,/*208*/ MTK_PULL_PU_PD_TYPE,/*209*/
+       MTK_PULL_PU_PD_TYPE,/*210*/ MTK_PULL_PU_PD_TYPE,/*211*/
+       MTK_PULL_PU_PD_TYPE,/*212*/ MTK_PULL_PU_PD_TYPE,/*213*/
+       MTK_PULL_PU_PD_TYPE,/*214*/ MTK_PULL_PU_PD_TYPE,/*215*/
+       MTK_PULL_PU_PD_TYPE,/*216*/ MTK_PULL_PU_PD_TYPE,/*217*/
+       MTK_PULL_PU_PD_TYPE,/*218*/ MTK_PULL_PU_PD_TYPE,/*219*/
+};
 
 static const char * const mt8192_pinctrl_register_base_names[] = {
        "iocfg0", "iocfg_rm", "iocfg_bm", "iocfg_bl", "iocfg_br",
@@ -1355,9 +1387,8 @@ static const struct mtk_pin_reg_calc mt8192_reg_cals[PINCTRL_PIN_REG_MAX] = {
        [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt8192_pin_pupd_range),
        [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt8192_pin_r0_range),
        [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt8192_pin_r1_range),
-       [PINCTRL_PIN_REG_DRV_EN] = MTK_RANGE(mt8192_pin_e1e0en_range),
-       [PINCTRL_PIN_REG_DRV_E0] = MTK_RANGE(mt8192_pin_e0_range),
-       [PINCTRL_PIN_REG_DRV_E1] = MTK_RANGE(mt8192_pin_e1_range),
+       [PINCTRL_PIN_REG_DRV_ADV] = MTK_RANGE(mt8192_pin_drv_adv_range),
+       [PINCTRL_PIN_REG_RSEL] = MTK_RANGE(mt8192_pin_rsel_range),
 };
 
 static const struct mtk_pin_soc mt8192_data = {
@@ -1367,17 +1398,16 @@ static const struct mtk_pin_soc mt8192_data = {
        .ngrps = ARRAY_SIZE(mtk_pins_mt8192),
        .base_names = mt8192_pinctrl_register_base_names,
        .nbase_names = ARRAY_SIZE(mt8192_pinctrl_register_base_names),
+       .pull_type = mt8192_pull_type,
        .eint_hw = &mt8192_eint_hw,
        .nfuncs = 8,
        .gpio_m = 0,
        .bias_set_combo = mtk_pinconf_bias_set_combo,
        .bias_get_combo = mtk_pinconf_bias_get_combo,
-       .drive_set = mtk_pinconf_drive_set_raw,
-       .drive_get = mtk_pinconf_drive_get_raw,
-       .adv_pull_get = mtk_pinconf_adv_pull_get,
-       .adv_pull_set = mtk_pinconf_adv_pull_set,
-       .adv_drive_get = mtk_pinconf_adv_drive_get,
-       .adv_drive_set = mtk_pinconf_adv_drive_set,
+       .drive_set = mtk_pinconf_drive_set_rev1,
+       .drive_get = mtk_pinconf_drive_get_rev1,
+       .adv_drive_get = mtk_pinconf_adv_drive_get_raw,
+       .adv_drive_set = mtk_pinconf_adv_drive_set_raw,
 };
 
 static const struct of_device_id mt8192_pinctrl_of_match[] = {
index a1f9385..8ef0a97 100644 (file)
@@ -96,10 +96,12 @@ static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_name(
        struct mvebu_pinctrl *pctl, const char *name)
 {
        unsigned n;
+
        for (n = 0; n < pctl->num_groups; n++) {
                if (strcmp(name, pctl->groups[n].name) == 0)
                        return &pctl->groups[n];
        }
+
        return NULL;
 }
 
@@ -108,6 +110,7 @@ static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_val(
        unsigned long config)
 {
        unsigned n;
+
        for (n = 0; n < grp->num_settings; n++) {
                if (config == grp->settings[n].val) {
                        if (!pctl->variant || (pctl->variant &
@@ -115,6 +118,7 @@ static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_val(
                                return &grp->settings[n];
                }
        }
+
        return NULL;
 }
 
@@ -123,6 +127,7 @@ static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_name(
        const char *name)
 {
        unsigned n;
+
        for (n = 0; n < grp->num_settings; n++) {
                if (strcmp(name, grp->settings[n].name) == 0) {
                        if (!pctl->variant || (pctl->variant &
@@ -130,6 +135,7 @@ static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_name(
                                return &grp->settings[n];
                }
        }
+
        return NULL;
 }
 
@@ -137,6 +143,7 @@ static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_gpio_setting(
        struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp)
 {
        unsigned n;
+
        for (n = 0; n < grp->num_settings; n++) {
                if (grp->settings[n].flags &
                        (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) {
@@ -145,6 +152,7 @@ static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_gpio_setting(
                                return &grp->settings[n];
                }
        }
+
        return NULL;
 }
 
@@ -152,10 +160,12 @@ static struct mvebu_pinctrl_function *mvebu_pinctrl_find_function_by_name(
        struct mvebu_pinctrl *pctl, const char *name)
 {
        unsigned n;
+
        for (n = 0; n < pctl->num_functions; n++) {
                if (strcmp(name, pctl->functions[n].name) == 0)
                        return &pctl->functions[n];
        }
+
        return NULL;
 }
 
index 640e50d..f5014d0 100644 (file)
@@ -1421,8 +1421,10 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
 
        has_config = nmk_pinctrl_dt_get_config(np, &configs);
        np_config = of_parse_phandle(np, "ste,config", 0);
-       if (np_config)
+       if (np_config) {
                has_config |= nmk_pinctrl_dt_get_config(np_config, &configs);
+               of_node_put(np_config);
+       }
        if (has_config) {
                const char *gpio_name;
                const char *pin;
index 0645c2c..4691a33 100644 (file)
@@ -6,8 +6,6 @@
  * Authors: Ken Xue <Ken.Xue@amd.com>
  *      Wu, Jeff <Jeff.Wu@amd.com>
  *
- * Contact Information: Nehal Shah <Nehal-bakulchandra.Shah@amd.com>
- *                     Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
  */
 
 #include <linux/err.h>
@@ -31,6 +29,7 @@
 #include <linux/bitops.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
 
 #include "core.h"
 #include "pinctrl-utils.h"
@@ -203,8 +202,6 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
        struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
        bool tmr_out_unit;
-       unsigned int time;
-       unsigned int unit;
        bool tmr_large;
 
        char *level_trig;
@@ -218,13 +215,13 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
        char *pull_up_sel;
        char *pull_up_enable;
        char *pull_down_enable;
-       char *output_value;
-       char *output_enable;
+       char *orientation;
        char debounce_value[40];
        char *debounce_enable;
 
        for (bank = 0; bank < gpio_dev->hwbank_num; bank++) {
-               seq_printf(s, "GPIO bank%d\t", bank);
+               unsigned int time = 0;
+               unsigned int unit = 0;
 
                switch (bank) {
                case 0:
@@ -247,8 +244,9 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
                        /* Illegal bank number, ignore */
                        continue;
                }
+               seq_printf(s, "GPIO bank%d\n", bank);
                for (; i < pin_num; i++) {
-                       seq_printf(s, "pin%d\t", i);
+                       seq_printf(s, "📌%d\t", i);
                        raw_spin_lock_irqsave(&gpio_dev->lock, flags);
                        pin_reg = readl(gpio_dev->base + i * 4);
                        raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
@@ -256,84 +254,91 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
                        if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) {
                                u8 level = (pin_reg >> ACTIVE_LEVEL_OFF) &
                                                ACTIVE_LEVEL_MASK;
-                               interrupt_enable = "interrupt is enabled|";
+                               interrupt_enable = "+";
 
                                if (level == ACTIVE_LEVEL_HIGH)
-                                       active_level = "Active high|";
+                                       active_level = "";
                                else if (level == ACTIVE_LEVEL_LOW)
-                                       active_level = "Active low|";
+                                       active_level = "";
                                else if (!(pin_reg & BIT(LEVEL_TRIG_OFF)) &&
                                         level == ACTIVE_LEVEL_BOTH)
-                                       active_level = "Active on both|";
+                                       active_level = "b";
                                else
-                                       active_level = "Unknown Active level|";
+                                       active_level = "?";
 
                                if (pin_reg & BIT(LEVEL_TRIG_OFF))
-                                       level_trig = "Level trigger|";
+                                       level_trig = "level";
                                else
-                                       level_trig = "Edge trigger|";
+                                       level_trig = " edge";
 
                        } else {
-                               interrupt_enable =
-                                       "interrupt is disabled|";
-                               active_level = " ";
-                               level_trig = " ";
+                               interrupt_enable = "∅";
+                               active_level = "∅";
+                               level_trig = "    ∅";
                        }
 
                        if (pin_reg & BIT(INTERRUPT_MASK_OFF))
-                               interrupt_mask =
-                                       "interrupt is unmasked|";
+                               interrupt_mask = "-";
                        else
-                               interrupt_mask =
-                                       "interrupt is masked|";
+                               interrupt_mask = "+";
+                       seq_printf(s, "int %s (🎭 %s)| active-%s| %s-🔫| ",
+                                  interrupt_enable,
+                                  interrupt_mask,
+                                  active_level,
+                                  level_trig);
 
                        if (pin_reg & BIT(WAKE_CNTRL_OFF_S0I3))
-                               wake_cntrl0 = "enable wakeup in S0i3 state|";
+                               wake_cntrl0 = "+";
                        else
-                               wake_cntrl0 = "disable wakeup in S0i3 state|";
+                               wake_cntrl0 = "∅";
+                       seq_printf(s, "S0i3 🌅 %s| ", wake_cntrl0);
 
                        if (pin_reg & BIT(WAKE_CNTRL_OFF_S3))
-                               wake_cntrl1 = "enable wakeup in S3 state|";
+                               wake_cntrl1 = "+";
                        else
-                               wake_cntrl1 = "disable wakeup in S3 state|";
+                               wake_cntrl1 = "∅";
+                       seq_printf(s, "S3 🌅 %s| ", wake_cntrl1);
 
                        if (pin_reg & BIT(WAKE_CNTRL_OFF_S4))
-                               wake_cntrl2 = "enable wakeup in S4/S5 state|";
+                               wake_cntrl2 = "+";
                        else
-                               wake_cntrl2 = "disable wakeup in S4/S5 state|";
+                               wake_cntrl2 = "∅";
+                       seq_printf(s, "S4/S5 🌅 %s| ", wake_cntrl2);
 
                        if (pin_reg & BIT(PULL_UP_ENABLE_OFF)) {
-                               pull_up_enable = "pull-up is enabled|";
+                               pull_up_enable = "+";
                                if (pin_reg & BIT(PULL_UP_SEL_OFF))
-                                       pull_up_sel = "8k pull-up|";
+                                       pull_up_sel = "8k";
                                else
-                                       pull_up_sel = "4k pull-up|";
+                                       pull_up_sel = "4k";
                        } else {
-                               pull_up_enable = "pull-up is disabled|";
-                               pull_up_sel = " ";
+                               pull_up_enable = "";
+                               pull_up_sel = "  ";
                        }
+                       seq_printf(s, "pull-↑ %s (%s)| ",
+                                  pull_up_enable,
+                                  pull_up_sel);
 
                        if (pin_reg & BIT(PULL_DOWN_ENABLE_OFF))
-                               pull_down_enable = "pull-down is enabled|";
+                               pull_down_enable = "+";
                        else
-                               pull_down_enable = "Pull-down is disabled|";
+                               pull_down_enable = "∅";
+                       seq_printf(s, "pull-↓ %s| ", pull_down_enable);
 
                        if (pin_reg & BIT(OUTPUT_ENABLE_OFF)) {
-                               pin_sts = " ";
-                               output_enable = "output is enabled|";
+                               pin_sts = "output";
                                if (pin_reg & BIT(OUTPUT_VALUE_OFF))
-                                       output_value = "output is high|";
+                                       orientation = "↑";
                                else
-                                       output_value = "output is low|";
+                                       orientation = "↓";
                        } else {
-                               output_enable = "output is disabled|";
-                               output_value = " ";
-
+                               pin_sts = "input ";
                                if (pin_reg & BIT(PIN_STS_OFF))
-                                       pin_sts = "input is high|";
+                                       orientation = "↑";
                                else
-                                       pin_sts = "input is low|";
+                                       orientation = "↓";
                        }
+                       seq_printf(s, "%s %s| ", pin_sts, orientation);
 
                        db_cntrl = (DB_CNTRl_MASK << DB_CNTRL_OFF) & pin_reg;
                        if (db_cntrl) {
@@ -352,27 +357,18 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
                                                unit = 61;
                                }
                                if ((DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF) == db_cntrl)
-                                       debounce_enable = "debouncing filter (high and low) enabled|";
+                                       debounce_enable = "b +";
                                else if ((DB_TYPE_PRESERVE_LOW_GLITCH << DB_CNTRL_OFF) == db_cntrl)
-                                       debounce_enable = "debouncing filter (low) enabled|";
+                                       debounce_enable = "↓ +";
                                else
-                                       debounce_enable = "debouncing filter (high) enabled|";
+                                       debounce_enable = "↑ +";
 
-                               snprintf(debounce_value, sizeof(debounce_value),
-                                        "debouncing timeout is %u (us)|", time * unit);
                        } else {
-                               debounce_enable = "debouncing filter disabled|";
-                               snprintf(debounce_value, sizeof(debounce_value), " ");
+                               debounce_enable = "  ∅";
                        }
-
-                       seq_printf(s, "%s %s %s %s %s %s\n"
-                               " %s %s %s %s %s %s %s %s %s 0x%x\n",
-                               level_trig, active_level, interrupt_enable,
-                               interrupt_mask, wake_cntrl0, wake_cntrl1,
-                               wake_cntrl2, pin_sts, pull_up_sel,
-                               pull_up_enable, pull_down_enable,
-                               output_value, output_enable,
-                               debounce_enable, debounce_value, pin_reg);
+                       snprintf(debounce_value, sizeof(debounce_value), "%u", time * unit);
+                       seq_printf(s, "debounce %s (⏰ %sus)| ", debounce_enable, debounce_value);
+                       seq_printf(s, " 0x%x\n", pin_reg);
                }
        }
 }
@@ -917,6 +913,7 @@ static int amd_gpio_suspend(struct device *dev)
 {
        struct amd_gpio *gpio_dev = dev_get_drvdata(dev);
        struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+       unsigned long flags;
        int i;
 
        for (i = 0; i < desc->npins; i++) {
@@ -925,7 +922,9 @@ static int amd_gpio_suspend(struct device *dev)
                if (!amd_gpio_should_save(gpio_dev, pin))
                        continue;
 
-               gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin*4);
+               raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+               gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin * 4) & ~PIN_IRQ_PENDING;
+               raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
        }
 
        return 0;
@@ -935,6 +934,7 @@ static int amd_gpio_resume(struct device *dev)
 {
        struct amd_gpio *gpio_dev = dev_get_drvdata(dev);
        struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+       unsigned long flags;
        int i;
 
        for (i = 0; i < desc->npins; i++) {
@@ -943,7 +943,10 @@ static int amd_gpio_resume(struct device *dev)
                if (!amd_gpio_should_save(gpio_dev, pin))
                        continue;
 
-               writel(gpio_dev->saved_regs[i], gpio_dev->base + pin*4);
+               raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+               gpio_dev->saved_regs[i] |= readl(gpio_dev->base + pin * 4) & PIN_IRQ_PENDING;
+               writel(gpio_dev->saved_regs[i], gpio_dev->base + pin * 4);
+               raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
        }
 
        return 0;
@@ -955,14 +958,115 @@ static const struct dev_pm_ops amd_gpio_pm_ops = {
 };
 #endif
 
+static int amd_get_functions_count(struct pinctrl_dev *pctldev)
+{
+       return ARRAY_SIZE(pmx_functions);
+}
+
+static const char *amd_get_fname(struct pinctrl_dev *pctrldev, unsigned int selector)
+{
+       return pmx_functions[selector].name;
+}
+
+static int amd_get_groups(struct pinctrl_dev *pctrldev, unsigned int selector,
+                         const char * const **groups,
+                         unsigned int * const num_groups)
+{
+       struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctrldev);
+
+       if (!gpio_dev->iomux_base) {
+               dev_err(&gpio_dev->pdev->dev, "iomux function %d group not supported\n", selector);
+               return -EINVAL;
+       }
+
+       *groups = pmx_functions[selector].groups;
+       *num_groups = pmx_functions[selector].ngroups;
+       return 0;
+}
+
+static int amd_set_mux(struct pinctrl_dev *pctrldev, unsigned int function, unsigned int group)
+{
+       struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctrldev);
+       struct device *dev = &gpio_dev->pdev->dev;
+       struct pin_desc *pd;
+       int ind, index;
+
+       if (!gpio_dev->iomux_base)
+               return -EINVAL;
+
+       for (index = 0; index < NSELECTS; index++) {
+               if (strcmp(gpio_dev->groups[group].name,  pmx_functions[function].groups[index]))
+                       continue;
+
+               if (readb(gpio_dev->iomux_base + pmx_functions[function].index) ==
+                               FUNCTION_INVALID) {
+                       dev_err(dev, "IOMUX_GPIO 0x%x not present or supported\n",
+                               pmx_functions[function].index);
+                       return -EINVAL;
+               }
+
+               writeb(index, gpio_dev->iomux_base + pmx_functions[function].index);
+
+               if (index != (readb(gpio_dev->iomux_base + pmx_functions[function].index) &
+                                       FUNCTION_MASK)) {
+                       dev_err(dev, "IOMUX_GPIO 0x%x not present or supported\n",
+                               pmx_functions[function].index);
+                       return -EINVAL;
+               }
+
+               for (ind = 0; ind < gpio_dev->groups[group].npins; ind++) {
+                       if (strncmp(gpio_dev->groups[group].name, "IMX_F", strlen("IMX_F")))
+                               continue;
+
+                       pd = pin_desc_get(gpio_dev->pctrl, gpio_dev->groups[group].pins[ind]);
+                       pd->mux_owner = gpio_dev->groups[group].name;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static const struct pinmux_ops amd_pmxops = {
+       .get_functions_count = amd_get_functions_count,
+       .get_function_name = amd_get_fname,
+       .get_function_groups = amd_get_groups,
+       .set_mux = amd_set_mux,
+};
+
 static struct pinctrl_desc amd_pinctrl_desc = {
        .pins   = kerncz_pins,
        .npins = ARRAY_SIZE(kerncz_pins),
        .pctlops = &amd_pinctrl_ops,
+       .pmxops = &amd_pmxops,
        .confops = &amd_pinconf_ops,
        .owner = THIS_MODULE,
 };
 
+static void amd_get_iomux_res(struct amd_gpio *gpio_dev)
+{
+       struct pinctrl_desc *desc = &amd_pinctrl_desc;
+       struct device *dev = &gpio_dev->pdev->dev;
+       int index;
+
+       index = device_property_match_string(dev, "pinctrl-resource-names",  "iomux");
+       if (index < 0) {
+               dev_warn(dev, "failed to get iomux index\n");
+               goto out_no_pinmux;
+       }
+
+       gpio_dev->iomux_base = devm_platform_ioremap_resource(gpio_dev->pdev, index);
+       if (IS_ERR(gpio_dev->iomux_base)) {
+               dev_warn(dev, "Failed to get iomux %d io resource\n", index);
+               goto out_no_pinmux;
+       }
+
+       return;
+
+out_no_pinmux:
+       desc->pmxops = NULL;
+}
+
 static int amd_gpio_probe(struct platform_device *pdev)
 {
        int ret = 0;
@@ -977,17 +1081,12 @@ static int amd_gpio_probe(struct platform_device *pdev)
 
        raw_spin_lock_init(&gpio_dev->lock);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
+       gpio_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       if (IS_ERR(gpio_dev->base)) {
                dev_err(&pdev->dev, "Failed to get gpio io resource.\n");
-               return -EINVAL;
+               return PTR_ERR(gpio_dev->base);
        }
 
-       gpio_dev->base = devm_ioremap(&pdev->dev, res->start,
-                                               resource_size(res));
-       if (!gpio_dev->base)
-               return -ENOMEM;
-
        gpio_dev->irq = platform_get_irq(pdev, 0);
        if (gpio_dev->irq < 0)
                return gpio_dev->irq;
@@ -1020,6 +1119,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
        gpio_dev->ngroups = ARRAY_SIZE(kerncz_groups);
 
        amd_pinctrl_desc.name = dev_name(&pdev->dev);
+       amd_get_iomux_res(gpio_dev);
        gpio_dev->pctrl = devm_pinctrl_register(&pdev->dev, &amd_pinctrl_desc,
                                                gpio_dev);
        if (IS_ERR(gpio_dev->pctrl)) {
index 1d43170..c863599 100644 (file)
 
 #define CLR_INTR_STAT  0x1UL
 
-struct amd_pingroup {
-       const char *name;
-       const unsigned *pins;
-       unsigned npins;
-};
+#define NSELECTS       0x4
+
+#define FUNCTION_MASK          GENMASK(1, 0)
+#define FUNCTION_INVALID       GENMASK(7, 0)
 
 struct amd_function {
        const char *name;
-       const char * const *groups;
+       const char * const groups[NSELECTS];
        unsigned ngroups;
+       int index;
 };
 
 struct amd_gpio {
        raw_spinlock_t          lock;
        void __iomem            *base;
+       void __iomem            *iomux_base;
 
-       const struct amd_pingroup *groups;
+       const struct pingroup *groups;
        u32 ngroups;
        struct pinctrl_dev *pctrl;
        struct gpio_chip        gc;
@@ -288,45 +289,1332 @@ static const struct pinctrl_pin_desc kerncz_pins[] = {
        PINCTRL_PIN(183, "GPIO_183"),
 };
 
-static const unsigned i2c0_pins[] = {145, 146};
-static const unsigned i2c1_pins[] = {147, 148};
-static const unsigned i2c2_pins[] = {113, 114};
-static const unsigned i2c3_pins[] = {19, 20};
+#define AMD_PINS(...) (const unsigned int []){__VA_ARGS__}
+
+enum amd_functions {
+       IMX_F0_GPIO0,
+       IMX_F1_GPIO0,
+       IMX_F2_GPIO0,
+       IMX_F3_GPIO0,
+       IMX_F0_GPIO1,
+       IMX_F1_GPIO1,
+       IMX_F2_GPIO1,
+       IMX_F3_GPIO1,
+       IMX_F0_GPIO2,
+       IMX_F1_GPIO2,
+       IMX_F2_GPIO2,
+       IMX_F3_GPIO2,
+       IMX_F0_GPIO3,
+       IMX_F1_GPIO3,
+       IMX_F2_GPIO3,
+       IMX_F3_GPIO3,
+       IMX_F0_GPIO4,
+       IMX_F1_GPIO4,
+       IMX_F2_GPIO4,
+       IMX_F3_GPIO4,
+       IMX_F0_GPIO5,
+       IMX_F1_GPIO5,
+       IMX_F2_GPIO5,
+       IMX_F3_GPIO5,
+       IMX_F0_GPIO6,
+       IMX_F1_GPIO6,
+       IMX_F2_GPIO6,
+       IMX_F3_GPIO6,
+       IMX_F0_GPIO7,
+       IMX_F1_GPIO7,
+       IMX_F2_GPIO7,
+       IMX_F3_GPIO7,
+       IMX_F0_GPIO8,
+       IMX_F1_GPIO8,
+       IMX_F2_GPIO8,
+       IMX_F3_GPIO8,
+       IMX_F0_GPIO9,
+       IMX_F1_GPIO9,
+       IMX_F2_GPIO9,
+       IMX_F3_GPIO9,
+       IMX_F0_GPIO10,
+       IMX_F1_GPIO10,
+       IMX_F2_GPIO10,
+       IMX_F3_GPIO10,
+       IMX_F0_GPIO11,
+       IMX_F1_GPIO11,
+       IMX_F2_GPIO11,
+       IMX_F3_GPIO11,
+       IMX_F0_GPIO12,
+       IMX_F1_GPIO12,
+       IMX_F2_GPIO12,
+       IMX_F3_GPIO12,
+       IMX_F0_GPIO13,
+       IMX_F1_GPIO13,
+       IMX_F2_GPIO13,
+       IMX_F3_GPIO13,
+       IMX_F0_GPIO14,
+       IMX_F1_GPIO14,
+       IMX_F2_GPIO14,
+       IMX_F3_GPIO14,
+       IMX_F0_GPIO15,
+       IMX_F1_GPIO15,
+       IMX_F2_GPIO15,
+       IMX_F3_GPIO15,
+       IMX_F0_GPIO16,
+       IMX_F1_GPIO16,
+       IMX_F2_GPIO16,
+       IMX_F3_GPIO16,
+       IMX_F0_GPIO17,
+       IMX_F1_GPIO17,
+       IMX_F2_GPIO17,
+       IMX_F3_GPIO17,
+       IMX_F0_GPIO18,
+       IMX_F1_GPIO18,
+       IMX_F2_GPIO18,
+       IMX_F3_GPIO18,
+       IMX_F0_GPIO19,
+       IMX_F1_GPIO19,
+       IMX_F2_GPIO19,
+       IMX_F3_GPIO19,
+       IMX_F0_GPIO20,
+       IMX_F1_GPIO20,
+       IMX_F2_GPIO20,
+       IMX_F3_GPIO20,
+       IMX_F0_GPIO21,
+       IMX_F1_GPIO21,
+       IMX_F2_GPIO21,
+       IMX_F3_GPIO21,
+       IMX_F0_GPIO22,
+       IMX_F1_GPIO22,
+       IMX_F2_GPIO22,
+       IMX_F3_GPIO22,
+       IMX_F0_GPIO23,
+       IMX_F1_GPIO23,
+       IMX_F2_GPIO23,
+       IMX_F3_GPIO23,
+       IMX_F0_GPIO24,
+       IMX_F1_GPIO24,
+       IMX_F2_GPIO24,
+       IMX_F3_GPIO24,
+       IMX_F0_GPIO25,
+       IMX_F1_GPIO25,
+       IMX_F2_GPIO25,
+       IMX_F3_GPIO25,
+       IMX_F0_GPIO26,
+       IMX_F1_GPIO26,
+       IMX_F2_GPIO26,
+       IMX_F3_GPIO26,
+       IMX_F0_GPIO27,
+       IMX_F1_GPIO27,
+       IMX_F2_GPIO27,
+       IMX_F3_GPIO27,
+       IMX_F0_GPIO28,
+       IMX_F1_GPIO28,
+       IMX_F2_GPIO28,
+       IMX_F3_GPIO28,
+       IMX_F0_GPIO29,
+       IMX_F1_GPIO29,
+       IMX_F2_GPIO29,
+       IMX_F3_GPIO29,
+       IMX_F0_GPIO30,
+       IMX_F1_GPIO30,
+       IMX_F2_GPIO30,
+       IMX_F3_GPIO30,
+       IMX_F0_GPIO31,
+       IMX_F1_GPIO31,
+       IMX_F2_GPIO31,
+       IMX_F3_GPIO31,
+       IMX_F0_GPIO32,
+       IMX_F1_GPIO32,
+       IMX_F2_GPIO32,
+       IMX_F3_GPIO32,
+       IMX_F0_GPIO33,
+       IMX_F1_GPIO33,
+       IMX_F2_GPIO33,
+       IMX_F3_GPIO33,
+       IMX_F0_GPIO34,
+       IMX_F1_GPIO34,
+       IMX_F2_GPIO34,
+       IMX_F3_GPIO34,
+       IMX_F0_GPIO35,
+       IMX_F1_GPIO35,
+       IMX_F2_GPIO35,
+       IMX_F3_GPIO35,
+       IMX_F0_GPIO36,
+       IMX_F1_GPIO36,
+       IMX_F2_GPIO36,
+       IMX_F3_GPIO36,
+       IMX_F0_GPIO37,
+       IMX_F1_GPIO37,
+       IMX_F2_GPIO37,
+       IMX_F3_GPIO37,
+       IMX_F0_GPIO38,
+       IMX_F1_GPIO38,
+       IMX_F2_GPIO38,
+       IMX_F3_GPIO38,
+       IMX_F0_GPIO39,
+       IMX_F1_GPIO39,
+       IMX_F2_GPIO39,
+       IMX_F3_GPIO39,
+       IMX_F0_GPIO40,
+       IMX_F1_GPIO40,
+       IMX_F2_GPIO40,
+       IMX_F3_GPIO40,
+       IMX_F0_GPIO41,
+       IMX_F1_GPIO41,
+       IMX_F2_GPIO41,
+       IMX_F3_GPIO41,
+       IMX_F0_GPIO42,
+       IMX_F1_GPIO42,
+       IMX_F2_GPIO42,
+       IMX_F3_GPIO42,
+       IMX_F0_GPIO43,
+       IMX_F1_GPIO43,
+       IMX_F2_GPIO43,
+       IMX_F3_GPIO43,
+       IMX_F0_GPIO44,
+       IMX_F1_GPIO44,
+       IMX_F2_GPIO44,
+       IMX_F3_GPIO44,
+       IMX_F0_GPIO45,
+       IMX_F1_GPIO45,
+       IMX_F2_GPIO45,
+       IMX_F3_GPIO45,
+       IMX_F0_GPIO46,
+       IMX_F1_GPIO46,
+       IMX_F2_GPIO46,
+       IMX_F3_GPIO46,
+       IMX_F0_GPIO47,
+       IMX_F1_GPIO47,
+       IMX_F2_GPIO47,
+       IMX_F3_GPIO47,
+       IMX_F0_GPIO48,
+       IMX_F1_GPIO48,
+       IMX_F2_GPIO48,
+       IMX_F3_GPIO48,
+       IMX_F0_GPIO49,
+       IMX_F1_GPIO49,
+       IMX_F2_GPIO49,
+       IMX_F3_GPIO49,
+       IMX_F0_GPIO50,
+       IMX_F1_GPIO50,
+       IMX_F2_GPIO50,
+       IMX_F3_GPIO50,
+       IMX_F0_GPIO51,
+       IMX_F1_GPIO51,
+       IMX_F2_GPIO51,
+       IMX_F3_GPIO51,
+       IMX_F0_GPIO52,
+       IMX_F1_GPIO52,
+       IMX_F2_GPIO52,
+       IMX_F3_GPIO52,
+       IMX_F0_GPIO53,
+       IMX_F1_GPIO53,
+       IMX_F2_GPIO53,
+       IMX_F3_GPIO53,
+       IMX_F0_GPIO54,
+       IMX_F1_GPIO54,
+       IMX_F2_GPIO54,
+       IMX_F3_GPIO54,
+       IMX_F0_GPIO55,
+       IMX_F1_GPIO55,
+       IMX_F2_GPIO55,
+       IMX_F3_GPIO55,
+       IMX_F0_GPIO56,
+       IMX_F1_GPIO56,
+       IMX_F2_GPIO56,
+       IMX_F3_GPIO56,
+       IMX_F0_GPIO57,
+       IMX_F1_GPIO57,
+       IMX_F2_GPIO57,
+       IMX_F3_GPIO57,
+       IMX_F0_GPIO58,
+       IMX_F1_GPIO58,
+       IMX_F2_GPIO58,
+       IMX_F3_GPIO58,
+       IMX_F0_GPIO59,
+       IMX_F1_GPIO59,
+       IMX_F2_GPIO59,
+       IMX_F3_GPIO59,
+       IMX_F0_GPIO60,
+       IMX_F1_GPIO60,
+       IMX_F2_GPIO60,
+       IMX_F3_GPIO60,
+       IMX_F0_GPIO61,
+       IMX_F1_GPIO61,
+       IMX_F2_GPIO61,
+       IMX_F3_GPIO61,
+       IMX_F0_GPIO62,
+       IMX_F1_GPIO62,
+       IMX_F2_GPIO62,
+       IMX_F3_GPIO62,
+       IMX_F0_GPIO64,
+       IMX_F1_GPIO64,
+       IMX_F2_GPIO64,
+       IMX_F3_GPIO64,
+       IMX_F0_GPIO65,
+       IMX_F1_GPIO65,
+       IMX_F2_GPIO65,
+       IMX_F3_GPIO65,
+       IMX_F0_GPIO66,
+       IMX_F1_GPIO66,
+       IMX_F2_GPIO66,
+       IMX_F3_GPIO66,
+       IMX_F0_GPIO67,
+       IMX_F1_GPIO67,
+       IMX_F2_GPIO67,
+       IMX_F3_GPIO67,
+       IMX_F0_GPIO68,
+       IMX_F1_GPIO68,
+       IMX_F2_GPIO68,
+       IMX_F3_GPIO68,
+       IMX_F0_GPIO69,
+       IMX_F1_GPIO69,
+       IMX_F2_GPIO69,
+       IMX_F3_GPIO69,
+       IMX_F0_GPIO70,
+       IMX_F1_GPIO70,
+       IMX_F2_GPIO70,
+       IMX_F3_GPIO70,
+       IMX_F0_GPIO71,
+       IMX_F1_GPIO71,
+       IMX_F2_GPIO71,
+       IMX_F3_GPIO71,
+       IMX_F0_GPIO72,
+       IMX_F1_GPIO72,
+       IMX_F2_GPIO72,
+       IMX_F3_GPIO72,
+       IMX_F0_GPIO73,
+       IMX_F1_GPIO73,
+       IMX_F2_GPIO73,
+       IMX_F3_GPIO73,
+       IMX_F0_GPIO74,
+       IMX_F1_GPIO74,
+       IMX_F2_GPIO74,
+       IMX_F3_GPIO74,
+       IMX_F0_GPIO75,
+       IMX_F1_GPIO75,
+       IMX_F2_GPIO75,
+       IMX_F3_GPIO75,
+       IMX_F0_GPIO76,
+       IMX_F1_GPIO76,
+       IMX_F2_GPIO76,
+       IMX_F3_GPIO76,
+       IMX_F0_GPIO77,
+       IMX_F1_GPIO77,
+       IMX_F2_GPIO77,
+       IMX_F3_GPIO77,
+       IMX_F0_GPIO78,
+       IMX_F1_GPIO78,
+       IMX_F2_GPIO78,
+       IMX_F3_GPIO78,
+       IMX_F0_GPIO79,
+       IMX_F1_GPIO79,
+       IMX_F2_GPIO79,
+       IMX_F3_GPIO79,
+       IMX_F0_GPIO80,
+       IMX_F1_GPIO80,
+       IMX_F2_GPIO80,
+       IMX_F3_GPIO80,
+       IMX_F0_GPIO81,
+       IMX_F1_GPIO81,
+       IMX_F2_GPIO81,
+       IMX_F3_GPIO81,
+       IMX_F0_GPIO82,
+       IMX_F1_GPIO82,
+       IMX_F2_GPIO82,
+       IMX_F3_GPIO82,
+       IMX_F0_GPIO83,
+       IMX_F1_GPIO83,
+       IMX_F2_GPIO83,
+       IMX_F3_GPIO83,
+       IMX_F0_GPIO84,
+       IMX_F1_GPIO84,
+       IMX_F2_GPIO84,
+       IMX_F3_GPIO84,
+       IMX_F0_GPIO85,
+       IMX_F1_GPIO85,
+       IMX_F2_GPIO85,
+       IMX_F3_GPIO85,
+       IMX_F0_GPIO86,
+       IMX_F1_GPIO86,
+       IMX_F2_GPIO86,
+       IMX_F3_GPIO86,
+       IMX_F0_GPIO87,
+       IMX_F1_GPIO87,
+       IMX_F2_GPIO87,
+       IMX_F3_GPIO87,
+       IMX_F0_GPIO88,
+       IMX_F1_GPIO88,
+       IMX_F2_GPIO88,
+       IMX_F3_GPIO88,
+       IMX_F0_GPIO89,
+       IMX_F1_GPIO89,
+       IMX_F2_GPIO89,
+       IMX_F3_GPIO89,
+       IMX_F0_GPIO90,
+       IMX_F1_GPIO90,
+       IMX_F2_GPIO90,
+       IMX_F3_GPIO90,
+       IMX_F0_GPIO91,
+       IMX_F1_GPIO91,
+       IMX_F2_GPIO91,
+       IMX_F3_GPIO91,
+       IMX_F0_GPIO92,
+       IMX_F1_GPIO92,
+       IMX_F2_GPIO92,
+       IMX_F3_GPIO92,
+       IMX_F0_GPIO93,
+       IMX_F1_GPIO93,
+       IMX_F2_GPIO93,
+       IMX_F3_GPIO93,
+       IMX_F0_GPIO94,
+       IMX_F1_GPIO94,
+       IMX_F2_GPIO94,
+       IMX_F3_GPIO94,
+       IMX_F0_GPIO95,
+       IMX_F1_GPIO95,
+       IMX_F2_GPIO95,
+       IMX_F3_GPIO95,
+       IMX_F0_GPIO96,
+       IMX_F1_GPIO96,
+       IMX_F2_GPIO96,
+       IMX_F3_GPIO96,
+       IMX_F0_GPIO97,
+       IMX_F1_GPIO97,
+       IMX_F2_GPIO97,
+       IMX_F3_GPIO97,
+       IMX_F0_GPIO98,
+       IMX_F1_GPIO98,
+       IMX_F2_GPIO98,
+       IMX_F3_GPIO98,
+       IMX_F0_GPIO99,
+       IMX_F1_GPIO99,
+       IMX_F2_GPIO99,
+       IMX_F3_GPIO99,
+       IMX_F0_GPIO100,
+       IMX_F1_GPIO100,
+       IMX_F2_GPIO100,
+       IMX_F3_GPIO100,
+       IMX_F0_GPIO101,
+       IMX_F1_GPIO101,
+       IMX_F2_GPIO101,
+       IMX_F3_GPIO101,
+       IMX_F0_GPIO102,
+       IMX_F1_GPIO102,
+       IMX_F2_GPIO102,
+       IMX_F3_GPIO102,
+       IMX_F0_GPIO103,
+       IMX_F1_GPIO103,
+       IMX_F2_GPIO103,
+       IMX_F3_GPIO103,
+       IMX_F0_GPIO104,
+       IMX_F1_GPIO104,
+       IMX_F2_GPIO104,
+       IMX_F3_GPIO104,
+       IMX_F0_GPIO105,
+       IMX_F1_GPIO105,
+       IMX_F2_GPIO105,
+       IMX_F3_GPIO105,
+       IMX_F0_GPIO106,
+       IMX_F1_GPIO106,
+       IMX_F2_GPIO106,
+       IMX_F3_GPIO106,
+       IMX_F0_GPIO107,
+       IMX_F1_GPIO107,
+       IMX_F2_GPIO107,
+       IMX_F3_GPIO107,
+       IMX_F0_GPIO108,
+       IMX_F1_GPIO108,
+       IMX_F2_GPIO108,
+       IMX_F3_GPIO108,
+       IMX_F0_GPIO109,
+       IMX_F1_GPIO109,
+       IMX_F2_GPIO109,
+       IMX_F3_GPIO109,
+       IMX_F0_GPIO110,
+       IMX_F1_GPIO110,
+       IMX_F2_GPIO110,
+       IMX_F3_GPIO110,
+       IMX_F0_GPIO111,
+       IMX_F1_GPIO111,
+       IMX_F2_GPIO111,
+       IMX_F3_GPIO111,
+       IMX_F0_GPIO112,
+       IMX_F1_GPIO112,
+       IMX_F2_GPIO112,
+       IMX_F3_GPIO112,
+       IMX_F0_GPIO113,
+       IMX_F1_GPIO113,
+       IMX_F2_GPIO113,
+       IMX_F3_GPIO113,
+       IMX_F0_GPIO114,
+       IMX_F1_GPIO114,
+       IMX_F2_GPIO114,
+       IMX_F3_GPIO114,
+       IMX_F0_GPIO115,
+       IMX_F1_GPIO115,
+       IMX_F2_GPIO115,
+       IMX_F3_GPIO115,
+       IMX_F0_GPIO116,
+       IMX_F1_GPIO116,
+       IMX_F2_GPIO116,
+       IMX_F3_GPIO116,
+       IMX_F0_GPIO117,
+       IMX_F1_GPIO117,
+       IMX_F2_GPIO117,
+       IMX_F3_GPIO117,
+       IMX_F0_GPIO118,
+       IMX_F1_GPIO118,
+       IMX_F2_GPIO118,
+       IMX_F3_GPIO118,
+       IMX_F0_GPIO119,
+       IMX_F1_GPIO119,
+       IMX_F2_GPIO119,
+       IMX_F3_GPIO119,
+       IMX_F0_GPIO120,
+       IMX_F1_GPIO120,
+       IMX_F2_GPIO120,
+       IMX_F3_GPIO120,
+       IMX_F0_GPIO121,
+       IMX_F1_GPIO121,
+       IMX_F2_GPIO121,
+       IMX_F3_GPIO121,
+       IMX_F0_GPIO122,
+       IMX_F1_GPIO122,
+       IMX_F2_GPIO122,
+       IMX_F3_GPIO122,
+       IMX_F0_GPIO123,
+       IMX_F1_GPIO123,
+       IMX_F2_GPIO123,
+       IMX_F3_GPIO123,
+       IMX_F0_GPIO124,
+       IMX_F1_GPIO124,
+       IMX_F2_GPIO124,
+       IMX_F3_GPIO124,
+       IMX_F0_GPIO125,
+       IMX_F1_GPIO125,
+       IMX_F2_GPIO125,
+       IMX_F3_GPIO125,
+       IMX_F0_GPIO126,
+       IMX_F1_GPIO126,
+       IMX_F2_GPIO126,
+       IMX_F3_GPIO126,
+       IMX_F0_GPIO127,
+       IMX_F1_GPIO127,
+       IMX_F2_GPIO127,
+       IMX_F3_GPIO127,
+       IMX_F0_GPIO128,
+       IMX_F1_GPIO128,
+       IMX_F2_GPIO128,
+       IMX_F3_GPIO128,
+       IMX_F0_GPIO129,
+       IMX_F1_GPIO129,
+       IMX_F2_GPIO129,
+       IMX_F3_GPIO129,
+       IMX_F0_GPIO130,
+       IMX_F1_GPIO130,
+       IMX_F2_GPIO130,
+       IMX_F3_GPIO130,
+       IMX_F0_GPIO131,
+       IMX_F1_GPIO131,
+       IMX_F2_GPIO131,
+       IMX_F3_GPIO131,
+       IMX_F0_GPIO132,
+       IMX_F1_GPIO132,
+       IMX_F2_GPIO132,
+       IMX_F3_GPIO132,
+       IMX_F0_GPIO133,
+       IMX_F1_GPIO133,
+       IMX_F2_GPIO133,
+       IMX_F3_GPIO133,
+       IMX_F0_GPIO134,
+       IMX_F1_GPIO134,
+       IMX_F2_GPIO134,
+       IMX_F3_GPIO134,
+       IMX_F0_GPIO135,
+       IMX_F1_GPIO135,
+       IMX_F2_GPIO135,
+       IMX_F3_GPIO135,
+       IMX_F0_GPIO136,
+       IMX_F1_GPIO136,
+       IMX_F2_GPIO136,
+       IMX_F3_GPIO136,
+       IMX_F0_GPIO137,
+       IMX_F1_GPIO137,
+       IMX_F2_GPIO137,
+       IMX_F3_GPIO137,
+       IMX_F0_GPIO138,
+       IMX_F1_GPIO138,
+       IMX_F2_GPIO138,
+       IMX_F3_GPIO138,
+       IMX_F0_GPIO139,
+       IMX_F1_GPIO139,
+       IMX_F2_GPIO139,
+       IMX_F3_GPIO139,
+       IMX_F0_GPIO140,
+       IMX_F1_GPIO140,
+       IMX_F2_GPIO140,
+       IMX_F3_GPIO140,
+       IMX_F0_GPIO141,
+       IMX_F1_GPIO141,
+       IMX_F2_GPIO141,
+       IMX_F3_GPIO141,
+       IMX_F0_GPIO142,
+       IMX_F1_GPIO142,
+       IMX_F2_GPIO142,
+       IMX_F3_GPIO142,
+       IMX_F0_GPIO143,
+       IMX_F1_GPIO143,
+       IMX_F2_GPIO143,
+       IMX_F3_GPIO143,
+       IMX_F0_GPIO144,
+       IMX_F1_GPIO144,
+       IMX_F2_GPIO144,
+       IMX_F3_GPIO144,
+};
+
+#define AMD_PINCTRL_FUNC_GRP(_number, _func)                                           \
+       [IMX_F##_func##_GPIO##_number] =                                                \
+               PINCTRL_PINGROUP("IMX_F"#_func "_GPIO"#_number, AMD_PINS(_number), 1)
+
+static const struct pingroup kerncz_groups[] = {
+       AMD_PINCTRL_FUNC_GRP(0, 0),
+       AMD_PINCTRL_FUNC_GRP(0, 1),
+       AMD_PINCTRL_FUNC_GRP(0, 2),
+       AMD_PINCTRL_FUNC_GRP(0, 3),
+       AMD_PINCTRL_FUNC_GRP(1, 0),
+       AMD_PINCTRL_FUNC_GRP(1, 1),
+       AMD_PINCTRL_FUNC_GRP(1, 2),
+       AMD_PINCTRL_FUNC_GRP(1, 3),
+       AMD_PINCTRL_FUNC_GRP(2, 0),
+       AMD_PINCTRL_FUNC_GRP(2, 1),
+       AMD_PINCTRL_FUNC_GRP(2, 2),
+       AMD_PINCTRL_FUNC_GRP(2, 3),
+       AMD_PINCTRL_FUNC_GRP(3, 0),
+       AMD_PINCTRL_FUNC_GRP(3, 1),
+       AMD_PINCTRL_FUNC_GRP(3, 2),
+       AMD_PINCTRL_FUNC_GRP(3, 3),
+       AMD_PINCTRL_FUNC_GRP(4, 0),
+       AMD_PINCTRL_FUNC_GRP(4, 1),
+       AMD_PINCTRL_FUNC_GRP(4, 2),
+       AMD_PINCTRL_FUNC_GRP(4, 3),
+       AMD_PINCTRL_FUNC_GRP(5, 0),
+       AMD_PINCTRL_FUNC_GRP(5, 1),
+       AMD_PINCTRL_FUNC_GRP(5, 2),
+       AMD_PINCTRL_FUNC_GRP(5, 3),
+       AMD_PINCTRL_FUNC_GRP(6, 0),
+       AMD_PINCTRL_FUNC_GRP(6, 1),
+       AMD_PINCTRL_FUNC_GRP(6, 2),
+       AMD_PINCTRL_FUNC_GRP(6, 3),
+       AMD_PINCTRL_FUNC_GRP(7, 0),
+       AMD_PINCTRL_FUNC_GRP(7, 1),
+       AMD_PINCTRL_FUNC_GRP(7, 2),
+       AMD_PINCTRL_FUNC_GRP(7, 3),
+       AMD_PINCTRL_FUNC_GRP(8, 0),
+       AMD_PINCTRL_FUNC_GRP(8, 1),
+       AMD_PINCTRL_FUNC_GRP(8, 2),
+       AMD_PINCTRL_FUNC_GRP(8, 3),
+       AMD_PINCTRL_FUNC_GRP(9, 0),
+       AMD_PINCTRL_FUNC_GRP(9, 1),
+       AMD_PINCTRL_FUNC_GRP(9, 2),
+       AMD_PINCTRL_FUNC_GRP(9, 3),
+       AMD_PINCTRL_FUNC_GRP(10, 0),
+       AMD_PINCTRL_FUNC_GRP(10, 1),
+       AMD_PINCTRL_FUNC_GRP(10, 2),
+       AMD_PINCTRL_FUNC_GRP(10, 3),
+       AMD_PINCTRL_FUNC_GRP(11, 0),
+       AMD_PINCTRL_FUNC_GRP(11, 1),
+       AMD_PINCTRL_FUNC_GRP(11, 2),
+       AMD_PINCTRL_FUNC_GRP(11, 3),
+       AMD_PINCTRL_FUNC_GRP(12, 0),
+       AMD_PINCTRL_FUNC_GRP(12, 1),
+       AMD_PINCTRL_FUNC_GRP(12, 2),
+       AMD_PINCTRL_FUNC_GRP(12, 3),
+       AMD_PINCTRL_FUNC_GRP(13, 0),
+       AMD_PINCTRL_FUNC_GRP(13, 1),
+       AMD_PINCTRL_FUNC_GRP(13, 2),
+       AMD_PINCTRL_FUNC_GRP(13, 3),
+       AMD_PINCTRL_FUNC_GRP(14, 0),
+       AMD_PINCTRL_FUNC_GRP(14, 1),
+       AMD_PINCTRL_FUNC_GRP(14, 2),
+       AMD_PINCTRL_FUNC_GRP(14, 3),
+       AMD_PINCTRL_FUNC_GRP(15, 0),
+       AMD_PINCTRL_FUNC_GRP(15, 1),
+       AMD_PINCTRL_FUNC_GRP(15, 2),
+       AMD_PINCTRL_FUNC_GRP(15, 3),
+       AMD_PINCTRL_FUNC_GRP(16, 0),
+       AMD_PINCTRL_FUNC_GRP(16, 1),
+       AMD_PINCTRL_FUNC_GRP(16, 2),
+       AMD_PINCTRL_FUNC_GRP(16, 3),
+       AMD_PINCTRL_FUNC_GRP(17, 0),
+       AMD_PINCTRL_FUNC_GRP(17, 1),
+       AMD_PINCTRL_FUNC_GRP(17, 2),
+       AMD_PINCTRL_FUNC_GRP(17, 3),
+       AMD_PINCTRL_FUNC_GRP(18, 0),
+       AMD_PINCTRL_FUNC_GRP(18, 1),
+       AMD_PINCTRL_FUNC_GRP(18, 2),
+       AMD_PINCTRL_FUNC_GRP(18, 3),
+       AMD_PINCTRL_FUNC_GRP(19, 0),
+       AMD_PINCTRL_FUNC_GRP(19, 1),
+       AMD_PINCTRL_FUNC_GRP(19, 2),
+       AMD_PINCTRL_FUNC_GRP(19, 3),
+       AMD_PINCTRL_FUNC_GRP(20, 0),
+       AMD_PINCTRL_FUNC_GRP(20, 1),
+       AMD_PINCTRL_FUNC_GRP(20, 2),
+       AMD_PINCTRL_FUNC_GRP(20, 3),
+       AMD_PINCTRL_FUNC_GRP(21, 0),
+       AMD_PINCTRL_FUNC_GRP(21, 1),
+       AMD_PINCTRL_FUNC_GRP(21, 2),
+       AMD_PINCTRL_FUNC_GRP(21, 3),
+       AMD_PINCTRL_FUNC_GRP(22, 0),
+       AMD_PINCTRL_FUNC_GRP(22, 1),
+       AMD_PINCTRL_FUNC_GRP(22, 2),
+       AMD_PINCTRL_FUNC_GRP(22, 3),
+       AMD_PINCTRL_FUNC_GRP(23, 0),
+       AMD_PINCTRL_FUNC_GRP(23, 1),
+       AMD_PINCTRL_FUNC_GRP(23, 2),
+       AMD_PINCTRL_FUNC_GRP(23, 3),
+       AMD_PINCTRL_FUNC_GRP(24, 0),
+       AMD_PINCTRL_FUNC_GRP(24, 1),
+       AMD_PINCTRL_FUNC_GRP(24, 2),
+       AMD_PINCTRL_FUNC_GRP(24, 3),
+       AMD_PINCTRL_FUNC_GRP(25, 0),
+       AMD_PINCTRL_FUNC_GRP(25, 1),
+       AMD_PINCTRL_FUNC_GRP(25, 2),
+       AMD_PINCTRL_FUNC_GRP(25, 3),
+       AMD_PINCTRL_FUNC_GRP(26, 0),
+       AMD_PINCTRL_FUNC_GRP(26, 1),
+       AMD_PINCTRL_FUNC_GRP(26, 2),
+       AMD_PINCTRL_FUNC_GRP(26, 3),
+       AMD_PINCTRL_FUNC_GRP(27, 0),
+       AMD_PINCTRL_FUNC_GRP(27, 1),
+       AMD_PINCTRL_FUNC_GRP(27, 2),
+       AMD_PINCTRL_FUNC_GRP(27, 3),
+       AMD_PINCTRL_FUNC_GRP(28, 0),
+       AMD_PINCTRL_FUNC_GRP(28, 1),
+       AMD_PINCTRL_FUNC_GRP(28, 2),
+       AMD_PINCTRL_FUNC_GRP(28, 3),
+       AMD_PINCTRL_FUNC_GRP(29, 0),
+       AMD_PINCTRL_FUNC_GRP(29, 1),
+       AMD_PINCTRL_FUNC_GRP(29, 2),
+       AMD_PINCTRL_FUNC_GRP(29, 3),
+       AMD_PINCTRL_FUNC_GRP(30, 0),
+       AMD_PINCTRL_FUNC_GRP(30, 1),
+       AMD_PINCTRL_FUNC_GRP(30, 2),
+       AMD_PINCTRL_FUNC_GRP(30, 3),
+       AMD_PINCTRL_FUNC_GRP(31, 0),
+       AMD_PINCTRL_FUNC_GRP(31, 1),
+       AMD_PINCTRL_FUNC_GRP(31, 2),
+       AMD_PINCTRL_FUNC_GRP(31, 3),
+       AMD_PINCTRL_FUNC_GRP(32, 0),
+       AMD_PINCTRL_FUNC_GRP(32, 1),
+       AMD_PINCTRL_FUNC_GRP(32, 2),
+       AMD_PINCTRL_FUNC_GRP(32, 3),
+       AMD_PINCTRL_FUNC_GRP(33, 0),
+       AMD_PINCTRL_FUNC_GRP(33, 1),
+       AMD_PINCTRL_FUNC_GRP(33, 2),
+       AMD_PINCTRL_FUNC_GRP(33, 3),
+       AMD_PINCTRL_FUNC_GRP(34, 0),
+       AMD_PINCTRL_FUNC_GRP(34, 1),
+       AMD_PINCTRL_FUNC_GRP(34, 2),
+       AMD_PINCTRL_FUNC_GRP(34, 3),
+       AMD_PINCTRL_FUNC_GRP(35, 0),
+       AMD_PINCTRL_FUNC_GRP(35, 1),
+       AMD_PINCTRL_FUNC_GRP(35, 2),
+       AMD_PINCTRL_FUNC_GRP(35, 3),
+       AMD_PINCTRL_FUNC_GRP(36, 0),
+       AMD_PINCTRL_FUNC_GRP(36, 1),
+       AMD_PINCTRL_FUNC_GRP(36, 2),
+       AMD_PINCTRL_FUNC_GRP(36, 3),
+       AMD_PINCTRL_FUNC_GRP(37, 0),
+       AMD_PINCTRL_FUNC_GRP(37, 1),
+       AMD_PINCTRL_FUNC_GRP(37, 2),
+       AMD_PINCTRL_FUNC_GRP(37, 3),
+       AMD_PINCTRL_FUNC_GRP(38, 0),
+       AMD_PINCTRL_FUNC_GRP(38, 1),
+       AMD_PINCTRL_FUNC_GRP(38, 2),
+       AMD_PINCTRL_FUNC_GRP(38, 3),
+       AMD_PINCTRL_FUNC_GRP(39, 0),
+       AMD_PINCTRL_FUNC_GRP(39, 1),
+       AMD_PINCTRL_FUNC_GRP(39, 2),
+       AMD_PINCTRL_FUNC_GRP(39, 3),
+       AMD_PINCTRL_FUNC_GRP(40, 0),
+       AMD_PINCTRL_FUNC_GRP(40, 1),
+       AMD_PINCTRL_FUNC_GRP(40, 2),
+       AMD_PINCTRL_FUNC_GRP(40, 3),
+       AMD_PINCTRL_FUNC_GRP(41, 0),
+       AMD_PINCTRL_FUNC_GRP(41, 1),
+       AMD_PINCTRL_FUNC_GRP(41, 2),
+       AMD_PINCTRL_FUNC_GRP(41, 3),
+       AMD_PINCTRL_FUNC_GRP(42, 0),
+       AMD_PINCTRL_FUNC_GRP(42, 1),
+       AMD_PINCTRL_FUNC_GRP(42, 2),
+       AMD_PINCTRL_FUNC_GRP(42, 3),
+       AMD_PINCTRL_FUNC_GRP(43, 0),
+       AMD_PINCTRL_FUNC_GRP(43, 1),
+       AMD_PINCTRL_FUNC_GRP(43, 2),
+       AMD_PINCTRL_FUNC_GRP(43, 3),
+       AMD_PINCTRL_FUNC_GRP(44, 0),
+       AMD_PINCTRL_FUNC_GRP(44, 1),
+       AMD_PINCTRL_FUNC_GRP(44, 2),
+       AMD_PINCTRL_FUNC_GRP(44, 3),
+       AMD_PINCTRL_FUNC_GRP(45, 0),
+       AMD_PINCTRL_FUNC_GRP(45, 1),
+       AMD_PINCTRL_FUNC_GRP(45, 2),
+       AMD_PINCTRL_FUNC_GRP(45, 3),
+       AMD_PINCTRL_FUNC_GRP(46, 0),
+       AMD_PINCTRL_FUNC_GRP(46, 1),
+       AMD_PINCTRL_FUNC_GRP(46, 2),
+       AMD_PINCTRL_FUNC_GRP(46, 3),
+       AMD_PINCTRL_FUNC_GRP(47, 0),
+       AMD_PINCTRL_FUNC_GRP(47, 1),
+       AMD_PINCTRL_FUNC_GRP(47, 2),
+       AMD_PINCTRL_FUNC_GRP(47, 3),
+       AMD_PINCTRL_FUNC_GRP(48, 0),
+       AMD_PINCTRL_FUNC_GRP(48, 1),
+       AMD_PINCTRL_FUNC_GRP(48, 2),
+       AMD_PINCTRL_FUNC_GRP(48, 3),
+       AMD_PINCTRL_FUNC_GRP(49, 0),
+       AMD_PINCTRL_FUNC_GRP(49, 1),
+       AMD_PINCTRL_FUNC_GRP(49, 2),
+       AMD_PINCTRL_FUNC_GRP(49, 3),
+       AMD_PINCTRL_FUNC_GRP(50, 0),
+       AMD_PINCTRL_FUNC_GRP(50, 1),
+       AMD_PINCTRL_FUNC_GRP(50, 2),
+       AMD_PINCTRL_FUNC_GRP(50, 3),
+       AMD_PINCTRL_FUNC_GRP(51, 0),
+       AMD_PINCTRL_FUNC_GRP(51, 1),
+       AMD_PINCTRL_FUNC_GRP(51, 2),
+       AMD_PINCTRL_FUNC_GRP(51, 3),
+       AMD_PINCTRL_FUNC_GRP(52, 0),
+       AMD_PINCTRL_FUNC_GRP(52, 1),
+       AMD_PINCTRL_FUNC_GRP(52, 2),
+       AMD_PINCTRL_FUNC_GRP(52, 3),
+       AMD_PINCTRL_FUNC_GRP(53, 0),
+       AMD_PINCTRL_FUNC_GRP(53, 1),
+       AMD_PINCTRL_FUNC_GRP(53, 2),
+       AMD_PINCTRL_FUNC_GRP(53, 3),
+       AMD_PINCTRL_FUNC_GRP(54, 0),
+       AMD_PINCTRL_FUNC_GRP(54, 1),
+       AMD_PINCTRL_FUNC_GRP(54, 2),
+       AMD_PINCTRL_FUNC_GRP(54, 3),
+       AMD_PINCTRL_FUNC_GRP(55, 0),
+       AMD_PINCTRL_FUNC_GRP(55, 1),
+       AMD_PINCTRL_FUNC_GRP(55, 2),
+       AMD_PINCTRL_FUNC_GRP(55, 3),
+       AMD_PINCTRL_FUNC_GRP(56, 0),
+       AMD_PINCTRL_FUNC_GRP(56, 1),
+       AMD_PINCTRL_FUNC_GRP(56, 2),
+       AMD_PINCTRL_FUNC_GRP(56, 3),
+       AMD_PINCTRL_FUNC_GRP(57, 0),
+       AMD_PINCTRL_FUNC_GRP(57, 1),
+       AMD_PINCTRL_FUNC_GRP(57, 2),
+       AMD_PINCTRL_FUNC_GRP(57, 3),
+       AMD_PINCTRL_FUNC_GRP(58, 0),
+       AMD_PINCTRL_FUNC_GRP(58, 1),
+       AMD_PINCTRL_FUNC_GRP(58, 2),
+       AMD_PINCTRL_FUNC_GRP(58, 3),
+       AMD_PINCTRL_FUNC_GRP(59, 0),
+       AMD_PINCTRL_FUNC_GRP(59, 1),
+       AMD_PINCTRL_FUNC_GRP(59, 2),
+       AMD_PINCTRL_FUNC_GRP(59, 3),
+       AMD_PINCTRL_FUNC_GRP(60, 0),
+       AMD_PINCTRL_FUNC_GRP(60, 1),
+       AMD_PINCTRL_FUNC_GRP(60, 2),
+       AMD_PINCTRL_FUNC_GRP(60, 3),
+       AMD_PINCTRL_FUNC_GRP(61, 0),
+       AMD_PINCTRL_FUNC_GRP(61, 1),
+       AMD_PINCTRL_FUNC_GRP(61, 2),
+       AMD_PINCTRL_FUNC_GRP(61, 3),
+       AMD_PINCTRL_FUNC_GRP(62, 0),
+       AMD_PINCTRL_FUNC_GRP(62, 1),
+       AMD_PINCTRL_FUNC_GRP(62, 2),
+       AMD_PINCTRL_FUNC_GRP(62, 3),
+       AMD_PINCTRL_FUNC_GRP(64, 0),
+       AMD_PINCTRL_FUNC_GRP(64, 1),
+       AMD_PINCTRL_FUNC_GRP(64, 2),
+       AMD_PINCTRL_FUNC_GRP(64, 3),
+       AMD_PINCTRL_FUNC_GRP(65, 0),
+       AMD_PINCTRL_FUNC_GRP(65, 1),
+       AMD_PINCTRL_FUNC_GRP(65, 2),
+       AMD_PINCTRL_FUNC_GRP(65, 3),
+       AMD_PINCTRL_FUNC_GRP(66, 0),
+       AMD_PINCTRL_FUNC_GRP(66, 1),
+       AMD_PINCTRL_FUNC_GRP(66, 2),
+       AMD_PINCTRL_FUNC_GRP(66, 3),
+       AMD_PINCTRL_FUNC_GRP(67, 0),
+       AMD_PINCTRL_FUNC_GRP(67, 1),
+       AMD_PINCTRL_FUNC_GRP(67, 2),
+       AMD_PINCTRL_FUNC_GRP(67, 3),
+       AMD_PINCTRL_FUNC_GRP(68, 0),
+       AMD_PINCTRL_FUNC_GRP(68, 1),
+       AMD_PINCTRL_FUNC_GRP(68, 2),
+       AMD_PINCTRL_FUNC_GRP(68, 3),
+       AMD_PINCTRL_FUNC_GRP(69, 0),
+       AMD_PINCTRL_FUNC_GRP(69, 1),
+       AMD_PINCTRL_FUNC_GRP(69, 2),
+       AMD_PINCTRL_FUNC_GRP(69, 3),
+       AMD_PINCTRL_FUNC_GRP(70, 0),
+       AMD_PINCTRL_FUNC_GRP(70, 1),
+       AMD_PINCTRL_FUNC_GRP(70, 2),
+       AMD_PINCTRL_FUNC_GRP(70, 3),
+       AMD_PINCTRL_FUNC_GRP(71, 0),
+       AMD_PINCTRL_FUNC_GRP(71, 1),
+       AMD_PINCTRL_FUNC_GRP(71, 2),
+       AMD_PINCTRL_FUNC_GRP(71, 3),
+       AMD_PINCTRL_FUNC_GRP(72, 0),
+       AMD_PINCTRL_FUNC_GRP(72, 1),
+       AMD_PINCTRL_FUNC_GRP(72, 2),
+       AMD_PINCTRL_FUNC_GRP(72, 3),
+       AMD_PINCTRL_FUNC_GRP(73, 0),
+       AMD_PINCTRL_FUNC_GRP(73, 1),
+       AMD_PINCTRL_FUNC_GRP(73, 2),
+       AMD_PINCTRL_FUNC_GRP(73, 3),
+       AMD_PINCTRL_FUNC_GRP(74, 0),
+       AMD_PINCTRL_FUNC_GRP(74, 1),
+       AMD_PINCTRL_FUNC_GRP(74, 2),
+       AMD_PINCTRL_FUNC_GRP(74, 3),
+       AMD_PINCTRL_FUNC_GRP(75, 0),
+       AMD_PINCTRL_FUNC_GRP(75, 1),
+       AMD_PINCTRL_FUNC_GRP(75, 2),
+       AMD_PINCTRL_FUNC_GRP(75, 3),
+       AMD_PINCTRL_FUNC_GRP(76, 0),
+       AMD_PINCTRL_FUNC_GRP(76, 1),
+       AMD_PINCTRL_FUNC_GRP(76, 2),
+       AMD_PINCTRL_FUNC_GRP(76, 3),
+       AMD_PINCTRL_FUNC_GRP(77, 0),
+       AMD_PINCTRL_FUNC_GRP(77, 1),
+       AMD_PINCTRL_FUNC_GRP(77, 2),
+       AMD_PINCTRL_FUNC_GRP(77, 3),
+       AMD_PINCTRL_FUNC_GRP(78, 0),
+       AMD_PINCTRL_FUNC_GRP(78, 1),
+       AMD_PINCTRL_FUNC_GRP(78, 2),
+       AMD_PINCTRL_FUNC_GRP(78, 3),
+       AMD_PINCTRL_FUNC_GRP(79, 0),
+       AMD_PINCTRL_FUNC_GRP(79, 1),
+       AMD_PINCTRL_FUNC_GRP(79, 2),
+       AMD_PINCTRL_FUNC_GRP(79, 3),
+       AMD_PINCTRL_FUNC_GRP(80, 0),
+       AMD_PINCTRL_FUNC_GRP(80, 1),
+       AMD_PINCTRL_FUNC_GRP(80, 2),
+       AMD_PINCTRL_FUNC_GRP(80, 3),
+       AMD_PINCTRL_FUNC_GRP(81, 0),
+       AMD_PINCTRL_FUNC_GRP(81, 1),
+       AMD_PINCTRL_FUNC_GRP(81, 2),
+       AMD_PINCTRL_FUNC_GRP(81, 3),
+       AMD_PINCTRL_FUNC_GRP(82, 0),
+       AMD_PINCTRL_FUNC_GRP(82, 1),
+       AMD_PINCTRL_FUNC_GRP(82, 2),
+       AMD_PINCTRL_FUNC_GRP(82, 3),
+       AMD_PINCTRL_FUNC_GRP(83, 0),
+       AMD_PINCTRL_FUNC_GRP(83, 1),
+       AMD_PINCTRL_FUNC_GRP(83, 2),
+       AMD_PINCTRL_FUNC_GRP(83, 3),
+       AMD_PINCTRL_FUNC_GRP(84, 0),
+       AMD_PINCTRL_FUNC_GRP(84, 1),
+       AMD_PINCTRL_FUNC_GRP(84, 2),
+       AMD_PINCTRL_FUNC_GRP(84, 3),
+       AMD_PINCTRL_FUNC_GRP(85, 0),
+       AMD_PINCTRL_FUNC_GRP(85, 1),
+       AMD_PINCTRL_FUNC_GRP(85, 2),
+       AMD_PINCTRL_FUNC_GRP(85, 3),
+       AMD_PINCTRL_FUNC_GRP(86, 0),
+       AMD_PINCTRL_FUNC_GRP(86, 1),
+       AMD_PINCTRL_FUNC_GRP(86, 2),
+       AMD_PINCTRL_FUNC_GRP(86, 3),
+       AMD_PINCTRL_FUNC_GRP(87, 0),
+       AMD_PINCTRL_FUNC_GRP(87, 1),
+       AMD_PINCTRL_FUNC_GRP(87, 2),
+       AMD_PINCTRL_FUNC_GRP(87, 3),
+       AMD_PINCTRL_FUNC_GRP(88, 0),
+       AMD_PINCTRL_FUNC_GRP(88, 1),
+       AMD_PINCTRL_FUNC_GRP(88, 2),
+       AMD_PINCTRL_FUNC_GRP(88, 3),
+       AMD_PINCTRL_FUNC_GRP(89, 0),
+       AMD_PINCTRL_FUNC_GRP(89, 1),
+       AMD_PINCTRL_FUNC_GRP(89, 2),
+       AMD_PINCTRL_FUNC_GRP(89, 3),
+       AMD_PINCTRL_FUNC_GRP(90, 0),
+       AMD_PINCTRL_FUNC_GRP(90, 1),
+       AMD_PINCTRL_FUNC_GRP(90, 2),
+       AMD_PINCTRL_FUNC_GRP(90, 3),
+       AMD_PINCTRL_FUNC_GRP(91, 0),
+       AMD_PINCTRL_FUNC_GRP(91, 1),
+       AMD_PINCTRL_FUNC_GRP(91, 2),
+       AMD_PINCTRL_FUNC_GRP(91, 3),
+       AMD_PINCTRL_FUNC_GRP(92, 0),
+       AMD_PINCTRL_FUNC_GRP(92, 1),
+       AMD_PINCTRL_FUNC_GRP(92, 2),
+       AMD_PINCTRL_FUNC_GRP(92, 3),
+       AMD_PINCTRL_FUNC_GRP(93, 0),
+       AMD_PINCTRL_FUNC_GRP(93, 1),
+       AMD_PINCTRL_FUNC_GRP(93, 2),
+       AMD_PINCTRL_FUNC_GRP(93, 3),
+       AMD_PINCTRL_FUNC_GRP(94, 0),
+       AMD_PINCTRL_FUNC_GRP(94, 1),
+       AMD_PINCTRL_FUNC_GRP(94, 2),
+       AMD_PINCTRL_FUNC_GRP(94, 3),
+       AMD_PINCTRL_FUNC_GRP(95, 0),
+       AMD_PINCTRL_FUNC_GRP(95, 1),
+       AMD_PINCTRL_FUNC_GRP(95, 2),
+       AMD_PINCTRL_FUNC_GRP(95, 3),
+       AMD_PINCTRL_FUNC_GRP(96, 0),
+       AMD_PINCTRL_FUNC_GRP(96, 1),
+       AMD_PINCTRL_FUNC_GRP(96, 2),
+       AMD_PINCTRL_FUNC_GRP(96, 3),
+       AMD_PINCTRL_FUNC_GRP(97, 0),
+       AMD_PINCTRL_FUNC_GRP(97, 1),
+       AMD_PINCTRL_FUNC_GRP(97, 2),
+       AMD_PINCTRL_FUNC_GRP(97, 3),
+       AMD_PINCTRL_FUNC_GRP(98, 0),
+       AMD_PINCTRL_FUNC_GRP(98, 1),
+       AMD_PINCTRL_FUNC_GRP(98, 2),
+       AMD_PINCTRL_FUNC_GRP(98, 3),
+       AMD_PINCTRL_FUNC_GRP(99, 0),
+       AMD_PINCTRL_FUNC_GRP(99, 1),
+       AMD_PINCTRL_FUNC_GRP(99, 2),
+       AMD_PINCTRL_FUNC_GRP(99, 3),
+       AMD_PINCTRL_FUNC_GRP(100, 0),
+       AMD_PINCTRL_FUNC_GRP(100, 1),
+       AMD_PINCTRL_FUNC_GRP(100, 2),
+       AMD_PINCTRL_FUNC_GRP(100, 3),
+       AMD_PINCTRL_FUNC_GRP(101, 0),
+       AMD_PINCTRL_FUNC_GRP(101, 1),
+       AMD_PINCTRL_FUNC_GRP(101, 2),
+       AMD_PINCTRL_FUNC_GRP(101, 3),
+       AMD_PINCTRL_FUNC_GRP(102, 0),
+       AMD_PINCTRL_FUNC_GRP(102, 1),
+       AMD_PINCTRL_FUNC_GRP(102, 2),
+       AMD_PINCTRL_FUNC_GRP(102, 3),
+       AMD_PINCTRL_FUNC_GRP(103, 0),
+       AMD_PINCTRL_FUNC_GRP(103, 1),
+       AMD_PINCTRL_FUNC_GRP(103, 2),
+       AMD_PINCTRL_FUNC_GRP(103, 3),
+       AMD_PINCTRL_FUNC_GRP(104, 0),
+       AMD_PINCTRL_FUNC_GRP(104, 1),
+       AMD_PINCTRL_FUNC_GRP(104, 2),
+       AMD_PINCTRL_FUNC_GRP(104, 3),
+       AMD_PINCTRL_FUNC_GRP(105, 0),
+       AMD_PINCTRL_FUNC_GRP(105, 1),
+       AMD_PINCTRL_FUNC_GRP(105, 2),
+       AMD_PINCTRL_FUNC_GRP(105, 3),
+       AMD_PINCTRL_FUNC_GRP(106, 0),
+       AMD_PINCTRL_FUNC_GRP(106, 1),
+       AMD_PINCTRL_FUNC_GRP(106, 2),
+       AMD_PINCTRL_FUNC_GRP(106, 3),
+       AMD_PINCTRL_FUNC_GRP(107, 0),
+       AMD_PINCTRL_FUNC_GRP(107, 1),
+       AMD_PINCTRL_FUNC_GRP(107, 2),
+       AMD_PINCTRL_FUNC_GRP(107, 3),
+       AMD_PINCTRL_FUNC_GRP(108, 0),
+       AMD_PINCTRL_FUNC_GRP(108, 1),
+       AMD_PINCTRL_FUNC_GRP(108, 2),
+       AMD_PINCTRL_FUNC_GRP(108, 3),
+       AMD_PINCTRL_FUNC_GRP(109, 0),
+       AMD_PINCTRL_FUNC_GRP(109, 1),
+       AMD_PINCTRL_FUNC_GRP(109, 2),
+       AMD_PINCTRL_FUNC_GRP(109, 3),
+       AMD_PINCTRL_FUNC_GRP(110, 0),
+       AMD_PINCTRL_FUNC_GRP(110, 1),
+       AMD_PINCTRL_FUNC_GRP(110, 2),
+       AMD_PINCTRL_FUNC_GRP(110, 3),
+       AMD_PINCTRL_FUNC_GRP(111, 0),
+       AMD_PINCTRL_FUNC_GRP(111, 1),
+       AMD_PINCTRL_FUNC_GRP(111, 2),
+       AMD_PINCTRL_FUNC_GRP(111, 3),
+       AMD_PINCTRL_FUNC_GRP(112, 0),
+       AMD_PINCTRL_FUNC_GRP(112, 1),
+       AMD_PINCTRL_FUNC_GRP(112, 2),
+       AMD_PINCTRL_FUNC_GRP(112, 3),
+       AMD_PINCTRL_FUNC_GRP(113, 0),
+       AMD_PINCTRL_FUNC_GRP(113, 1),
+       AMD_PINCTRL_FUNC_GRP(113, 2),
+       AMD_PINCTRL_FUNC_GRP(113, 3),
+       AMD_PINCTRL_FUNC_GRP(114, 0),
+       AMD_PINCTRL_FUNC_GRP(114, 1),
+       AMD_PINCTRL_FUNC_GRP(114, 2),
+       AMD_PINCTRL_FUNC_GRP(114, 3),
+       AMD_PINCTRL_FUNC_GRP(115, 0),
+       AMD_PINCTRL_FUNC_GRP(115, 1),
+       AMD_PINCTRL_FUNC_GRP(115, 2),
+       AMD_PINCTRL_FUNC_GRP(115, 3),
+       AMD_PINCTRL_FUNC_GRP(116, 0),
+       AMD_PINCTRL_FUNC_GRP(116, 1),
+       AMD_PINCTRL_FUNC_GRP(116, 2),
+       AMD_PINCTRL_FUNC_GRP(116, 3),
+       AMD_PINCTRL_FUNC_GRP(117, 0),
+       AMD_PINCTRL_FUNC_GRP(117, 1),
+       AMD_PINCTRL_FUNC_GRP(117, 2),
+       AMD_PINCTRL_FUNC_GRP(117, 3),
+       AMD_PINCTRL_FUNC_GRP(118, 0),
+       AMD_PINCTRL_FUNC_GRP(118, 1),
+       AMD_PINCTRL_FUNC_GRP(118, 2),
+       AMD_PINCTRL_FUNC_GRP(118, 3),
+       AMD_PINCTRL_FUNC_GRP(119, 0),
+       AMD_PINCTRL_FUNC_GRP(119, 1),
+       AMD_PINCTRL_FUNC_GRP(119, 2),
+       AMD_PINCTRL_FUNC_GRP(119, 3),
+       AMD_PINCTRL_FUNC_GRP(120, 0),
+       AMD_PINCTRL_FUNC_GRP(120, 1),
+       AMD_PINCTRL_FUNC_GRP(120, 2),
+       AMD_PINCTRL_FUNC_GRP(120, 3),
+       AMD_PINCTRL_FUNC_GRP(121, 0),
+       AMD_PINCTRL_FUNC_GRP(121, 1),
+       AMD_PINCTRL_FUNC_GRP(121, 2),
+       AMD_PINCTRL_FUNC_GRP(121, 3),
+       AMD_PINCTRL_FUNC_GRP(122, 0),
+       AMD_PINCTRL_FUNC_GRP(122, 1),
+       AMD_PINCTRL_FUNC_GRP(122, 2),
+       AMD_PINCTRL_FUNC_GRP(122, 3),
+       AMD_PINCTRL_FUNC_GRP(123, 0),
+       AMD_PINCTRL_FUNC_GRP(123, 1),
+       AMD_PINCTRL_FUNC_GRP(123, 2),
+       AMD_PINCTRL_FUNC_GRP(123, 3),
+       AMD_PINCTRL_FUNC_GRP(124, 0),
+       AMD_PINCTRL_FUNC_GRP(124, 1),
+       AMD_PINCTRL_FUNC_GRP(124, 2),
+       AMD_PINCTRL_FUNC_GRP(124, 3),
+       AMD_PINCTRL_FUNC_GRP(125, 0),
+       AMD_PINCTRL_FUNC_GRP(125, 1),
+       AMD_PINCTRL_FUNC_GRP(125, 2),
+       AMD_PINCTRL_FUNC_GRP(125, 3),
+       AMD_PINCTRL_FUNC_GRP(126, 0),
+       AMD_PINCTRL_FUNC_GRP(126, 1),
+       AMD_PINCTRL_FUNC_GRP(126, 2),
+       AMD_PINCTRL_FUNC_GRP(126, 3),
+       AMD_PINCTRL_FUNC_GRP(127, 0),
+       AMD_PINCTRL_FUNC_GRP(127, 1),
+       AMD_PINCTRL_FUNC_GRP(127, 2),
+       AMD_PINCTRL_FUNC_GRP(127, 3),
+       AMD_PINCTRL_FUNC_GRP(128, 0),
+       AMD_PINCTRL_FUNC_GRP(128, 1),
+       AMD_PINCTRL_FUNC_GRP(128, 2),
+       AMD_PINCTRL_FUNC_GRP(128, 3),
+       AMD_PINCTRL_FUNC_GRP(129, 0),
+       AMD_PINCTRL_FUNC_GRP(129, 1),
+       AMD_PINCTRL_FUNC_GRP(129, 2),
+       AMD_PINCTRL_FUNC_GRP(129, 3),
+       AMD_PINCTRL_FUNC_GRP(130, 0),
+       AMD_PINCTRL_FUNC_GRP(130, 1),
+       AMD_PINCTRL_FUNC_GRP(130, 2),
+       AMD_PINCTRL_FUNC_GRP(130, 3),
+       AMD_PINCTRL_FUNC_GRP(131, 0),
+       AMD_PINCTRL_FUNC_GRP(131, 1),
+       AMD_PINCTRL_FUNC_GRP(131, 2),
+       AMD_PINCTRL_FUNC_GRP(131, 3),
+       AMD_PINCTRL_FUNC_GRP(132, 0),
+       AMD_PINCTRL_FUNC_GRP(132, 1),
+       AMD_PINCTRL_FUNC_GRP(132, 2),
+       AMD_PINCTRL_FUNC_GRP(132, 3),
+       AMD_PINCTRL_FUNC_GRP(133, 0),
+       AMD_PINCTRL_FUNC_GRP(133, 1),
+       AMD_PINCTRL_FUNC_GRP(133, 2),
+       AMD_PINCTRL_FUNC_GRP(133, 3),
+       AMD_PINCTRL_FUNC_GRP(134, 0),
+       AMD_PINCTRL_FUNC_GRP(134, 1),
+       AMD_PINCTRL_FUNC_GRP(134, 2),
+       AMD_PINCTRL_FUNC_GRP(134, 3),
+       AMD_PINCTRL_FUNC_GRP(135, 0),
+       AMD_PINCTRL_FUNC_GRP(135, 1),
+       AMD_PINCTRL_FUNC_GRP(135, 2),
+       AMD_PINCTRL_FUNC_GRP(135, 3),
+       AMD_PINCTRL_FUNC_GRP(136, 0),
+       AMD_PINCTRL_FUNC_GRP(136, 1),
+       AMD_PINCTRL_FUNC_GRP(136, 2),
+       AMD_PINCTRL_FUNC_GRP(136, 3),
+       AMD_PINCTRL_FUNC_GRP(137, 0),
+       AMD_PINCTRL_FUNC_GRP(137, 1),
+       AMD_PINCTRL_FUNC_GRP(137, 2),
+       AMD_PINCTRL_FUNC_GRP(137, 3),
+       AMD_PINCTRL_FUNC_GRP(138, 0),
+       AMD_PINCTRL_FUNC_GRP(138, 1),
+       AMD_PINCTRL_FUNC_GRP(138, 2),
+       AMD_PINCTRL_FUNC_GRP(138, 3),
+       AMD_PINCTRL_FUNC_GRP(139, 0),
+       AMD_PINCTRL_FUNC_GRP(139, 1),
+       AMD_PINCTRL_FUNC_GRP(139, 2),
+       AMD_PINCTRL_FUNC_GRP(139, 3),
+       AMD_PINCTRL_FUNC_GRP(140, 0),
+       AMD_PINCTRL_FUNC_GRP(140, 1),
+       AMD_PINCTRL_FUNC_GRP(140, 2),
+       AMD_PINCTRL_FUNC_GRP(140, 3),
+       AMD_PINCTRL_FUNC_GRP(141, 0),
+       AMD_PINCTRL_FUNC_GRP(141, 1),
+       AMD_PINCTRL_FUNC_GRP(141, 2),
+       AMD_PINCTRL_FUNC_GRP(141, 3),
+       AMD_PINCTRL_FUNC_GRP(142, 0),
+       AMD_PINCTRL_FUNC_GRP(142, 1),
+       AMD_PINCTRL_FUNC_GRP(142, 2),
+       AMD_PINCTRL_FUNC_GRP(142, 3),
+       AMD_PINCTRL_FUNC_GRP(143, 0),
+       AMD_PINCTRL_FUNC_GRP(143, 1),
+       AMD_PINCTRL_FUNC_GRP(143, 2),
+       AMD_PINCTRL_FUNC_GRP(143, 3),
+       AMD_PINCTRL_FUNC_GRP(144, 0),
+       AMD_PINCTRL_FUNC_GRP(144, 1),
+       AMD_PINCTRL_FUNC_GRP(144, 2),
+       AMD_PINCTRL_FUNC_GRP(144, 3),
+
+       PINCTRL_PINGROUP("i2c0", AMD_PINS(145, 146), 2),
+       PINCTRL_PINGROUP("i2c1", AMD_PINS(147, 148), 2),
+       PINCTRL_PINGROUP("i2c2", AMD_PINS(113, 114), 2),
+       PINCTRL_PINGROUP("i2c3", AMD_PINS(19, 20), 2),
+       PINCTRL_PINGROUP("uart0", AMD_PINS(135, 136, 137, 138, 139), 5),
+       PINCTRL_PINGROUP("uart1", AMD_PINS(140, 141, 142, 143, 144), 5),
+};
 
-static const unsigned uart0_pins[] = {135, 136, 137, 138, 139};
-static const unsigned uart1_pins[] = {140, 141, 142, 143, 144};
+#define AMD_PMUX_FUNC(_number) {                                               \
+       .name = "iomux_gpio_"#_number,                                          \
+       .groups = {                                                             \
+               "IMX_F0_GPIO"#_number, "IMX_F1_GPIO"#_number,                   \
+               "IMX_F2_GPIO"#_number, "IMX_F3_GPIO"#_number,                   \
+       },                                                                      \
+       .index = _number,                                                       \
+       .ngroups = NSELECTS,                                                    \
+}
 
-static const struct amd_pingroup kerncz_groups[] = {
-       {
-               .name = "i2c0",
-               .pins = i2c0_pins,
-               .npins = 2,
-       },
-       {
-               .name = "i2c1",
-               .pins = i2c1_pins,
-               .npins = 2,
-       },
-       {
-               .name = "i2c2",
-               .pins = i2c2_pins,
-               .npins = 2,
-       },
-       {
-               .name = "i2c3",
-               .pins = i2c3_pins,
-               .npins = 2,
-       },
-       {
-               .name = "uart0",
-               .pins = uart0_pins,
-               .npins = 5,
-       },
-       {
-               .name = "uart1",
-               .pins = uart1_pins,
-               .npins = 5,
-       },
+static const struct amd_function pmx_functions[] = {
+       AMD_PMUX_FUNC(0),
+       AMD_PMUX_FUNC(1),
+       AMD_PMUX_FUNC(2),
+       AMD_PMUX_FUNC(3),
+       AMD_PMUX_FUNC(4),
+       AMD_PMUX_FUNC(5),
+       AMD_PMUX_FUNC(6),
+       AMD_PMUX_FUNC(7),
+       AMD_PMUX_FUNC(8),
+       AMD_PMUX_FUNC(9),
+       AMD_PMUX_FUNC(10),
+       AMD_PMUX_FUNC(11),
+       AMD_PMUX_FUNC(12),
+       AMD_PMUX_FUNC(13),
+       AMD_PMUX_FUNC(14),
+       AMD_PMUX_FUNC(15),
+       AMD_PMUX_FUNC(16),
+       AMD_PMUX_FUNC(17),
+       AMD_PMUX_FUNC(18),
+       AMD_PMUX_FUNC(19),
+       AMD_PMUX_FUNC(20),
+       AMD_PMUX_FUNC(21),
+       AMD_PMUX_FUNC(22),
+       AMD_PMUX_FUNC(23),
+       AMD_PMUX_FUNC(24),
+       AMD_PMUX_FUNC(25),
+       AMD_PMUX_FUNC(26),
+       AMD_PMUX_FUNC(27),
+       AMD_PMUX_FUNC(28),
+       AMD_PMUX_FUNC(29),
+       AMD_PMUX_FUNC(30),
+       AMD_PMUX_FUNC(31),
+       AMD_PMUX_FUNC(32),
+       AMD_PMUX_FUNC(33),
+       AMD_PMUX_FUNC(34),
+       AMD_PMUX_FUNC(35),
+       AMD_PMUX_FUNC(36),
+       AMD_PMUX_FUNC(37),
+       AMD_PMUX_FUNC(38),
+       AMD_PMUX_FUNC(39),
+       AMD_PMUX_FUNC(40),
+       AMD_PMUX_FUNC(41),
+       AMD_PMUX_FUNC(42),
+       AMD_PMUX_FUNC(43),
+       AMD_PMUX_FUNC(44),
+       AMD_PMUX_FUNC(45),
+       AMD_PMUX_FUNC(46),
+       AMD_PMUX_FUNC(47),
+       AMD_PMUX_FUNC(48),
+       AMD_PMUX_FUNC(49),
+       AMD_PMUX_FUNC(50),
+       AMD_PMUX_FUNC(51),
+       AMD_PMUX_FUNC(52),
+       AMD_PMUX_FUNC(53),
+       AMD_PMUX_FUNC(54),
+       AMD_PMUX_FUNC(55),
+       AMD_PMUX_FUNC(56),
+       AMD_PMUX_FUNC(57),
+       AMD_PMUX_FUNC(58),
+       AMD_PMUX_FUNC(59),
+       AMD_PMUX_FUNC(60),
+       AMD_PMUX_FUNC(61),
+       AMD_PMUX_FUNC(62),
+       AMD_PMUX_FUNC(64),
+       AMD_PMUX_FUNC(65),
+       AMD_PMUX_FUNC(66),
+       AMD_PMUX_FUNC(67),
+       AMD_PMUX_FUNC(68),
+       AMD_PMUX_FUNC(69),
+       AMD_PMUX_FUNC(70),
+       AMD_PMUX_FUNC(71),
+       AMD_PMUX_FUNC(72),
+       AMD_PMUX_FUNC(73),
+       AMD_PMUX_FUNC(74),
+       AMD_PMUX_FUNC(75),
+       AMD_PMUX_FUNC(76),
+       AMD_PMUX_FUNC(77),
+       AMD_PMUX_FUNC(78),
+       AMD_PMUX_FUNC(79),
+       AMD_PMUX_FUNC(80),
+       AMD_PMUX_FUNC(81),
+       AMD_PMUX_FUNC(82),
+       AMD_PMUX_FUNC(83),
+       AMD_PMUX_FUNC(84),
+       AMD_PMUX_FUNC(85),
+       AMD_PMUX_FUNC(86),
+       AMD_PMUX_FUNC(87),
+       AMD_PMUX_FUNC(88),
+       AMD_PMUX_FUNC(89),
+       AMD_PMUX_FUNC(90),
+       AMD_PMUX_FUNC(91),
+       AMD_PMUX_FUNC(92),
+       AMD_PMUX_FUNC(93),
+       AMD_PMUX_FUNC(94),
+       AMD_PMUX_FUNC(95),
+       AMD_PMUX_FUNC(96),
+       AMD_PMUX_FUNC(97),
+       AMD_PMUX_FUNC(98),
+       AMD_PMUX_FUNC(99),
+       AMD_PMUX_FUNC(100),
+       AMD_PMUX_FUNC(101),
+       AMD_PMUX_FUNC(102),
+       AMD_PMUX_FUNC(103),
+       AMD_PMUX_FUNC(104),
+       AMD_PMUX_FUNC(105),
+       AMD_PMUX_FUNC(106),
+       AMD_PMUX_FUNC(107),
+       AMD_PMUX_FUNC(108),
+       AMD_PMUX_FUNC(109),
+       AMD_PMUX_FUNC(110),
+       AMD_PMUX_FUNC(111),
+       AMD_PMUX_FUNC(112),
+       AMD_PMUX_FUNC(113),
+       AMD_PMUX_FUNC(114),
+       AMD_PMUX_FUNC(115),
+       AMD_PMUX_FUNC(116),
+       AMD_PMUX_FUNC(117),
+       AMD_PMUX_FUNC(118),
+       AMD_PMUX_FUNC(119),
+       AMD_PMUX_FUNC(120),
+       AMD_PMUX_FUNC(121),
+       AMD_PMUX_FUNC(122),
+       AMD_PMUX_FUNC(123),
+       AMD_PMUX_FUNC(124),
+       AMD_PMUX_FUNC(125),
+       AMD_PMUX_FUNC(126),
+       AMD_PMUX_FUNC(127),
+       AMD_PMUX_FUNC(128),
+       AMD_PMUX_FUNC(129),
+       AMD_PMUX_FUNC(130),
+       AMD_PMUX_FUNC(131),
+       AMD_PMUX_FUNC(132),
+       AMD_PMUX_FUNC(133),
+       AMD_PMUX_FUNC(134),
+       AMD_PMUX_FUNC(135),
+       AMD_PMUX_FUNC(136),
+       AMD_PMUX_FUNC(137),
+       AMD_PMUX_FUNC(138),
+       AMD_PMUX_FUNC(139),
+       AMD_PMUX_FUNC(140),
+       AMD_PMUX_FUNC(141),
+       AMD_PMUX_FUNC(142),
+       AMD_PMUX_FUNC(143),
+       AMD_PMUX_FUNC(144),
 };
 
 #endif
index 517f2a6..82b921f 100644 (file)
@@ -237,8 +237,6 @@ static void atmel_gpio_irq_unmask(struct irq_data *d)
                         BIT(pin->line));
 }
 
-#ifdef CONFIG_PM_SLEEP
-
 static int atmel_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
 {
        struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d);
@@ -255,9 +253,6 @@ static int atmel_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
 
        return 0;
 }
-#else
-#define atmel_gpio_irq_set_wake NULL
-#endif /* CONFIG_PM_SLEEP */
 
 static struct irq_chip atmel_gpio_irq_chip = {
        .name           = "GPIO",
@@ -265,7 +260,7 @@ static struct irq_chip atmel_gpio_irq_chip = {
        .irq_mask       = atmel_gpio_irq_mask,
        .irq_unmask     = atmel_gpio_irq_unmask,
        .irq_set_type   = atmel_gpio_irq_set_type,
-       .irq_set_wake   = atmel_gpio_irq_set_wake,
+       .irq_set_wake   = pm_sleep_ptr(atmel_gpio_irq_set_wake),
 };
 
 static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
index d91a010..5634fa0 100644 (file)
@@ -1615,8 +1615,6 @@ static void gpio_irq_ack(struct irq_data *d)
        /* the interrupt is already cleared before by reading ISR */
 }
 
-#ifdef CONFIG_PM
-
 static u32 wakeups[MAX_GPIO_BANKS];
 static u32 backups[MAX_GPIO_BANKS];
 
@@ -1683,10 +1681,6 @@ void at91_pinctrl_gpio_resume(void)
        }
 }
 
-#else
-#define gpio_irq_set_wake      NULL
-#endif /* CONFIG_PM */
-
 static void gpio_irq_handler(struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -1741,14 +1735,14 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev,
        gpio_irqchip->irq_disable = gpio_irq_mask;
        gpio_irqchip->irq_mask = gpio_irq_mask;
        gpio_irqchip->irq_unmask = gpio_irq_unmask;
-       gpio_irqchip->irq_set_wake = gpio_irq_set_wake;
+       gpio_irqchip->irq_set_wake = pm_ptr(gpio_irq_set_wake);
        gpio_irqchip->irq_set_type = at91_gpio->ops->irq_type;
 
        /* Disable irqs of this PIO controller */
        writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
 
        /*
-        * Let the generic code handle this edge IRQ, the the chained
+        * Let the generic code handle this edge IRQ, the chained
         * handler will perform the actual work of handling the parent
         * interrupt.
         */
index 207cbae..7ab20ac 100644 (file)
@@ -73,7 +73,7 @@ static const struct pinctrl_pin_desc axp209_pins[] = {
        PINCTRL_PIN(2, "GPIO2"),
 };
 
-static const struct pinctrl_pin_desc axp813_pins[] = {
+static const struct pinctrl_pin_desc axp22x_pins[] = {
        PINCTRL_PIN(0, "GPIO0"),
        PINCTRL_PIN(1, "GPIO1"),
 };
@@ -87,9 +87,16 @@ static const struct axp20x_pctrl_desc axp20x_data = {
        .adc_mux = AXP20X_MUX_ADC,
 };
 
+static const struct axp20x_pctrl_desc axp22x_data = {
+       .pins   = axp22x_pins,
+       .npins  = ARRAY_SIZE(axp22x_pins),
+       .ldo_mask = BIT(0) | BIT(1),
+       .gpio_status_offset = 0,
+};
+
 static const struct axp20x_pctrl_desc axp813_data = {
-       .pins   = axp813_pins,
-       .npins  = ARRAY_SIZE(axp813_pins),
+       .pins   = axp22x_pins,
+       .npins  = ARRAY_SIZE(axp22x_pins),
        .ldo_mask = BIT(0) | BIT(1),
        .adc_mask = BIT(0),
        .gpio_status_offset = 0,
@@ -388,6 +395,7 @@ static int axp20x_build_funcs_groups(struct platform_device *pdev)
 
 static const struct of_device_id axp20x_pctl_match[] = {
        { .compatible = "x-powers,axp209-gpio", .data = &axp20x_data, },
+       { .compatible = "x-powers,axp221-gpio", .data = &axp22x_data, },
        { .compatible = "x-powers,axp813-gpio", .data = &axp813_data, },
        { }
 };
index 1ca1161..3a9ee9c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 
 #include "core.h"
@@ -135,7 +136,6 @@ struct ingenic_pinctrl {
 struct ingenic_gpio_chip {
        struct ingenic_pinctrl *jzpc;
        struct gpio_chip gc;
-       struct irq_chip irq_chip;
        unsigned int irq, reg_base;
 };
 
@@ -3393,7 +3393,7 @@ static void ingenic_gpio_irq_mask(struct irq_data *irqd)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
        struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-       int irq = irqd->hwirq;
+       irq_hw_number_t irq = irqd_to_hwirq(irqd);
 
        if (is_soc_or_above(jzgc->jzpc, ID_JZ4740))
                ingenic_gpio_set_bit(jzgc, GPIO_MSK, irq, true);
@@ -3405,7 +3405,7 @@ static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
        struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-       int irq = irqd->hwirq;
+       irq_hw_number_t irq = irqd_to_hwirq(irqd);
 
        if (is_soc_or_above(jzgc->jzpc, ID_JZ4740))
                ingenic_gpio_set_bit(jzgc, GPIO_MSK, irq, false);
@@ -3417,7 +3417,9 @@ static void ingenic_gpio_irq_enable(struct irq_data *irqd)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
        struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-       int irq = irqd->hwirq;
+       irq_hw_number_t irq = irqd_to_hwirq(irqd);
+
+       gpiochip_enable_irq(gc, irq);
 
        if (is_soc_or_above(jzgc->jzpc, ID_JZ4770))
                ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_INT, irq, true);
@@ -3433,7 +3435,7 @@ static void ingenic_gpio_irq_disable(struct irq_data *irqd)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
        struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-       int irq = irqd->hwirq;
+       irq_hw_number_t irq = irqd_to_hwirq(irqd);
 
        ingenic_gpio_irq_mask(irqd);
 
@@ -3443,13 +3445,15 @@ static void ingenic_gpio_irq_disable(struct irq_data *irqd)
                ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false);
        else
                ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_GPIER, irq, false);
+
+       gpiochip_disable_irq(gc, irq);
 }
 
 static void ingenic_gpio_irq_ack(struct irq_data *irqd)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
        struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-       int irq = irqd->hwirq;
+       irq_hw_number_t irq = irqd_to_hwirq(irqd);
        bool high;
 
        if ((irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) &&
@@ -3477,6 +3481,7 @@ static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
        struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+       irq_hw_number_t irq = irqd_to_hwirq(irqd);
 
        switch (type) {
        case IRQ_TYPE_EDGE_BOTH:
@@ -3498,12 +3503,12 @@ static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
                 * best we can do is to set up a single-edge interrupt and then
                 * switch to the opposing edge when ACKing the interrupt.
                 */
-               bool high = ingenic_gpio_get_value(jzgc, irqd->hwirq);
+               bool high = ingenic_gpio_get_value(jzgc, irq);
 
                type = high ? IRQ_TYPE_LEVEL_LOW : IRQ_TYPE_LEVEL_HIGH;
        }
 
-       irq_set_type(jzgc, irqd->hwirq, type);
+       irq_set_type(jzgc, irq, type);
        return 0;
 }
 
@@ -3668,22 +3673,45 @@ static const struct pinctrl_ops ingenic_pctlops = {
 static int ingenic_gpio_irq_request(struct irq_data *data)
 {
        struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+       irq_hw_number_t irq = irqd_to_hwirq(data);
        int ret;
 
-       ret = ingenic_gpio_direction_input(gpio_chip, data->hwirq);
+       ret = ingenic_gpio_direction_input(gpio_chip, irq);
        if (ret)
                return ret;
 
-       return gpiochip_reqres_irq(gpio_chip, data->hwirq);
+       return gpiochip_reqres_irq(gpio_chip, irq);
 }
 
 static void ingenic_gpio_irq_release(struct irq_data *data)
+{
+       struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+       irq_hw_number_t irq = irqd_to_hwirq(data);
+
+       return gpiochip_relres_irq(gpio_chip, irq);
+}
+
+static void ingenic_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p)
 {
        struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
 
-       return gpiochip_relres_irq(gpio_chip, data->hwirq);
+       seq_printf(p, "%s", gpio_chip->label);
 }
 
+static const struct irq_chip ingenic_gpio_irqchip = {
+       .irq_enable             = ingenic_gpio_irq_enable,
+       .irq_disable            = ingenic_gpio_irq_disable,
+       .irq_unmask             = ingenic_gpio_irq_unmask,
+       .irq_mask               = ingenic_gpio_irq_mask,
+       .irq_ack                = ingenic_gpio_irq_ack,
+       .irq_set_type           = ingenic_gpio_irq_set_type,
+       .irq_set_wake           = ingenic_gpio_irq_set_wake,
+       .irq_request_resources  = ingenic_gpio_irq_request,
+       .irq_release_resources  = ingenic_gpio_irq_release,
+       .irq_print_chip         = ingenic_gpio_irq_print_chip,
+       .flags                  = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
+};
+
 static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
                int pin, int func)
 {
@@ -4172,20 +4200,8 @@ static int __init ingenic_gpio_probe(struct ingenic_pinctrl *jzpc,
        if (!jzgc->irq)
                return -EINVAL;
 
-       jzgc->irq_chip.name = jzgc->gc.label;
-       jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable;
-       jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable;
-       jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
-       jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
-       jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
-       jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
-       jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
-       jzgc->irq_chip.irq_request_resources = ingenic_gpio_irq_request;
-       jzgc->irq_chip.irq_release_resources = ingenic_gpio_irq_release;
-       jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
-
        girq = &jzgc->gc.irq;
-       girq->chip = &jzgc->irq_chip;
+       gpio_irq_chip_set_chip(girq, &ingenic_gpio_irqchip);
        girq->parent_handler = ingenic_gpio_irq_handler;
        girq->num_parents = 1;
        girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
index 771dd1f..c5fd154 100644 (file)
@@ -1944,6 +1944,7 @@ static const struct of_device_id ocelot_pinctrl_of_match[] = {
        { .compatible = "microchip,lan966x-pinctrl", .data = &lan966x_desc },
        {},
 };
+MODULE_DEVICE_TABLE(of, ocelot_pinctrl_of_match);
 
 static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev,
                                                   const struct ocelot_pinctrl *info)
@@ -2050,4 +2051,5 @@ static struct platform_driver ocelot_pinctrl_driver = {
        },
        .probe = ocelot_pinctrl_probe,
 };
-builtin_platform_driver(ocelot_pinctrl_driver);
+module_platform_driver(ocelot_pinctrl_driver);
+MODULE_LICENSE("Dual MIT/GPL");
index 2a86c10..3eb40e2 100644 (file)
@@ -207,6 +207,7 @@ struct starfive_pinctrl {
        void __iomem *base;
        void __iomem *padctl;
        struct pinctrl_dev *pctl;
+       struct mutex mutex; /* serialize adding groups and functions */
 };
 
 static inline unsigned int starfive_pin_to_gpio(const struct starfive_pinctrl *sfp,
@@ -522,6 +523,7 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev,
 
        nmaps = 0;
        ngroups = 0;
+       mutex_lock(&sfp->mutex);
        for_each_child_of_node(np, child) {
                int npins;
                int i;
@@ -615,12 +617,14 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev,
 
        *maps = map;
        *num_maps = nmaps;
+       mutex_unlock(&sfp->mutex);
        return 0;
 
 put_child:
        of_node_put(child);
 free_map:
        pinctrl_utils_free_map(pctldev, map, nmaps);
+       mutex_unlock(&sfp->mutex);
        return ret;
 }
 
@@ -1267,6 +1271,7 @@ static int starfive_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, sfp);
        sfp->gc.parent = dev;
        raw_spin_lock_init(&sfp->lock);
+       mutex_init(&sfp->mutex);
 
        ret = devm_pinctrl_register_and_init(dev, &starfive_desc, sfp, &sfp->pctl);
        if (ret)
index e140122..7d2fbf8 100644 (file)
@@ -163,6 +163,8 @@ static const char *zynqmp_pmux_get_function_name(struct pinctrl_dev *pctldev,
  * @num_groups:        Number of function groups.
  *
  * Get function's group count and group names.
+ *
+ * Return: 0
  */
 static int zynqmp_pmux_get_function_groups(struct pinctrl_dev *pctldev,
                                           unsigned int selector,
@@ -410,6 +412,10 @@ static int zynqmp_pinconf_cfg_set(struct pinctrl_dev *pctldev,
 
                        break;
                case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+                       param = PM_PINCTRL_CONFIG_TRI_STATE;
+                       arg = PM_PINCTRL_TRI_STATE_ENABLE;
+                       ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+                       break;
                case PIN_CONFIG_MODE_LOW_POWER:
                        /*
                         * These cases are mentioned in dts but configurable
@@ -418,6 +424,11 @@ static int zynqmp_pinconf_cfg_set(struct pinctrl_dev *pctldev,
                         */
                        ret = 0;
                        break;
+               case PIN_CONFIG_OUTPUT_ENABLE:
+                       param = PM_PINCTRL_CONFIG_TRI_STATE;
+                       arg = PM_PINCTRL_TRI_STATE_DISABLE;
+                       ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+                       break;
                default:
                        dev_warn(pctldev->dev,
                                 "unsupported configuration parameter '%u'\n",
index 3daeb97..f415c13 100644 (file)
@@ -113,6 +113,14 @@ config PINCTRL_MSM8X74
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
          Qualcomm TLMM block found in the Qualcomm 8974 platform.
 
+config PINCTRL_MSM8909
+       tristate "Qualcomm 8909 pin controller driver"
+       depends on OF
+       depends on PINCTRL_MSM
+       help
+         This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+         Qualcomm TLMM block found on the Qualcomm MSM8909 platform.
+
 config PINCTRL_MSM8916
        tristate "Qualcomm 8916 pin controller driver"
        depends on OF
@@ -320,6 +328,15 @@ config PINCTRL_SM6350
         Qualcomm Technologies Inc TLMM block found on the Qualcomm
         Technologies Inc SM6350 platform.
 
+config PINCTRL_SM6375
+       tristate "Qualcomm Technologies Inc SM6375 pin controller driver"
+       depends on GPIOLIB && OF
+       depends on PINCTRL_MSM
+       help
+        This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+        Qualcomm Technologies Inc TLMM block found on the Qualcomm
+        Technologies Inc SM6375 platform.
+
 config PINCTRL_SDX65
        tristate "Qualcomm Technologies Inc SDX65 pin controller driver"
        depends on GPIOLIB && OF
@@ -367,7 +384,7 @@ config PINCTRL_SM8350
 config PINCTRL_SM8450
        tristate "Qualcomm Technologies Inc SM8450 pin controller driver"
        depends on GPIOLIB && OF
-       select PINCTRL_MSM
+       depends on PINCTRL_MSM
        help
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
          Qualcomm Technologies Inc TLMM block found on the Qualcomm
index 4f0ee75..fbd6485 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_PINCTRL_MSM8226) += pinctrl-msm8226.o
 obj-$(CONFIG_PINCTRL_MSM8660)  += pinctrl-msm8660.o
 obj-$(CONFIG_PINCTRL_MSM8960)  += pinctrl-msm8960.o
 obj-$(CONFIG_PINCTRL_MSM8X74)  += pinctrl-msm8x74.o
+obj-$(CONFIG_PINCTRL_MSM8909)  += pinctrl-msm8909.o
 obj-$(CONFIG_PINCTRL_MSM8916)  += pinctrl-msm8916.o
 obj-$(CONFIG_PINCTRL_MSM8953)  += pinctrl-msm8953.o
 obj-$(CONFIG_PINCTRL_MSM8976)  += pinctrl-msm8976.o
@@ -37,6 +38,7 @@ obj-$(CONFIG_PINCTRL_SDX55) += pinctrl-sdx55.o
 obj-$(CONFIG_PINCTRL_SM6115) += pinctrl-sm6115.o
 obj-$(CONFIG_PINCTRL_SM6125) += pinctrl-sm6125.o
 obj-$(CONFIG_PINCTRL_SM6350) += pinctrl-sm6350.o
+obj-$(CONFIG_PINCTRL_SM6375) += pinctrl-sm6375.o
 obj-$(CONFIG_PINCTRL_SDX65) += pinctrl-sdx65.o
 obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o
 obj-$(CONFIG_PINCTRL_SM8250) += pinctrl-sm8250.o
index 74810ec..e97ce45 100644 (file)
@@ -401,7 +401,7 @@ int lpi_pinctrl_probe(struct platform_device *pdev)
                return dev_err_probe(dev, PTR_ERR(pctrl->slew_base),
                                     "Slew resource not provided\n");
 
-       if (data->is_clk_optional)
+       if (of_property_read_bool(dev->of_node, "qcom,adsp-bypass-mode"))
                ret = devm_clk_bulk_get_optional(dev, MAX_LPI_NUM_CLKS, pctrl->clks);
        else
                ret = devm_clk_bulk_get(dev, MAX_LPI_NUM_CLKS, pctrl->clks);
index 759d5d8..afbac2a 100644 (file)
@@ -77,7 +77,6 @@ struct lpi_pinctrl_variant_data {
        int ngroups;
        const struct lpi_function *functions;
        int nfunctions;
-       bool is_clk_optional;
 };
 
 int lpi_pinctrl_probe(struct platform_device *pdev);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8909.c b/drivers/pinctrl/qcom/pinctrl-msm8909.c
new file mode 100644 (file)
index 0000000..6dd15b9
--- /dev/null
@@ -0,0 +1,956 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2022, Kernkonzept GmbH.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname)                                        \
+       [msm_mux_##fname] = {                           \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)       \
+       {                                               \
+               .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,                   \
+               },                                      \
+               .nfuncs = 10,                           \
+               .ctl_reg = REG_SIZE * id,               \
+               .io_reg = 0x4 + REG_SIZE * id,          \
+               .intr_cfg_reg = 0x8 + REG_SIZE * id,    \
+               .intr_status_reg = 0xc + REG_SIZE * id, \
+               .intr_target_reg = 0x8 + REG_SIZE * 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_target_bit = 5,                   \
+               .intr_target_kpss_val = 4,              \
+               .intr_raw_status_bit = 4,               \
+               .intr_polarity_bit = 1,                 \
+               .intr_detection_bit = 2,                \
+               .intr_detection_width = 2,              \
+       }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)     \
+       {                                               \
+               .name = #pg_name,                       \
+               .pins = pg_name##_pins,                 \
+               .npins = ARRAY_SIZE(pg_name##_pins),    \
+               .ctl_reg = ctl,                         \
+               .io_reg = 0,                            \
+               .intr_cfg_reg = 0,                      \
+               .intr_status_reg = 0,                   \
+               .intr_target_reg = 0,                   \
+               .mux_bit = -1,                          \
+               .pull_bit = pull,                       \
+               .drv_bit = drv,                         \
+               .oe_bit = -1,                           \
+               .in_bit = -1,                           \
+               .out_bit = -1,                          \
+               .intr_enable_bit = -1,                  \
+               .intr_status_bit = -1,                  \
+               .intr_target_bit = -1,                  \
+               .intr_raw_status_bit = -1,              \
+               .intr_polarity_bit = -1,                \
+               .intr_detection_bit = -1,               \
+               .intr_detection_width = -1,             \
+       }
+static const struct pinctrl_pin_desc msm8909_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"),
+       PINCTRL_PIN(88, "GPIO_88"),
+       PINCTRL_PIN(89, "GPIO_89"),
+       PINCTRL_PIN(90, "GPIO_90"),
+       PINCTRL_PIN(91, "GPIO_91"),
+       PINCTRL_PIN(92, "GPIO_92"),
+       PINCTRL_PIN(93, "GPIO_93"),
+       PINCTRL_PIN(94, "GPIO_94"),
+       PINCTRL_PIN(95, "GPIO_95"),
+       PINCTRL_PIN(96, "GPIO_96"),
+       PINCTRL_PIN(97, "GPIO_97"),
+       PINCTRL_PIN(98, "GPIO_98"),
+       PINCTRL_PIN(99, "GPIO_99"),
+       PINCTRL_PIN(100, "GPIO_100"),
+       PINCTRL_PIN(101, "GPIO_101"),
+       PINCTRL_PIN(102, "GPIO_102"),
+       PINCTRL_PIN(103, "GPIO_103"),
+       PINCTRL_PIN(104, "GPIO_104"),
+       PINCTRL_PIN(105, "GPIO_105"),
+       PINCTRL_PIN(106, "GPIO_106"),
+       PINCTRL_PIN(107, "GPIO_107"),
+       PINCTRL_PIN(108, "GPIO_108"),
+       PINCTRL_PIN(109, "GPIO_109"),
+       PINCTRL_PIN(110, "GPIO_110"),
+       PINCTRL_PIN(111, "GPIO_111"),
+       PINCTRL_PIN(112, "GPIO_112"),
+       PINCTRL_PIN(113, "SDC1_CLK"),
+       PINCTRL_PIN(114, "SDC1_CMD"),
+       PINCTRL_PIN(115, "SDC1_DATA"),
+       PINCTRL_PIN(116, "SDC2_CLK"),
+       PINCTRL_PIN(117, "SDC2_CMD"),
+       PINCTRL_PIN(118, "SDC2_DATA"),
+       PINCTRL_PIN(119, "QDSD_CLK"),
+       PINCTRL_PIN(120, "QDSD_CMD"),
+       PINCTRL_PIN(121, "QDSD_DATA0"),
+       PINCTRL_PIN(122, "QDSD_DATA1"),
+       PINCTRL_PIN(123, "QDSD_DATA2"),
+       PINCTRL_PIN(124, "QDSD_DATA3"),
+};
+
+#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);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+
+static const unsigned int sdc1_clk_pins[] = { 113 };
+static const unsigned int sdc1_cmd_pins[] = { 114 };
+static const unsigned int sdc1_data_pins[] = { 115 };
+static const unsigned int sdc2_clk_pins[] = { 116 };
+static const unsigned int sdc2_cmd_pins[] = { 117 };
+static const unsigned int sdc2_data_pins[] = { 118 };
+static const unsigned int qdsd_clk_pins[] = { 119 };
+static const unsigned int qdsd_cmd_pins[] = { 120 };
+static const unsigned int qdsd_data0_pins[] = { 121 };
+static const unsigned int qdsd_data1_pins[] = { 122 };
+static const unsigned int qdsd_data2_pins[] = { 123 };
+static const unsigned int qdsd_data3_pins[] = { 124 };
+
+enum msm8909_functions {
+       msm_mux_gpio,
+       msm_mux_adsp_ext,
+       msm_mux_atest_bbrx0,
+       msm_mux_atest_bbrx1,
+       msm_mux_atest_char,
+       msm_mux_atest_char0,
+       msm_mux_atest_char1,
+       msm_mux_atest_char2,
+       msm_mux_atest_char3,
+       msm_mux_atest_combodac,
+       msm_mux_atest_gpsadc0,
+       msm_mux_atest_gpsadc1,
+       msm_mux_atest_wlan0,
+       msm_mux_atest_wlan1,
+       msm_mux_bimc_dte0,
+       msm_mux_bimc_dte1,
+       msm_mux_blsp_i2c1,
+       msm_mux_blsp_i2c2,
+       msm_mux_blsp_i2c3,
+       msm_mux_blsp_i2c4,
+       msm_mux_blsp_i2c5,
+       msm_mux_blsp_i2c6,
+       msm_mux_blsp_spi1,
+       msm_mux_blsp_spi1_cs1,
+       msm_mux_blsp_spi1_cs2,
+       msm_mux_blsp_spi1_cs3,
+       msm_mux_blsp_spi2,
+       msm_mux_blsp_spi2_cs1,
+       msm_mux_blsp_spi2_cs2,
+       msm_mux_blsp_spi2_cs3,
+       msm_mux_blsp_spi3,
+       msm_mux_blsp_spi3_cs1,
+       msm_mux_blsp_spi3_cs2,
+       msm_mux_blsp_spi3_cs3,
+       msm_mux_blsp_spi4,
+       msm_mux_blsp_spi5,
+       msm_mux_blsp_spi6,
+       msm_mux_blsp_uart1,
+       msm_mux_blsp_uart2,
+       msm_mux_blsp_uim1,
+       msm_mux_blsp_uim2,
+       msm_mux_cam_mclk,
+       msm_mux_cci_async,
+       msm_mux_cci_timer0,
+       msm_mux_cci_timer1,
+       msm_mux_cci_timer2,
+       msm_mux_cdc_pdm0,
+       msm_mux_dbg_out,
+       msm_mux_dmic0_clk,
+       msm_mux_dmic0_data,
+       msm_mux_ebi0_wrcdc,
+       msm_mux_ebi2_a,
+       msm_mux_ebi2_lcd,
+       msm_mux_ext_lpass,
+       msm_mux_gcc_gp1_clk_a,
+       msm_mux_gcc_gp1_clk_b,
+       msm_mux_gcc_gp2_clk_a,
+       msm_mux_gcc_gp2_clk_b,
+       msm_mux_gcc_gp3_clk_a,
+       msm_mux_gcc_gp3_clk_b,
+       msm_mux_gcc_plltest,
+       msm_mux_gsm0_tx,
+       msm_mux_ldo_en,
+       msm_mux_ldo_update,
+       msm_mux_m_voc,
+       msm_mux_mdp_vsync,
+       msm_mux_modem_tsync,
+       msm_mux_nav_pps,
+       msm_mux_nav_tsync,
+       msm_mux_pa_indicator,
+       msm_mux_pbs0,
+       msm_mux_pbs1,
+       msm_mux_pbs2,
+       msm_mux_pri_mi2s_data0_a,
+       msm_mux_pri_mi2s_data0_b,
+       msm_mux_pri_mi2s_data1_a,
+       msm_mux_pri_mi2s_data1_b,
+       msm_mux_pri_mi2s_mclk_a,
+       msm_mux_pri_mi2s_mclk_b,
+       msm_mux_pri_mi2s_sck_a,
+       msm_mux_pri_mi2s_sck_b,
+       msm_mux_pri_mi2s_ws_a,
+       msm_mux_pri_mi2s_ws_b,
+       msm_mux_prng_rosc,
+       msm_mux_pwr_crypto_enabled_a,
+       msm_mux_pwr_crypto_enabled_b,
+       msm_mux_pwr_modem_enabled_a,
+       msm_mux_pwr_modem_enabled_b,
+       msm_mux_pwr_nav_enabled_a,
+       msm_mux_pwr_nav_enabled_b,
+       msm_mux_qdss_cti_trig_in_a0,
+       msm_mux_qdss_cti_trig_in_a1,
+       msm_mux_qdss_cti_trig_in_b0,
+       msm_mux_qdss_cti_trig_in_b1,
+       msm_mux_qdss_cti_trig_out_a0,
+       msm_mux_qdss_cti_trig_out_a1,
+       msm_mux_qdss_cti_trig_out_b0,
+       msm_mux_qdss_cti_trig_out_b1,
+       msm_mux_qdss_traceclk_a,
+       msm_mux_qdss_tracectl_a,
+       msm_mux_qdss_tracedata_a,
+       msm_mux_qdss_tracedata_b,
+       msm_mux_sd_write,
+       msm_mux_sec_mi2s,
+       msm_mux_smb_int,
+       msm_mux_ssbi0,
+       msm_mux_ssbi1,
+       msm_mux_uim1_clk,
+       msm_mux_uim1_data,
+       msm_mux_uim1_present,
+       msm_mux_uim1_reset,
+       msm_mux_uim2_clk,
+       msm_mux_uim2_data,
+       msm_mux_uim2_present,
+       msm_mux_uim2_reset,
+       msm_mux_uim3_clk,
+       msm_mux_uim3_data,
+       msm_mux_uim3_present,
+       msm_mux_uim3_reset,
+       msm_mux_uim_batt,
+       msm_mux_wcss_bt,
+       msm_mux_wcss_fm,
+       msm_mux_wcss_wlan,
+       msm_mux__,
+};
+
+static const char * const adsp_ext_groups[] = { "gpio38" };
+static const char * const atest_bbrx0_groups[] = { "gpio37" };
+static const char * const atest_bbrx1_groups[] = { "gpio36" };
+static const char * const atest_char0_groups[] = { "gpio62" };
+static const char * const atest_char1_groups[] = { "gpio61" };
+static const char * const atest_char2_groups[] = { "gpio60" };
+static const char * const atest_char3_groups[] = { "gpio59" };
+static const char * const atest_char_groups[] = { "gpio63" };
+static const char * const atest_combodac_groups[] = {
+       "gpio32", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
+       "gpio44", "gpio45", "gpio47", "gpio48", "gpio66", "gpio81", "gpio83",
+       "gpio84", "gpio85", "gpio86", "gpio94", "gpio95", "gpio110"
+};
+static const char * const atest_gpsadc0_groups[] = { "gpio65" };
+static const char * const atest_gpsadc1_groups[] = { "gpio79" };
+static const char * const atest_wlan0_groups[] = { "gpio96" };
+static const char * const atest_wlan1_groups[] = { "gpio97" };
+static const char * const bimc_dte0_groups[] = { "gpio6", "gpio59" };
+static const char * const bimc_dte1_groups[] = { "gpio7", "gpio60" };
+static const char * const blsp_i2c1_groups[] = { "gpio6", "gpio7" };
+static const char * const blsp_i2c2_groups[] = { "gpio111", "gpio112" };
+static const char * const blsp_i2c3_groups[] = { "gpio29", "gpio30" };
+static const char * const blsp_i2c4_groups[] = { "gpio14", "gpio15" };
+static const char * const blsp_i2c5_groups[] = { "gpio18", "gpio19" };
+static const char * const blsp_i2c6_groups[] = { "gpio10", "gpio11" };
+static const char * const blsp_spi1_cs1_groups[] = { "gpio97" };
+static const char * const blsp_spi1_cs2_groups[] = { "gpio37" };
+static const char * const blsp_spi1_cs3_groups[] = { "gpio65" };
+static const char * const blsp_spi1_groups[] = {
+       "gpio4", "gpio5", "gpio6", "gpio7"
+};
+static const char * const blsp_spi2_cs1_groups[] = { "gpio98" };
+static const char * const blsp_spi2_cs2_groups[] = { "gpio17" };
+static const char * const blsp_spi2_cs3_groups[] = { "gpio5" };
+static const char * const blsp_spi2_groups[] = {
+       "gpio20", "gpio21", "gpio111", "gpio112"
+};
+static const char * const blsp_spi3_cs1_groups[] = { "gpio95" };
+static const char * const blsp_spi3_cs2_groups[] = { "gpio65" };
+static const char * const blsp_spi3_cs3_groups[] = { "gpio4" };
+static const char * const blsp_spi3_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3"
+};
+static const char * const blsp_spi4_groups[] = {
+       "gpio12", "gpio13", "gpio14", "gpio15"
+};
+static const char * const blsp_spi5_groups[] = {
+       "gpio16", "gpio17", "gpio18", "gpio19"
+};
+static const char * const blsp_spi6_groups[] = {
+       "gpio8", "gpio9", "gpio10", "gpio11"
+};
+static const char * const blsp_uart1_groups[] = {
+       "gpio4", "gpio5", "gpio6", "gpio7"
+};
+static const char * const blsp_uart2_groups[] = {
+       "gpio20", "gpio21", "gpio111", "gpio112"
+};
+static const char * const blsp_uim1_groups[] = { "gpio4", "gpio5" };
+static const char * const blsp_uim2_groups[] = { "gpio20", "gpio21" };
+static const char * const cam_mclk_groups[] = { "gpio26", "gpio27" };
+static const char * const cci_async_groups[] = { "gpio33" };
+static const char * const cci_timer0_groups[] = { "gpio31" };
+static const char * const cci_timer1_groups[] = { "gpio32" };
+static const char * const cci_timer2_groups[] = { "gpio38" };
+static const char * const cdc_pdm0_groups[] = {
+       "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", "gpio64"
+};
+static const char * const dbg_out_groups[] = { "gpio10" };
+static const char * const dmic0_clk_groups[] = { "gpio4" };
+static const char * const dmic0_data_groups[] = { "gpio5" };
+static const char * const ebi0_wrcdc_groups[] = { "gpio64" };
+static const char * const ebi2_a_groups[] = { "gpio99" };
+static const char * const ebi2_lcd_groups[] = {
+       "gpio24", "gpio24", "gpio25", "gpio95"
+};
+static const char * const ext_lpass_groups[] = { "gpio45" };
+static const char * const gcc_gp1_clk_a_groups[] = { "gpio49" };
+static const char * const gcc_gp1_clk_b_groups[] = { "gpio14" };
+static const char * const gcc_gp2_clk_a_groups[] = { "gpio50" };
+static const char * const gcc_gp2_clk_b_groups[] = { "gpio12" };
+static const char * const gcc_gp3_clk_a_groups[] = { "gpio51" };
+static const char * const gcc_gp3_clk_b_groups[] = { "gpio13" };
+static const char * const gcc_plltest_groups[] = { "gpio66", "gpio67" };
+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", "gpio88", "gpio89", "gpio90", "gpio91",
+       "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+       "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+       "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+       "gpio111", "gpio112"
+};
+static const char * const gsm0_tx_groups[] = { "gpio85" };
+static const char * const ldo_en_groups[] = { "gpio99" };
+static const char * const ldo_update_groups[] = { "gpio98" };
+static const char * const m_voc_groups[] = { "gpio8", "gpio95" };
+static const char * const mdp_vsync_groups[] = { "gpio24", "gpio25" };
+static const char * const modem_tsync_groups[] = { "gpio83" };
+static const char * const nav_pps_groups[] = { "gpio83" };
+static const char * const nav_tsync_groups[] = { "gpio83" };
+static const char * const pa_indicator_groups[] = { "gpio82" };
+static const char * const pbs0_groups[] = { "gpio90" };
+static const char * const pbs1_groups[] = { "gpio91" };
+static const char * const pbs2_groups[] = { "gpio92" };
+static const char * const pri_mi2s_data0_a_groups[] = { "gpio62" };
+static const char * const pri_mi2s_data0_b_groups[] = { "gpio95" };
+static const char * const pri_mi2s_data1_a_groups[] = { "gpio63" };
+static const char * const pri_mi2s_data1_b_groups[] = { "gpio96" };
+static const char * const pri_mi2s_mclk_a_groups[] = { "gpio59" };
+static const char * const pri_mi2s_mclk_b_groups[] = { "gpio98" };
+static const char * const pri_mi2s_sck_a_groups[] = { "gpio60" };
+static const char * const pri_mi2s_sck_b_groups[] = { "gpio94" };
+static const char * const pri_mi2s_ws_a_groups[] = { "gpio61" };
+static const char * const pri_mi2s_ws_b_groups[] = { "gpio110" };
+static const char * const prng_rosc_groups[] = { "gpio43" };
+static const char * const pwr_crypto_enabled_a_groups[] = { "gpio35" };
+static const char * const pwr_crypto_enabled_b_groups[] = { "gpio96" };
+static const char * const pwr_modem_enabled_a_groups[] = { "gpio28" };
+static const char * const pwr_modem_enabled_b_groups[] = { "gpio94" };
+static const char * const pwr_nav_enabled_a_groups[] = { "gpio34" };
+static const char * const pwr_nav_enabled_b_groups[] = { "gpio95" };
+static const char * const qdss_cti_trig_in_a0_groups[] = { "gpio20" };
+static const char * const qdss_cti_trig_in_a1_groups[] = { "gpio49" };
+static const char * const qdss_cti_trig_in_b0_groups[] = { "gpio21" };
+static const char * const qdss_cti_trig_in_b1_groups[] = { "gpio50" };
+static const char * const qdss_cti_trig_out_a0_groups[] = { "gpio23" };
+static const char * const qdss_cti_trig_out_a1_groups[] = { "gpio52" };
+static const char * const qdss_cti_trig_out_b0_groups[] = { "gpio22" };
+static const char * const qdss_cti_trig_out_b1_groups[] = { "gpio51" };
+static const char * const qdss_traceclk_a_groups[] = { "gpio46" };
+static const char * const qdss_tracectl_a_groups[] = { "gpio45" };
+static const char * const qdss_tracedata_a_groups[] = {
+       "gpio8", "gpio9", "gpio10", "gpio39", "gpio40", "gpio41", "gpio42",
+       "gpio43", "gpio47", "gpio48", "gpio58", "gpio65", "gpio94", "gpio96",
+       "gpio97"
+};
+static const char * const qdss_tracedata_b_groups[] = {
+       "gpio14", "gpio16", "gpio17", "gpio29", "gpio30", "gpio31", "gpio32",
+       "gpio33", "gpio34", "gpio35", "gpio36", "gpio37", "gpio93"
+};
+static const char * const sd_write_groups[] = { "gpio99" };
+static const char * const sec_mi2s_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3", "gpio98"
+};
+static const char * const smb_int_groups[] = { "gpio58" };
+static const char * const ssbi0_groups[] = { "gpio88" };
+static const char * const ssbi1_groups[] = { "gpio89" };
+static const char * const uim1_clk_groups[] = { "gpio54" };
+static const char * const uim1_data_groups[] = { "gpio53" };
+static const char * const uim1_present_groups[] = { "gpio56" };
+static const char * const uim1_reset_groups[] = { "gpio55" };
+static const char * const uim2_clk_groups[] = { "gpio50" };
+static const char * const uim2_data_groups[] = { "gpio49" };
+static const char * const uim2_present_groups[] = { "gpio52" };
+static const char * const uim2_reset_groups[] = { "gpio51" };
+static const char * const uim3_clk_groups[] = { "gpio23" };
+static const char * const uim3_data_groups[] = { "gpio20" };
+static const char * const uim3_present_groups[] = { "gpio21" };
+static const char * const uim3_reset_groups[] = { "gpio22" };
+static const char * const uim_batt_groups[] = { "gpio57" };
+static const char * const wcss_bt_groups[] = { "gpio39", "gpio47", "gpio48" };
+static const char * const wcss_fm_groups[] = { "gpio45", "gpio46" };
+static const char * const wcss_wlan_groups[] = {
+       "gpio40", "gpio41", "gpio42", "gpio43", "gpio44"
+};
+
+static const struct msm_function msm8909_functions[] = {
+       FUNCTION(adsp_ext),
+       FUNCTION(atest_bbrx0),
+       FUNCTION(atest_bbrx1),
+       FUNCTION(atest_char),
+       FUNCTION(atest_char0),
+       FUNCTION(atest_char1),
+       FUNCTION(atest_char2),
+       FUNCTION(atest_char3),
+       FUNCTION(atest_combodac),
+       FUNCTION(atest_gpsadc0),
+       FUNCTION(atest_gpsadc1),
+       FUNCTION(atest_wlan0),
+       FUNCTION(atest_wlan1),
+       FUNCTION(bimc_dte0),
+       FUNCTION(bimc_dte1),
+       FUNCTION(blsp_i2c1),
+       FUNCTION(blsp_i2c2),
+       FUNCTION(blsp_i2c3),
+       FUNCTION(blsp_i2c4),
+       FUNCTION(blsp_i2c5),
+       FUNCTION(blsp_i2c6),
+       FUNCTION(blsp_spi1),
+       FUNCTION(blsp_spi1_cs1),
+       FUNCTION(blsp_spi1_cs2),
+       FUNCTION(blsp_spi1_cs3),
+       FUNCTION(blsp_spi2),
+       FUNCTION(blsp_spi2_cs1),
+       FUNCTION(blsp_spi2_cs2),
+       FUNCTION(blsp_spi2_cs3),
+       FUNCTION(blsp_spi3),
+       FUNCTION(blsp_spi3_cs1),
+       FUNCTION(blsp_spi3_cs2),
+       FUNCTION(blsp_spi3_cs3),
+       FUNCTION(blsp_spi4),
+       FUNCTION(blsp_spi5),
+       FUNCTION(blsp_spi6),
+       FUNCTION(blsp_uart1),
+       FUNCTION(blsp_uart2),
+       FUNCTION(blsp_uim1),
+       FUNCTION(blsp_uim2),
+       FUNCTION(cam_mclk),
+       FUNCTION(cci_async),
+       FUNCTION(cci_timer0),
+       FUNCTION(cci_timer1),
+       FUNCTION(cci_timer2),
+       FUNCTION(cdc_pdm0),
+       FUNCTION(dbg_out),
+       FUNCTION(dmic0_clk),
+       FUNCTION(dmic0_data),
+       FUNCTION(ebi0_wrcdc),
+       FUNCTION(ebi2_a),
+       FUNCTION(ebi2_lcd),
+       FUNCTION(ext_lpass),
+       FUNCTION(gcc_gp1_clk_a),
+       FUNCTION(gcc_gp1_clk_b),
+       FUNCTION(gcc_gp2_clk_a),
+       FUNCTION(gcc_gp2_clk_b),
+       FUNCTION(gcc_gp3_clk_a),
+       FUNCTION(gcc_gp3_clk_b),
+       FUNCTION(gcc_plltest),
+       FUNCTION(gpio),
+       FUNCTION(gsm0_tx),
+       FUNCTION(ldo_en),
+       FUNCTION(ldo_update),
+       FUNCTION(m_voc),
+       FUNCTION(mdp_vsync),
+       FUNCTION(modem_tsync),
+       FUNCTION(nav_pps),
+       FUNCTION(nav_tsync),
+       FUNCTION(pa_indicator),
+       FUNCTION(pbs0),
+       FUNCTION(pbs1),
+       FUNCTION(pbs2),
+       FUNCTION(pri_mi2s_data0_a),
+       FUNCTION(pri_mi2s_data0_b),
+       FUNCTION(pri_mi2s_data1_a),
+       FUNCTION(pri_mi2s_data1_b),
+       FUNCTION(pri_mi2s_mclk_a),
+       FUNCTION(pri_mi2s_mclk_b),
+       FUNCTION(pri_mi2s_sck_a),
+       FUNCTION(pri_mi2s_sck_b),
+       FUNCTION(pri_mi2s_ws_a),
+       FUNCTION(pri_mi2s_ws_b),
+       FUNCTION(prng_rosc),
+       FUNCTION(pwr_crypto_enabled_a),
+       FUNCTION(pwr_crypto_enabled_b),
+       FUNCTION(pwr_modem_enabled_a),
+       FUNCTION(pwr_modem_enabled_b),
+       FUNCTION(pwr_nav_enabled_a),
+       FUNCTION(pwr_nav_enabled_b),
+       FUNCTION(qdss_cti_trig_in_a0),
+       FUNCTION(qdss_cti_trig_in_a1),
+       FUNCTION(qdss_cti_trig_in_b0),
+       FUNCTION(qdss_cti_trig_in_b1),
+       FUNCTION(qdss_cti_trig_out_a0),
+       FUNCTION(qdss_cti_trig_out_a1),
+       FUNCTION(qdss_cti_trig_out_b0),
+       FUNCTION(qdss_cti_trig_out_b1),
+       FUNCTION(qdss_traceclk_a),
+       FUNCTION(qdss_tracectl_a),
+       FUNCTION(qdss_tracedata_a),
+       FUNCTION(qdss_tracedata_b),
+       FUNCTION(sd_write),
+       FUNCTION(sec_mi2s),
+       FUNCTION(smb_int),
+       FUNCTION(ssbi0),
+       FUNCTION(ssbi1),
+       FUNCTION(uim1_clk),
+       FUNCTION(uim1_data),
+       FUNCTION(uim1_present),
+       FUNCTION(uim1_reset),
+       FUNCTION(uim2_clk),
+       FUNCTION(uim2_data),
+       FUNCTION(uim2_present),
+       FUNCTION(uim2_reset),
+       FUNCTION(uim3_clk),
+       FUNCTION(uim3_data),
+       FUNCTION(uim3_present),
+       FUNCTION(uim3_reset),
+       FUNCTION(uim_batt),
+       FUNCTION(wcss_bt),
+       FUNCTION(wcss_fm),
+       FUNCTION(wcss_wlan),
+};
+
+static const struct msm_pingroup msm8909_groups[] = {
+       PINGROUP(0, blsp_spi3, sec_mi2s, _, _, _, _, _, _, _),
+       PINGROUP(1, blsp_spi3, sec_mi2s, _, _, _, _, _, _, _),
+       PINGROUP(2, blsp_spi3, sec_mi2s, _, _, _, _, _, _, _),
+       PINGROUP(3, blsp_spi3, sec_mi2s, _, _, _, _, _, _, _),
+       PINGROUP(4, blsp_spi1, blsp_uart1, blsp_uim1, blsp_spi3_cs3, dmic0_clk, _, _, _, _),
+       PINGROUP(5, blsp_spi1, blsp_uart1, blsp_uim1, blsp_spi2_cs3, dmic0_data, _, _, _, _),
+       PINGROUP(6, blsp_spi1, blsp_uart1, blsp_i2c1, _, _, _, _, _, bimc_dte0),
+       PINGROUP(7, blsp_spi1, blsp_uart1, blsp_i2c1, _, _, _, _, _, bimc_dte1),
+       PINGROUP(8, blsp_spi6, m_voc, _, _, _, _, _, qdss_tracedata_a, _),
+       PINGROUP(9, blsp_spi6, _, _, _, _, _, qdss_tracedata_a, _, _),
+       PINGROUP(10, blsp_spi6, blsp_i2c6, dbg_out, qdss_tracedata_a, _, _, _, _, _),
+       PINGROUP(11, blsp_spi6, blsp_i2c6, _, _, _, _, _, _, _),
+       PINGROUP(12, blsp_spi4, gcc_gp2_clk_b, _, _, _, _, _, _, _),
+       PINGROUP(13, blsp_spi4, gcc_gp3_clk_b, _, _, _, _, _, _, _),
+       PINGROUP(14, blsp_spi4, blsp_i2c4, gcc_gp1_clk_b, _, _, _, _, _, qdss_tracedata_b),
+       PINGROUP(15, blsp_spi4, blsp_i2c4, _, _, _, _, _, _, _),
+       PINGROUP(16, blsp_spi5, _, _, _, _, _, qdss_tracedata_b, _, _),
+       PINGROUP(17, blsp_spi5, blsp_spi2_cs2, _, _, _, _, _, qdss_tracedata_b, _),
+       PINGROUP(18, blsp_spi5, blsp_i2c5, _, _, _, _, _, _, _),
+       PINGROUP(19, blsp_spi5, blsp_i2c5, _, _, _, _, _, _, _),
+       PINGROUP(20, uim3_data, blsp_spi2, blsp_uart2, blsp_uim2, _, qdss_cti_trig_in_a0, _, _, _),
+       PINGROUP(21, uim3_present, blsp_spi2, blsp_uart2, blsp_uim2, _, qdss_cti_trig_in_b0, _, _, _),
+       PINGROUP(22, uim3_reset, _, qdss_cti_trig_out_b0, _, _, _, _, _, _),
+       PINGROUP(23, uim3_clk, qdss_cti_trig_out_a0, _, _, _, _, _, _, _),
+       PINGROUP(24, mdp_vsync, ebi2_lcd, ebi2_lcd, _, _, _, _, _, _),
+       PINGROUP(25, mdp_vsync, ebi2_lcd, _, _, _, _, _, _, _),
+       PINGROUP(26, cam_mclk, _, _, _, _, _, _, _, _),
+       PINGROUP(27, cam_mclk, _, _, _, _, _, _, _, _),
+       PINGROUP(28, _, pwr_modem_enabled_a, _, _, _, _, _, _, _),
+       PINGROUP(29, blsp_i2c3, _, _, _, _, _, qdss_tracedata_b, _, _),
+       PINGROUP(30, blsp_i2c3, _, _, _, _, _, qdss_tracedata_b, _, _),
+       PINGROUP(31, cci_timer0, _, _, _, _, _, _, qdss_tracedata_b, _),
+       PINGROUP(32, cci_timer1, _, qdss_tracedata_b, _, atest_combodac, _, _, _, _),
+       PINGROUP(33, cci_async, qdss_tracedata_b, _, _, _, _, _, _, _),
+       PINGROUP(34, pwr_nav_enabled_a, qdss_tracedata_b, _, _, _, _, _, _, _),
+       PINGROUP(35, pwr_crypto_enabled_a, qdss_tracedata_b, _, _, _, _, _, _, _),
+       PINGROUP(36, qdss_tracedata_b, _, atest_bbrx1, _, _, _, _, _, _),
+       PINGROUP(37, blsp_spi1_cs2, qdss_tracedata_b, _, atest_bbrx0, _, _, _, _, _),
+       PINGROUP(38, cci_timer2, adsp_ext, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(39, wcss_bt, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(40, wcss_wlan, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(41, wcss_wlan, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(42, wcss_wlan, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(43, wcss_wlan, prng_rosc, qdss_tracedata_a, _, atest_combodac, _, _, _, _),
+       PINGROUP(44, wcss_wlan, _, atest_combodac, _, _, _, _, _, _),
+       PINGROUP(45, wcss_fm, ext_lpass, qdss_tracectl_a, _, atest_combodac, _, _, _, _),
+       PINGROUP(46, wcss_fm, qdss_traceclk_a, _, _, _, _, _, _, _),
+       PINGROUP(47, wcss_bt, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(48, wcss_bt, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(49, uim2_data, gcc_gp1_clk_a, qdss_cti_trig_in_a1, _, _, _, _, _, _),
+       PINGROUP(50, uim2_clk, gcc_gp2_clk_a, qdss_cti_trig_in_b1, _, _, _, _, _, _),
+       PINGROUP(51, uim2_reset, gcc_gp3_clk_a, qdss_cti_trig_out_b1, _, _, _, _, _, _),
+       PINGROUP(52, uim2_present, qdss_cti_trig_out_a1, _, _, _, _, _, _, _),
+       PINGROUP(53, uim1_data, _, _, _, _, _, _, _, _),
+       PINGROUP(54, uim1_clk, _, _, _, _, _, _, _, _),
+       PINGROUP(55, uim1_reset, _, _, _, _, _, _, _, _),
+       PINGROUP(56, uim1_present, _, _, _, _, _, _, _, _),
+       PINGROUP(57, uim_batt, _, _, _, _, _, _, _, _),
+       PINGROUP(58, qdss_tracedata_a, smb_int, _, _, _, _, _, _, _),
+       PINGROUP(59, cdc_pdm0, pri_mi2s_mclk_a, atest_char3, _, _, _, _, _, bimc_dte0),
+       PINGROUP(60, cdc_pdm0, pri_mi2s_sck_a, atest_char2, _, _, _, _, _, bimc_dte1),
+       PINGROUP(61, cdc_pdm0, pri_mi2s_ws_a, atest_char1, _, _, _, _, _, _),
+       PINGROUP(62, cdc_pdm0, pri_mi2s_data0_a, atest_char0, _, _, _, _, _, _),
+       PINGROUP(63, cdc_pdm0, pri_mi2s_data1_a, atest_char, _, _, _, _, _, _),
+       PINGROUP(64, cdc_pdm0, _, _, _, _, _, ebi0_wrcdc, _, _),
+       PINGROUP(65, blsp_spi3_cs2, blsp_spi1_cs3, qdss_tracedata_a, _, atest_gpsadc0, _, _, _, _),
+       PINGROUP(66, _, gcc_plltest, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(67, _, gcc_plltest, _, _, _, _, _, _, _),
+       PINGROUP(68, _, _, _, _, _, _, _, _, _),
+       PINGROUP(69, _, _, _, _, _, _, _, _, _),
+       PINGROUP(70, _, _, _, _, _, _, _, _, _),
+       PINGROUP(71, _, _, _, _, _, _, _, _, _),
+       PINGROUP(72, _, _, _, _, _, _, _, _, _),
+       PINGROUP(73, _, _, _, _, _, _, _, _, _),
+       PINGROUP(74, _, _, _, _, _, _, _, _, _),
+       PINGROUP(75, _, _, _, _, _, _, _, _, _),
+       PINGROUP(76, _, _, _, _, _, _, _, _, _),
+       PINGROUP(77, _, _, _, _, _, _, _, _, _),
+       PINGROUP(78, _, _, _, _, _, _, _, _, _),
+       PINGROUP(79, _, _, atest_gpsadc1, _, _, _, _, _, _),
+       PINGROUP(80, _, _, _, _, _, _, _, _, _),
+       PINGROUP(81, _, _, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(82, _, pa_indicator, _, _, _, _, _, _, _),
+       PINGROUP(83, _, modem_tsync, nav_tsync, nav_pps, _, atest_combodac, _, _, _),
+       PINGROUP(84, _, _, atest_combodac, _, _, _, _, _, _),
+       PINGROUP(85, gsm0_tx, _, _, atest_combodac, _, _, _, _, _),
+       PINGROUP(86, _, _, atest_combodac, _, _, _, _, _, _),
+       PINGROUP(87, _, _, _, _, _, _, _, _, _),
+       PINGROUP(88, _, ssbi0, _, _, _, _, _, _, _),
+       PINGROUP(89, _, ssbi1, _, _, _, _, _, _, _),
+       PINGROUP(90, pbs0, _, _, _, _, _, _, _, _),
+       PINGROUP(91, pbs1, _, _, _, _, _, _, _, _),
+       PINGROUP(92, pbs2, _, _, _, _, _, _, _, _),
+       PINGROUP(93, qdss_tracedata_b, _, _, _, _, _, _, _, _),
+       PINGROUP(94, pri_mi2s_sck_b, pwr_modem_enabled_b, qdss_tracedata_a, _, atest_combodac, _, _, _, _),
+       PINGROUP(95, blsp_spi3_cs1, pri_mi2s_data0_b, ebi2_lcd, m_voc, pwr_nav_enabled_b, _, atest_combodac, _, _),
+       PINGROUP(96, pri_mi2s_data1_b, _, pwr_crypto_enabled_b, qdss_tracedata_a, _, atest_wlan0, _, _, _),
+       PINGROUP(97, blsp_spi1_cs1, qdss_tracedata_a, _, atest_wlan1, _, _, _, _, _),
+       PINGROUP(98, sec_mi2s, pri_mi2s_mclk_b, blsp_spi2_cs1, ldo_update, _, _, _, _, _),
+       PINGROUP(99, ebi2_a, sd_write, ldo_en, _, _, _, _, _, _),
+       PINGROUP(100, _, _, _, _, _, _, _, _, _),
+       PINGROUP(101, _, _, _, _, _, _, _, _, _),
+       PINGROUP(102, _, _, _, _, _, _, _, _, _),
+       PINGROUP(103, _, _, _, _, _, _, _, _, _),
+       PINGROUP(104, _, _, _, _, _, _, _, _, _),
+       PINGROUP(105, _, _, _, _, _, _, _, _, _),
+       PINGROUP(106, _, _, _, _, _, _, _, _, _),
+       PINGROUP(107, _, _, _, _, _, _, _, _, _),
+       PINGROUP(108, _, _, _, _, _, _, _, _, _),
+       PINGROUP(109, _, _, _, _, _, _, _, _, _),
+       PINGROUP(110, pri_mi2s_ws_b, _, atest_combodac, _, _, _, _, _, _),
+       PINGROUP(111, blsp_spi2, blsp_uart2, blsp_i2c2, _, _, _, _, _, _),
+       PINGROUP(112, blsp_spi2, blsp_uart2, blsp_i2c2, _, _, _, _, _, _),
+       SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+       SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+       SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+       SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+       SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+       SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+       SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+       SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+       SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+       SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+       SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+       SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_gpio_wakeirq_map msm8909_mpm_map[] = {
+       { 65, 3 }, { 5, 4 }, { 11, 5 }, { 12, 6 }, { 64, 7 }, { 58, 8 },
+       { 50, 9 }, { 13, 10 }, { 49, 11 }, { 20, 12 }, { 21, 13 }, { 25, 14 },
+       { 46, 15 }, { 45, 16 }, { 28, 17 }, { 44, 18 }, { 31, 19 }, { 43, 20 },
+       { 42, 21 }, { 34, 22 }, { 35, 23 }, { 36, 24 }, { 37, 25 }, { 38, 26 },
+       { 39, 27 }, { 40, 28 }, { 41, 29 }, { 90, 30 }, { 91, 32 }, { 92, 33 },
+       { 94, 34 }, { 95, 35 }, { 96, 36 }, { 97, 37 }, { 98, 38 },
+       { 110, 39 }, { 111, 40 }, { 112, 41 }, { 105, 42 }, { 107, 43 },
+       { 47, 50 }, { 48, 51 },
+};
+
+static const struct msm_pinctrl_soc_data msm8909_pinctrl = {
+       .pins = msm8909_pins,
+       .npins = ARRAY_SIZE(msm8909_pins),
+       .functions = msm8909_functions,
+       .nfunctions = ARRAY_SIZE(msm8909_functions),
+       .groups = msm8909_groups,
+       .ngroups = ARRAY_SIZE(msm8909_groups),
+       .ngpios = 113,
+       .wakeirq_map = msm8909_mpm_map,
+       .nwakeirq_map = ARRAY_SIZE(msm8909_mpm_map),
+};
+
+static int msm8909_pinctrl_probe(struct platform_device *pdev)
+{
+       return msm_pinctrl_probe(pdev, &msm8909_pinctrl);
+}
+
+static const struct of_device_id msm8909_pinctrl_of_match[] = {
+       { .compatible = "qcom,msm8909-tlmm", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, msm8909_pinctrl_of_match);
+
+static struct platform_driver msm8909_pinctrl_driver = {
+       .driver = {
+               .name = "msm8909-pinctrl",
+               .of_match_table = msm8909_pinctrl_of_match,
+       },
+       .probe = msm8909_pinctrl_probe,
+       .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8909_pinctrl_init(void)
+{
+       return platform_driver_register(&msm8909_pinctrl_driver);
+}
+arch_initcall(msm8909_pinctrl_init);
+
+static void __exit msm8909_pinctrl_exit(void)
+{
+       platform_driver_unregister(&msm8909_pinctrl_driver);
+}
+module_exit(msm8909_pinctrl_exit);
+
+MODULE_DESCRIPTION("Qualcomm MSM8909 TLMM pinctrl driver");
+MODULE_LICENSE("GPL");
index 396db12..bf68913 100644 (file)
@@ -844,8 +844,8 @@ static const struct msm_pingroup msm8916_groups[] = {
        PINGROUP(28, pwr_modem_enabled_a, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, atest_combodac),
        PINGROUP(29, cci_i2c, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, atest_combodac),
        PINGROUP(30, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
-       PINGROUP(31, cci_timer0, NA, NA, NA, NA, NA, NA, NA, NA),
-       PINGROUP(32, cci_timer1, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(31, cci_timer0, flash_strobe, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(32, cci_timer1, flash_strobe, NA, NA, NA, NA, NA, NA, NA),
        PINGROUP(33, cci_async, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
        PINGROUP(34, pwr_nav_enabled_a, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
        PINGROUP(35, pwr_crypto_enabled_a, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
index 2add9a4..d615b6c 100644 (file)
@@ -141,7 +141,6 @@ static const struct lpi_pinctrl_variant_data sc7280_lpi_data = {
        .ngroups = ARRAY_SIZE(sc7280_groups),
        .functions = sc7280_functions,
        .nfunctions = ARRAY_SIZE(sc7280_functions),
-       .is_clk_optional = true,
 };
 
 static const struct of_device_id lpi_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/qcom/pinctrl-sm6375.c b/drivers/pinctrl/qcom/pinctrl-sm6375.c
new file mode 100644 (file)
index 0000000..1138e68
--- /dev/null
@@ -0,0 +1,1544 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname)                                        \
+       [msm_mux_##fname] = {                           \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+#define REG_BASE 0x100000
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)       \
+       {                                               \
+               .name = "gpio" #id,                     \
+               .pins = gpio##id##_pins,                \
+               .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins),     \
+               .funcs = (int[]){                       \
+                       msm_mux_gpio, /* gpio mode */   \
+                       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                    \
+               },                                      \
+               .nfuncs = 10,                           \
+               .ctl_reg = REG_SIZE * id,               \
+               .io_reg = REG_SIZE * id + 0x4,          \
+               .intr_cfg_reg = REG_SIZE * id + 0x8,    \
+               .intr_status_reg = REG_SIZE * id + 0xc, \
+               .intr_target_reg = REG_SIZE * id + 0x8, \
+               .mux_bit = 2,                   \
+               .pull_bit = 0,                  \
+               .drv_bit = 6,                   \
+               .egpio_enable = 12,             \
+               .egpio_present = 11,            \
+               .oe_bit = 9,                    \
+               .in_bit = 0,                    \
+               .out_bit = 1,                   \
+               .intr_enable_bit = 0,           \
+               .intr_status_bit = 0,           \
+               .intr_target_bit = 5,           \
+               .intr_target_kpss_val = 3,      \
+               .intr_raw_status_bit = 4,       \
+               .intr_polarity_bit = 1,         \
+               .intr_detection_bit = 2,        \
+               .intr_detection_width = 2,      \
+       }
+
+#define SDC_PINGROUP(pg_name, ctl, pull, drv)  \
+       {                                               \
+               .name = #pg_name,                       \
+               .pins = pg_name##_pins,                 \
+               .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins),      \
+               .ctl_reg = ctl,                         \
+               .io_reg = 0,                            \
+               .intr_cfg_reg = 0,                      \
+               .intr_status_reg = 0,                   \
+               .intr_target_reg = 0,                   \
+               .mux_bit = -1,                          \
+               .pull_bit = pull,                       \
+               .drv_bit = drv,                         \
+               .oe_bit = -1,                           \
+               .in_bit = -1,                           \
+               .out_bit = -1,                          \
+               .intr_enable_bit = -1,                  \
+               .intr_status_bit = -1,                  \
+               .intr_target_bit = -1,                  \
+               .intr_raw_status_bit = -1,              \
+               .intr_polarity_bit = -1,                \
+               .intr_detection_bit = -1,               \
+               .intr_detection_width = -1,             \
+       }
+
+#define UFS_RESET(pg_name, offset)                             \
+       {                                               \
+               .name = #pg_name,                       \
+               .pins = pg_name##_pins,                 \
+               .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins),      \
+               .ctl_reg = offset,                      \
+               .io_reg = offset + 0x4,                 \
+               .intr_cfg_reg = 0,                      \
+               .intr_status_reg = 0,                   \
+               .intr_target_reg = 0,                   \
+               .mux_bit = -1,                          \
+               .pull_bit = 3,                          \
+               .drv_bit = 0,                           \
+               .oe_bit = -1,                           \
+               .in_bit = -1,                           \
+               .out_bit = 0,                           \
+               .intr_enable_bit = -1,                  \
+               .intr_status_bit = -1,                  \
+               .intr_target_bit = -1,                  \
+               .intr_raw_status_bit = -1,              \
+               .intr_polarity_bit = -1,                \
+               .intr_detection_bit = -1,               \
+               .intr_detection_width = -1,             \
+       }
+
+static const struct pinctrl_pin_desc sm6375_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"),
+       PINCTRL_PIN(88, "GPIO_88"),
+       PINCTRL_PIN(89, "GPIO_89"),
+       PINCTRL_PIN(90, "GPIO_90"),
+       PINCTRL_PIN(91, "GPIO_91"),
+       PINCTRL_PIN(92, "GPIO_92"),
+       PINCTRL_PIN(93, "GPIO_93"),
+       PINCTRL_PIN(94, "GPIO_94"),
+       PINCTRL_PIN(95, "GPIO_95"),
+       PINCTRL_PIN(96, "GPIO_96"),
+       PINCTRL_PIN(97, "GPIO_97"),
+       PINCTRL_PIN(98, "GPIO_98"),
+       PINCTRL_PIN(99, "GPIO_99"),
+       PINCTRL_PIN(100, "GPIO_100"),
+       PINCTRL_PIN(101, "GPIO_101"),
+       PINCTRL_PIN(102, "GPIO_102"),
+       PINCTRL_PIN(103, "GPIO_103"),
+       PINCTRL_PIN(104, "GPIO_104"),
+       PINCTRL_PIN(105, "GPIO_105"),
+       PINCTRL_PIN(106, "GPIO_106"),
+       PINCTRL_PIN(107, "GPIO_107"),
+       PINCTRL_PIN(108, "GPIO_108"),
+       PINCTRL_PIN(109, "GPIO_109"),
+       PINCTRL_PIN(110, "GPIO_110"),
+       PINCTRL_PIN(111, "GPIO_111"),
+       PINCTRL_PIN(112, "GPIO_112"),
+       PINCTRL_PIN(113, "GPIO_113"),
+       PINCTRL_PIN(114, "GPIO_114"),
+       PINCTRL_PIN(115, "GPIO_115"),
+       PINCTRL_PIN(116, "GPIO_116"),
+       PINCTRL_PIN(117, "GPIO_117"),
+       PINCTRL_PIN(118, "GPIO_118"),
+       PINCTRL_PIN(119, "GPIO_119"),
+       PINCTRL_PIN(120, "GPIO_120"),
+       PINCTRL_PIN(121, "GPIO_121"),
+       PINCTRL_PIN(122, "GPIO_122"),
+       PINCTRL_PIN(123, "GPIO_123"),
+       PINCTRL_PIN(124, "GPIO_124"),
+       PINCTRL_PIN(125, "GPIO_125"),
+       PINCTRL_PIN(126, "GPIO_126"),
+       PINCTRL_PIN(127, "GPIO_127"),
+       PINCTRL_PIN(128, "GPIO_128"),
+       PINCTRL_PIN(129, "GPIO_129"),
+       PINCTRL_PIN(130, "GPIO_130"),
+       PINCTRL_PIN(131, "GPIO_131"),
+       PINCTRL_PIN(132, "GPIO_132"),
+       PINCTRL_PIN(133, "GPIO_133"),
+       PINCTRL_PIN(134, "GPIO_134"),
+       PINCTRL_PIN(135, "GPIO_135"),
+       PINCTRL_PIN(136, "GPIO_136"),
+       PINCTRL_PIN(137, "GPIO_137"),
+       PINCTRL_PIN(138, "GPIO_138"),
+       PINCTRL_PIN(139, "GPIO_139"),
+       PINCTRL_PIN(140, "GPIO_140"),
+       PINCTRL_PIN(141, "GPIO_141"),
+       PINCTRL_PIN(142, "GPIO_142"),
+       PINCTRL_PIN(143, "GPIO_143"),
+       PINCTRL_PIN(144, "GPIO_144"),
+       PINCTRL_PIN(145, "GPIO_145"),
+       PINCTRL_PIN(146, "GPIO_146"),
+       PINCTRL_PIN(147, "GPIO_147"),
+       PINCTRL_PIN(148, "GPIO_148"),
+       PINCTRL_PIN(149, "GPIO_149"),
+       PINCTRL_PIN(150, "GPIO_150"),
+       PINCTRL_PIN(151, "GPIO_151"),
+       PINCTRL_PIN(152, "GPIO_152"),
+       PINCTRL_PIN(153, "GPIO_153"),
+       PINCTRL_PIN(154, "GPIO_154"),
+       PINCTRL_PIN(155, "GPIO_155"),
+       PINCTRL_PIN(156, "UFS_RESET"),
+       PINCTRL_PIN(157, "SDC1_RCLK"),
+       PINCTRL_PIN(158, "SDC1_CLK"),
+       PINCTRL_PIN(159, "SDC1_CMD"),
+       PINCTRL_PIN(160, "SDC1_DATA"),
+       PINCTRL_PIN(161, "SDC2_CLK"),
+       PINCTRL_PIN(162, "SDC2_CMD"),
+       PINCTRL_PIN(163, "SDC2_DATA"),
+};
+
+#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);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+
+
+static const unsigned int sdc1_rclk_pins[] = { 157 };
+static const unsigned int sdc1_clk_pins[] = { 158 };
+static const unsigned int sdc1_cmd_pins[] = { 159 };
+static const unsigned int sdc1_data_pins[] = { 160 };
+static const unsigned int sdc2_clk_pins[] = { 161 };
+static const unsigned int sdc2_cmd_pins[] = { 162 };
+static const unsigned int sdc2_data_pins[] = { 163 };
+static const unsigned int ufs_reset_pins[] = { 156 };
+
+enum sm6375_functions {
+       msm_mux_adsp_ext,
+       msm_mux_agera_pll,
+       msm_mux_atest_char,
+       msm_mux_atest_char0,
+       msm_mux_atest_char1,
+       msm_mux_atest_char2,
+       msm_mux_atest_char3,
+       msm_mux_atest_tsens,
+       msm_mux_atest_tsens2,
+       msm_mux_atest_usb1,
+       msm_mux_atest_usb10,
+       msm_mux_atest_usb11,
+       msm_mux_atest_usb12,
+       msm_mux_atest_usb13,
+       msm_mux_atest_usb2,
+       msm_mux_atest_usb20,
+       msm_mux_atest_usb21,
+       msm_mux_atest_usb22,
+       msm_mux_atest_usb23,
+       msm_mux_audio_ref,
+       msm_mux_btfm_slimbus,
+       msm_mux_cam_mclk,
+       msm_mux_cci_async,
+       msm_mux_cci_i2c,
+       msm_mux_cci_timer0,
+       msm_mux_cci_timer1,
+       msm_mux_cci_timer2,
+       msm_mux_cci_timer3,
+       msm_mux_cci_timer4,
+       msm_mux_cri_trng,
+       msm_mux_dbg_out,
+       msm_mux_ddr_bist,
+       msm_mux_ddr_pxi0,
+       msm_mux_ddr_pxi1,
+       msm_mux_ddr_pxi2,
+       msm_mux_ddr_pxi3,
+       msm_mux_dp_hot,
+       msm_mux_edp_lcd,
+       msm_mux_gcc_gp1,
+       msm_mux_gcc_gp2,
+       msm_mux_gcc_gp3,
+       msm_mux_gp_pdm0,
+       msm_mux_gp_pdm1,
+       msm_mux_gp_pdm2,
+       msm_mux_gpio,
+       msm_mux_gps_tx,
+       msm_mux_ibi_i3c,
+       msm_mux_jitter_bist,
+       msm_mux_ldo_en,
+       msm_mux_ldo_update,
+       msm_mux_lpass_ext,
+       msm_mux_m_voc,
+       msm_mux_mclk,
+       msm_mux_mdp_vsync,
+       msm_mux_mdp_vsync0,
+       msm_mux_mdp_vsync1,
+       msm_mux_mdp_vsync2,
+       msm_mux_mdp_vsync3,
+       msm_mux_mi2s_0,
+       msm_mux_mi2s_1,
+       msm_mux_mi2s_2,
+       msm_mux_mss_lte,
+       msm_mux_nav_gpio,
+       msm_mux_nav_pps,
+       msm_mux_pa_indicator,
+       msm_mux_phase_flag0,
+       msm_mux_phase_flag1,
+       msm_mux_phase_flag10,
+       msm_mux_phase_flag11,
+       msm_mux_phase_flag12,
+       msm_mux_phase_flag13,
+       msm_mux_phase_flag14,
+       msm_mux_phase_flag15,
+       msm_mux_phase_flag16,
+       msm_mux_phase_flag17,
+       msm_mux_phase_flag18,
+       msm_mux_phase_flag19,
+       msm_mux_phase_flag2,
+       msm_mux_phase_flag20,
+       msm_mux_phase_flag21,
+       msm_mux_phase_flag22,
+       msm_mux_phase_flag23,
+       msm_mux_phase_flag24,
+       msm_mux_phase_flag25,
+       msm_mux_phase_flag26,
+       msm_mux_phase_flag27,
+       msm_mux_phase_flag28,
+       msm_mux_phase_flag29,
+       msm_mux_phase_flag3,
+       msm_mux_phase_flag30,
+       msm_mux_phase_flag31,
+       msm_mux_phase_flag4,
+       msm_mux_phase_flag5,
+       msm_mux_phase_flag6,
+       msm_mux_phase_flag7,
+       msm_mux_phase_flag8,
+       msm_mux_phase_flag9,
+       msm_mux_pll_bist,
+       msm_mux_pll_bypassnl,
+       msm_mux_pll_clk,
+       msm_mux_pll_reset,
+       msm_mux_prng_rosc0,
+       msm_mux_prng_rosc1,
+       msm_mux_prng_rosc2,
+       msm_mux_prng_rosc3,
+       msm_mux_qdss_cti,
+       msm_mux_qdss_gpio,
+       msm_mux_qdss_gpio0,
+       msm_mux_qdss_gpio1,
+       msm_mux_qdss_gpio10,
+       msm_mux_qdss_gpio11,
+       msm_mux_qdss_gpio12,
+       msm_mux_qdss_gpio13,
+       msm_mux_qdss_gpio14,
+       msm_mux_qdss_gpio15,
+       msm_mux_qdss_gpio2,
+       msm_mux_qdss_gpio3,
+       msm_mux_qdss_gpio4,
+       msm_mux_qdss_gpio5,
+       msm_mux_qdss_gpio6,
+       msm_mux_qdss_gpio7,
+       msm_mux_qdss_gpio8,
+       msm_mux_qdss_gpio9,
+       msm_mux_qlink0_enable,
+       msm_mux_qlink0_request,
+       msm_mux_qlink0_wmss,
+       msm_mux_qlink1_enable,
+       msm_mux_qlink1_request,
+       msm_mux_qlink1_wmss,
+       msm_mux_qup00,
+       msm_mux_qup01,
+       msm_mux_qup02,
+       msm_mux_qup10,
+       msm_mux_qup11_f1,
+       msm_mux_qup11_f2,
+       msm_mux_qup12,
+       msm_mux_qup13_f1,
+       msm_mux_qup13_f2,
+       msm_mux_qup14,
+       msm_mux_sd_write,
+       msm_mux_sdc1_tb,
+       msm_mux_sdc2_tb,
+       msm_mux_sp_cmu,
+       msm_mux_tgu_ch0,
+       msm_mux_tgu_ch1,
+       msm_mux_tgu_ch2,
+       msm_mux_tgu_ch3,
+       msm_mux_tsense_pwm1,
+       msm_mux_tsense_pwm2,
+       msm_mux_uim1_clk,
+       msm_mux_uim1_data,
+       msm_mux_uim1_present,
+       msm_mux_uim1_reset,
+       msm_mux_uim2_clk,
+       msm_mux_uim2_data,
+       msm_mux_uim2_present,
+       msm_mux_uim2_reset,
+       msm_mux_usb2phy_ac,
+       msm_mux_usb_phy,
+       msm_mux_vfr_1,
+       msm_mux_vsense_trigger,
+       msm_mux_wlan1_adc0,
+       msm_mux_wlan1_adc1,
+       msm_mux_wlan2_adc0,
+       msm_mux_wlan2_adc1,
+       msm_mux__,
+};
+
+static const char * const gpio_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+       "gpio8", "gpio9", "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", "gpio56", "gpio57", "gpio58", "gpio59",
+       "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65", "gpio66",
+       "gpio67", "gpio68", "gpio69", "gpio75", "gpio76", "gpio77", "gpio78",
+       "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", "gpio85",
+       "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", "gpio92",
+       "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", "gpio99",
+       "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", "gpio105",
+       "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", "gpio111",
+       "gpio112", "gpio113", "gpio114", "gpio115", "gpio116", "gpio117",
+       "gpio118", "gpio119", "gpio120", "gpio124", "gpio125", "gpio126",
+       "gpio127", "gpio128", "gpio129", "gpio130", "gpio131", "gpio132",
+       "gpio133", "gpio134", "gpio135", "gpio136", "gpio141", "gpio142",
+       "gpio143", "gpio150", "gpio151", "gpio152", "gpio153", "gpio154",
+       "gpio155",
+};
+static const char * const agera_pll_groups[] = {
+       "gpio89",
+};
+static const char * const cci_async_groups[] = {
+       "gpio35", "gpio36", "gpio48", "gpio52", "gpio53",
+};
+static const char * const cci_i2c_groups[] = {
+       "gpio2", "gpio3", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
+       "gpio44",
+};
+static const char * const gps_tx_groups[] = {
+       "gpio101", "gpio102", "gpio107", "gpio108",
+};
+static const char * const gp_pdm0_groups[] = {
+       "gpio37", "gpio68",
+};
+static const char * const gp_pdm1_groups[] = {
+       "gpio8", "gpio52",
+};
+static const char * const gp_pdm2_groups[] = {
+       "gpio57",
+};
+static const char * const jitter_bist_groups[] = {
+       "gpio90",
+};
+static const char * const mclk_groups[] = {
+       "gpio93",
+};
+static const char * const mdp_vsync_groups[] = {
+       "gpio6", "gpio23", "gpio24", "gpio27", "gpio28",
+};
+static const char * const mss_lte_groups[] = {
+       "gpio65", "gpio66",
+};
+static const char * const nav_pps_groups[] = {
+       "gpio101", "gpio101", "gpio102", "gpio102",
+};
+static const char * const pll_bist_groups[] = {
+       "gpio27",
+};
+static const char * const qlink0_wmss_groups[] = {
+       "gpio103",
+};
+static const char * const qlink1_wmss_groups[] = {
+       "gpio106",
+};
+static const char * const usb_phy_groups[] = {
+       "gpio124",
+};
+static const char * const adsp_ext_groups[] = {
+       "gpio87",
+};
+static const char * const atest_char_groups[] = {
+       "gpio95",
+};
+static const char * const atest_char0_groups[] = {
+       "gpio96",
+};
+static const char * const atest_char1_groups[] = {
+       "gpio97",
+};
+static const char * const atest_char2_groups[] = {
+       "gpio98",
+};
+static const char * const atest_char3_groups[] = {
+       "gpio99",
+};
+static const char * const atest_tsens_groups[] = {
+       "gpio92",
+};
+static const char * const atest_tsens2_groups[] = {
+       "gpio93",
+};
+static const char * const atest_usb1_groups[] = {
+       "gpio83",
+};
+static const char * const atest_usb10_groups[] = {
+       "gpio84",
+};
+static const char * const atest_usb11_groups[] = {
+       "gpio85",
+};
+static const char * const atest_usb12_groups[] = {
+       "gpio86",
+};
+static const char * const atest_usb13_groups[] = {
+       "gpio87",
+};
+static const char * const atest_usb2_groups[] = {
+       "gpio88",
+};
+static const char * const atest_usb20_groups[] = {
+       "gpio89",
+};
+static const char * const atest_usb21_groups[] = {
+       "gpio90",
+};
+static const char * const atest_usb22_groups[] = {
+       "gpio91",
+};
+static const char * const atest_usb23_groups[] = {
+       "gpio92",
+};
+static const char * const audio_ref_groups[] = {
+       "gpio60",
+};
+static const char * const btfm_slimbus_groups[] = {
+       "gpio67", "gpio68", "gpio86", "gpio87",
+};
+static const char * const cam_mclk_groups[] = {
+       "gpio29", "gpio30", "gpio31", "gpio32", "gpio33",
+};
+static const char * const cci_timer0_groups[] = {
+       "gpio34",
+};
+static const char * const cci_timer1_groups[] = {
+       "gpio35",
+};
+static const char * const cci_timer2_groups[] = {
+       "gpio36",
+};
+static const char * const cci_timer3_groups[] = {
+       "gpio37",
+};
+static const char * const cci_timer4_groups[] = {
+       "gpio38",
+};
+static const char * const cri_trng_groups[] = {
+       "gpio0", "gpio1", "gpio2",
+};
+static const char * const dbg_out_groups[] = {
+       "gpio3",
+};
+static const char * const ddr_bist_groups[] = {
+       "gpio19", "gpio20", "gpio21", "gpio22",
+};
+static const char * const ddr_pxi0_groups[] = {
+       "gpio86", "gpio90",
+};
+static const char * const ddr_pxi1_groups[] = {
+       "gpio87", "gpio91",
+};
+static const char * const ddr_pxi2_groups[] = {
+       "gpio88", "gpio92",
+};
+static const char * const ddr_pxi3_groups[] = {
+       "gpio89", "gpio93",
+};
+static const char * const dp_hot_groups[] = {
+       "gpio12", "gpio118",
+};
+static const char * const edp_lcd_groups[] = {
+       "gpio23",
+};
+static const char * const gcc_gp1_groups[] = {
+       "gpio48", "gpio58",
+};
+static const char * const gcc_gp2_groups[] = {
+       "gpio21",
+};
+static const char * const gcc_gp3_groups[] = {
+       "gpio22",
+};
+static const char * const ibi_i3c_groups[] = {
+       "gpio0", "gpio1",
+};
+static const char * const ldo_en_groups[] = {
+       "gpio95",
+};
+static const char * const ldo_update_groups[] = {
+       "gpio96",
+};
+static const char * const lpass_ext_groups[] = {
+       "gpio60", "gpio93",
+};
+static const char * const m_voc_groups[] = {
+       "gpio12",
+};
+static const char * const mdp_vsync0_groups[] = {
+       "gpio47",
+};
+static const char * const mdp_vsync1_groups[] = {
+       "gpio48",
+};
+static const char * const mdp_vsync2_groups[] = {
+       "gpio56",
+};
+static const char * const mdp_vsync3_groups[] = {
+       "gpio57",
+};
+static const char * const mi2s_0_groups[] = {
+       "gpio88", "gpio89", "gpio90", "gpio91",
+};
+static const char * const mi2s_1_groups[] = {
+       "gpio67", "gpio68", "gpio86", "gpio87",
+};
+static const char * const mi2s_2_groups[] = {
+       "gpio60",
+};
+static const char * const nav_gpio_groups[] = {
+       "gpio101", "gpio102",
+};
+static const char * const pa_indicator_groups[] = {
+       "gpio118",
+};
+static const char * const phase_flag0_groups[] = {
+       "gpio12",
+};
+static const char * const phase_flag1_groups[] = {
+       "gpio17",
+};
+static const char * const phase_flag10_groups[] = {
+       "gpio41",
+};
+static const char * const phase_flag11_groups[] = {
+       "gpio42",
+};
+static const char * const phase_flag12_groups[] = {
+       "gpio43",
+};
+static const char * const phase_flag13_groups[] = {
+       "gpio44",
+};
+static const char * const phase_flag14_groups[] = {
+       "gpio45",
+};
+static const char * const phase_flag15_groups[] = {
+       "gpio46",
+};
+static const char * const phase_flag16_groups[] = {
+       "gpio47",
+};
+static const char * const phase_flag17_groups[] = {
+       "gpio48",
+};
+static const char * const phase_flag18_groups[] = {
+       "gpio49",
+};
+static const char * const phase_flag19_groups[] = {
+       "gpio50",
+};
+static const char * const phase_flag2_groups[] = {
+       "gpio18",
+};
+static const char * const phase_flag20_groups[] = {
+       "gpio51",
+};
+static const char * const phase_flag21_groups[] = {
+       "gpio52",
+};
+static const char * const phase_flag22_groups[] = {
+       "gpio53",
+};
+static const char * const phase_flag23_groups[] = {
+       "gpio56",
+};
+static const char * const phase_flag24_groups[] = {
+       "gpio57",
+};
+static const char * const phase_flag25_groups[] = {
+       "gpio60",
+};
+static const char * const phase_flag26_groups[] = {
+       "gpio61",
+};
+static const char * const phase_flag27_groups[] = {
+       "gpio62",
+};
+static const char * const phase_flag28_groups[] = {
+       "gpio63",
+};
+static const char * const phase_flag29_groups[] = {
+       "gpio64",
+};
+static const char * const phase_flag3_groups[] = {
+       "gpio34",
+};
+static const char * const phase_flag30_groups[] = {
+       "gpio67",
+};
+static const char * const phase_flag31_groups[] = {
+       "gpio68",
+};
+static const char * const phase_flag4_groups[] = {
+       "gpio35",
+};
+static const char * const phase_flag5_groups[] = {
+       "gpio36",
+};
+static const char * const phase_flag6_groups[] = {
+       "gpio37",
+};
+static const char * const phase_flag7_groups[] = {
+       "gpio38",
+};
+static const char * const phase_flag8_groups[] = {
+       "gpio39",
+};
+static const char * const phase_flag9_groups[] = {
+       "gpio40",
+};
+static const char * const pll_bypassnl_groups[] = {
+       "gpio13",
+};
+static const char * const pll_clk_groups[] = {
+       "gpio98",
+};
+static const char * const pll_reset_groups[] = {
+       "gpio14",
+};
+static const char * const prng_rosc0_groups[] = {
+       "gpio97",
+};
+static const char * const prng_rosc1_groups[] = {
+       "gpio98",
+};
+static const char * const prng_rosc2_groups[] = {
+       "gpio99",
+};
+static const char * const prng_rosc3_groups[] = {
+       "gpio100",
+};
+static const char * const qdss_cti_groups[] = {
+       "gpio2", "gpio3", "gpio6", "gpio7", "gpio61", "gpio62", "gpio86",
+       "gpio87",
+};
+static const char * const qdss_gpio_groups[] = {
+       "gpio8", "gpio9", "gpio63", "gpio64",
+};
+static const char * const qdss_gpio0_groups[] = {
+       "gpio39", "gpio65",
+};
+static const char * const qdss_gpio1_groups[] = {
+       "gpio40", "gpio66",
+};
+static const char * const qdss_gpio10_groups[] = {
+       "gpio50", "gpio56",
+};
+static const char * const qdss_gpio11_groups[] = {
+       "gpio51", "gpio57",
+};
+static const char * const qdss_gpio12_groups[] = {
+       "gpio34", "gpio52",
+};
+static const char * const qdss_gpio13_groups[] = {
+       "gpio35", "gpio53",
+};
+static const char * const qdss_gpio14_groups[] = {
+       "gpio27", "gpio36",
+};
+static const char * const qdss_gpio15_groups[] = {
+       "gpio28", "gpio37",
+};
+static const char * const qdss_gpio2_groups[] = {
+       "gpio38", "gpio41",
+};
+static const char * const qdss_gpio3_groups[] = {
+       "gpio42", "gpio47",
+};
+static const char * const qdss_gpio4_groups[] = {
+       "gpio43", "gpio88",
+};
+static const char * const qdss_gpio5_groups[] = {
+       "gpio44", "gpio89",
+};
+static const char * const qdss_gpio6_groups[] = {
+       "gpio45", "gpio90",
+};
+static const char * const qdss_gpio7_groups[] = {
+       "gpio46", "gpio91",
+};
+static const char * const qdss_gpio8_groups[] = {
+       "gpio48", "gpio92",
+};
+static const char * const qdss_gpio9_groups[] = {
+       "gpio49", "gpio93",
+};
+static const char * const qlink0_enable_groups[] = {
+       "gpio105",
+};
+static const char * const qlink0_request_groups[] = {
+       "gpio104",
+};
+static const char * const qlink1_enable_groups[] = {
+       "gpio108",
+};
+static const char * const qlink1_request_groups[] = {
+       "gpio107",
+};
+static const char * const qup00_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const qup01_groups[] = {
+       "gpio61", "gpio62", "gpio63", "gpio64",
+};
+static const char * const qup02_groups[] = {
+       "gpio45", "gpio46", "gpio48", "gpio56", "gpio57",
+};
+static const char * const qup10_groups[] = {
+       "gpio13", "gpio14", "gpio15", "gpio16", "gpio17",
+};
+static const char * const qup11_f1_groups[] = {
+       "gpio27", "gpio28",
+};
+static const char * const qup11_f2_groups[] = {
+       "gpio27", "gpio28",
+};
+
+static const char * const qup12_groups[] = {
+       "gpio19", "gpio19", "gpio20", "gpio20",
+};
+static const char * const qup13_f1_groups[] = {
+       "gpio25", "gpio26",
+};
+static const char * const qup13_f2_groups[] = {
+       "gpio25", "gpio26",
+};
+static const char * const qup14_groups[] = {
+       "gpio4", "gpio4", "gpio5", "gpio5",
+};
+static const char * const sd_write_groups[] = {
+       "gpio85",
+};
+static const char * const sdc1_tb_groups[] = {
+       "gpio4",
+};
+static const char * const sdc2_tb_groups[] = {
+       "gpio5",
+};
+static const char * const sp_cmu_groups[] = {
+       "gpio3",
+};
+static const char * const tgu_ch0_groups[] = {
+       "gpio61",
+};
+static const char * const tgu_ch1_groups[] = {
+       "gpio62",
+};
+static const char * const tgu_ch2_groups[] = {
+       "gpio63",
+};
+static const char * const tgu_ch3_groups[] = {
+       "gpio64",
+};
+static const char * const tsense_pwm1_groups[] = {
+       "gpio88",
+};
+static const char * const tsense_pwm2_groups[] = {
+       "gpio88",
+};
+static const char * const uim1_clk_groups[] = {
+       "gpio80",
+};
+static const char * const uim1_data_groups[] = {
+       "gpio79",
+};
+static const char * const uim1_present_groups[] = {
+       "gpio82",
+};
+static const char * const uim1_reset_groups[] = {
+       "gpio81",
+};
+static const char * const uim2_clk_groups[] = {
+       "gpio76",
+};
+static const char * const uim2_data_groups[] = {
+       "gpio75",
+};
+static const char * const uim2_present_groups[] = {
+       "gpio78",
+};
+static const char * const uim2_reset_groups[] = {
+       "gpio77",
+};
+static const char * const usb2phy_ac_groups[] = {
+       "gpio47",
+};
+static const char * const vfr_1_groups[] = {
+       "gpio49",
+};
+static const char * const vsense_trigger_groups[] = {
+       "gpio89",
+};
+static const char * const wlan1_adc0_groups[] = {
+       "gpio90",
+};
+static const char * const wlan1_adc1_groups[] = {
+       "gpio92",
+};
+static const char * const wlan2_adc0_groups[] = {
+       "gpio91",
+};
+static const char * const wlan2_adc1_groups[] = {
+       "gpio93",
+};
+
+static const struct msm_function sm6375_functions[] = {
+       FUNCTION(adsp_ext),
+       FUNCTION(agera_pll),
+       FUNCTION(atest_char),
+       FUNCTION(atest_char0),
+       FUNCTION(atest_char1),
+       FUNCTION(atest_char2),
+       FUNCTION(atest_char3),
+       FUNCTION(atest_tsens),
+       FUNCTION(atest_tsens2),
+       FUNCTION(atest_usb1),
+       FUNCTION(atest_usb10),
+       FUNCTION(atest_usb11),
+       FUNCTION(atest_usb12),
+       FUNCTION(atest_usb13),
+       FUNCTION(atest_usb2),
+       FUNCTION(atest_usb20),
+       FUNCTION(atest_usb21),
+       FUNCTION(atest_usb22),
+       FUNCTION(atest_usb23),
+       FUNCTION(audio_ref),
+       FUNCTION(btfm_slimbus),
+       FUNCTION(cam_mclk),
+       FUNCTION(cci_async),
+       FUNCTION(cci_i2c),
+       FUNCTION(cci_timer0),
+       FUNCTION(cci_timer1),
+       FUNCTION(cci_timer2),
+       FUNCTION(cci_timer3),
+       FUNCTION(cci_timer4),
+       FUNCTION(cri_trng),
+       FUNCTION(dbg_out),
+       FUNCTION(ddr_bist),
+       FUNCTION(ddr_pxi0),
+       FUNCTION(ddr_pxi1),
+       FUNCTION(ddr_pxi2),
+       FUNCTION(ddr_pxi3),
+       FUNCTION(dp_hot),
+       FUNCTION(edp_lcd),
+       FUNCTION(gcc_gp1),
+       FUNCTION(gcc_gp2),
+       FUNCTION(gcc_gp3),
+       FUNCTION(gp_pdm0),
+       FUNCTION(gp_pdm1),
+       FUNCTION(gp_pdm2),
+       FUNCTION(gpio),
+       FUNCTION(gps_tx),
+       FUNCTION(ibi_i3c),
+       FUNCTION(jitter_bist),
+       FUNCTION(ldo_en),
+       FUNCTION(ldo_update),
+       FUNCTION(lpass_ext),
+       FUNCTION(m_voc),
+       FUNCTION(mclk),
+       FUNCTION(mdp_vsync),
+       FUNCTION(mdp_vsync0),
+       FUNCTION(mdp_vsync1),
+       FUNCTION(mdp_vsync2),
+       FUNCTION(mdp_vsync3),
+       FUNCTION(mi2s_0),
+       FUNCTION(mi2s_1),
+       FUNCTION(mi2s_2),
+       FUNCTION(mss_lte),
+       FUNCTION(nav_gpio),
+       FUNCTION(nav_pps),
+       FUNCTION(pa_indicator),
+       FUNCTION(phase_flag0),
+       FUNCTION(phase_flag1),
+       FUNCTION(phase_flag10),
+       FUNCTION(phase_flag11),
+       FUNCTION(phase_flag12),
+       FUNCTION(phase_flag13),
+       FUNCTION(phase_flag14),
+       FUNCTION(phase_flag15),
+       FUNCTION(phase_flag16),
+       FUNCTION(phase_flag17),
+       FUNCTION(phase_flag18),
+       FUNCTION(phase_flag19),
+       FUNCTION(phase_flag2),
+       FUNCTION(phase_flag20),
+       FUNCTION(phase_flag21),
+       FUNCTION(phase_flag22),
+       FUNCTION(phase_flag23),
+       FUNCTION(phase_flag24),
+       FUNCTION(phase_flag25),
+       FUNCTION(phase_flag26),
+       FUNCTION(phase_flag27),
+       FUNCTION(phase_flag28),
+       FUNCTION(phase_flag29),
+       FUNCTION(phase_flag3),
+       FUNCTION(phase_flag30),
+       FUNCTION(phase_flag31),
+       FUNCTION(phase_flag4),
+       FUNCTION(phase_flag5),
+       FUNCTION(phase_flag6),
+       FUNCTION(phase_flag7),
+       FUNCTION(phase_flag8),
+       FUNCTION(phase_flag9),
+       FUNCTION(pll_bist),
+       FUNCTION(pll_bypassnl),
+       FUNCTION(pll_clk),
+       FUNCTION(pll_reset),
+       FUNCTION(prng_rosc0),
+       FUNCTION(prng_rosc1),
+       FUNCTION(prng_rosc2),
+       FUNCTION(prng_rosc3),
+       FUNCTION(qdss_cti),
+       FUNCTION(qdss_gpio),
+       FUNCTION(qdss_gpio0),
+       FUNCTION(qdss_gpio1),
+       FUNCTION(qdss_gpio10),
+       FUNCTION(qdss_gpio11),
+       FUNCTION(qdss_gpio12),
+       FUNCTION(qdss_gpio13),
+       FUNCTION(qdss_gpio14),
+       FUNCTION(qdss_gpio15),
+       FUNCTION(qdss_gpio2),
+       FUNCTION(qdss_gpio3),
+       FUNCTION(qdss_gpio4),
+       FUNCTION(qdss_gpio5),
+       FUNCTION(qdss_gpio6),
+       FUNCTION(qdss_gpio7),
+       FUNCTION(qdss_gpio8),
+       FUNCTION(qdss_gpio9),
+       FUNCTION(qlink0_enable),
+       FUNCTION(qlink0_request),
+       FUNCTION(qlink0_wmss),
+       FUNCTION(qlink1_enable),
+       FUNCTION(qlink1_request),
+       FUNCTION(qlink1_wmss),
+       FUNCTION(qup00),
+       FUNCTION(qup01),
+       FUNCTION(qup02),
+       FUNCTION(qup10),
+       FUNCTION(qup11_f1),
+       FUNCTION(qup11_f2),
+       FUNCTION(qup12),
+       FUNCTION(qup13_f1),
+       FUNCTION(qup13_f2),
+       FUNCTION(qup14),
+       FUNCTION(sd_write),
+       FUNCTION(sdc1_tb),
+       FUNCTION(sdc2_tb),
+       FUNCTION(sp_cmu),
+       FUNCTION(tgu_ch0),
+       FUNCTION(tgu_ch1),
+       FUNCTION(tgu_ch2),
+       FUNCTION(tgu_ch3),
+       FUNCTION(tsense_pwm1),
+       FUNCTION(tsense_pwm2),
+       FUNCTION(uim1_clk),
+       FUNCTION(uim1_data),
+       FUNCTION(uim1_present),
+       FUNCTION(uim1_reset),
+       FUNCTION(uim2_clk),
+       FUNCTION(uim2_data),
+       FUNCTION(uim2_present),
+       FUNCTION(uim2_reset),
+       FUNCTION(usb2phy_ac),
+       FUNCTION(usb_phy),
+       FUNCTION(vfr_1),
+       FUNCTION(vsense_trigger),
+       FUNCTION(wlan1_adc0),
+       FUNCTION(wlan1_adc1),
+       FUNCTION(wlan2_adc0),
+       FUNCTION(wlan2_adc1),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sm6375_groups[] = {
+       [0] = PINGROUP(0, ibi_i3c, qup00, cri_trng, _, _, _, _, _, _),
+       [1] = PINGROUP(1, ibi_i3c, qup00, cri_trng, _, _, _, _, _, _),
+       [2] = PINGROUP(2, qup00, cci_i2c, cri_trng, qdss_cti, _, _, _, _, _),
+       [3] = PINGROUP(3, qup00, cci_i2c, sp_cmu, dbg_out, qdss_cti, _, _, _, _),
+       [4] = PINGROUP(4, qup14, qup14, sdc1_tb, _, _, _, _, _, _),
+       [5] = PINGROUP(5, qup14, qup14, sdc2_tb, _, _, _, _, _, _),
+       [6] = PINGROUP(6, mdp_vsync, qdss_cti, _, _, _, _, _, _, _),
+       [7] = PINGROUP(7, qdss_cti, _, _, _, _, _, _, _, _),
+       [8] = PINGROUP(8, gp_pdm1, qdss_gpio, _, _, _, _, _, _, _),
+       [9] = PINGROUP(9, qdss_gpio, _, _, _, _, _, _, _, _),
+       [10] = PINGROUP(10, _, _, _, _, _, _, _, _, _),
+       [11] = PINGROUP(11, _, _, _, _, _, _, _, _, _),
+       [12] = PINGROUP(12, m_voc, dp_hot, _, phase_flag0, _, _, _, _, _),
+       [13] = PINGROUP(13, qup10, pll_bypassnl, _, _, _, _, _, _, _),
+       [14] = PINGROUP(14, qup10, pll_reset, _, _, _, _, _, _, _),
+       [15] = PINGROUP(15, qup10, _, _, _, _, _, _, _, _),
+       [16] = PINGROUP(16, qup10, _, _, _, _, _, _, _, _),
+       [17] = PINGROUP(17, _, phase_flag1, qup10, _, _, _, _, _, _),
+       [18] = PINGROUP(18, _, phase_flag2, _, _, _, _, _, _, _),
+       [19] = PINGROUP(19, qup12, qup12, ddr_bist, _, _, _, _, _, _),
+       [20] = PINGROUP(20, qup12, qup12, ddr_bist, _, _, _, _, _, _),
+       [21] = PINGROUP(21, gcc_gp2, ddr_bist, _, _, _, _, _, _, _),
+       [22] = PINGROUP(22, gcc_gp3, ddr_bist, _, _, _, _, _, _, _),
+       [23] = PINGROUP(23, mdp_vsync, edp_lcd, _, _, _, _, _, _, _),
+       [24] = PINGROUP(24, mdp_vsync, _, _, _, _, _, _, _, _),
+       [25] = PINGROUP(25, qup13_f1, qup13_f2, _, _, _, _, _, _, _),
+       [26] = PINGROUP(26, qup13_f1, qup13_f2, _, _, _, _, _, _, _),
+       [27] = PINGROUP(27, qup11_f1, qup11_f2, mdp_vsync, pll_bist, _, qdss_gpio14, _, _, _),
+       [28] = PINGROUP(28, qup11_f1, qup11_f2, mdp_vsync, _, qdss_gpio15, _, _, _, _),
+       [29] = PINGROUP(29, cam_mclk, _, _, _, _, _, _, _, _),
+       [30] = PINGROUP(30, cam_mclk, _, _, _, _, _, _, _, _),
+       [31] = PINGROUP(31, cam_mclk, _, _, _, _, _, _, _, _),
+       [32] = PINGROUP(32, cam_mclk, _, _, _, _, _, _, _, _),
+       [33] = PINGROUP(33, cam_mclk, _, _, _, _, _, _, _, _),
+       [34] = PINGROUP(34, cci_timer0, _, phase_flag3, qdss_gpio12, _, _, _, _, _),
+       [35] = PINGROUP(35, cci_timer1, cci_async, _, phase_flag4, qdss_gpio13, _, _, _, _),
+       [36] = PINGROUP(36, cci_timer2, cci_async, _, phase_flag5, qdss_gpio14, _, _, _, _),
+       [37] = PINGROUP(37, cci_timer3, gp_pdm0, _, phase_flag6, qdss_gpio15, _, _, _, _),
+       [38] = PINGROUP(38, cci_timer4, _, phase_flag7, qdss_gpio2, _, _, _, _, _),
+       [39] = PINGROUP(39, cci_i2c, _, phase_flag8, qdss_gpio0, _, _, _, _, _),
+       [40] = PINGROUP(40, cci_i2c, _, phase_flag9, qdss_gpio1, _, _, _, _, _),
+       [41] = PINGROUP(41, cci_i2c, _, phase_flag10, qdss_gpio2, _, _, _, _, _),
+       [42] = PINGROUP(42, cci_i2c, _, phase_flag11, qdss_gpio3, _, _, _, _, _),
+       [43] = PINGROUP(43, cci_i2c, _, phase_flag12, qdss_gpio4, _, _, _, _, _),
+       [44] = PINGROUP(44, cci_i2c, _, phase_flag13, qdss_gpio5, _, _, _, _, _),
+       [45] = PINGROUP(45, qup02, _, phase_flag14, qdss_gpio6, _, _, _, _, _),
+       [46] = PINGROUP(46, qup02, _, phase_flag15, qdss_gpio7, _, _, _, _, _),
+       [47] = PINGROUP(47, mdp_vsync0, _, phase_flag16, qdss_gpio3, _, _, usb2phy_ac, _, _),
+       [48] = PINGROUP(48, cci_async, mdp_vsync1, gcc_gp1, _, phase_flag17, qdss_gpio8, qup02,
+                       _, _),
+       [49] = PINGROUP(49, vfr_1, _, phase_flag18, qdss_gpio9, _, _, _, _, _),
+       [50] = PINGROUP(50, _, phase_flag19, qdss_gpio10, _, _, _, _, _, _),
+       [51] = PINGROUP(51, _, phase_flag20, qdss_gpio11, _, _, _, _, _, _),
+       [52] = PINGROUP(52, cci_async, gp_pdm1, _, phase_flag21, qdss_gpio12, _, _, _, _),
+       [53] = PINGROUP(53, cci_async, _, phase_flag22, qdss_gpio13, _, _, _, _, _),
+       [54] = PINGROUP(54, _, _, _, _, _, _, _, _, _),
+       [55] = PINGROUP(55, _, _, _, _, _, _, _, _, _),
+       [56] = PINGROUP(56, qup02, mdp_vsync2, _, phase_flag23, qdss_gpio10, _, _, _, _),
+       [57] = PINGROUP(57, qup02, mdp_vsync3, gp_pdm2, _, phase_flag24, qdss_gpio11, _, _, _),
+       [58] = PINGROUP(58, gcc_gp1, _, _, _, _, _, _, _, _),
+       [59] = PINGROUP(59, _, _, _, _, _, _, _, _, _),
+       [60] = PINGROUP(60, audio_ref, lpass_ext, mi2s_2, _, phase_flag25, _, _, _, _),
+       [61] = PINGROUP(61, qup01, tgu_ch0, _, phase_flag26, qdss_cti, _, _, _, _),
+       [62] = PINGROUP(62, qup01, tgu_ch1, _, phase_flag27, qdss_cti, _, _, _, _),
+       [63] = PINGROUP(63, qup01, tgu_ch2, _, phase_flag28, qdss_gpio, _, _, _, _),
+       [64] = PINGROUP(64, qup01, tgu_ch3, _, phase_flag29, qdss_gpio, _, _, _, _),
+       [65] = PINGROUP(65, mss_lte, _, qdss_gpio0, _, _, _, _, _, _),
+       [66] = PINGROUP(66, mss_lte, _, qdss_gpio1, _, _, _, _, _, _),
+       [67] = PINGROUP(67, btfm_slimbus, mi2s_1, _, phase_flag30, _, _, _, _, _),
+       [68] = PINGROUP(68, btfm_slimbus, mi2s_1, gp_pdm0, _, phase_flag31, _, _, _, _),
+       [69] = PINGROUP(69, _, _, _, _, _, _, _, _, _),
+       [70] = PINGROUP(70, _, _, _, _, _, _, _, _, _),
+       [71] = PINGROUP(71, _, _, _, _, _, _, _, _, _),
+       [72] = PINGROUP(72, _, _, _, _, _, _, _, _, _),
+       [73] = PINGROUP(73, _, _, _, _, _, _, _, _, _),
+       [74] = PINGROUP(74, _, _, _, _, _, _, _, _, _),
+       [75] = PINGROUP(75, uim2_data, _, _, _, _, _, _, _, _),
+       [76] = PINGROUP(76, uim2_clk, _, _, _, _, _, _, _, _),
+       [77] = PINGROUP(77, uim2_reset, _, _, _, _, _, _, _, _),
+       [78] = PINGROUP(78, uim2_present, _, _, _, _, _, _, _, _),
+       [79] = PINGROUP(79, uim1_data, _, _, _, _, _, _, _, _),
+       [80] = PINGROUP(80, uim1_clk, _, _, _, _, _, _, _, _),
+       [81] = PINGROUP(81, uim1_reset, _, _, _, _, _, _, _, _),
+       [82] = PINGROUP(82, uim1_present, _, _, _, _, _, _, _, _),
+       [83] = PINGROUP(83, atest_usb1, _, _, _, _, _, _, _, _),
+       [84] = PINGROUP(84, _, atest_usb10, _, _, _, _, _, _, _),
+       [85] = PINGROUP(85, sd_write, _, atest_usb11, _, _, _, _, _, _),
+       [86] = PINGROUP(86, btfm_slimbus, mi2s_1, _, qdss_cti, atest_usb12, ddr_pxi0, _, _, _),
+       [87] = PINGROUP(87, btfm_slimbus, mi2s_1, adsp_ext, _, qdss_cti, atest_usb13, ddr_pxi1, _,
+                       _),
+       [88] = PINGROUP(88, mi2s_0, _, qdss_gpio4, _, atest_usb2, ddr_pxi2, tsense_pwm1,
+                       tsense_pwm2, _),
+       [89] = PINGROUP(89, mi2s_0, agera_pll, _, qdss_gpio5, _, vsense_trigger, atest_usb20,
+                       ddr_pxi3, _),
+       [90] = PINGROUP(90, mi2s_0, jitter_bist, _, qdss_gpio6, _, wlan1_adc0, atest_usb21,
+                       ddr_pxi0, _),
+       [91] = PINGROUP(91, mi2s_0, _, qdss_gpio7, _, wlan2_adc0, atest_usb22, ddr_pxi1, _, _),
+       [92] = PINGROUP(92, _, qdss_gpio8, atest_tsens, wlan1_adc1, atest_usb23, ddr_pxi2, _, _,
+                       _),
+       [93] = PINGROUP(93, mclk, lpass_ext, _, qdss_gpio9, atest_tsens2, wlan2_adc1, ddr_pxi3,
+                       _, _),
+       [94] = PINGROUP(94, _, _, _, _, _, _, _, _, _),
+       [95] = PINGROUP(95, ldo_en, _, atest_char, _, _, _, _, _, _),
+       [96] = PINGROUP(96, ldo_update, _, atest_char0, _, _, _, _, _, _),
+       [97] = PINGROUP(97, prng_rosc0, _, atest_char1, _, _, _, _, _, _),
+       [98] = PINGROUP(98, _, atest_char2, _, _, prng_rosc1, pll_clk, _, _, _),
+       [99] = PINGROUP(99, _, atest_char3, _, _, prng_rosc2, _, _, _, _),
+       [100] = PINGROUP(100, _, _, prng_rosc3, _, _, _, _, _, _),
+       [101] = PINGROUP(101, nav_gpio, nav_pps, nav_pps, gps_tx, _, _, _, _, _),
+       [102] = PINGROUP(102, nav_gpio, nav_pps, nav_pps, gps_tx, _, _, _, _, _),
+       [103] = PINGROUP(103, qlink0_wmss, _, _, _, _, _, _, _, _),
+       [104] = PINGROUP(104, qlink0_request, _, _, _, _, _, _, _, _),
+       [105] = PINGROUP(105, qlink0_enable, _, _, _, _, _, _, _, _),
+       [106] = PINGROUP(106, qlink1_wmss, _, _, _, _, _, _, _, _),
+       [107] = PINGROUP(107, qlink1_request, gps_tx, _, _, _, _, _, _, _),
+       [108] = PINGROUP(108, qlink1_enable, gps_tx, _, _, _, _, _, _, _),
+       [109] = PINGROUP(109, _, _, _, _, _, _, _, _, _),
+       [110] = PINGROUP(110, _, _, _, _, _, _, _, _, _),
+       [111] = PINGROUP(111, _, _, _, _, _, _, _, _, _),
+       [112] = PINGROUP(112, _, _, _, _, _, _, _, _, _),
+       [113] = PINGROUP(113, _, _, _, _, _, _, _, _, _),
+       [114] = PINGROUP(114, _, _, _, _, _, _, _, _, _),
+       [115] = PINGROUP(115, _, _, _, _, _, _, _, _, _),
+       [116] = PINGROUP(116, _, _, _, _, _, _, _, _, _),
+       [117] = PINGROUP(117, _, _, _, _, _, _, _, _, _),
+       [118] = PINGROUP(118, _, _, pa_indicator, dp_hot, _, _, _, _, _),
+       [119] = PINGROUP(119, _, _, _, _, _, _, _, _, _),
+       [120] = PINGROUP(120, _, _, _, _, _, _, _, _, _),
+       [121] = PINGROUP(121, _, _, _, _, _, _, _, _, _),
+       [122] = PINGROUP(122, _, _, _, _, _, _, _, _, _),
+       [123] = PINGROUP(123, _, _, _, _, _, _, _, _, _),
+       [124] = PINGROUP(124, usb_phy, _, _, _, _, _, _, _, _),
+       [125] = PINGROUP(125, _, _, _, _, _, _, _, _, _),
+       [126] = PINGROUP(126, _, _, _, _, _, _, _, _, _),
+       [127] = PINGROUP(127, _, _, _, _, _, _, _, _, _),
+       [128] = PINGROUP(128, _, _, _, _, _, _, _, _, _),
+       [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _),
+       [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _),
+       [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _),
+       [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _),
+       [133] = PINGROUP(133, _, _, _, _, _, _, _, _, _),
+       [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _),
+       [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _),
+       [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _),
+       [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _),
+       [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _),
+       [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _),
+       [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _),
+       [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _),
+       [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _),
+       [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _),
+       [144] = PINGROUP(144, _, _, _, _, _, _, _, _, _),
+       [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _),
+       [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _),
+       [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _),
+       [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _),
+       [149] = PINGROUP(149, _, _, _, _, _, _, _, _, _),
+       [150] = PINGROUP(150, _, _, _, _, _, _, _, _, _),
+       [151] = PINGROUP(151, _, _, _, _, _, _, _, _, _),
+       [152] = PINGROUP(152, _, _, _, _, _, _, _, _, _),
+       [153] = PINGROUP(153, _, _, _, _, _, _, _, _, _),
+       [154] = PINGROUP(154, _, _, _, _, _, _, _, _, _),
+       [155] = PINGROUP(155, _, _, _, _, _, _, _, _, _),
+       [156] = UFS_RESET(ufs_reset, 0x1ae000),
+       [157] = SDC_PINGROUP(sdc1_rclk, 0x1a1000, 0, 0),
+       [158] = SDC_PINGROUP(sdc1_clk, 0x1a0000, 13, 6),
+       [159] = SDC_PINGROUP(sdc1_cmd, 0x1a0000, 11, 3),
+       [160] = SDC_PINGROUP(sdc1_data, 0x1a0000, 9, 0),
+       [161] = SDC_PINGROUP(sdc2_clk, 0x1a2000, 14, 6),
+       [162] = SDC_PINGROUP(sdc2_cmd, 0x1a2000, 11, 3),
+       [163] = SDC_PINGROUP(sdc2_data, 0x1a2000, 9, 0),
+};
+
+static const struct msm_gpio_wakeirq_map sm6375_mpm_map[] = {
+       { 0, 84 }, { 3, 6 }, { 4, 7 }, { 7, 8 }, { 8, 9 }, { 9, 10 }, { 11, 11 }, { 12, 13 },
+       { 13, 14 }, { 16, 16 }, { 17, 17 }, { 18, 18 }, { 19, 19 }, { 21, 20 }, { 22, 21 },
+       { 23, 23 }, { 24, 24 }, { 25, 25 }, { 27, 26 }, { 28, 27 }, { 37, 28 }, { 38, 29 },
+       { 48, 30 }, { 50, 31 }, { 51, 32 }, { 52, 33 }, { 57, 34 }, { 59, 35 }, { 60, 37 },
+       { 61, 38 }, { 62, 39 }, { 64, 40 }, { 66, 41 }, { 67, 42 }, { 68, 43 }, { 69, 44 },
+       { 78, 45 }, { 82, 36 }, { 83, 47 }, { 84, 48 }, { 85, 49 }, { 87, 50 }, { 88, 51 },
+       { 91, 52 }, { 94, 53 }, { 95, 54 }, { 96, 55 }, { 97, 56 }, { 98, 57 }, { 99, 58 },
+       { 100, 59 }, { 104, 60 }, { 107, 61 }, { 118, 62 }, { 124, 63 }, { 125, 64 }, { 126, 65 },
+       { 128, 66 }, { 129, 67 }, { 131, 69 }, { 133, 70 }, { 134, 71 }, { 136, 73 }, { 142, 74 },
+       { 150, 75 }, { 153, 76 }, { 155, 77 },
+};
+
+static const struct msm_pinctrl_soc_data sm6375_tlmm = {
+       .pins = sm6375_pins,
+       .npins = ARRAY_SIZE(sm6375_pins),
+       .functions = sm6375_functions,
+       .nfunctions = ARRAY_SIZE(sm6375_functions),
+       .groups = sm6375_groups,
+       .ngroups = ARRAY_SIZE(sm6375_groups),
+       .ngpios = 157,
+       .wakeirq_map = sm6375_mpm_map,
+       .nwakeirq_map = ARRAY_SIZE(sm6375_mpm_map),
+};
+
+static int sm6375_tlmm_probe(struct platform_device *pdev)
+{
+       return msm_pinctrl_probe(pdev, &sm6375_tlmm);
+}
+
+static const struct of_device_id sm6375_tlmm_of_match[] = {
+       { .compatible = "qcom,sm6375-tlmm", },
+       { },
+};
+
+static struct platform_driver sm6375_tlmm_driver = {
+       .driver = {
+               .name = "sm6375-tlmm",
+               .of_match_table = sm6375_tlmm_of_match,
+       },
+       .probe = sm6375_tlmm_probe,
+       .remove = msm_pinctrl_remove,
+};
+
+static int __init sm6375_tlmm_init(void)
+{
+       return platform_driver_register(&sm6375_tlmm_driver);
+}
+arch_initcall(sm6375_tlmm_init);
+
+static void __exit sm6375_tlmm_exit(void)
+{
+       platform_driver_unregister(&sm6375_tlmm_driver);
+}
+module_exit(sm6375_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI SM6375 TLMM driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, sm6375_tlmm_of_match);
index af144e7..3bd7f9f 100644 (file)
@@ -1316,7 +1316,7 @@ static const struct msm_pingroup sm8250_groups[] = {
 static const struct msm_gpio_wakeirq_map sm8250_pdc_map[] = {
        { 0, 79 }, { 1, 84 }, { 2, 80 }, { 3, 82 }, { 4, 107 }, { 7, 43 },
        { 11, 42 }, { 14, 44 }, { 15, 52 }, { 19, 67 }, { 23, 68 }, { 24, 105 },
-       { 27, 92 }, { 28, 106 }, { 31, 69 }, { 35, 70 }, { 39, 37 },
+       { 27, 92 }, { 28, 106 }, { 31, 69 }, { 35, 70 }, { 39, 73 },
        { 40, 108 }, { 43, 71 }, { 45, 72 }, { 47, 83 }, { 51, 74 }, { 55, 77 },
        { 59, 78 }, { 63, 75 }, { 64, 81 }, { 65, 87 }, { 66, 88 }, { 67, 89 },
        { 68, 54 }, { 70, 85 }, { 77, 46 }, { 80, 90 }, { 81, 91 }, { 83, 97 },
index 3be2a08..ccaf40a 100644 (file)
@@ -1159,6 +1159,7 @@ static const struct of_device_id pmic_gpio_of_match[] = {
        /* pm8150l has 12 GPIOs with holes on 7 */
        { .compatible = "qcom,pm8150l-gpio", .data = (void *) 12 },
        { .compatible = "qcom,pmc8180c-gpio", .data = (void *) 12 },
+       { .compatible = "qcom,pm8226-gpio", .data = (void *) 8 },
        { .compatible = "qcom,pm8350-gpio", .data = (void *) 10 },
        { .compatible = "qcom,pm8350b-gpio", .data = (void *) 8 },
        { .compatible = "qcom,pm8350c-gpio", .data = (void *) 9 },
@@ -1175,6 +1176,8 @@ static const struct of_device_id pmic_gpio_of_match[] = {
        { .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 },
        { .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 },
        { .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 },
+       /* pmp8074 has 12 GPIOs with holes on 1 and 12 */
+       { .compatible = "qcom,pmp8074-gpio", .data = (void *) 12 },
        { .compatible = "qcom,pmr735a-gpio", .data = (void *) 4 },
        { .compatible = "qcom,pmr735b-gpio", .data = (void *) 4 },
        /* pms405 has 12 GPIOs with holes on 1, 9, and 10 */
index 961007c..0903a0a 100644 (file)
@@ -38,7 +38,9 @@ config PINCTRL_RENESAS
        select PINCTRL_PFC_R8A77995 if ARCH_R8A77995
        select PINCTRL_PFC_R8A779A0 if ARCH_R8A779A0
        select PINCTRL_PFC_R8A779F0 if ARCH_R8A779F0
+       select PINCTRL_PFC_R8A779G0 if ARCH_R8A779G0
        select PINCTRL_RZG2L if ARCH_RZG2L
+       select PINCTRL_RZV2M if ARCH_R9A09G011
        select PINCTRL_PFC_SH7203 if CPU_SUBTYPE_SH7203
        select PINCTRL_PFC_SH7264 if CPU_SUBTYPE_SH7264
        select PINCTRL_PFC_SH7269 if CPU_SUBTYPE_SH7269
@@ -153,6 +155,10 @@ config PINCTRL_PFC_R8A779A0
        bool "pin control support for R-Car V3U" if COMPILE_TEST
        select PINCTRL_SH_PFC
 
+config PINCTRL_PFC_R8A779G0
+       bool "pin control support for R-Car V4H" if COMPILE_TEST
+       select PINCTRL_SH_PFC
+
 config PINCTRL_PFC_R8A7740
        bool "pin control support for R-Mobile A1" if COMPILE_TEST
        select PINCTRL_SH_PFC_GPIO
@@ -237,6 +243,18 @@ config PINCTRL_RZN1
        help
          This selects pinctrl driver for Renesas RZ/N1 devices.
 
+config PINCTRL_RZV2M
+       bool "pin control support for RZ/V2M"
+       depends on OF
+       depends on ARCH_R9A09G011 || COMPILE_TEST
+       select GPIOLIB
+       select GENERIC_PINCTRL_GROUPS
+       select GENERIC_PINMUX_FUNCTIONS
+       select GENERIC_PINCONF
+       help
+         This selects GPIO and pinctrl driver for Renesas RZ/V2M
+         platforms.
+
 config PINCTRL_PFC_SH7203
        bool "pin control support for SH7203" if COMPILE_TEST
        select PINCTRL_SH_FUNC_GPIO
index 5d936c1..558b30c 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_PINCTRL_PFC_R8A77990)    += pfc-r8a77990.o
 obj-$(CONFIG_PINCTRL_PFC_R8A77995)     += pfc-r8a77995.o
 obj-$(CONFIG_PINCTRL_PFC_R8A779A0)     += pfc-r8a779a0.o
 obj-$(CONFIG_PINCTRL_PFC_R8A779F0)     += pfc-r8a779f0.o
+obj-$(CONFIG_PINCTRL_PFC_R8A779G0)     += pfc-r8a779g0.o
 obj-$(CONFIG_PINCTRL_PFC_SH7203)       += pfc-sh7203.o
 obj-$(CONFIG_PINCTRL_PFC_SH7264)       += pfc-sh7264.o
 obj-$(CONFIG_PINCTRL_PFC_SH7269)       += pfc-sh7269.o
@@ -49,6 +50,7 @@ obj-$(CONFIG_PINCTRL_RZA1)    += pinctrl-rza1.o
 obj-$(CONFIG_PINCTRL_RZA2)     += pinctrl-rza2.o
 obj-$(CONFIG_PINCTRL_RZG2L)    += pinctrl-rzg2l.o
 obj-$(CONFIG_PINCTRL_RZN1)     += pinctrl-rzn1.o
+obj-$(CONFIG_PINCTRL_RZV2M)    += pinctrl-rzv2m.o
 
 ifeq ($(CONFIG_COMPILE_TEST),y)
 CFLAGS_pfc-sh7203.o    += -I$(srctree)/arch/sh/include/cpu-sh2a
index 8c14b20..c91102d 100644 (file)
@@ -644,6 +644,12 @@ static const struct of_device_id sh_pfc_of_table[] = {
                .data = &r8a779f0_pinmux_info,
        },
 #endif
+#ifdef CONFIG_PINCTRL_PFC_R8A779G0
+       {
+               .compatible = "renesas,pfc-r8a779g0",
+               .data = &r8a779g0_pinmux_info,
+       },
+#endif
 #ifdef CONFIG_PINCTRL_PFC_SH73A0
        {
                .compatible = "renesas,pfc-sh73a0",
index aaca4ee..417c357 100644 (file)
@@ -1902,7 +1902,6 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
 enum ioctrl_regs {
        POC0,
        POC1,
-       POC2,
        POC3,
        TD0SEL1,
 };
@@ -1910,7 +1909,6 @@ enum ioctrl_regs {
 static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = {
        [POC0] = { 0xe60500a0, },
        [POC1] = { 0xe60508a0, },
-       [POC2] = { 0xe60510a0, },
        [POC3] = { 0xe60518a0, },
        [TD0SEL1] = { 0xe6050920, },
        { /* sentinel */ },
diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c
new file mode 100644 (file)
index 0000000..5dd1c2c
--- /dev/null
@@ -0,0 +1,4262 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * R8A779A0 processor support - PFC hardware block.
+ *
+ * Copyright (C) 2021 Renesas Electronics Corp.
+ *
+ * This file is based on the drivers/pinctrl/renesas/pfc-r8a779a0.c
+ */
+
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#include "sh_pfc.h"
+
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
+#define CPU_ALL_GP(fn, sfx)                                                            \
+       PORT_GP_CFG_19(0,       fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33),  \
+       PORT_GP_CFG_23(1,       fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33),  \
+       PORT_GP_CFG_1(1, 23,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(1, 24,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(1, 25,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(1, 26,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(1, 27,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(1, 28,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_20(2,       fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_13(3,       fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33),  \
+       PORT_GP_CFG_1(3, 13,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 14,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 15,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 16,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 17,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 18,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 19,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 20,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 21,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 22,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 23,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 24,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 25,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 26,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 27,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 28,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_1(3, 29,    fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_25(4,       fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_21(5,       fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_21(6,       fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_21(7,       fn, sfx, CFG_FLAGS),                                    \
+       PORT_GP_CFG_14(8,       fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33)
+
+/* GPSR0 */
+#define GPSR0_18       F_(MSIOF2_RXD,          IP2SR0_11_8)
+#define GPSR0_17       F_(MSIOF2_SCK,          IP2SR0_7_4)
+#define GPSR0_16       F_(MSIOF2_TXD,          IP2SR0_3_0)
+#define GPSR0_15       F_(MSIOF2_SYNC,         IP1SR0_31_28)
+#define GPSR0_14       F_(MSIOF2_SS1,          IP1SR0_27_24)
+#define GPSR0_13       F_(MSIOF2_SS2,          IP1SR0_23_20)
+#define GPSR0_12       F_(MSIOF5_RXD,          IP1SR0_19_16)
+#define GPSR0_11       F_(MSIOF5_SCK,          IP1SR0_15_12)
+#define GPSR0_10       F_(MSIOF5_TXD,          IP1SR0_11_8)
+#define GPSR0_9                F_(MSIOF5_SYNC,         IP1SR0_7_4)
+#define GPSR0_8                F_(MSIOF5_SS1,          IP1SR0_3_0)
+#define GPSR0_7                F_(MSIOF5_SS2,          IP0SR0_31_28)
+#define GPSR0_6                F_(IRQ0,                IP0SR0_27_24)
+#define GPSR0_5                F_(IRQ1,                IP0SR0_23_20)
+#define GPSR0_4                F_(IRQ2,                IP0SR0_19_16)
+#define GPSR0_3                F_(IRQ3,                IP0SR0_15_12)
+#define GPSR0_2                F_(GP0_02,              IP0SR0_11_8)
+#define GPSR0_1                F_(GP0_01,              IP0SR0_7_4)
+#define GPSR0_0                F_(GP0_00,              IP0SR0_3_0)
+
+/* GPSR1 */
+#define GPSR1_28       F_(HTX3,                IP3SR1_19_16)
+#define GPSR1_27       F_(HCTS3_N,             IP3SR1_15_12)
+#define GPSR1_26       F_(HRTS3_N,             IP3SR1_11_8)
+#define GPSR1_25       F_(HSCK3,               IP3SR1_7_4)
+#define GPSR1_24       F_(HRX3,                IP3SR1_3_0)
+#define GPSR1_23       F_(GP1_23,              IP2SR1_31_28)
+#define GPSR1_22       F_(AUDIO_CLKIN,         IP2SR1_27_24)
+#define GPSR1_21       F_(AUDIO_CLKOUT,        IP2SR1_23_20)
+#define GPSR1_20       F_(SSI_SD,              IP2SR1_19_16)
+#define GPSR1_19       F_(SSI_WS,              IP2SR1_15_12)
+#define GPSR1_18       F_(SSI_SCK,             IP2SR1_11_8)
+#define GPSR1_17       F_(SCIF_CLK,            IP2SR1_7_4)
+#define GPSR1_16       F_(HRX0,                IP2SR1_3_0)
+#define GPSR1_15       F_(HSCK0,               IP1SR1_31_28)
+#define GPSR1_14       F_(HRTS0_N,             IP1SR1_27_24)
+#define GPSR1_13       F_(HCTS0_N,             IP1SR1_23_20)
+#define GPSR1_12       F_(HTX0,                IP1SR1_19_16)
+#define GPSR1_11       F_(MSIOF0_RXD,          IP1SR1_15_12)
+#define GPSR1_10       F_(MSIOF0_SCK,          IP1SR1_11_8)
+#define GPSR1_9                F_(MSIOF0_TXD,          IP1SR1_7_4)
+#define GPSR1_8                F_(MSIOF0_SYNC,         IP1SR1_3_0)
+#define GPSR1_7                F_(MSIOF0_SS1,          IP0SR1_31_28)
+#define GPSR1_6                F_(MSIOF0_SS2,          IP0SR1_27_24)
+#define GPSR1_5                F_(MSIOF1_RXD,          IP0SR1_23_20)
+#define GPSR1_4                F_(MSIOF1_TXD,          IP0SR1_19_16)
+#define GPSR1_3                F_(MSIOF1_SCK,          IP0SR1_15_12)
+#define GPSR1_2                F_(MSIOF1_SYNC,         IP0SR1_11_8)
+#define GPSR1_1                F_(MSIOF1_SS1,          IP0SR1_7_4)
+#define GPSR1_0                F_(MSIOF1_SS2,          IP0SR1_3_0)
+
+/* GPSR2 */
+#define GPSR2_19       F_(CANFD7_RX,           IP2SR2_15_12)
+#define GPSR2_18       F_(CANFD7_TX,           IP2SR2_11_8)
+#define GPSR2_17       F_(CANFD4_RX,           IP2SR2_7_4)
+#define GPSR2_16       F_(CANFD4_TX,           IP2SR2_3_0)
+#define GPSR2_15       F_(CANFD3_RX,           IP1SR2_31_28)
+#define GPSR2_14       F_(CANFD3_TX,           IP1SR2_27_24)
+#define GPSR2_13       F_(CANFD2_RX,           IP1SR2_23_20)
+#define GPSR2_12       F_(CANFD2_TX,           IP1SR2_19_16)
+#define GPSR2_11       F_(CANFD0_RX,           IP1SR2_15_12)
+#define GPSR2_10       F_(CANFD0_TX,           IP1SR2_11_8)
+#define GPSR2_9                F_(CAN_CLK,             IP1SR2_7_4)
+#define GPSR2_8                F_(TPU0TO0,             IP1SR2_3_0)
+#define GPSR2_7                F_(TPU0TO1,             IP0SR2_31_28)
+#define GPSR2_6                F_(FXR_TXDB,            IP0SR2_27_24)
+#define GPSR2_5                F_(FXR_TXENB_N,         IP0SR2_23_20)
+#define GPSR2_4                F_(RXDB_EXTFXR,         IP0SR2_19_16)
+#define GPSR2_3                F_(CLK_EXTFXR,          IP0SR2_15_12)
+#define GPSR2_2                F_(RXDA_EXTFXR,         IP0SR2_11_8)
+#define GPSR2_1                F_(FXR_TXENA_N,         IP0SR2_7_4)
+#define GPSR2_0                F_(FXR_TXDA,            IP0SR2_3_0)
+
+/* GPSR3 */
+#define GPSR3_29       F_(RPC_INT_N,           IP3SR3_23_20)
+#define GPSR3_28       F_(RPC_WP_N,            IP3SR3_19_16)
+#define GPSR3_27       F_(RPC_RESET_N,         IP3SR3_15_12)
+#define GPSR3_26       F_(QSPI1_IO3,           IP3SR3_11_8)
+#define GPSR3_25       F_(QSPI1_SSL,           IP3SR3_7_4)
+#define GPSR3_24       F_(QSPI1_IO2,           IP3SR3_3_0)
+#define GPSR3_23       F_(QSPI1_MISO_IO1,      IP2SR3_31_28)
+#define GPSR3_22       F_(QSPI1_SPCLK,         IP2SR3_27_24)
+#define GPSR3_21       F_(QSPI1_MOSI_IO0,      IP2SR3_23_20)
+#define GPSR3_20       F_(QSPI0_SPCLK,         IP2SR3_19_16)
+#define GPSR3_19       F_(QSPI0_MOSI_IO0,      IP2SR3_15_12)
+#define GPSR3_18       F_(QSPI0_MISO_IO1,      IP2SR3_11_8)
+#define GPSR3_17       F_(QSPI0_IO2,           IP2SR3_7_4)
+#define GPSR3_16       F_(QSPI0_IO3,           IP2SR3_3_0)
+#define GPSR3_15       F_(QSPI0_SSL,           IP1SR3_31_28)
+#define GPSR3_14       F_(IPC_CLKOUT,          IP1SR3_27_24)
+#define GPSR3_13       F_(IPC_CLKIN,           IP1SR3_23_20)
+#define GPSR3_12       F_(SD_WP,               IP1SR3_19_16)
+#define GPSR3_11       F_(SD_CD,               IP1SR3_15_12)
+#define GPSR3_10       F_(MMC_SD_CMD,          IP1SR3_11_8)
+#define GPSR3_9                F_(MMC_D6,              IP1SR3_7_4)
+#define GPSR3_8                F_(MMC_D7,              IP1SR3_3_0)
+#define GPSR3_7                F_(MMC_D4,              IP0SR3_31_28)
+#define GPSR3_6                F_(MMC_D5,              IP0SR3_27_24)
+#define GPSR3_5                F_(MMC_SD_D3,           IP0SR3_23_20)
+#define GPSR3_4                F_(MMC_DS,              IP0SR3_19_16)
+#define GPSR3_3                F_(MMC_SD_CLK,          IP0SR3_15_12)
+#define GPSR3_2                F_(MMC_SD_D2,           IP0SR3_11_8)
+#define GPSR3_1                F_(MMC_SD_D0,           IP0SR3_7_4)
+#define GPSR3_0                F_(MMC_SD_D1,           IP0SR3_3_0)
+
+/* GPSR4 */
+#define GPSR4_24       FM(AVS1)
+#define GPSR4_23       FM(AVS0)
+#define GPSR4_22       FM(PCIE1_CLKREQ_N)
+#define GPSR4_21       FM(PCIE0_CLKREQ_N)
+#define GPSR4_20       FM(TSN0_TXCREFCLK)
+#define GPSR4_19       FM(TSN0_TD2)
+#define GPSR4_18       FM(TSN0_TD3)
+#define GPSR4_17       FM(TSN0_RD2)
+#define GPSR4_16       FM(TSN0_RD3)
+#define GPSR4_15       FM(TSN0_TD0)
+#define GPSR4_14       FM(TSN0_TD1)
+#define GPSR4_13       FM(TSN0_RD1)
+#define GPSR4_12       FM(TSN0_TXC)
+#define GPSR4_11       FM(TSN0_RXC)
+#define GPSR4_10       FM(TSN0_RD0)
+#define GPSR4_9                FM(TSN0_TX_CTL)
+#define GPSR4_8                FM(TSN0_AVTP_PPS0)
+#define GPSR4_7                FM(TSN0_RX_CTL)
+#define GPSR4_6                FM(TSN0_AVTP_CAPTURE)
+#define GPSR4_5                FM(TSN0_AVTP_MATCH)
+#define GPSR4_4                FM(TSN0_LINK)
+#define GPSR4_3                FM(TSN0_PHY_INT)
+#define GPSR4_2                FM(TSN0_AVTP_PPS1)
+#define GPSR4_1                FM(TSN0_MDC)
+#define GPSR4_0                FM(TSN0_MDIO)
+
+/* GPSR 5 */
+#define GPSR5_20       FM(AVB2_RX_CTL)
+#define GPSR5_19       FM(AVB2_TX_CTL)
+#define GPSR5_18       FM(AVB2_RXC)
+#define GPSR5_17       FM(AVB2_RD0)
+#define GPSR5_16       FM(AVB2_TXC)
+#define GPSR5_15       FM(AVB2_TD0)
+#define GPSR5_14       FM(AVB2_RD1)
+#define GPSR5_13       FM(AVB2_RD2)
+#define GPSR5_12       FM(AVB2_TD1)
+#define GPSR5_11       FM(AVB2_TD2)
+#define GPSR5_10       FM(AVB2_MDIO)
+#define GPSR5_9                FM(AVB2_RD3)
+#define GPSR5_8                FM(AVB2_TD3)
+#define GPSR5_7                FM(AVB2_TXCREFCLK)
+#define GPSR5_6                FM(AVB2_MDC)
+#define GPSR5_5                FM(AVB2_MAGIC)
+#define GPSR5_4                FM(AVB2_PHY_INT)
+#define GPSR5_3                FM(AVB2_LINK)
+#define GPSR5_2                FM(AVB2_AVTP_MATCH)
+#define GPSR5_1                FM(AVB2_AVTP_CAPTURE)
+#define GPSR5_0                FM(AVB2_AVTP_PPS)
+
+/* GPSR 6 */
+#define GPSR6_20       F_(AVB1_TXCREFCLK,              IP2SR6_19_16)
+#define GPSR6_19       F_(AVB1_RD3,                    IP2SR6_15_12)
+#define GPSR6_18       F_(AVB1_TD3,                    IP2SR6_11_8)
+#define GPSR6_17       F_(AVB1_RD2,                    IP2SR6_7_4)
+#define GPSR6_16       F_(AVB1_TD2,                    IP2SR6_3_0)
+#define GPSR6_15       F_(AVB1_RD0,                    IP1SR6_31_28)
+#define GPSR6_14       F_(AVB1_RD1,                    IP1SR6_27_24)
+#define GPSR6_13       F_(AVB1_TD0,                    IP1SR6_23_20)
+#define GPSR6_12       F_(AVB1_TD1,                    IP1SR6_19_16)
+#define GPSR6_11       F_(AVB1_AVTP_CAPTURE,           IP1SR6_15_12)
+#define GPSR6_10       F_(AVB1_AVTP_PPS,               IP1SR6_11_8)
+#define GPSR6_9                F_(AVB1_RX_CTL,                 IP1SR6_7_4)
+#define GPSR6_8                F_(AVB1_RXC,                    IP1SR6_3_0)
+#define GPSR6_7                F_(AVB1_TX_CTL,                 IP0SR6_31_28)
+#define GPSR6_6                F_(AVB1_TXC,                    IP0SR6_27_24)
+#define GPSR6_5                F_(AVB1_AVTP_MATCH,             IP0SR6_23_20)
+#define GPSR6_4                F_(AVB1_LINK,                   IP0SR6_19_16)
+#define GPSR6_3                F_(AVB1_PHY_INT,                IP0SR6_15_12)
+#define GPSR6_2                F_(AVB1_MDC,                    IP0SR6_11_8)
+#define GPSR6_1                F_(AVB1_MAGIC,                  IP0SR6_7_4)
+#define GPSR6_0                F_(AVB1_MDIO,                   IP0SR6_3_0)
+
+/* GPSR7 */
+#define GPSR7_20       F_(AVB0_RX_CTL,                 IP2SR7_19_16)
+#define GPSR7_19       F_(AVB0_RXC,                    IP2SR7_15_12)
+#define GPSR7_18       F_(AVB0_RD0,                    IP2SR7_11_8)
+#define GPSR7_17       F_(AVB0_RD1,                    IP2SR7_7_4)
+#define GPSR7_16       F_(AVB0_TX_CTL,                 IP2SR7_3_0)
+#define GPSR7_15       F_(AVB0_TXC,                    IP1SR7_31_28)
+#define GPSR7_14       F_(AVB0_MDIO,                   IP1SR7_27_24)
+#define GPSR7_13       F_(AVB0_MDC,                    IP1SR7_23_20)
+#define GPSR7_12       F_(AVB0_RD2,                    IP1SR7_19_16)
+#define GPSR7_11       F_(AVB0_TD0,                    IP1SR7_15_12)
+#define GPSR7_10       F_(AVB0_MAGIC,                  IP1SR7_11_8)
+#define GPSR7_9                F_(AVB0_TXCREFCLK,              IP1SR7_7_4)
+#define GPSR7_8                F_(AVB0_RD3,                    IP1SR7_3_0)
+#define GPSR7_7                F_(AVB0_TD1,                    IP0SR7_31_28)
+#define GPSR7_6                F_(AVB0_TD2,                    IP0SR7_27_24)
+#define GPSR7_5                F_(AVB0_PHY_INT,                IP0SR7_23_20)
+#define GPSR7_4                F_(AVB0_LINK,                   IP0SR7_19_16)
+#define GPSR7_3                F_(AVB0_TD3,                    IP0SR7_15_12)
+#define GPSR7_2                F_(AVB0_AVTP_MATCH,             IP0SR7_11_8)
+#define GPSR7_1                F_(AVB0_AVTP_CAPTURE,           IP0SR7_7_4)
+#define GPSR7_0                F_(AVB0_AVTP_PPS,               IP0SR7_3_0)
+
+/* GPSR8 */
+#define GPSR8_13       F_(GP8_13,                      IP1SR8_23_20)
+#define GPSR8_12       F_(GP8_12,                      IP1SR8_19_16)
+#define GPSR8_11       F_(SDA5,                        IP1SR8_15_12)
+#define GPSR8_10       F_(SCL5,                        IP1SR8_11_8)
+#define GPSR8_9                F_(SDA4,                        IP1SR8_7_4)
+#define GPSR8_8                F_(SCL4,                        IP1SR8_3_0)
+#define GPSR8_7                F_(SDA3,                        IP0SR8_31_28)
+#define GPSR8_6                F_(SCL3,                        IP0SR8_27_24)
+#define GPSR8_5                F_(SDA2,                        IP0SR8_23_20)
+#define GPSR8_4                F_(SCL2,                        IP0SR8_19_16)
+#define GPSR8_3                F_(SDA1,                        IP0SR8_15_12)
+#define GPSR8_2                F_(SCL1,                        IP0SR8_11_8)
+#define GPSR8_1                F_(SDA0,                        IP0SR8_7_4)
+#define GPSR8_0                F_(SCL0,                        IP0SR8_3_0)
+
+/* SR0 */
+/* IP0SR0 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP0SR0_3_0     F_(0, 0)                FM(ERROROUTC_B)         FM(TCLK2_A)     F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR0_7_4     F_(0, 0)                FM(MSIOF3_SS1)          F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR0_11_8    F_(0, 0)                FM(MSIOF3_SS2)          F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR0_15_12   FM(IRQ3)                FM(MSIOF3_SCK)          F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR0_19_16   FM(IRQ2)                FM(MSIOF3_TXD)          F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR0_23_20   FM(IRQ1)                FM(MSIOF3_RXD)          F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR0_27_24   FM(IRQ0)                FM(MSIOF3_SYNC)         F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR0_31_28   FM(MSIOF5_SS2)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR0 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP1SR0_3_0     FM(MSIOF5_SS1)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR0_7_4     FM(MSIOF5_SYNC)         F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR0_11_8    FM(MSIOF5_TXD)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR0_15_12   FM(MSIOF5_SCK)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR0_19_16   FM(MSIOF5_RXD)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR0_23_20   FM(MSIOF2_SS2)          FM(TCLK1)               FM(IRQ2_A)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR0_27_24   FM(MSIOF2_SS1)          FM(HTX1)                FM(TX1)         F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR0_31_28   FM(MSIOF2_SYNC)         FM(HRX1)                FM(RX1)         F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP2SR0 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP2SR0_3_0     FM(MSIOF2_TXD)          FM(HCTS1_N)             FM(CTS1_N)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR0_7_4     FM(MSIOF2_SCK)          FM(HRTS1_N)             FM(RTS1_N)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR0_11_8    FM(MSIOF2_RXD)          FM(HSCK1)               FM(SCK1)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR1 */
+/* IP0SR1 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP0SR1_3_0     FM(MSIOF1_SS2)          FM(HTX3_A)              FM(TX3)         F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR1_7_4     FM(MSIOF1_SS1)          FM(HCTS3_N_A)           FM(RX3)         F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR1_11_8    FM(MSIOF1_SYNC)         FM(HRTS3_N_A)           FM(RTS3_N)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR1_15_12   FM(MSIOF1_SCK)          FM(HSCK3_A)             FM(CTS3_N)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR1_19_16   FM(MSIOF1_TXD)          FM(HRX3_A)              FM(SCK3)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR1_23_20   FM(MSIOF1_RXD)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR1_27_24   FM(MSIOF0_SS2)          FM(HTX1_X)              FM(TX1_X)       F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR1_31_28   FM(MSIOF0_SS1)          FM(HRX1_X)              FM(RX1_X)       F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR1 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP1SR1_3_0     FM(MSIOF0_SYNC)         FM(HCTS1_N_X)           FM(CTS1_N_X)    FM(CANFD5_TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR1_7_4     FM(MSIOF0_TXD)          FM(HRTS1_N_X)           FM(RTS1_N_X)    FM(CANFD5_RX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR1_11_8    FM(MSIOF0_SCK)          FM(HSCK1_X)             FM(SCK1_X)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR1_15_12   FM(MSIOF0_RXD)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR1_19_16   FM(HTX0)                FM(TX0)                 F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR1_23_20   FM(HCTS0_N)             FM(CTS0_N)              FM(PWM8_A)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR1_27_24   FM(HRTS0_N)             FM(RTS0_N)              FM(PWM9_A)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR1_31_28   FM(HSCK0)               FM(SCK0)                FM(PWM0_A)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP2SR1 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP2SR1_3_0     FM(HRX0)                FM(RX0)                 F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR1_7_4     FM(SCIF_CLK)            FM(IRQ4_A)              F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR1_11_8    FM(SSI_SCK)             FM(TCLK3)               F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR1_15_12   FM(SSI_WS)              FM(TCLK4)               F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR1_19_16   FM(SSI_SD)              FM(IRQ0_A)              F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR1_23_20   FM(AUDIO_CLKOUT)        FM(IRQ1_A)              F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR1_27_24   FM(AUDIO_CLKIN)         FM(PWM3_A)              F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR1_31_28   F_(0, 0)                FM(TCLK2)               FM(MSIOF4_SS1)  FM(IRQ3_B)      F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP3SR1 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP3SR1_3_0     FM(HRX3)                FM(SCK3_A)              FM(MSIOF4_SS2)  F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR1_7_4     FM(HSCK3)               FM(CTS3_N_A)            FM(MSIOF4_SCK)  FM(TPU0TO0_A)   F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR1_11_8    FM(HRTS3_N)             FM(RTS3_N_A)            FM(MSIOF4_TXD)  FM(TPU0TO1_A)   F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR1_15_12   FM(HCTS3_N)             FM(RX3_A)               FM(MSIOF4_RXD)  F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR1_19_16   FM(HTX3)                FM(TX3_A)               FM(MSIOF4_SYNC) F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR2 */
+/* IP0SR2 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP0SR2_3_0     FM(FXR_TXDA)            FM(CANFD1_TX)           FM(TPU0TO2_A)   F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR2_7_4     FM(FXR_TXENA_N)         FM(CANFD1_RX)           FM(TPU0TO3_A)   F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR2_11_8    FM(RXDA_EXTFXR)         FM(CANFD5_TX)           FM(IRQ5)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR2_15_12   FM(CLK_EXTFXR)          FM(CANFD5_RX)           FM(IRQ4_B)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR2_19_16   FM(RXDB_EXTFXR)         F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR2_23_20   FM(FXR_TXENB_N)         F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR2_27_24   FM(FXR_TXDB)            F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR2_31_28   FM(TPU0TO1)             FM(CANFD6_TX)           F_(0, 0)        FM(TCLK2_B)     F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR2 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP1SR2_3_0     FM(TPU0TO0)             FM(CANFD6_RX)           F_(0, 0)        FM(TCLK1_A)     F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_7_4     FM(CAN_CLK)             FM(FXR_TXENA_N_X)       F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_11_8    FM(CANFD0_TX)           FM(FXR_TXENB_N_X)       F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_15_12   FM(CANFD0_RX)           FM(STPWT_EXTFXR)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_19_16   FM(CANFD2_TX)           FM(TPU0TO2)             F_(0, 0)        FM(TCLK3_A)     F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_23_20   FM(CANFD2_RX)           FM(TPU0TO3)             FM(PWM1_B)      FM(TCLK4_A)     F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_27_24   FM(CANFD3_TX)           F_(0, 0)                FM(PWM2_B)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_31_28   FM(CANFD3_RX)           F_(0, 0)                FM(PWM3_B)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP2SR2 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP2SR2_3_0     FM(CANFD4_TX)           F_(0, 0)                FM(PWM4)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR2_7_4     FM(CANFD4_RX)           F_(0, 0)                FM(PWM5)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR2_11_8    FM(CANFD7_TX)           F_(0, 0)                FM(PWM6)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR2_15_12   FM(CANFD7_RX)           F_(0, 0)                FM(PWM7)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR3 */
+/* IP0SR3 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP0SR3_3_0     FM(MMC_SD_D1)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR3_7_4     FM(MMC_SD_D0)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR3_11_8    FM(MMC_SD_D2)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR3_15_12   FM(MMC_SD_CLK)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR3_19_16   FM(MMC_DS)              F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR3_23_20   FM(MMC_SD_D3)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR3_27_24   FM(MMC_D5)              F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR3_31_28   FM(MMC_D4)              F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR3 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP1SR3_3_0     FM(MMC_D7)              F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR3_7_4     FM(MMC_D6)              F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR3_11_8    FM(MMC_SD_CMD)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR3_15_12   FM(SD_CD)               F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR3_19_16   FM(SD_WP)               F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR3_23_20   FM(IPC_CLKIN)           FM(IPC_CLKEN_IN)        FM(PWM1_A)      FM(TCLK3_X)     F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR3_27_24   FM(IPC_CLKOUT)          FM(IPC_CLKEN_OUT)       FM(ERROROUTC_A) FM(TCLK4_X)     F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR3_31_28   FM(QSPI0_SSL)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP2SR3 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP2SR3_3_0     FM(QSPI0_IO3)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR3_7_4     FM(QSPI0_IO2)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR3_11_8    FM(QSPI0_MISO_IO1)      F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR3_15_12   FM(QSPI0_MOSI_IO0)      F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR3_19_16   FM(QSPI0_SPCLK)         F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR3_23_20   FM(QSPI1_MOSI_IO0)      F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR3_27_24   FM(QSPI1_SPCLK)         F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR3_31_28   FM(QSPI1_MISO_IO1)      F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP3SR3 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP3SR3_3_0     FM(QSPI1_IO2)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR3_7_4     FM(QSPI1_SSL)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR3_11_8    FM(QSPI1_IO3)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR3_15_12   FM(RPC_RESET_N)         F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR3_19_16   FM(RPC_WP_N)            F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP3SR3_23_20   FM(RPC_INT_N)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR6 */
+/* IP0SR6 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP0SR6_3_0     FM(AVB1_MDIO)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_7_4     FM(AVB1_MAGIC)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_11_8    FM(AVB1_MDC)            F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_15_12   FM(AVB1_PHY_INT)        F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_19_16   FM(AVB1_LINK)           FM(AVB1_MII_TX_ER)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_23_20   FM(AVB1_AVTP_MATCH)     FM(AVB1_MII_RX_ER)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_27_24   FM(AVB1_TXC)            FM(AVB1_MII_TXC)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_31_28   FM(AVB1_TX_CTL)         FM(AVB1_MII_TX_EN)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR6 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP1SR6_3_0     FM(AVB1_RXC)            FM(AVB1_MII_RXC)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_7_4     FM(AVB1_RX_CTL)         FM(AVB1_MII_RX_DV)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_11_8    FM(AVB1_AVTP_PPS)       FM(AVB1_MII_COL)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_15_12   FM(AVB1_AVTP_CAPTURE)   FM(AVB1_MII_CRS)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_19_16   FM(AVB1_TD1)            FM(AVB1_MII_TD1)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_23_20   FM(AVB1_TD0)            FM(AVB1_MII_TD0)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_27_24   FM(AVB1_RD1)            FM(AVB1_MII_RD1)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_31_28   FM(AVB1_RD0)            FM(AVB1_MII_RD0)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP2SR6 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP2SR6_3_0     FM(AVB1_TD2)            FM(AVB1_MII_TD2)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR6_7_4     FM(AVB1_RD2)            FM(AVB1_MII_RD2)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR6_11_8    FM(AVB1_TD3)            FM(AVB1_MII_TD3)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR6_15_12   FM(AVB1_RD3)            FM(AVB1_MII_RD3)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR6_19_16   FM(AVB1_TXCREFCLK)      F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR7 */
+/* IP0SR7 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP0SR7_3_0     FM(AVB0_AVTP_PPS)       FM(AVB0_MII_COL)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_7_4     FM(AVB0_AVTP_CAPTURE)   FM(AVB0_MII_CRS)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_11_8    FM(AVB0_AVTP_MATCH)     FM(AVB0_MII_RX_ER)      FM(CC5_OSCOUT)  F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_15_12   FM(AVB0_TD3)            FM(AVB0_MII_TD3)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_19_16   FM(AVB0_LINK)           FM(AVB0_MII_TX_ER)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_23_20   FM(AVB0_PHY_INT)        F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_27_24   FM(AVB0_TD2)            FM(AVB0_MII_TD2)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_31_28   FM(AVB0_TD1)            FM(AVB0_MII_TD1)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR7 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP1SR7_3_0     FM(AVB0_RD3)            FM(AVB0_MII_RD3)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_7_4     FM(AVB0_TXCREFCLK)      F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_11_8    FM(AVB0_MAGIC)          F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_15_12   FM(AVB0_TD0)            FM(AVB0_MII_TD0)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_19_16   FM(AVB0_RD2)            FM(AVB0_MII_RD2)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_23_20   FM(AVB0_MDC)            F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_27_24   FM(AVB0_MDIO)           F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_31_28   FM(AVB0_TXC)            FM(AVB0_MII_TXC)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP2SR7 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP2SR7_3_0     FM(AVB0_TX_CTL)         FM(AVB0_MII_TX_EN)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_7_4     FM(AVB0_RD1)            FM(AVB0_MII_RD1)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_11_8    FM(AVB0_RD0)            FM(AVB0_MII_RD0)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_15_12   FM(AVB0_RXC)            FM(AVB0_MII_RXC)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_19_16   FM(AVB0_RX_CTL)         FM(AVB0_MII_RX_DV)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR8 */
+/* IP0SR8 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP0SR8_3_0     FM(SCL0)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR8_7_4     FM(SDA0)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR8_11_8    FM(SCL1)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR8_15_12   FM(SDA1)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR8_19_16   FM(SCL2)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR8_23_20   FM(SDA2)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR8_27_24   FM(SCL3)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR8_31_28   FM(SDA3)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR8 */           /* 0 */                 /* 1 */                 /* 2 */         /* 3            4        5        6        7        8        9        A        B        C        D        E        F */
+#define IP1SR8_3_0     FM(SCL4)                FM(HRX2)                FM(SCK4)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR8_7_4     FM(SDA4)                FM(HTX2)                FM(CTS4_N)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR8_11_8    FM(SCL5)                FM(HRTS2_N)             FM(RTS4_N)      F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR8_15_12   FM(SDA5)                FM(SCIF_CLK2)           F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR8_19_16   F_(0, 0)                FM(HCTS2_N)             FM(TX4)         F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR8_23_20   F_(0, 0)                FM(HSCK2)               FM(RX4)         F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+#define PINMUX_GPSR    \
+                                               GPSR3_29                                                                                        \
+               GPSR1_28                        GPSR3_28                                                                                        \
+               GPSR1_27                        GPSR3_27                                                                                        \
+               GPSR1_26                        GPSR3_26                                                                                        \
+               GPSR1_25                        GPSR3_25                                                                                        \
+               GPSR1_24                        GPSR3_24        GPSR4_24                                                                        \
+               GPSR1_23                        GPSR3_23        GPSR4_23                                                                        \
+               GPSR1_22                        GPSR3_22        GPSR4_22                                                                        \
+               GPSR1_21                        GPSR3_21        GPSR4_21                                                                        \
+               GPSR1_20                        GPSR3_20        GPSR4_20        GPSR5_20        GPSR6_20        GPSR7_20                        \
+               GPSR1_19        GPSR2_19        GPSR3_19        GPSR4_19        GPSR5_19        GPSR6_19        GPSR7_19                        \
+GPSR0_18       GPSR1_18        GPSR2_18        GPSR3_18        GPSR4_18        GPSR5_18        GPSR6_18        GPSR7_18                        \
+GPSR0_17       GPSR1_17        GPSR2_17        GPSR3_17        GPSR4_17        GPSR5_17        GPSR6_17        GPSR7_17                        \
+GPSR0_16       GPSR1_16        GPSR2_16        GPSR3_16        GPSR4_16        GPSR5_16        GPSR6_16        GPSR7_16                        \
+GPSR0_15       GPSR1_15        GPSR2_15        GPSR3_15        GPSR4_15        GPSR5_15        GPSR6_15        GPSR7_15                        \
+GPSR0_14       GPSR1_14        GPSR2_14        GPSR3_14        GPSR4_14        GPSR5_14        GPSR6_14        GPSR7_14                        \
+GPSR0_13       GPSR1_13        GPSR2_13        GPSR3_13        GPSR4_13        GPSR5_13        GPSR6_13        GPSR7_13        GPSR8_13        \
+GPSR0_12       GPSR1_12        GPSR2_12        GPSR3_12        GPSR4_12        GPSR5_12        GPSR6_12        GPSR7_12        GPSR8_12        \
+GPSR0_11       GPSR1_11        GPSR2_11        GPSR3_11        GPSR4_11        GPSR5_11        GPSR6_11        GPSR7_11        GPSR8_11        \
+GPSR0_10       GPSR1_10        GPSR2_10        GPSR3_10        GPSR4_10        GPSR5_10        GPSR6_10        GPSR7_10        GPSR8_10        \
+GPSR0_9                GPSR1_9         GPSR2_9         GPSR3_9         GPSR4_9         GPSR5_9         GPSR6_9         GPSR7_9         GPSR8_9         \
+GPSR0_8                GPSR1_8         GPSR2_8         GPSR3_8         GPSR4_8         GPSR5_8         GPSR6_8         GPSR7_8         GPSR8_8         \
+GPSR0_7                GPSR1_7         GPSR2_7         GPSR3_7         GPSR4_7         GPSR5_7         GPSR6_7         GPSR7_7         GPSR8_7         \
+GPSR0_6                GPSR1_6         GPSR2_6         GPSR3_6         GPSR4_6         GPSR5_6         GPSR6_6         GPSR7_6         GPSR8_6         \
+GPSR0_5                GPSR1_5         GPSR2_5         GPSR3_5         GPSR4_5         GPSR5_5         GPSR6_5         GPSR7_5         GPSR8_5         \
+GPSR0_4                GPSR1_4         GPSR2_4         GPSR3_4         GPSR4_4         GPSR5_4         GPSR6_4         GPSR7_4         GPSR8_4         \
+GPSR0_3                GPSR1_3         GPSR2_3         GPSR3_3         GPSR4_3         GPSR5_3         GPSR6_3         GPSR7_3         GPSR8_3         \
+GPSR0_2                GPSR1_2         GPSR2_2         GPSR3_2         GPSR4_2         GPSR5_2         GPSR6_2         GPSR7_2         GPSR8_2         \
+GPSR0_1                GPSR1_1         GPSR2_1         GPSR3_1         GPSR4_1         GPSR5_1         GPSR6_1         GPSR7_1         GPSR8_1         \
+GPSR0_0                GPSR1_0         GPSR2_0         GPSR3_0         GPSR4_0         GPSR5_0         GPSR6_0         GPSR7_0         GPSR8_0
+
+#define PINMUX_IPSR    \
+\
+FM(IP0SR0_3_0)         IP0SR0_3_0      FM(IP1SR0_3_0)          IP1SR0_3_0      FM(IP2SR0_3_0)          IP2SR0_3_0      \
+FM(IP0SR0_7_4)         IP0SR0_7_4      FM(IP1SR0_7_4)          IP1SR0_7_4      FM(IP2SR0_7_4)          IP2SR0_7_4      \
+FM(IP0SR0_11_8)                IP0SR0_11_8     FM(IP1SR0_11_8)         IP1SR0_11_8     FM(IP2SR0_11_8)         IP2SR0_11_8     \
+FM(IP0SR0_15_12)       IP0SR0_15_12    FM(IP1SR0_15_12)        IP1SR0_15_12    \
+FM(IP0SR0_19_16)       IP0SR0_19_16    FM(IP1SR0_19_16)        IP1SR0_19_16    \
+FM(IP0SR0_23_20)       IP0SR0_23_20    FM(IP1SR0_23_20)        IP1SR0_23_20    \
+FM(IP0SR0_27_24)       IP0SR0_27_24    FM(IP1SR0_27_24)        IP1SR0_27_24    \
+FM(IP0SR0_31_28)       IP0SR0_31_28    FM(IP1SR0_31_28)        IP1SR0_31_28    \
+\
+FM(IP0SR1_3_0)         IP0SR1_3_0      FM(IP1SR1_3_0)          IP1SR1_3_0      FM(IP2SR1_3_0)          IP2SR1_3_0      FM(IP3SR1_3_0)          IP3SR1_3_0      \
+FM(IP0SR1_7_4)         IP0SR1_7_4      FM(IP1SR1_7_4)          IP1SR1_7_4      FM(IP2SR1_7_4)          IP2SR1_7_4      FM(IP3SR1_7_4)          IP3SR1_7_4      \
+FM(IP0SR1_11_8)                IP0SR1_11_8     FM(IP1SR1_11_8)         IP1SR1_11_8     FM(IP2SR1_11_8)         IP2SR1_11_8     FM(IP3SR1_11_8)         IP3SR1_11_8     \
+FM(IP0SR1_15_12)       IP0SR1_15_12    FM(IP1SR1_15_12)        IP1SR1_15_12    FM(IP2SR1_15_12)        IP2SR1_15_12    FM(IP3SR1_15_12)        IP3SR1_15_12    \
+FM(IP0SR1_19_16)       IP0SR1_19_16    FM(IP1SR1_19_16)        IP1SR1_19_16    FM(IP2SR1_19_16)        IP2SR1_19_16    FM(IP3SR1_19_16)        IP3SR1_19_16    \
+FM(IP0SR1_23_20)       IP0SR1_23_20    FM(IP1SR1_23_20)        IP1SR1_23_20    FM(IP2SR1_23_20)        IP2SR1_23_20    \
+FM(IP0SR1_27_24)       IP0SR1_27_24    FM(IP1SR1_27_24)        IP1SR1_27_24    FM(IP2SR1_27_24)        IP2SR1_27_24    \
+FM(IP0SR1_31_28)       IP0SR1_31_28    FM(IP1SR1_31_28)        IP1SR1_31_28    FM(IP2SR1_31_28)        IP2SR1_31_28    \
+\
+FM(IP0SR2_3_0)         IP0SR2_3_0      FM(IP1SR2_3_0)          IP1SR2_3_0      FM(IP2SR2_3_0)          IP2SR2_3_0      \
+FM(IP0SR2_7_4)         IP0SR2_7_4      FM(IP1SR2_7_4)          IP1SR2_7_4      FM(IP2SR2_7_4)          IP2SR2_7_4      \
+FM(IP0SR2_11_8)                IP0SR2_11_8     FM(IP1SR2_11_8)         IP1SR2_11_8     FM(IP2SR2_11_8)         IP2SR2_11_8     \
+FM(IP0SR2_15_12)       IP0SR2_15_12    FM(IP1SR2_15_12)        IP1SR2_15_12    FM(IP2SR2_15_12)        IP2SR2_15_12    \
+FM(IP0SR2_19_16)       IP0SR2_19_16    FM(IP1SR2_19_16)        IP1SR2_19_16    \
+FM(IP0SR2_23_20)       IP0SR2_23_20    FM(IP1SR2_23_20)        IP1SR2_23_20    \
+FM(IP0SR2_27_24)       IP0SR2_27_24    FM(IP1SR2_27_24)        IP1SR2_27_24    \
+FM(IP0SR2_31_28)       IP0SR2_31_28    FM(IP1SR2_31_28)        IP1SR2_31_28    \
+\
+FM(IP0SR3_3_0)         IP0SR3_3_0      FM(IP1SR3_3_0)          IP1SR3_3_0      FM(IP2SR3_3_0)          IP2SR3_3_0      FM(IP3SR3_3_0)          IP3SR3_3_0      \
+FM(IP0SR3_7_4)         IP0SR3_7_4      FM(IP1SR3_7_4)          IP1SR3_7_4      FM(IP2SR3_7_4)          IP2SR3_7_4      FM(IP3SR3_7_4)          IP3SR3_7_4      \
+FM(IP0SR3_11_8)                IP0SR3_11_8     FM(IP1SR3_11_8)         IP1SR3_11_8     FM(IP2SR3_11_8)         IP2SR3_11_8     FM(IP3SR3_11_8)         IP3SR3_11_8     \
+FM(IP0SR3_15_12)       IP0SR3_15_12    FM(IP1SR3_15_12)        IP1SR3_15_12    FM(IP2SR3_15_12)        IP2SR3_15_12    FM(IP3SR3_15_12)        IP3SR3_15_12    \
+FM(IP0SR3_19_16)       IP0SR3_19_16    FM(IP1SR3_19_16)        IP1SR3_19_16    FM(IP2SR3_19_16)        IP2SR3_19_16    FM(IP3SR3_19_16)        IP3SR3_19_16    \
+FM(IP0SR3_23_20)       IP0SR3_23_20    FM(IP1SR3_23_20)        IP1SR3_23_20    FM(IP2SR3_23_20)        IP2SR3_23_20    FM(IP3SR3_23_20)        IP3SR3_23_20    \
+FM(IP0SR3_27_24)       IP0SR3_27_24    FM(IP1SR3_27_24)        IP1SR3_27_24    FM(IP2SR3_27_24)        IP2SR3_27_24                                            \
+FM(IP0SR3_31_28)       IP0SR3_31_28    FM(IP1SR3_31_28)        IP1SR3_31_28    FM(IP2SR3_31_28)        IP2SR3_31_28                                            \
+\
+FM(IP0SR6_3_0)         IP0SR6_3_0      FM(IP1SR6_3_0)          IP1SR6_3_0      FM(IP2SR6_3_0)          IP2SR6_3_0      \
+FM(IP0SR6_7_4)         IP0SR6_7_4      FM(IP1SR6_7_4)          IP1SR6_7_4      FM(IP2SR6_7_4)          IP2SR6_7_4      \
+FM(IP0SR6_11_8)                IP0SR6_11_8     FM(IP1SR6_11_8)         IP1SR6_11_8     FM(IP2SR6_11_8)         IP2SR6_11_8     \
+FM(IP0SR6_15_12)       IP0SR6_15_12    FM(IP1SR6_15_12)        IP1SR6_15_12    FM(IP2SR6_15_12)        IP2SR6_15_12    \
+FM(IP0SR6_19_16)       IP0SR6_19_16    FM(IP1SR6_19_16)        IP1SR6_19_16    FM(IP2SR6_19_16)        IP2SR6_19_16    \
+FM(IP0SR6_23_20)       IP0SR6_23_20    FM(IP1SR6_23_20)        IP1SR6_23_20    \
+FM(IP0SR6_27_24)       IP0SR6_27_24    FM(IP1SR6_27_24)        IP1SR6_27_24    \
+FM(IP0SR6_31_28)       IP0SR6_31_28    FM(IP1SR6_31_28)        IP1SR6_31_28    \
+\
+FM(IP0SR7_3_0)         IP0SR7_3_0      FM(IP1SR7_3_0)          IP1SR7_3_0      FM(IP2SR7_3_0)          IP2SR7_3_0      \
+FM(IP0SR7_7_4)         IP0SR7_7_4      FM(IP1SR7_7_4)          IP1SR7_7_4      FM(IP2SR7_7_4)          IP2SR7_7_4      \
+FM(IP0SR7_11_8)                IP0SR7_11_8     FM(IP1SR7_11_8)         IP1SR7_11_8     FM(IP2SR7_11_8)         IP2SR7_11_8     \
+FM(IP0SR7_15_12)       IP0SR7_15_12    FM(IP1SR7_15_12)        IP1SR7_15_12    FM(IP2SR7_15_12)        IP2SR7_15_12    \
+FM(IP0SR7_19_16)       IP0SR7_19_16    FM(IP1SR7_19_16)        IP1SR7_19_16    FM(IP2SR7_19_16)        IP2SR7_19_16    \
+FM(IP0SR7_23_20)       IP0SR7_23_20    FM(IP1SR7_23_20)        IP1SR7_23_20    \
+FM(IP0SR7_27_24)       IP0SR7_27_24    FM(IP1SR7_27_24)        IP1SR7_27_24    \
+FM(IP0SR7_31_28)       IP0SR7_31_28    FM(IP1SR7_31_28)        IP1SR7_31_28    \
+\
+FM(IP0SR8_3_0)         IP0SR8_3_0      FM(IP1SR8_3_0)          IP1SR8_3_0      \
+FM(IP0SR8_7_4)         IP0SR8_7_4      FM(IP1SR8_7_4)          IP1SR8_7_4      \
+FM(IP0SR8_11_8)                IP0SR8_11_8     FM(IP1SR8_11_8)         IP1SR8_11_8     \
+FM(IP0SR8_15_12)       IP0SR8_15_12    FM(IP1SR8_15_12)        IP1SR8_15_12    \
+FM(IP0SR8_19_16)       IP0SR8_19_16    FM(IP1SR8_19_16)        IP1SR8_19_16    \
+FM(IP0SR8_23_20)       IP0SR8_23_20    FM(IP1SR8_23_20)        IP1SR8_23_20    \
+FM(IP0SR8_27_24)       IP0SR8_27_24    \
+FM(IP0SR8_31_28)       IP0SR8_31_28
+
+/* MOD_SEL4 */                 /* 0 */                         /* 1 */
+#define MOD_SEL4_19            FM(SEL_TSN0_TD2_0)              FM(SEL_TSN0_TD2_1)
+#define MOD_SEL4_18            FM(SEL_TSN0_TD3_0)              FM(SEL_TSN0_TD3_1)
+#define MOD_SEL4_15            FM(SEL_TSN0_TD0_0)              FM(SEL_TSN0_TD0_1)
+#define MOD_SEL4_14            FM(SEL_TSN0_TD1_0)              FM(SEL_TSN0_TD1_1)
+#define MOD_SEL4_12            FM(SEL_TSN0_TXC_0)              FM(SEL_TSN0_TXC_1)
+#define MOD_SEL4_9             FM(SEL_TSN0_TX_CTL_0)           FM(SEL_TSN0_TX_CTL_1)
+#define MOD_SEL4_8             FM(SEL_TSN0_AVTP_PPS0_0)        FM(SEL_TSN0_AVTP_PPS0_1)
+#define MOD_SEL4_5             FM(SEL_TSN0_AVTP_MATCH_0)       FM(SEL_TSN0_AVTP_MATCH_1)
+#define MOD_SEL4_2             FM(SEL_TSN0_AVTP_PPS1_0)        FM(SEL_TSN0_AVTP_PPS1_1)
+#define MOD_SEL4_1             FM(SEL_TSN0_MDC_0)              FM(SEL_TSN0_MDC_1)
+
+/* MOD_SEL5 */                 /* 0 */                         /* 1 */
+#define MOD_SEL5_19            FM(SEL_AVB2_TX_CTL_0)           FM(SEL_AVB2_TX_CTL_1)
+#define MOD_SEL5_16            FM(SEL_AVB2_TXC_0)              FM(SEL_AVB2_TXC_1)
+#define MOD_SEL5_15            FM(SEL_AVB2_TD0_0)              FM(SEL_AVB2_TD0_1)
+#define MOD_SEL5_12            FM(SEL_AVB2_TD1_0)              FM(SEL_AVB2_TD1_1)
+#define MOD_SEL5_11            FM(SEL_AVB2_TD2_0)              FM(SEL_AVB2_TD2_1)
+#define MOD_SEL5_8             FM(SEL_AVB2_TD3_0)              FM(SEL_AVB2_TD3_1)
+#define MOD_SEL5_6             FM(SEL_AVB2_MDC_0)              FM(SEL_AVB2_MDC_1)
+#define MOD_SEL5_5             FM(SEL_AVB2_MAGIC_0)            FM(SEL_AVB2_MAGIC_1)
+#define MOD_SEL5_2             FM(SEL_AVB2_AVTP_MATCH_0)       FM(SEL_AVB2_AVTP_MATCH_1)
+#define MOD_SEL5_0             FM(SEL_AVB2_AVTP_PPS_0)         FM(SEL_AVB2_AVTP_PPS_1)
+
+/* MOD_SEL6 */                 /* 0 */                         /* 1 */
+#define MOD_SEL6_18            FM(SEL_AVB1_TD3_0)              FM(SEL_AVB1_TD3_1)
+#define MOD_SEL6_16            FM(SEL_AVB1_TD2_0)              FM(SEL_AVB1_TD2_1)
+#define MOD_SEL6_13            FM(SEL_AVB1_TD0_0)              FM(SEL_AVB1_TD0_1)
+#define MOD_SEL6_12            FM(SEL_AVB1_TD1_0)              FM(SEL_AVB1_TD1_1)
+#define MOD_SEL6_10            FM(SEL_AVB1_AVTP_PPS_0)         FM(SEL_AVB1_AVTP_PPS_1)
+#define MOD_SEL6_7             FM(SEL_AVB1_TX_CTL_0)           FM(SEL_AVB1_TX_CTL_1)
+#define MOD_SEL6_6             FM(SEL_AVB1_TXC_0)              FM(SEL_AVB1_TXC_1)
+#define MOD_SEL6_5             FM(SEL_AVB1_AVTP_MATCH_0)       FM(SEL_AVB1_AVTP_MATCH_1)
+#define MOD_SEL6_2             FM(SEL_AVB1_MDC_0)              FM(SEL_AVB1_MDC_1)
+#define MOD_SEL6_1             FM(SEL_AVB1_MAGIC_0)            FM(SEL_AVB1_MAGIC_1)
+
+/* MOD_SEL7 */                 /* 0 */                         /* 1 */
+#define MOD_SEL7_16            FM(SEL_AVB0_TX_CTL_0)           FM(SEL_AVB0_TX_CTL_1)
+#define MOD_SEL7_15            FM(SEL_AVB0_TXC_0)              FM(SEL_AVB0_TXC_1)
+#define MOD_SEL7_13            FM(SEL_AVB0_MDC_0)              FM(SEL_AVB0_MDC_1)
+#define MOD_SEL7_11            FM(SEL_AVB0_TD0_0)              FM(SEL_AVB0_TD0_1)
+#define MOD_SEL7_10            FM(SEL_AVB0_MAGIC_0)            FM(SEL_AVB0_MAGIC_1)
+#define MOD_SEL7_7             FM(SEL_AVB0_TD1_0)              FM(SEL_AVB0_TD1_1)
+#define MOD_SEL7_6             FM(SEL_AVB0_TD2_0)              FM(SEL_AVB0_TD2_1)
+#define MOD_SEL7_3             FM(SEL_AVB0_TD3_0)              FM(SEL_AVB0_TD3_1)
+#define MOD_SEL7_2             FM(SEL_AVB0_AVTP_MATCH_0)       FM(SEL_AVB0_AVTP_MATCH_1)
+#define MOD_SEL7_0             FM(SEL_AVB0_AVTP_PPS_0)         FM(SEL_AVB0_AVTP_PPS_1)
+
+/* MOD_SEL8 */                 /* 0 */                         /* 1 */
+#define MOD_SEL8_11            FM(SEL_SDA5_0)                  FM(SEL_SDA5_1)
+#define MOD_SEL8_10            FM(SEL_SCL5_0)                  FM(SEL_SCL5_1)
+#define MOD_SEL8_9             FM(SEL_SDA4_0)                  FM(SEL_SDA4_1)
+#define MOD_SEL8_8             FM(SEL_SCL4_0)                  FM(SEL_SCL4_1)
+#define MOD_SEL8_7             FM(SEL_SDA3_0)                  FM(SEL_SDA3_1)
+#define MOD_SEL8_6             FM(SEL_SCL3_0)                  FM(SEL_SCL3_1)
+#define MOD_SEL8_5             FM(SEL_SDA2_0)                  FM(SEL_SDA2_1)
+#define MOD_SEL8_4             FM(SEL_SCL2_0)                  FM(SEL_SCL2_1)
+#define MOD_SEL8_3             FM(SEL_SDA1_0)                  FM(SEL_SDA1_1)
+#define MOD_SEL8_2             FM(SEL_SCL1_0)                  FM(SEL_SCL1_1)
+#define MOD_SEL8_1             FM(SEL_SDA0_0)                  FM(SEL_SDA0_1)
+#define MOD_SEL8_0             FM(SEL_SCL0_0)                  FM(SEL_SCL0_1)
+
+#define PINMUX_MOD_SELS \
+\
+MOD_SEL4_19            MOD_SEL5_19                                                                             \
+MOD_SEL4_18                                    MOD_SEL6_18                                                     \
+                                                                                                               \
+                       MOD_SEL5_16             MOD_SEL6_16             MOD_SEL7_16                             \
+MOD_SEL4_15            MOD_SEL5_15                                     MOD_SEL7_15                             \
+MOD_SEL4_14                                                                                                    \
+                                               MOD_SEL6_13             MOD_SEL7_13                             \
+MOD_SEL4_12            MOD_SEL5_12             MOD_SEL6_12                                                     \
+                       MOD_SEL5_11                                     MOD_SEL7_11             MOD_SEL8_11     \
+                                               MOD_SEL6_10             MOD_SEL7_10             MOD_SEL8_10     \
+MOD_SEL4_9                                                                                     MOD_SEL8_9      \
+MOD_SEL4_8             MOD_SEL5_8                                                              MOD_SEL8_8      \
+                                               MOD_SEL6_7              MOD_SEL7_7              MOD_SEL8_7      \
+                       MOD_SEL5_6              MOD_SEL6_6              MOD_SEL7_6              MOD_SEL8_6      \
+MOD_SEL4_5             MOD_SEL5_5              MOD_SEL6_5                                      MOD_SEL8_5      \
+                                                                                               MOD_SEL8_4      \
+                                                                       MOD_SEL7_3              MOD_SEL8_3      \
+MOD_SEL4_2             MOD_SEL5_2              MOD_SEL6_2              MOD_SEL7_2              MOD_SEL8_2      \
+MOD_SEL4_1                                     MOD_SEL6_1                                      MOD_SEL8_1      \
+                       MOD_SEL5_0                                      MOD_SEL7_0              MOD_SEL8_0
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       PINMUX_DATA_BEGIN,
+       GP_ALL(DATA),
+       PINMUX_DATA_END,
+
+#define F_(x, y)
+#define FM(x)   FN_##x,
+       PINMUX_FUNCTION_BEGIN,
+       GP_ALL(FN),
+       PINMUX_GPSR
+       PINMUX_IPSR
+       PINMUX_MOD_SELS
+       PINMUX_FUNCTION_END,
+#undef F_
+#undef FM
+
+#define F_(x, y)
+#define FM(x)  x##_MARK,
+       PINMUX_MARK_BEGIN,
+       PINMUX_GPSR
+       PINMUX_IPSR
+       PINMUX_MOD_SELS
+       PINMUX_MARK_END,
+#undef F_
+#undef FM
+};
+
+static const u16 pinmux_data[] = {
+       PINMUX_DATA_GP_ALL(),
+
+       PINMUX_SINGLE(AVS1),
+       PINMUX_SINGLE(AVS0),
+       PINMUX_SINGLE(PCIE1_CLKREQ_N),
+       PINMUX_SINGLE(PCIE0_CLKREQ_N),
+
+       /* TSN0 without MODSEL4 */
+       PINMUX_SINGLE(TSN0_TXCREFCLK),
+       PINMUX_SINGLE(TSN0_RD2),
+       PINMUX_SINGLE(TSN0_RD3),
+       PINMUX_SINGLE(TSN0_RD1),
+       PINMUX_SINGLE(TSN0_RXC),
+       PINMUX_SINGLE(TSN0_RD0),
+       PINMUX_SINGLE(TSN0_RX_CTL),
+       PINMUX_SINGLE(TSN0_AVTP_CAPTURE),
+       PINMUX_SINGLE(TSN0_LINK),
+       PINMUX_SINGLE(TSN0_PHY_INT),
+       PINMUX_SINGLE(TSN0_MDIO),
+       /* TSN0 with MODSEL4 */
+       PINMUX_IPSR_NOGM(0, TSN0_TD2,           SEL_TSN0_TD2_1),
+       PINMUX_IPSR_NOGM(0, TSN0_TD3,           SEL_TSN0_TD3_1),
+       PINMUX_IPSR_NOGM(0, TSN0_TD0,           SEL_TSN0_TD0_1),
+       PINMUX_IPSR_NOGM(0, TSN0_TD1,           SEL_TSN0_TD1_1),
+       PINMUX_IPSR_NOGM(0, TSN0_TXC,           SEL_TSN0_TXC_1),
+       PINMUX_IPSR_NOGM(0, TSN0_TX_CTL,        SEL_TSN0_TX_CTL_1),
+       PINMUX_IPSR_NOGM(0, TSN0_AVTP_PPS0,     SEL_TSN0_AVTP_PPS0_1),
+       PINMUX_IPSR_NOGM(0, TSN0_AVTP_MATCH,    SEL_TSN0_AVTP_MATCH_1),
+       PINMUX_IPSR_NOGM(0, TSN0_AVTP_PPS1,     SEL_TSN0_AVTP_PPS1_1),
+       PINMUX_IPSR_NOGM(0, TSN0_MDC,           SEL_TSN0_MDC_1),
+
+       /* TSN0 without MODSEL5 */
+       PINMUX_SINGLE(AVB2_RX_CTL),
+       PINMUX_SINGLE(AVB2_RXC),
+       PINMUX_SINGLE(AVB2_RD0),
+       PINMUX_SINGLE(AVB2_RD1),
+       PINMUX_SINGLE(AVB2_RD2),
+       PINMUX_SINGLE(AVB2_MDIO),
+       PINMUX_SINGLE(AVB2_RD3),
+       PINMUX_SINGLE(AVB2_TXCREFCLK),
+       PINMUX_SINGLE(AVB2_PHY_INT),
+       PINMUX_SINGLE(AVB2_LINK),
+       PINMUX_SINGLE(AVB2_AVTP_CAPTURE),
+       /* TSN0 with MODSEL5 */
+       PINMUX_IPSR_NOGM(0, AVB2_TX_CTL,        SEL_AVB2_TX_CTL_1),
+       PINMUX_IPSR_NOGM(0, AVB2_TXC,           SEL_AVB2_TXC_1),
+       PINMUX_IPSR_NOGM(0, AVB2_TD0,           SEL_AVB2_TD0_1),
+       PINMUX_IPSR_NOGM(0, AVB2_TD1,           SEL_AVB2_TD1_1),
+       PINMUX_IPSR_NOGM(0, AVB2_TD2,           SEL_AVB2_TD2_1),
+       PINMUX_IPSR_NOGM(0, AVB2_TD3,           SEL_AVB2_TD3_1),
+       PINMUX_IPSR_NOGM(0, AVB2_MDC,           SEL_AVB2_MDC_1),
+       PINMUX_IPSR_NOGM(0, AVB2_MAGIC,         SEL_AVB2_MAGIC_1),
+       PINMUX_IPSR_NOGM(0, AVB2_AVTP_MATCH,    SEL_AVB2_AVTP_MATCH_1),
+       PINMUX_IPSR_NOGM(0, AVB2_AVTP_PPS,      SEL_AVB2_AVTP_PPS_1),
+
+       /* IP0SR0 */
+       PINMUX_IPSR_GPSR(IP0SR0_3_0,    ERROROUTC_B),
+       PINMUX_IPSR_GPSR(IP0SR0_3_0,    TCLK2_A),
+
+       PINMUX_IPSR_GPSR(IP0SR0_7_4,    MSIOF3_SS1),
+
+       PINMUX_IPSR_GPSR(IP0SR0_11_8,   MSIOF3_SS2),
+
+       PINMUX_IPSR_GPSR(IP0SR0_15_12,  IRQ3),
+       PINMUX_IPSR_GPSR(IP0SR0_15_12,  MSIOF3_SCK),
+
+       PINMUX_IPSR_GPSR(IP0SR0_19_16,  IRQ2),
+       PINMUX_IPSR_GPSR(IP0SR0_19_16,  MSIOF3_TXD),
+
+       PINMUX_IPSR_GPSR(IP0SR0_23_20,  IRQ1),
+       PINMUX_IPSR_GPSR(IP0SR0_23_20,  MSIOF3_RXD),
+
+       PINMUX_IPSR_GPSR(IP0SR0_27_24,  IRQ0),
+       PINMUX_IPSR_GPSR(IP0SR0_27_24,  MSIOF3_SYNC),
+
+       PINMUX_IPSR_GPSR(IP0SR0_31_28,  MSIOF5_SS2),
+
+       /* IP1SR0 */
+       PINMUX_IPSR_GPSR(IP1SR0_3_0,    MSIOF5_SS1),
+
+       PINMUX_IPSR_GPSR(IP1SR0_7_4,    MSIOF5_SYNC),
+
+       PINMUX_IPSR_GPSR(IP1SR0_11_8,   MSIOF5_TXD),
+
+       PINMUX_IPSR_GPSR(IP1SR0_15_12,  MSIOF5_SCK),
+
+       PINMUX_IPSR_GPSR(IP1SR0_19_16,  MSIOF5_RXD),
+
+       PINMUX_IPSR_GPSR(IP1SR0_23_20,  MSIOF2_SS2),
+       PINMUX_IPSR_GPSR(IP1SR0_23_20,  TCLK1),
+       PINMUX_IPSR_GPSR(IP1SR0_23_20,  IRQ2_A),
+
+       PINMUX_IPSR_GPSR(IP1SR0_27_24,  MSIOF2_SS1),
+       PINMUX_IPSR_GPSR(IP1SR0_27_24,  HTX1),
+       PINMUX_IPSR_GPSR(IP1SR0_27_24,  TX1),
+
+       PINMUX_IPSR_GPSR(IP1SR0_31_28,  MSIOF2_SYNC),
+       PINMUX_IPSR_GPSR(IP1SR0_31_28,  HRX1),
+       PINMUX_IPSR_GPSR(IP1SR0_31_28,  RX1),
+
+       /* IP2SR0 */
+       PINMUX_IPSR_GPSR(IP2SR0_3_0,    MSIOF2_TXD),
+       PINMUX_IPSR_GPSR(IP2SR0_3_0,    HCTS1_N),
+       PINMUX_IPSR_GPSR(IP2SR0_3_0,    CTS1_N),
+
+       PINMUX_IPSR_GPSR(IP2SR0_7_4,    MSIOF2_SCK),
+       PINMUX_IPSR_GPSR(IP2SR0_7_4,    HRTS1_N),
+       PINMUX_IPSR_GPSR(IP2SR0_7_4,    RTS1_N),
+
+       PINMUX_IPSR_GPSR(IP2SR0_11_8,   MSIOF2_RXD),
+       PINMUX_IPSR_GPSR(IP2SR0_11_8,   HSCK1),
+       PINMUX_IPSR_GPSR(IP2SR0_11_8,   SCK1),
+
+       /* IP0SR1 */
+       PINMUX_IPSR_GPSR(IP0SR1_3_0,    MSIOF1_SS2),
+       PINMUX_IPSR_GPSR(IP0SR1_3_0,    HTX3_A),
+       PINMUX_IPSR_GPSR(IP0SR1_3_0,    TX3),
+
+       PINMUX_IPSR_GPSR(IP0SR1_7_4,    MSIOF1_SS1),
+       PINMUX_IPSR_GPSR(IP0SR1_7_4,    HCTS3_N_A),
+       PINMUX_IPSR_GPSR(IP0SR1_7_4,    RX3),
+
+       PINMUX_IPSR_GPSR(IP0SR1_11_8,   MSIOF1_SYNC),
+       PINMUX_IPSR_GPSR(IP0SR1_11_8,   HRTS3_N_A),
+       PINMUX_IPSR_GPSR(IP0SR1_11_8,   RTS3_N),
+
+       PINMUX_IPSR_GPSR(IP0SR1_15_12,  MSIOF1_SCK),
+       PINMUX_IPSR_GPSR(IP0SR1_15_12,  HSCK3_A),
+       PINMUX_IPSR_GPSR(IP0SR1_15_12,  CTS3_N),
+
+       PINMUX_IPSR_GPSR(IP0SR1_19_16,  MSIOF1_TXD),
+       PINMUX_IPSR_GPSR(IP0SR1_19_16,  HRX3_A),
+       PINMUX_IPSR_GPSR(IP0SR1_19_16,  SCK3),
+
+       PINMUX_IPSR_GPSR(IP0SR1_23_20,  MSIOF1_RXD),
+
+       PINMUX_IPSR_GPSR(IP0SR1_27_24,  MSIOF0_SS2),
+       PINMUX_IPSR_GPSR(IP0SR1_27_24,  HTX1_X),
+       PINMUX_IPSR_GPSR(IP0SR1_27_24,  TX1_X),
+
+       PINMUX_IPSR_GPSR(IP0SR1_31_28,  MSIOF0_SS1),
+       PINMUX_IPSR_GPSR(IP0SR1_31_28,  HRX1_X),
+       PINMUX_IPSR_GPSR(IP0SR1_31_28,  RX1_X),
+
+       /* IP1SR1 */
+       PINMUX_IPSR_GPSR(IP1SR1_3_0,    MSIOF0_SYNC),
+       PINMUX_IPSR_GPSR(IP1SR1_3_0,    HCTS1_N_X),
+       PINMUX_IPSR_GPSR(IP1SR1_3_0,    CTS1_N_X),
+       PINMUX_IPSR_GPSR(IP1SR1_3_0,    CANFD5_TX_B),
+
+       PINMUX_IPSR_GPSR(IP1SR1_7_4,    MSIOF0_TXD),
+       PINMUX_IPSR_GPSR(IP1SR1_7_4,    HRTS1_N_X),
+       PINMUX_IPSR_GPSR(IP1SR1_7_4,    RTS1_N_X),
+       PINMUX_IPSR_GPSR(IP1SR1_7_4,    CANFD5_RX_B),
+
+       PINMUX_IPSR_GPSR(IP1SR1_11_8,   MSIOF0_SCK),
+       PINMUX_IPSR_GPSR(IP1SR1_11_8,   HSCK1_X),
+       PINMUX_IPSR_GPSR(IP1SR1_11_8,   SCK1_X),
+
+       PINMUX_IPSR_GPSR(IP1SR1_15_12,  MSIOF0_RXD),
+
+       PINMUX_IPSR_GPSR(IP1SR1_19_16,  HTX0),
+       PINMUX_IPSR_GPSR(IP1SR1_19_16,  TX0),
+
+       PINMUX_IPSR_GPSR(IP1SR1_23_20,  HCTS0_N),
+       PINMUX_IPSR_GPSR(IP1SR1_23_20,  CTS0_N),
+       PINMUX_IPSR_GPSR(IP1SR1_23_20,  PWM8_A),
+
+       PINMUX_IPSR_GPSR(IP1SR1_27_24,  HRTS0_N),
+       PINMUX_IPSR_GPSR(IP1SR1_27_24,  RTS0_N),
+       PINMUX_IPSR_GPSR(IP1SR1_27_24,  PWM9_A),
+
+       PINMUX_IPSR_GPSR(IP1SR1_31_28,  HSCK0),
+       PINMUX_IPSR_GPSR(IP1SR1_31_28,  SCK0),
+       PINMUX_IPSR_GPSR(IP1SR1_31_28,  PWM0_A),
+
+       /* IP2SR1 */
+       PINMUX_IPSR_GPSR(IP2SR1_3_0,    HRX0),
+       PINMUX_IPSR_GPSR(IP2SR1_3_0,    RX0),
+
+       PINMUX_IPSR_GPSR(IP2SR1_7_4,    SCIF_CLK),
+       PINMUX_IPSR_GPSR(IP2SR1_7_4,    IRQ4_A),
+
+       PINMUX_IPSR_GPSR(IP2SR1_11_8,   SSI_SCK),
+       PINMUX_IPSR_GPSR(IP2SR1_11_8,   TCLK3),
+
+       PINMUX_IPSR_GPSR(IP2SR1_15_12,  SSI_WS),
+       PINMUX_IPSR_GPSR(IP2SR1_15_12,  TCLK4),
+
+       PINMUX_IPSR_GPSR(IP2SR1_19_16,  SSI_SD),
+       PINMUX_IPSR_GPSR(IP2SR1_19_16,  IRQ0_A),
+
+       PINMUX_IPSR_GPSR(IP2SR1_23_20,  AUDIO_CLKOUT),
+       PINMUX_IPSR_GPSR(IP2SR1_23_20,  IRQ1_A),
+
+       PINMUX_IPSR_GPSR(IP2SR1_27_24,  AUDIO_CLKIN),
+       PINMUX_IPSR_GPSR(IP2SR1_27_24,  PWM3_A),
+
+       PINMUX_IPSR_GPSR(IP2SR1_31_28,  TCLK2),
+       PINMUX_IPSR_GPSR(IP2SR1_31_28,  MSIOF4_SS1),
+       PINMUX_IPSR_GPSR(IP2SR1_31_28,  IRQ3_B),
+
+       /* IP3SR1 */
+       PINMUX_IPSR_GPSR(IP3SR1_3_0,    HRX3),
+       PINMUX_IPSR_GPSR(IP3SR1_3_0,    SCK3_A),
+       PINMUX_IPSR_GPSR(IP3SR1_3_0,    MSIOF4_SS2),
+
+       PINMUX_IPSR_GPSR(IP3SR1_7_4,    HSCK3),
+       PINMUX_IPSR_GPSR(IP3SR1_7_4,    CTS3_N_A),
+       PINMUX_IPSR_GPSR(IP3SR1_7_4,    MSIOF4_SCK),
+       PINMUX_IPSR_GPSR(IP3SR1_7_4,    TPU0TO0_A),
+
+       PINMUX_IPSR_GPSR(IP3SR1_11_8,   HRTS3_N),
+       PINMUX_IPSR_GPSR(IP3SR1_11_8,   RTS3_N_A),
+       PINMUX_IPSR_GPSR(IP3SR1_11_8,   MSIOF4_TXD),
+       PINMUX_IPSR_GPSR(IP3SR1_11_8,   TPU0TO1_A),
+
+       PINMUX_IPSR_GPSR(IP3SR1_15_12,  HCTS3_N),
+       PINMUX_IPSR_GPSR(IP3SR1_15_12,  RX3_A),
+       PINMUX_IPSR_GPSR(IP3SR1_15_12,  MSIOF4_RXD),
+
+       PINMUX_IPSR_GPSR(IP3SR1_19_16,  HTX3),
+       PINMUX_IPSR_GPSR(IP3SR1_19_16,  TX3_A),
+       PINMUX_IPSR_GPSR(IP3SR1_19_16,  MSIOF4_SYNC),
+
+       /* IP0SR2 */
+       PINMUX_IPSR_GPSR(IP0SR2_3_0,    FXR_TXDA),
+       PINMUX_IPSR_GPSR(IP0SR2_3_0,    CANFD1_TX),
+       PINMUX_IPSR_GPSR(IP0SR2_3_0,    TPU0TO2_A),
+
+       PINMUX_IPSR_GPSR(IP0SR2_7_4,    FXR_TXENA_N),
+       PINMUX_IPSR_GPSR(IP0SR2_7_4,    CANFD1_RX),
+       PINMUX_IPSR_GPSR(IP0SR2_7_4,    TPU0TO3_A),
+
+       PINMUX_IPSR_GPSR(IP0SR2_11_8,   RXDA_EXTFXR),
+       PINMUX_IPSR_GPSR(IP0SR2_11_8,   CANFD5_TX),
+       PINMUX_IPSR_GPSR(IP0SR2_11_8,   IRQ5),
+
+       PINMUX_IPSR_GPSR(IP0SR2_15_12,  CLK_EXTFXR),
+       PINMUX_IPSR_GPSR(IP0SR2_15_12,  CANFD5_RX),
+       PINMUX_IPSR_GPSR(IP0SR2_15_12,  IRQ4_B),
+
+       PINMUX_IPSR_GPSR(IP0SR2_19_16,  RXDB_EXTFXR),
+
+       PINMUX_IPSR_GPSR(IP0SR2_23_20,  FXR_TXENB_N),
+
+       PINMUX_IPSR_GPSR(IP0SR2_27_24,  FXR_TXDB),
+
+       PINMUX_IPSR_GPSR(IP0SR2_31_28,  TPU0TO1),
+       PINMUX_IPSR_GPSR(IP0SR2_31_28,  CANFD6_TX),
+       PINMUX_IPSR_GPSR(IP0SR2_31_28,  TCLK2_B),
+
+       /* IP1SR2 */
+       PINMUX_IPSR_GPSR(IP1SR2_3_0,    TPU0TO0),
+       PINMUX_IPSR_GPSR(IP1SR2_3_0,    CANFD6_RX),
+       PINMUX_IPSR_GPSR(IP1SR2_3_0,    TCLK1_A),
+
+       PINMUX_IPSR_GPSR(IP1SR2_7_4,    CAN_CLK),
+       PINMUX_IPSR_GPSR(IP1SR2_7_4,    FXR_TXENA_N_X),
+
+       PINMUX_IPSR_GPSR(IP1SR2_11_8,   CANFD0_TX),
+       PINMUX_IPSR_GPSR(IP1SR2_11_8,   FXR_TXENB_N_X),
+
+       PINMUX_IPSR_GPSR(IP1SR2_15_12,  CANFD0_RX),
+       PINMUX_IPSR_GPSR(IP1SR2_15_12,  STPWT_EXTFXR),
+
+       PINMUX_IPSR_GPSR(IP1SR2_19_16,  CANFD2_TX),
+       PINMUX_IPSR_GPSR(IP1SR2_19_16,  TPU0TO2),
+       PINMUX_IPSR_GPSR(IP1SR2_19_16,  TCLK3_A),
+
+       PINMUX_IPSR_GPSR(IP1SR2_23_20,  CANFD2_RX),
+       PINMUX_IPSR_GPSR(IP1SR2_23_20,  TPU0TO3),
+       PINMUX_IPSR_GPSR(IP1SR2_23_20,  PWM1_B),
+       PINMUX_IPSR_GPSR(IP1SR2_23_20,  TCLK4_A),
+
+       PINMUX_IPSR_GPSR(IP1SR2_27_24,  CANFD3_TX),
+       PINMUX_IPSR_GPSR(IP1SR2_27_24,  PWM2_B),
+
+       PINMUX_IPSR_GPSR(IP1SR2_31_28,  CANFD3_RX),
+       PINMUX_IPSR_GPSR(IP1SR2_31_28,  PWM3_B),
+
+       /* IP2SR2 */
+       PINMUX_IPSR_GPSR(IP2SR2_3_0,    CANFD4_TX),
+       PINMUX_IPSR_GPSR(IP2SR2_3_0,    PWM4),
+
+       PINMUX_IPSR_GPSR(IP2SR2_7_4,    CANFD4_RX),
+       PINMUX_IPSR_GPSR(IP2SR2_7_4,    PWM5),
+
+       PINMUX_IPSR_GPSR(IP2SR2_11_8,   CANFD7_TX),
+       PINMUX_IPSR_GPSR(IP2SR2_11_8,   PWM6),
+
+       PINMUX_IPSR_GPSR(IP2SR2_15_12,  CANFD7_RX),
+       PINMUX_IPSR_GPSR(IP2SR2_15_12,  PWM7),
+
+       /* IP0SR3 */
+       PINMUX_IPSR_GPSR(IP0SR3_3_0,    MMC_SD_D1),
+       PINMUX_IPSR_GPSR(IP0SR3_7_4,    MMC_SD_D0),
+       PINMUX_IPSR_GPSR(IP0SR3_11_8,   MMC_SD_D2),
+       PINMUX_IPSR_GPSR(IP0SR3_15_12,  MMC_SD_CLK),
+       PINMUX_IPSR_GPSR(IP0SR3_19_16,  MMC_DS),
+       PINMUX_IPSR_GPSR(IP0SR3_23_20,  MMC_SD_D3),
+       PINMUX_IPSR_GPSR(IP0SR3_27_24,  MMC_D5),
+       PINMUX_IPSR_GPSR(IP0SR3_31_28,  MMC_D4),
+
+       /* IP1SR3 */
+       PINMUX_IPSR_GPSR(IP1SR3_3_0,    MMC_D7),
+
+       PINMUX_IPSR_GPSR(IP1SR3_7_4,    MMC_D6),
+
+       PINMUX_IPSR_GPSR(IP1SR3_11_8,   MMC_SD_CMD),
+
+       PINMUX_IPSR_GPSR(IP1SR3_15_12,  SD_CD),
+
+       PINMUX_IPSR_GPSR(IP1SR3_19_16,  SD_WP),
+
+       PINMUX_IPSR_GPSR(IP1SR3_23_20,  IPC_CLKIN),
+       PINMUX_IPSR_GPSR(IP1SR3_23_20,  IPC_CLKEN_IN),
+       PINMUX_IPSR_GPSR(IP1SR3_23_20,  PWM1_A),
+       PINMUX_IPSR_GPSR(IP1SR3_23_20,  TCLK3_X),
+
+       PINMUX_IPSR_GPSR(IP1SR3_27_24,  IPC_CLKOUT),
+       PINMUX_IPSR_GPSR(IP1SR3_27_24,  IPC_CLKEN_OUT),
+       PINMUX_IPSR_GPSR(IP1SR3_27_24,  ERROROUTC_A),
+       PINMUX_IPSR_GPSR(IP1SR3_27_24,  TCLK4_X),
+
+       PINMUX_IPSR_GPSR(IP1SR3_31_28,  QSPI0_SSL),
+
+       /* IP2SR3 */
+       PINMUX_IPSR_GPSR(IP2SR3_3_0,    QSPI0_IO3),
+       PINMUX_IPSR_GPSR(IP2SR3_7_4,    QSPI0_IO2),
+       PINMUX_IPSR_GPSR(IP2SR3_11_8,   QSPI0_MISO_IO1),
+       PINMUX_IPSR_GPSR(IP2SR3_15_12,  QSPI0_MOSI_IO0),
+       PINMUX_IPSR_GPSR(IP2SR3_19_16,  QSPI0_SPCLK),
+       PINMUX_IPSR_GPSR(IP2SR3_23_20,  QSPI1_MOSI_IO0),
+       PINMUX_IPSR_GPSR(IP2SR3_27_24,  QSPI1_SPCLK),
+       PINMUX_IPSR_GPSR(IP2SR3_31_28,  QSPI1_MISO_IO1),
+
+       /* IP3SR3 */
+       PINMUX_IPSR_GPSR(IP3SR3_3_0,    QSPI1_IO2),
+       PINMUX_IPSR_GPSR(IP3SR3_7_4,    QSPI1_SSL),
+       PINMUX_IPSR_GPSR(IP3SR3_11_8,   QSPI1_IO3),
+       PINMUX_IPSR_GPSR(IP3SR3_15_12,  RPC_RESET_N),
+       PINMUX_IPSR_GPSR(IP3SR3_19_16,  RPC_WP_N),
+       PINMUX_IPSR_GPSR(IP3SR3_23_20,  RPC_INT_N),
+
+       /* IP0SR6 */
+       PINMUX_IPSR_GPSR(IP0SR6_3_0,    AVB1_MDIO),
+
+       PINMUX_IPSR_MSEL(IP0SR6_7_4,    AVB1_MAGIC,             SEL_AVB1_MAGIC_1),
+
+       PINMUX_IPSR_MSEL(IP0SR6_11_8,   AVB1_MDC,               SEL_AVB1_MDC_1),
+
+       PINMUX_IPSR_GPSR(IP0SR6_15_12,  AVB1_PHY_INT),
+
+       PINMUX_IPSR_GPSR(IP0SR6_19_16,  AVB1_LINK),
+       PINMUX_IPSR_GPSR(IP0SR6_19_16,  AVB1_MII_TX_ER),
+
+       PINMUX_IPSR_MSEL(IP0SR6_23_20,  AVB1_AVTP_MATCH,        SEL_AVB1_AVTP_MATCH_1),
+       PINMUX_IPSR_MSEL(IP0SR6_23_20,  AVB1_MII_RX_ER,         SEL_AVB1_AVTP_MATCH_0),
+
+       PINMUX_IPSR_MSEL(IP0SR6_27_24,  AVB1_TXC,               SEL_AVB1_TXC_1),
+       PINMUX_IPSR_MSEL(IP0SR6_27_24,  AVB1_MII_TXC,           SEL_AVB1_TXC_0),
+
+       PINMUX_IPSR_MSEL(IP0SR6_31_28,  AVB1_TX_CTL,            SEL_AVB1_TX_CTL_1),
+       PINMUX_IPSR_MSEL(IP0SR6_31_28,  AVB1_MII_TX_EN,         SEL_AVB1_TX_CTL_0),
+
+       /* IP1SR6 */
+       PINMUX_IPSR_GPSR(IP1SR6_3_0,    AVB1_RXC),
+       PINMUX_IPSR_GPSR(IP1SR6_3_0,    AVB1_MII_RXC),
+
+       PINMUX_IPSR_GPSR(IP1SR6_7_4,    AVB1_RX_CTL),
+       PINMUX_IPSR_GPSR(IP1SR6_7_4,    AVB1_MII_RX_DV),
+
+       PINMUX_IPSR_MSEL(IP1SR6_11_8,   AVB1_AVTP_PPS,          SEL_AVB1_AVTP_PPS_1),
+       PINMUX_IPSR_MSEL(IP1SR6_11_8,   AVB1_MII_COL,           SEL_AVB1_AVTP_PPS_0),
+
+       PINMUX_IPSR_GPSR(IP1SR6_15_12,  AVB1_AVTP_CAPTURE),
+       PINMUX_IPSR_GPSR(IP1SR6_15_12,  AVB1_MII_CRS),
+
+       PINMUX_IPSR_MSEL(IP1SR6_19_16,  AVB1_TD1,               SEL_AVB1_TD1_1),
+       PINMUX_IPSR_MSEL(IP1SR6_19_16,  AVB1_MII_TD1,           SEL_AVB1_TD1_0),
+
+       PINMUX_IPSR_MSEL(IP1SR6_23_20,  AVB1_TD0,               SEL_AVB1_TD0_1),
+       PINMUX_IPSR_MSEL(IP1SR6_23_20,  AVB1_MII_TD0,           SEL_AVB1_TD0_0),
+
+       PINMUX_IPSR_GPSR(IP1SR6_27_24,  AVB1_RD1),
+       PINMUX_IPSR_GPSR(IP1SR6_27_24,  AVB1_MII_RD1),
+
+       PINMUX_IPSR_GPSR(IP1SR6_31_28,  AVB1_RD0),
+       PINMUX_IPSR_GPSR(IP1SR6_31_28,  AVB1_MII_RD0),
+
+       /* IP2SR6 */
+       PINMUX_IPSR_MSEL(IP2SR6_3_0,    AVB1_TD2,               SEL_AVB1_TD2_1),
+       PINMUX_IPSR_MSEL(IP2SR6_3_0,    AVB1_MII_TD2,           SEL_AVB1_TD2_0),
+
+       PINMUX_IPSR_GPSR(IP2SR6_7_4,    AVB1_RD2),
+       PINMUX_IPSR_GPSR(IP2SR6_7_4,    AVB1_MII_RD2),
+
+       PINMUX_IPSR_MSEL(IP2SR6_11_8,   AVB1_TD3,               SEL_AVB1_TD3_1),
+       PINMUX_IPSR_MSEL(IP2SR6_11_8,   AVB1_MII_TD3,           SEL_AVB1_TD3_0),
+
+       PINMUX_IPSR_GPSR(IP2SR6_15_12,  AVB1_RD3),
+       PINMUX_IPSR_GPSR(IP2SR6_15_12,  AVB1_MII_RD3),
+
+       PINMUX_IPSR_GPSR(IP2SR6_19_16,  AVB1_TXCREFCLK),
+
+       /* IP0SR7 */
+       PINMUX_IPSR_MSEL(IP0SR7_3_0,    AVB0_AVTP_PPS,          SEL_AVB0_AVTP_PPS_1),
+       PINMUX_IPSR_MSEL(IP0SR7_3_0,    AVB0_MII_COL,           SEL_AVB0_AVTP_PPS_0),
+
+       PINMUX_IPSR_GPSR(IP0SR7_7_4,    AVB0_AVTP_CAPTURE),
+       PINMUX_IPSR_GPSR(IP0SR7_7_4,    AVB0_MII_CRS),
+
+       PINMUX_IPSR_MSEL(IP0SR7_11_8,   AVB0_AVTP_MATCH,        SEL_AVB0_AVTP_MATCH_1),
+       PINMUX_IPSR_MSEL(IP0SR7_11_8,   AVB0_MII_RX_ER,         SEL_AVB0_AVTP_MATCH_0),
+       PINMUX_IPSR_MSEL(IP0SR7_11_8,   CC5_OSCOUT,             SEL_AVB0_AVTP_MATCH_0),
+
+       PINMUX_IPSR_MSEL(IP0SR7_15_12,  AVB0_TD3,               SEL_AVB0_TD3_1),
+       PINMUX_IPSR_MSEL(IP0SR7_15_12,  AVB0_MII_TD3,           SEL_AVB0_TD3_0),
+
+       PINMUX_IPSR_GPSR(IP0SR7_19_16,  AVB0_LINK),
+       PINMUX_IPSR_GPSR(IP0SR7_19_16,  AVB0_MII_TX_ER),
+
+       PINMUX_IPSR_GPSR(IP0SR7_23_20,  AVB0_PHY_INT),
+
+       PINMUX_IPSR_MSEL(IP0SR7_27_24,  AVB0_TD2,               SEL_AVB0_TD2_1),
+       PINMUX_IPSR_MSEL(IP0SR7_27_24,  AVB0_MII_TD2,           SEL_AVB0_TD2_0),
+
+       PINMUX_IPSR_MSEL(IP0SR7_31_28,  AVB0_TD1,               SEL_AVB0_TD1_1),
+       PINMUX_IPSR_MSEL(IP0SR7_31_28,  AVB0_MII_TD1,           SEL_AVB0_TD1_0),
+
+       /* IP1SR7 */
+       PINMUX_IPSR_GPSR(IP1SR7_3_0,    AVB0_RD3),
+       PINMUX_IPSR_GPSR(IP1SR7_3_0,    AVB0_MII_RD3),
+
+       PINMUX_IPSR_GPSR(IP1SR7_7_4,    AVB0_TXCREFCLK),
+
+       PINMUX_IPSR_MSEL(IP1SR7_11_8,   AVB0_MAGIC,             SEL_AVB0_MAGIC_1),
+
+       PINMUX_IPSR_MSEL(IP1SR7_15_12,  AVB0_TD0,               SEL_AVB0_TD0_1),
+       PINMUX_IPSR_MSEL(IP1SR7_15_12,  AVB0_MII_TD0,           SEL_AVB0_TD0_0),
+
+       PINMUX_IPSR_GPSR(IP1SR7_19_16,  AVB0_RD2),
+       PINMUX_IPSR_GPSR(IP1SR7_19_16,  AVB0_MII_RD2),
+
+       PINMUX_IPSR_MSEL(IP1SR7_23_20,  AVB0_MDC,               SEL_AVB0_MDC_1),
+
+       PINMUX_IPSR_GPSR(IP1SR7_27_24,  AVB0_MDIO),
+
+       PINMUX_IPSR_MSEL(IP1SR7_31_28,  AVB0_TXC,               SEL_AVB0_TXC_1),
+       PINMUX_IPSR_MSEL(IP1SR7_31_28,  AVB0_MII_TXC,           SEL_AVB0_TXC_0),
+
+       /* IP2SR7 */
+       PINMUX_IPSR_MSEL(IP2SR7_3_0,    AVB0_TX_CTL,            SEL_AVB0_TX_CTL_1),
+       PINMUX_IPSR_MSEL(IP2SR7_3_0,    AVB0_MII_TX_EN,         SEL_AVB0_TX_CTL_0),
+
+       PINMUX_IPSR_GPSR(IP2SR7_7_4,    AVB0_RD1),
+       PINMUX_IPSR_GPSR(IP2SR7_7_4,    AVB0_MII_RD1),
+
+       PINMUX_IPSR_GPSR(IP2SR7_11_8,   AVB0_RD0),
+       PINMUX_IPSR_GPSR(IP2SR7_11_8,   AVB0_MII_RD0),
+
+       PINMUX_IPSR_GPSR(IP2SR7_15_12,  AVB0_RXC),
+       PINMUX_IPSR_GPSR(IP2SR7_15_12,  AVB0_MII_RXC),
+
+       PINMUX_IPSR_GPSR(IP2SR7_19_16,  AVB0_RX_CTL),
+       PINMUX_IPSR_GPSR(IP2SR7_19_16,  AVB0_MII_RX_DV),
+
+       /* IP0SR8 */
+       PINMUX_IPSR_MSEL(IP0SR8_3_0,    SCL0,                   SEL_SCL0_0),
+       PINMUX_IPSR_MSEL(IP0SR8_7_4,    SDA0,                   SEL_SDA0_0),
+       PINMUX_IPSR_MSEL(IP0SR8_11_8,   SCL1,                   SEL_SCL1_0),
+       PINMUX_IPSR_MSEL(IP0SR8_15_12,  SDA1,                   SEL_SDA1_0),
+       PINMUX_IPSR_MSEL(IP0SR8_19_16,  SCL2,                   SEL_SCL2_0),
+       PINMUX_IPSR_MSEL(IP0SR8_23_20,  SDA2,                   SEL_SDA2_0),
+       PINMUX_IPSR_MSEL(IP0SR8_27_24,  SCL3,                   SEL_SCL3_0),
+       PINMUX_IPSR_MSEL(IP0SR8_31_28,  SDA3,                   SEL_SDA3_0),
+
+       /* IP1SR8 */
+       PINMUX_IPSR_MSEL(IP1SR8_3_0,    SCL4,                   SEL_SCL4_0),
+       PINMUX_IPSR_MSEL(IP1SR8_3_0,    HRX2,                   SEL_SCL4_0),
+       PINMUX_IPSR_MSEL(IP1SR8_3_0,    SCK4,                   SEL_SCL4_0),
+
+       PINMUX_IPSR_MSEL(IP1SR8_7_4,    SDA4,                   SEL_SDA4_0),
+       PINMUX_IPSR_MSEL(IP1SR8_7_4,    HTX2,                   SEL_SDA4_0),
+       PINMUX_IPSR_MSEL(IP1SR8_7_4,    CTS4_N,                 SEL_SDA4_0),
+
+       PINMUX_IPSR_MSEL(IP1SR8_11_8,   SCL5,                   SEL_SCL5_0),
+       PINMUX_IPSR_MSEL(IP1SR8_11_8,   HRTS2_N,                SEL_SCL5_0),
+       PINMUX_IPSR_MSEL(IP1SR8_11_8,   RTS4_N,                 SEL_SCL5_0),
+
+       PINMUX_IPSR_MSEL(IP1SR8_15_12,  SDA5,                   SEL_SDA5_0),
+       PINMUX_IPSR_MSEL(IP1SR8_15_12,  SCIF_CLK2,              SEL_SDA5_0),
+
+       PINMUX_IPSR_GPSR(IP1SR8_19_16,  HCTS2_N),
+       PINMUX_IPSR_GPSR(IP1SR8_19_16,  TX4),
+
+       PINMUX_IPSR_GPSR(IP1SR8_23_20,  HSCK2),
+       PINMUX_IPSR_GPSR(IP1SR8_23_20,  RX4),
+};
+
+/*
+ * Pins not associated with a GPIO port.
+ */
+enum {
+       GP_ASSIGN_LAST(),
+};
+
+static const struct sh_pfc_pin pinmux_pins[] = {
+       PINMUX_GPIO_GP_ALL(),
+};
+
+/* - AVB0 ------------------------------------------------ */
+static const unsigned int avb0_link_pins[] = {
+       /* AVB0_LINK */
+       RCAR_GP_PIN(7, 4),
+};
+static const unsigned int avb0_link_mux[] = {
+       AVB0_LINK_MARK,
+};
+static const unsigned int avb0_magic_pins[] = {
+       /* AVB0_MAGIC */
+       RCAR_GP_PIN(7, 10),
+};
+static const unsigned int avb0_magic_mux[] = {
+       AVB0_MAGIC_MARK,
+};
+static const unsigned int avb0_phy_int_pins[] = {
+       /* AVB0_PHY_INT */
+       RCAR_GP_PIN(7, 5),
+};
+static const unsigned int avb0_phy_int_mux[] = {
+       AVB0_PHY_INT_MARK,
+};
+static const unsigned int avb0_mdio_pins[] = {
+       /* AVB0_MDC, AVB0_MDIO */
+       RCAR_GP_PIN(7, 13), RCAR_GP_PIN(7, 14),
+};
+static const unsigned int avb0_mdio_mux[] = {
+       AVB0_MDC_MARK, AVB0_MDIO_MARK,
+};
+static const unsigned int avb0_rgmii_pins[] = {
+       /*
+        * AVB0_TX_CTL, AVB0_TXC, AVB0_TD0, AVB0_TD1, AVB0_TD2, AVB0_TD3,
+        * AVB0_RX_CTL, AVB0_RXC, AVB0_RD0, AVB0_RD1, AVB0_RD2, AVB0_RD3,
+        */
+       RCAR_GP_PIN(7, 16), RCAR_GP_PIN(7, 15),
+       RCAR_GP_PIN(7, 11), RCAR_GP_PIN(7,  7),
+       RCAR_GP_PIN(7,  6), RCAR_GP_PIN(7,  3),
+       RCAR_GP_PIN(7, 20), RCAR_GP_PIN(7, 19),
+       RCAR_GP_PIN(7, 18), RCAR_GP_PIN(7, 17),
+       RCAR_GP_PIN(7, 12), RCAR_GP_PIN(7,  8),
+};
+static const unsigned int avb0_rgmii_mux[] = {
+       AVB0_TX_CTL_MARK,       AVB0_TXC_MARK,
+       AVB0_TD0_MARK,          AVB0_TD1_MARK,
+       AVB0_TD2_MARK,          AVB0_TD3_MARK,
+       AVB0_RX_CTL_MARK,       AVB0_RXC_MARK,
+       AVB0_RD0_MARK,          AVB0_RD1_MARK,
+       AVB0_RD2_MARK,          AVB0_RD3_MARK,
+};
+static const unsigned int avb0_txcrefclk_pins[] = {
+       /* AVB0_TXCREFCLK */
+       RCAR_GP_PIN(7, 9),
+};
+static const unsigned int avb0_txcrefclk_mux[] = {
+       AVB0_TXCREFCLK_MARK,
+};
+static const unsigned int avb0_avtp_pps_pins[] = {
+       /* AVB0_AVTP_PPS */
+       RCAR_GP_PIN(7, 0),
+};
+static const unsigned int avb0_avtp_pps_mux[] = {
+       AVB0_AVTP_PPS_MARK,
+};
+static const unsigned int avb0_avtp_capture_pins[] = {
+       /* AVB0_AVTP_CAPTURE */
+       RCAR_GP_PIN(7, 1),
+};
+static const unsigned int avb0_avtp_capture_mux[] = {
+       AVB0_AVTP_CAPTURE_MARK,
+};
+static const unsigned int avb0_avtp_match_pins[] = {
+       /* AVB0_AVTP_MATCH */
+       RCAR_GP_PIN(7, 2),
+};
+static const unsigned int avb0_avtp_match_mux[] = {
+       AVB0_AVTP_MATCH_MARK,
+};
+
+/* - AVB1 ------------------------------------------------ */
+static const unsigned int avb1_link_pins[] = {
+       /* AVB1_LINK */
+       RCAR_GP_PIN(6, 4),
+};
+static const unsigned int avb1_link_mux[] = {
+       AVB1_LINK_MARK,
+};
+static const unsigned int avb1_magic_pins[] = {
+       /* AVB1_MAGIC */
+       RCAR_GP_PIN(6, 1),
+};
+static const unsigned int avb1_magic_mux[] = {
+       AVB1_MAGIC_MARK,
+};
+static const unsigned int avb1_phy_int_pins[] = {
+       /* AVB1_PHY_INT */
+       RCAR_GP_PIN(6, 3),
+};
+static const unsigned int avb1_phy_int_mux[] = {
+       AVB1_PHY_INT_MARK,
+};
+static const unsigned int avb1_mdio_pins[] = {
+       /* AVB1_MDC, AVB1_MDIO */
+       RCAR_GP_PIN(6, 2), RCAR_GP_PIN(6, 0),
+};
+static const unsigned int avb1_mdio_mux[] = {
+       AVB1_MDC_MARK, AVB1_MDIO_MARK,
+};
+static const unsigned int avb1_rgmii_pins[] = {
+       /*
+        * AVB1_TX_CTL, AVB1_TXC, AVB1_TD0, AVB1_TD1, AVB1_TD2, AVB1_TD3,
+        * AVB1_RX_CTL, AVB1_RXC, AVB1_RD0, AVB1_RD1, AVB1_RD2, AVB1_RD3,
+        */
+       RCAR_GP_PIN(6,  7), RCAR_GP_PIN(6,  6),
+       RCAR_GP_PIN(6, 13), RCAR_GP_PIN(6, 12),
+       RCAR_GP_PIN(6, 16), RCAR_GP_PIN(6, 18),
+       RCAR_GP_PIN(6,  9), RCAR_GP_PIN(6,  8),
+       RCAR_GP_PIN(6, 15), RCAR_GP_PIN(6, 14),
+       RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 19),
+};
+static const unsigned int avb1_rgmii_mux[] = {
+       AVB1_TX_CTL_MARK,       AVB1_TXC_MARK,
+       AVB1_TD0_MARK,          AVB1_TD1_MARK,
+       AVB1_TD2_MARK,          AVB1_TD3_MARK,
+       AVB1_RX_CTL_MARK,       AVB1_RXC_MARK,
+       AVB1_RD0_MARK,          AVB1_RD1_MARK,
+       AVB1_RD2_MARK,          AVB1_RD3_MARK,
+};
+static const unsigned int avb1_txcrefclk_pins[] = {
+       /* AVB1_TXCREFCLK */
+       RCAR_GP_PIN(6, 20),
+};
+static const unsigned int avb1_txcrefclk_mux[] = {
+       AVB1_TXCREFCLK_MARK,
+};
+static const unsigned int avb1_avtp_pps_pins[] = {
+       /* AVB1_AVTP_PPS */
+       RCAR_GP_PIN(6, 10),
+};
+static const unsigned int avb1_avtp_pps_mux[] = {
+       AVB1_AVTP_PPS_MARK,
+};
+static const unsigned int avb1_avtp_capture_pins[] = {
+       /* AVB1_AVTP_CAPTURE */
+       RCAR_GP_PIN(6, 11),
+};
+static const unsigned int avb1_avtp_capture_mux[] = {
+       AVB1_AVTP_CAPTURE_MARK,
+};
+static const unsigned int avb1_avtp_match_pins[] = {
+       /* AVB1_AVTP_MATCH */
+       RCAR_GP_PIN(6, 5),
+};
+static const unsigned int avb1_avtp_match_mux[] = {
+       AVB1_AVTP_MATCH_MARK,
+};
+
+/* - AVB2 ------------------------------------------------ */
+static const unsigned int avb2_link_pins[] = {
+       /* AVB2_LINK */
+       RCAR_GP_PIN(5, 3),
+};
+static const unsigned int avb2_link_mux[] = {
+       AVB2_LINK_MARK,
+};
+static const unsigned int avb2_magic_pins[] = {
+       /* AVB2_MAGIC */
+       RCAR_GP_PIN(5, 5),
+};
+static const unsigned int avb2_magic_mux[] = {
+       AVB2_MAGIC_MARK,
+};
+static const unsigned int avb2_phy_int_pins[] = {
+       /* AVB2_PHY_INT */
+       RCAR_GP_PIN(5, 4),
+};
+static const unsigned int avb2_phy_int_mux[] = {
+       AVB2_PHY_INT_MARK,
+};
+static const unsigned int avb2_mdio_pins[] = {
+       /* AVB2_MDC, AVB2_MDIO */
+       RCAR_GP_PIN(5, 6), RCAR_GP_PIN(5, 10),
+};
+static const unsigned int avb2_mdio_mux[] = {
+       AVB2_MDC_MARK, AVB2_MDIO_MARK,
+};
+static const unsigned int avb2_rgmii_pins[] = {
+       /*
+        * AVB2_TX_CTL, AVB2_TXC, AVB2_TD0, AVB2_TD1, AVB2_TD2, AVB2_TD3,
+        * AVB2_RX_CTL, AVB2_RXC, AVB2_RD0, AVB2_RD1, AVB2_RD2, AVB2_RD3,
+        */
+       RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 16),
+       RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 12),
+       RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5,  8),
+       RCAR_GP_PIN(5, 20), RCAR_GP_PIN(5, 18),
+       RCAR_GP_PIN(5, 17), RCAR_GP_PIN(5, 14),
+       RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5,  9),
+};
+static const unsigned int avb2_rgmii_mux[] = {
+       AVB2_TX_CTL_MARK,       AVB2_TXC_MARK,
+       AVB2_TD0_MARK,          AVB2_TD1_MARK,
+       AVB2_TD2_MARK,          AVB2_TD3_MARK,
+       AVB2_RX_CTL_MARK,       AVB2_RXC_MARK,
+       AVB2_RD0_MARK,          AVB2_RD1_MARK,
+       AVB2_RD2_MARK,          AVB2_RD3_MARK,
+};
+static const unsigned int avb2_txcrefclk_pins[] = {
+       /* AVB2_TXCREFCLK */
+       RCAR_GP_PIN(5, 7),
+};
+static const unsigned int avb2_txcrefclk_mux[] = {
+       AVB2_TXCREFCLK_MARK,
+};
+static const unsigned int avb2_avtp_pps_pins[] = {
+       /* AVB2_AVTP_PPS */
+       RCAR_GP_PIN(5, 0),
+};
+static const unsigned int avb2_avtp_pps_mux[] = {
+       AVB2_AVTP_PPS_MARK,
+};
+static const unsigned int avb2_avtp_capture_pins[] = {
+       /* AVB2_AVTP_CAPTURE */
+       RCAR_GP_PIN(5, 1),
+};
+static const unsigned int avb2_avtp_capture_mux[] = {
+       AVB2_AVTP_CAPTURE_MARK,
+};
+static const unsigned int avb2_avtp_match_pins[] = {
+       /* AVB2_AVTP_MATCH */
+       RCAR_GP_PIN(5, 2),
+};
+static const unsigned int avb2_avtp_match_mux[] = {
+       AVB2_AVTP_MATCH_MARK,
+};
+
+/* - CANFD0 ----------------------------------------------------------------- */
+static const unsigned int canfd0_data_pins[] = {
+       /* CANFD0_TX, CANFD0_RX */
+       RCAR_GP_PIN(2, 10), RCAR_GP_PIN(2, 11),
+};
+static const unsigned int canfd0_data_mux[] = {
+       CANFD0_TX_MARK, CANFD0_RX_MARK,
+};
+
+/* - CANFD1 ----------------------------------------------------------------- */
+static const unsigned int canfd1_data_pins[] = {
+       /* CANFD1_TX, CANFD1_RX */
+       RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1),
+};
+static const unsigned int canfd1_data_mux[] = {
+       CANFD1_TX_MARK, CANFD1_RX_MARK,
+};
+
+/* - CANFD2 ----------------------------------------------------------------- */
+static const unsigned int canfd2_data_pins[] = {
+       /* CANFD2_TX, CANFD2_RX */
+       RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 13),
+};
+static const unsigned int canfd2_data_mux[] = {
+       CANFD2_TX_MARK, CANFD2_RX_MARK,
+};
+
+/* - CANFD3 ----------------------------------------------------------------- */
+static const unsigned int canfd3_data_pins[] = {
+       /* CANFD3_TX, CANFD3_RX */
+       RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 15),
+};
+static const unsigned int canfd3_data_mux[] = {
+       CANFD3_TX_MARK, CANFD3_RX_MARK,
+};
+
+/* - CANFD4 ----------------------------------------------------------------- */
+static const unsigned int canfd4_data_pins[] = {
+       /* CANFD4_TX, CANFD4_RX */
+       RCAR_GP_PIN(2, 16), RCAR_GP_PIN(2, 17),
+};
+static const unsigned int canfd4_data_mux[] = {
+       CANFD4_TX_MARK, CANFD4_RX_MARK,
+};
+
+/* - CANFD5 ----------------------------------------------------------------- */
+static const unsigned int canfd5_data_pins[] = {
+       /* CANFD5_TX, CANFD5_RX */
+       RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3),
+};
+static const unsigned int canfd5_data_mux[] = {
+       CANFD5_TX_MARK, CANFD5_RX_MARK,
+};
+
+/* - CANFD5_B ----------------------------------------------------------------- */
+static const unsigned int canfd5_data_b_pins[] = {
+       /* CANFD5_TX_B, CANFD5_RX_B */
+       RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int canfd5_data_b_mux[] = {
+       CANFD5_TX_B_MARK, CANFD5_RX_B_MARK,
+};
+
+/* - CANFD6 ----------------------------------------------------------------- */
+static const unsigned int canfd6_data_pins[] = {
+       /* CANFD6_TX, CANFD6_RX */
+       RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8),
+};
+static const unsigned int canfd6_data_mux[] = {
+       CANFD6_TX_MARK, CANFD6_RX_MARK,
+};
+
+/* - CANFD7 ----------------------------------------------------------------- */
+static const unsigned int canfd7_data_pins[] = {
+       /* CANFD7_TX, CANFD7_RX */
+       RCAR_GP_PIN(2, 18), RCAR_GP_PIN(2, 19),
+};
+static const unsigned int canfd7_data_mux[] = {
+       CANFD7_TX_MARK, CANFD7_RX_MARK,
+};
+
+/* - CANFD Clock ------------------------------------------------------------ */
+static const unsigned int can_clk_pins[] = {
+       /* CAN_CLK */
+       RCAR_GP_PIN(2, 9),
+};
+static const unsigned int can_clk_mux[] = {
+       CAN_CLK_MARK,
+};
+
+/* - HSCIF0 ----------------------------------------------------------------- */
+static const unsigned int hscif0_data_pins[] = {
+       /* HRX0, HTX0 */
+       RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 12),
+};
+static const unsigned int hscif0_data_mux[] = {
+       HRX0_MARK, HTX0_MARK,
+};
+static const unsigned int hscif0_clk_pins[] = {
+       /* HSCK0 */
+       RCAR_GP_PIN(1, 15),
+};
+static const unsigned int hscif0_clk_mux[] = {
+       HSCK0_MARK,
+};
+static const unsigned int hscif0_ctrl_pins[] = {
+       /* HRTS0_N, HCTS0_N */
+       RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13),
+};
+static const unsigned int hscif0_ctrl_mux[] = {
+       HRTS0_N_MARK, HCTS0_N_MARK,
+};
+
+/* - HSCIF1 ----------------------------------------------------------------- */
+static const unsigned int hscif1_data_pins[] = {
+       /* HRX1, HTX1 */
+       RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14),
+};
+static const unsigned int hscif1_data_mux[] = {
+       HRX1_MARK, HTX1_MARK,
+};
+static const unsigned int hscif1_clk_pins[] = {
+       /* HSCK1 */
+       RCAR_GP_PIN(0, 18),
+};
+static const unsigned int hscif1_clk_mux[] = {
+       HSCK1_MARK,
+};
+static const unsigned int hscif1_ctrl_pins[] = {
+       /* HRTS1_N, HCTS1_N */
+       RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16),
+};
+static const unsigned int hscif1_ctrl_mux[] = {
+       HRTS1_N_MARK, HCTS1_N_MARK,
+};
+
+/* - HSCIF1_X---------------------------------------------------------------- */
+static const unsigned int hscif1_data_x_pins[] = {
+       /* HRX1_X, HTX1_X */
+       RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int hscif1_data_x_mux[] = {
+       HRX1_X_MARK, HTX1_X_MARK,
+};
+static const unsigned int hscif1_clk_x_pins[] = {
+       /* HSCK1_X */
+       RCAR_GP_PIN(1, 10),
+};
+static const unsigned int hscif1_clk_x_mux[] = {
+       HSCK1_X_MARK,
+};
+static const unsigned int hscif1_ctrl_x_pins[] = {
+       /* HRTS1_N_X, HCTS1_N_X */
+       RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 8),
+};
+static const unsigned int hscif1_ctrl_x_mux[] = {
+       HRTS1_N_X_MARK, HCTS1_N_X_MARK,
+};
+
+/* - HSCIF2 ----------------------------------------------------------------- */
+static const unsigned int hscif2_data_pins[] = {
+       /* HRX2, HTX2 */
+       RCAR_GP_PIN(8, 8), RCAR_GP_PIN(8, 9),
+};
+static const unsigned int hscif2_data_mux[] = {
+       HRX2_MARK, HTX2_MARK,
+};
+static const unsigned int hscif2_clk_pins[] = {
+       /* HSCK2 */
+       RCAR_GP_PIN(8, 13),
+};
+static const unsigned int hscif2_clk_mux[] = {
+       HSCK2_MARK,
+};
+static const unsigned int hscif2_ctrl_pins[] = {
+       /* HRTS2_N, HCTS2_N */
+       RCAR_GP_PIN(8, 10), RCAR_GP_PIN(8, 12),
+};
+static const unsigned int hscif2_ctrl_mux[] = {
+       HRTS2_N_MARK, HCTS2_N_MARK,
+};
+
+/* - HSCIF3 ----------------------------------------------------------------- */
+static const unsigned int hscif3_data_pins[] = {
+       /* HRX3, HTX3 */
+       RCAR_GP_PIN(1, 24), RCAR_GP_PIN(1, 28),
+};
+static const unsigned int hscif3_data_mux[] = {
+       HRX3_MARK, HTX3_MARK,
+};
+static const unsigned int hscif3_clk_pins[] = {
+       /* HSCK3 */
+       RCAR_GP_PIN(1, 25),
+};
+static const unsigned int hscif3_clk_mux[] = {
+       HSCK3_MARK,
+};
+static const unsigned int hscif3_ctrl_pins[] = {
+       /* HRTS3_N, HCTS3_N */
+       RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 27),
+};
+static const unsigned int hscif3_ctrl_mux[] = {
+       HRTS3_N_MARK, HCTS3_N_MARK,
+};
+
+/* - HSCIF3_A ----------------------------------------------------------------- */
+static const unsigned int hscif3_data_a_pins[] = {
+       /* HRX3_A, HTX3_A */
+       RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 0),
+};
+static const unsigned int hscif3_data_a_mux[] = {
+       HRX3_A_MARK, HTX3_A_MARK,
+};
+static const unsigned int hscif3_clk_a_pins[] = {
+       /* HSCK3_A */
+       RCAR_GP_PIN(1, 3),
+};
+static const unsigned int hscif3_clk_a_mux[] = {
+       HSCK3_A_MARK,
+};
+static const unsigned int hscif3_ctrl_a_pins[] = {
+       /* HRTS3_N_A, HCTS3_N_A */
+       RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 1),
+};
+static const unsigned int hscif3_ctrl_a_mux[] = {
+       HRTS3_N_A_MARK, HCTS3_N_A_MARK,
+};
+
+/* - I2C0 ------------------------------------------------------------------- */
+static const unsigned int i2c0_pins[] = {
+       /* SDA0, SCL0 */
+       RCAR_GP_PIN(8, 1), RCAR_GP_PIN(8, 0),
+};
+static const unsigned int i2c0_mux[] = {
+       SDA0_MARK, SCL0_MARK,
+};
+
+/* - I2C1 ------------------------------------------------------------------- */
+static const unsigned int i2c1_pins[] = {
+       /* SDA1, SCL1 */
+       RCAR_GP_PIN(8, 3), RCAR_GP_PIN(8, 2),
+};
+static const unsigned int i2c1_mux[] = {
+       SDA1_MARK, SCL1_MARK,
+};
+
+/* - I2C2 ------------------------------------------------------------------- */
+static const unsigned int i2c2_pins[] = {
+       /* SDA2, SCL2 */
+       RCAR_GP_PIN(8, 5), RCAR_GP_PIN(8, 4),
+};
+static const unsigned int i2c2_mux[] = {
+       SDA2_MARK, SCL2_MARK,
+};
+
+/* - I2C3 ------------------------------------------------------------------- */
+static const unsigned int i2c3_pins[] = {
+       /* SDA3, SCL3 */
+       RCAR_GP_PIN(8, 7), RCAR_GP_PIN(8, 6),
+};
+static const unsigned int i2c3_mux[] = {
+       SDA3_MARK, SCL3_MARK,
+};
+
+/* - I2C4 ------------------------------------------------------------------- */
+static const unsigned int i2c4_pins[] = {
+       /* SDA4, SCL4 */
+       RCAR_GP_PIN(8, 9), RCAR_GP_PIN(8, 8),
+};
+static const unsigned int i2c4_mux[] = {
+       SDA4_MARK, SCL4_MARK,
+};
+
+/* - I2C5 ------------------------------------------------------------------- */
+static const unsigned int i2c5_pins[] = {
+       /* SDA5, SCL5 */
+       RCAR_GP_PIN(8, 11), RCAR_GP_PIN(8, 10),
+};
+static const unsigned int i2c5_mux[] = {
+       SDA5_MARK, SCL5_MARK,
+};
+
+/* - MMC -------------------------------------------------------------------- */
+static const unsigned int mmc_data_pins[] = {
+       /* MMC_SD_D[0:3], MMC_D[4:7] */
+       RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 0),
+       RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 5),
+       RCAR_GP_PIN(3, 7), RCAR_GP_PIN(3, 6),
+       RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 8),
+};
+static const unsigned int mmc_data_mux[] = {
+       MMC_SD_D0_MARK, MMC_SD_D1_MARK,
+       MMC_SD_D2_MARK, MMC_SD_D3_MARK,
+       MMC_D4_MARK, MMC_D5_MARK,
+       MMC_D6_MARK, MMC_D7_MARK,
+};
+static const unsigned int mmc_ctrl_pins[] = {
+       /* MMC_SD_CLK, MMC_SD_CMD */
+       RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 10),
+};
+static const unsigned int mmc_ctrl_mux[] = {
+       MMC_SD_CLK_MARK, MMC_SD_CMD_MARK,
+};
+static const unsigned int mmc_cd_pins[] = {
+       /* SD_CD */
+       RCAR_GP_PIN(3, 11),
+};
+static const unsigned int mmc_cd_mux[] = {
+       SD_CD_MARK,
+};
+static const unsigned int mmc_wp_pins[] = {
+       /* SD_WP */
+       RCAR_GP_PIN(3, 12),
+};
+static const unsigned int mmc_wp_mux[] = {
+       SD_WP_MARK,
+};
+static const unsigned int mmc_ds_pins[] = {
+       /* MMC_DS */
+       RCAR_GP_PIN(3, 4),
+};
+static const unsigned int mmc_ds_mux[] = {
+       MMC_DS_MARK,
+};
+
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_clk_pins[] = {
+       /* MSIOF0_SCK */
+       RCAR_GP_PIN(1, 10),
+};
+static const unsigned int msiof0_clk_mux[] = {
+       MSIOF0_SCK_MARK,
+};
+static const unsigned int msiof0_sync_pins[] = {
+       /* MSIOF0_SYNC */
+       RCAR_GP_PIN(1, 8),
+};
+static const unsigned int msiof0_sync_mux[] = {
+       MSIOF0_SYNC_MARK,
+};
+static const unsigned int msiof0_ss1_pins[] = {
+       /* MSIOF0_SS1 */
+       RCAR_GP_PIN(1, 7),
+};
+static const unsigned int msiof0_ss1_mux[] = {
+       MSIOF0_SS1_MARK,
+};
+static const unsigned int msiof0_ss2_pins[] = {
+       /* MSIOF0_SS2 */
+       RCAR_GP_PIN(1, 6),
+};
+static const unsigned int msiof0_ss2_mux[] = {
+       MSIOF0_SS2_MARK,
+};
+static const unsigned int msiof0_txd_pins[] = {
+       /* MSIOF0_TXD */
+       RCAR_GP_PIN(1, 9),
+};
+static const unsigned int msiof0_txd_mux[] = {
+       MSIOF0_TXD_MARK,
+};
+static const unsigned int msiof0_rxd_pins[] = {
+       /* MSIOF0_RXD */
+       RCAR_GP_PIN(1, 11),
+};
+static const unsigned int msiof0_rxd_mux[] = {
+       MSIOF0_RXD_MARK,
+};
+
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_clk_pins[] = {
+       /* MSIOF1_SCK */
+       RCAR_GP_PIN(1, 3),
+};
+static const unsigned int msiof1_clk_mux[] = {
+       MSIOF1_SCK_MARK,
+};
+static const unsigned int msiof1_sync_pins[] = {
+       /* MSIOF1_SYNC */
+       RCAR_GP_PIN(1, 2),
+};
+static const unsigned int msiof1_sync_mux[] = {
+       MSIOF1_SYNC_MARK,
+};
+static const unsigned int msiof1_ss1_pins[] = {
+       /* MSIOF1_SS1 */
+       RCAR_GP_PIN(1, 1),
+};
+static const unsigned int msiof1_ss1_mux[] = {
+       MSIOF1_SS1_MARK,
+};
+static const unsigned int msiof1_ss2_pins[] = {
+       /* MSIOF1_SS2 */
+       RCAR_GP_PIN(1, 0),
+};
+static const unsigned int msiof1_ss2_mux[] = {
+       MSIOF1_SS2_MARK,
+};
+static const unsigned int msiof1_txd_pins[] = {
+       /* MSIOF1_TXD */
+       RCAR_GP_PIN(1, 4),
+};
+static const unsigned int msiof1_txd_mux[] = {
+       MSIOF1_TXD_MARK,
+};
+static const unsigned int msiof1_rxd_pins[] = {
+       /* MSIOF1_RXD */
+       RCAR_GP_PIN(1, 5),
+};
+static const unsigned int msiof1_rxd_mux[] = {
+       MSIOF1_RXD_MARK,
+};
+
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_clk_pins[] = {
+       /* MSIOF2_SCK */
+       RCAR_GP_PIN(0, 17),
+};
+static const unsigned int msiof2_clk_mux[] = {
+       MSIOF2_SCK_MARK,
+};
+static const unsigned int msiof2_sync_pins[] = {
+       /* MSIOF2_SYNC */
+       RCAR_GP_PIN(0, 15),
+};
+static const unsigned int msiof2_sync_mux[] = {
+       MSIOF2_SYNC_MARK,
+};
+static const unsigned int msiof2_ss1_pins[] = {
+       /* MSIOF2_SS1 */
+       RCAR_GP_PIN(0, 14),
+};
+static const unsigned int msiof2_ss1_mux[] = {
+       MSIOF2_SS1_MARK,
+};
+static const unsigned int msiof2_ss2_pins[] = {
+       /* MSIOF2_SS2 */
+       RCAR_GP_PIN(0, 13),
+};
+static const unsigned int msiof2_ss2_mux[] = {
+       MSIOF2_SS2_MARK,
+};
+static const unsigned int msiof2_txd_pins[] = {
+       /* MSIOF2_TXD */
+       RCAR_GP_PIN(0, 16),
+};
+static const unsigned int msiof2_txd_mux[] = {
+       MSIOF2_TXD_MARK,
+};
+static const unsigned int msiof2_rxd_pins[] = {
+       /* MSIOF2_RXD */
+       RCAR_GP_PIN(0, 18),
+};
+static const unsigned int msiof2_rxd_mux[] = {
+       MSIOF2_RXD_MARK,
+};
+
+/* - MSIOF3 ----------------------------------------------------------------- */
+static const unsigned int msiof3_clk_pins[] = {
+       /* MSIOF3_SCK */
+       RCAR_GP_PIN(0, 3),
+};
+static const unsigned int msiof3_clk_mux[] = {
+       MSIOF3_SCK_MARK,
+};
+static const unsigned int msiof3_sync_pins[] = {
+       /* MSIOF3_SYNC */
+       RCAR_GP_PIN(0, 6),
+};
+static const unsigned int msiof3_sync_mux[] = {
+       MSIOF3_SYNC_MARK,
+};
+static const unsigned int msiof3_ss1_pins[] = {
+       /* MSIOF3_SS1 */
+       RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof3_ss1_mux[] = {
+       MSIOF3_SS1_MARK,
+};
+static const unsigned int msiof3_ss2_pins[] = {
+       /* MSIOF3_SS2 */
+       RCAR_GP_PIN(0, 2),
+};
+static const unsigned int msiof3_ss2_mux[] = {
+       MSIOF3_SS2_MARK,
+};
+static const unsigned int msiof3_txd_pins[] = {
+       /* MSIOF3_TXD */
+       RCAR_GP_PIN(0, 4),
+};
+static const unsigned int msiof3_txd_mux[] = {
+       MSIOF3_TXD_MARK,
+};
+static const unsigned int msiof3_rxd_pins[] = {
+       /* MSIOF3_RXD */
+       RCAR_GP_PIN(0, 5),
+};
+static const unsigned int msiof3_rxd_mux[] = {
+       MSIOF3_RXD_MARK,
+};
+
+/* - MSIOF4 ----------------------------------------------------------------- */
+static const unsigned int msiof4_clk_pins[] = {
+       /* MSIOF4_SCK */
+       RCAR_GP_PIN(1, 25),
+};
+static const unsigned int msiof4_clk_mux[] = {
+       MSIOF4_SCK_MARK,
+};
+static const unsigned int msiof4_sync_pins[] = {
+       /* MSIOF4_SYNC */
+       RCAR_GP_PIN(1, 28),
+};
+static const unsigned int msiof4_sync_mux[] = {
+       MSIOF4_SYNC_MARK,
+};
+static const unsigned int msiof4_ss1_pins[] = {
+       /* MSIOF4_SS1 */
+       RCAR_GP_PIN(1, 23),
+};
+static const unsigned int msiof4_ss1_mux[] = {
+       MSIOF4_SS1_MARK,
+};
+static const unsigned int msiof4_ss2_pins[] = {
+       /* MSIOF4_SS2 */
+       RCAR_GP_PIN(1, 24),
+};
+static const unsigned int msiof4_ss2_mux[] = {
+       MSIOF4_SS2_MARK,
+};
+static const unsigned int msiof4_txd_pins[] = {
+       /* MSIOF4_TXD */
+       RCAR_GP_PIN(1, 26),
+};
+static const unsigned int msiof4_txd_mux[] = {
+       MSIOF4_TXD_MARK,
+};
+static const unsigned int msiof4_rxd_pins[] = {
+       /* MSIOF4_RXD */
+       RCAR_GP_PIN(1, 27),
+};
+static const unsigned int msiof4_rxd_mux[] = {
+       MSIOF4_RXD_MARK,
+};
+
+/* - MSIOF5 ----------------------------------------------------------------- */
+static const unsigned int msiof5_clk_pins[] = {
+       /* MSIOF5_SCK */
+       RCAR_GP_PIN(0, 11),
+};
+static const unsigned int msiof5_clk_mux[] = {
+       MSIOF5_SCK_MARK,
+};
+static const unsigned int msiof5_sync_pins[] = {
+       /* MSIOF5_SYNC */
+       RCAR_GP_PIN(0, 9),
+};
+static const unsigned int msiof5_sync_mux[] = {
+       MSIOF5_SYNC_MARK,
+};
+static const unsigned int msiof5_ss1_pins[] = {
+       /* MSIOF5_SS1 */
+       RCAR_GP_PIN(0, 8),
+};
+static const unsigned int msiof5_ss1_mux[] = {
+       MSIOF5_SS1_MARK,
+};
+static const unsigned int msiof5_ss2_pins[] = {
+       /* MSIOF5_SS2 */
+       RCAR_GP_PIN(0, 7),
+};
+static const unsigned int msiof5_ss2_mux[] = {
+       MSIOF5_SS2_MARK,
+};
+static const unsigned int msiof5_txd_pins[] = {
+       /* MSIOF5_TXD */
+       RCAR_GP_PIN(0, 10),
+};
+static const unsigned int msiof5_txd_mux[] = {
+       MSIOF5_TXD_MARK,
+};
+static const unsigned int msiof5_rxd_pins[] = {
+       /* MSIOF5_RXD */
+       RCAR_GP_PIN(0, 12),
+};
+static const unsigned int msiof5_rxd_mux[] = {
+       MSIOF5_RXD_MARK,
+};
+
+/* - PCIE ------------------------------------------------------------------- */
+static const unsigned int pcie0_clkreq_n_pins[] = {
+       /* PCIE0_CLKREQ_N */
+       RCAR_GP_PIN(4, 21),
+};
+
+static const unsigned int pcie0_clkreq_n_mux[] = {
+       PCIE0_CLKREQ_N_MARK,
+};
+
+static const unsigned int pcie1_clkreq_n_pins[] = {
+       /* PCIE1_CLKREQ_N */
+       RCAR_GP_PIN(4, 22),
+};
+
+static const unsigned int pcie1_clkreq_n_mux[] = {
+       PCIE1_CLKREQ_N_MARK,
+};
+
+/* - PWM0_A ------------------------------------------------------------------- */
+static const unsigned int pwm0_a_pins[] = {
+       /* PWM0_A */
+       RCAR_GP_PIN(1, 15),
+};
+static const unsigned int pwm0_a_mux[] = {
+       PWM0_A_MARK,
+};
+
+/* - PWM1_A ------------------------------------------------------------------- */
+static const unsigned int pwm1_a_pins[] = {
+       /* PWM1_A */
+       RCAR_GP_PIN(3, 13),
+};
+static const unsigned int pwm1_a_mux[] = {
+       PWM1_A_MARK,
+};
+
+/* - PWM1_B ------------------------------------------------------------------- */
+static const unsigned int pwm1_b_pins[] = {
+       /* PWM1_B */
+       RCAR_GP_PIN(2, 13),
+};
+static const unsigned int pwm1_b_mux[] = {
+       PWM1_B_MARK,
+};
+
+/* - PWM2_B ------------------------------------------------------------------- */
+static const unsigned int pwm2_b_pins[] = {
+       /* PWM2_B */
+       RCAR_GP_PIN(2, 14),
+};
+static const unsigned int pwm2_b_mux[] = {
+       PWM2_B_MARK,
+};
+
+/* - PWM3_A ------------------------------------------------------------------- */
+static const unsigned int pwm3_a_pins[] = {
+       /* PWM3_A */
+       RCAR_GP_PIN(1, 22),
+};
+static const unsigned int pwm3_a_mux[] = {
+       PWM3_A_MARK,
+};
+
+/* - PWM3_B ------------------------------------------------------------------- */
+static const unsigned int pwm3_b_pins[] = {
+       /* PWM3_B */
+       RCAR_GP_PIN(2, 15),
+};
+static const unsigned int pwm3_b_mux[] = {
+       PWM3_B_MARK,
+};
+
+/* - PWM4 ------------------------------------------------------------------- */
+static const unsigned int pwm4_pins[] = {
+       /* PWM4 */
+       RCAR_GP_PIN(2, 16),
+};
+static const unsigned int pwm4_mux[] = {
+       PWM4_MARK,
+};
+
+/* - PWM5 ------------------------------------------------------------------- */
+static const unsigned int pwm5_pins[] = {
+       /* PWM5 */
+       RCAR_GP_PIN(2, 17),
+};
+static const unsigned int pwm5_mux[] = {
+       PWM5_MARK,
+};
+
+/* - PWM6 ------------------------------------------------------------------- */
+static const unsigned int pwm6_pins[] = {
+       /* PWM6 */
+       RCAR_GP_PIN(2, 18),
+};
+static const unsigned int pwm6_mux[] = {
+       PWM6_MARK,
+};
+
+/* - PWM7 ------------------------------------------------------------------- */
+static const unsigned int pwm7_pins[] = {
+       /* PWM7 */
+       RCAR_GP_PIN(2, 19),
+};
+static const unsigned int pwm7_mux[] = {
+       PWM7_MARK,
+};
+
+/* - PWM8_A ------------------------------------------------------------------- */
+static const unsigned int pwm8_a_pins[] = {
+       /* PWM8_A */
+       RCAR_GP_PIN(1, 13),
+};
+static const unsigned int pwm8_a_mux[] = {
+       PWM8_A_MARK,
+};
+
+/* - PWM9_A ------------------------------------------------------------------- */
+static const unsigned int pwm9_a_pins[] = {
+       /* PWM9_A */
+       RCAR_GP_PIN(1, 14),
+};
+static const unsigned int pwm9_a_mux[] = {
+       PWM9_A_MARK,
+};
+
+/* - QSPI0 ------------------------------------------------------------------ */
+static const unsigned int qspi0_ctrl_pins[] = {
+       /* SPCLK, SSL */
+       RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 15),
+};
+static const unsigned int qspi0_ctrl_mux[] = {
+       QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
+};
+static const unsigned int qspi0_data_pins[] = {
+       /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+       RCAR_GP_PIN(3, 19), RCAR_GP_PIN(3, 18),
+       RCAR_GP_PIN(3, 17), RCAR_GP_PIN(3, 16),
+};
+static const unsigned int qspi0_data_mux[] = {
+       QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
+       QSPI0_IO2_MARK, QSPI0_IO3_MARK
+};
+
+/* - QSPI1 ------------------------------------------------------------------ */
+static const unsigned int qspi1_ctrl_pins[] = {
+       /* SPCLK, SSL */
+       RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 25),
+};
+static const unsigned int qspi1_ctrl_mux[] = {
+       QSPI1_SPCLK_MARK, QSPI1_SSL_MARK,
+};
+static const unsigned int qspi1_data_pins[] = {
+       /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+       RCAR_GP_PIN(3, 21), RCAR_GP_PIN(3, 23),
+       RCAR_GP_PIN(3, 24), RCAR_GP_PIN(3, 26),
+};
+static const unsigned int qspi1_data_mux[] = {
+       QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
+       QSPI1_IO2_MARK, QSPI1_IO3_MARK
+};
+
+/* - SCIF0 ------------------------------------------------------------------ */
+static const unsigned int scif0_data_pins[] = {
+       /* RX0, TX0 */
+       RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 12),
+};
+static const unsigned int scif0_data_mux[] = {
+       RX0_MARK, TX0_MARK,
+};
+static const unsigned int scif0_clk_pins[] = {
+       /* SCK0 */
+       RCAR_GP_PIN(1, 15),
+};
+static const unsigned int scif0_clk_mux[] = {
+       SCK0_MARK,
+};
+static const unsigned int scif0_ctrl_pins[] = {
+       /* RTS0_N, CTS0_N */
+       RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13),
+};
+static const unsigned int scif0_ctrl_mux[] = {
+       RTS0_N_MARK, CTS0_N_MARK,
+};
+
+/* - SCIF1 ------------------------------------------------------------------ */
+static const unsigned int scif1_data_pins[] = {
+       /* RX1, TX1 */
+       RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14),
+};
+static const unsigned int scif1_data_mux[] = {
+       RX1_MARK, TX1_MARK,
+};
+static const unsigned int scif1_clk_pins[] = {
+       /* SCK1 */
+       RCAR_GP_PIN(0, 18),
+};
+static const unsigned int scif1_clk_mux[] = {
+       SCK1_MARK,
+};
+static const unsigned int scif1_ctrl_pins[] = {
+       /* RTS1_N, CTS1_N */
+       RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16),
+};
+static const unsigned int scif1_ctrl_mux[] = {
+       RTS1_N_MARK, CTS1_N_MARK,
+};
+
+/* - SCIF1_X ------------------------------------------------------------------ */
+static const unsigned int scif1_data_x_pins[] = {
+       /* RX1_X, TX1_X */
+       RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int scif1_data_x_mux[] = {
+       RX1_X_MARK, TX1_X_MARK,
+};
+static const unsigned int scif1_clk_x_pins[] = {
+       /* SCK1_X */
+       RCAR_GP_PIN(1, 10),
+};
+static const unsigned int scif1_clk_x_mux[] = {
+       SCK1_X_MARK,
+};
+static const unsigned int scif1_ctrl_x_pins[] = {
+       /* RTS1_N_X, CTS1_N_X */
+       RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 8),
+};
+static const unsigned int scif1_ctrl_x_mux[] = {
+       RTS1_N_X_MARK, CTS1_N_X_MARK,
+};
+
+/* - SCIF3 ------------------------------------------------------------------ */
+static const unsigned int scif3_data_pins[] = {
+       /* RX3, TX3 */
+       RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 0),
+};
+static const unsigned int scif3_data_mux[] = {
+       RX3_MARK, TX3_MARK,
+};
+static const unsigned int scif3_clk_pins[] = {
+       /* SCK3 */
+       RCAR_GP_PIN(1, 4),
+};
+static const unsigned int scif3_clk_mux[] = {
+       SCK3_MARK,
+};
+static const unsigned int scif3_ctrl_pins[] = {
+       /* RTS3_N, CTS3_N */
+       RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3),
+};
+static const unsigned int scif3_ctrl_mux[] = {
+       RTS3_N_MARK, CTS3_N_MARK,
+};
+
+/* - SCIF3_A ------------------------------------------------------------------ */
+static const unsigned int scif3_data_a_pins[] = {
+       /* RX3_A, TX3_A */
+       RCAR_GP_PIN(1, 27), RCAR_GP_PIN(1, 28),
+};
+static const unsigned int scif3_data_a_mux[] = {
+       RX3_A_MARK, TX3_A_MARK,
+};
+static const unsigned int scif3_clk_a_pins[] = {
+       /* SCK3_A */
+       RCAR_GP_PIN(1, 24),
+};
+static const unsigned int scif3_clk_a_mux[] = {
+       SCK3_A_MARK,
+};
+static const unsigned int scif3_ctrl_a_pins[] = {
+       /* RTS3_N_A, CTS3_N_A */
+       RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25),
+};
+static const unsigned int scif3_ctrl_a_mux[] = {
+       RTS3_N_A_MARK, CTS3_N_A_MARK,
+};
+
+/* - SCIF4 ------------------------------------------------------------------ */
+static const unsigned int scif4_data_pins[] = {
+       /* RX4, TX4 */
+       RCAR_GP_PIN(8, 13), RCAR_GP_PIN(8, 12),
+};
+static const unsigned int scif4_data_mux[] = {
+       RX4_MARK, TX4_MARK,
+};
+static const unsigned int scif4_clk_pins[] = {
+       /* SCK4 */
+       RCAR_GP_PIN(8, 8),
+};
+static const unsigned int scif4_clk_mux[] = {
+       SCK4_MARK,
+};
+static const unsigned int scif4_ctrl_pins[] = {
+       /* RTS4_N, CTS4_N */
+       RCAR_GP_PIN(8, 10), RCAR_GP_PIN(8, 9),
+};
+static const unsigned int scif4_ctrl_mux[] = {
+       RTS4_N_MARK, CTS4_N_MARK,
+};
+
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+       /* SCIF_CLK */
+       RCAR_GP_PIN(1, 17),
+};
+static const unsigned int scif_clk_mux[] = {
+       SCIF_CLK_MARK,
+};
+
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+       /* TPU0TO0 */
+       RCAR_GP_PIN(2, 8),
+};
+static const unsigned int tpu_to0_mux[] = {
+       TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+       /* TPU0TO1 */
+       RCAR_GP_PIN(2, 7),
+};
+static const unsigned int tpu_to1_mux[] = {
+       TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+       /* TPU0TO2 */
+       RCAR_GP_PIN(2, 12),
+};
+static const unsigned int tpu_to2_mux[] = {
+       TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+       /* TPU0TO3 */
+       RCAR_GP_PIN(2, 13),
+};
+static const unsigned int tpu_to3_mux[] = {
+       TPU0TO3_MARK,
+};
+
+/* - TPU_A ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_a_pins[] = {
+       /* TPU0TO0_A */
+       RCAR_GP_PIN(1, 25),
+};
+static const unsigned int tpu_to0_a_mux[] = {
+       TPU0TO0_A_MARK,
+};
+static const unsigned int tpu_to1_a_pins[] = {
+       /* TPU0TO1_A */
+       RCAR_GP_PIN(1, 26),
+};
+static const unsigned int tpu_to1_a_mux[] = {
+       TPU0TO1_A_MARK,
+};
+static const unsigned int tpu_to2_a_pins[] = {
+       /* TPU0TO2_A */
+       RCAR_GP_PIN(2, 0),
+};
+static const unsigned int tpu_to2_a_mux[] = {
+       TPU0TO2_A_MARK,
+};
+static const unsigned int tpu_to3_a_pins[] = {
+       /* TPU0TO3_A */
+       RCAR_GP_PIN(2, 1),
+};
+static const unsigned int tpu_to3_a_mux[] = {
+       TPU0TO3_A_MARK,
+};
+
+/* - TSN0 ------------------------------------------------ */
+static const unsigned int tsn0_link_pins[] = {
+       /* TSN0_LINK */
+       RCAR_GP_PIN(4, 4),
+};
+static const unsigned int tsn0_link_mux[] = {
+       TSN0_LINK_MARK,
+};
+static const unsigned int tsn0_phy_int_pins[] = {
+       /* TSN0_PHY_INT */
+       RCAR_GP_PIN(4, 3),
+};
+static const unsigned int tsn0_phy_int_mux[] = {
+       TSN0_PHY_INT_MARK,
+};
+static const unsigned int tsn0_mdio_pins[] = {
+       /* TSN0_MDC, TSN0_MDIO */
+       RCAR_GP_PIN(4, 1), RCAR_GP_PIN(4, 0),
+};
+static const unsigned int tsn0_mdio_mux[] = {
+       TSN0_MDC_MARK, TSN0_MDIO_MARK,
+};
+static const unsigned int tsn0_rgmii_pins[] = {
+       /*
+        * TSN0_TX_CTL, TSN0_TXC, TSN0_TD0, TSN0_TD1, TSN0_TD2, TSN0_TD3,
+        * TSN0_RX_CTL, TSN0_RXC, TSN0_RD0, TSN0_RD1, TSN0_RD2, TSN0_RD3,
+        */
+       RCAR_GP_PIN(4,  9), RCAR_GP_PIN(4, 12),
+       RCAR_GP_PIN(4, 15), RCAR_GP_PIN(4, 14),
+       RCAR_GP_PIN(4, 19), RCAR_GP_PIN(4, 18),
+       RCAR_GP_PIN(4,  7), RCAR_GP_PIN(4, 11),
+       RCAR_GP_PIN(4, 10), RCAR_GP_PIN(4, 13),
+       RCAR_GP_PIN(4, 17), RCAR_GP_PIN(4, 16),
+};
+static const unsigned int tsn0_rgmii_mux[] = {
+       TSN0_TX_CTL_MARK,       TSN0_TXC_MARK,
+       TSN0_TD0_MARK,          TSN0_TD1_MARK,
+       TSN0_TD2_MARK,          TSN0_TD3_MARK,
+       TSN0_RX_CTL_MARK,       TSN0_RXC_MARK,
+       TSN0_RD0_MARK,          TSN0_RD1_MARK,
+       TSN0_RD2_MARK,          TSN0_RD3_MARK,
+};
+static const unsigned int tsn0_txcrefclk_pins[] = {
+       /* TSN0_TXCREFCLK */
+       RCAR_GP_PIN(4, 20),
+};
+static const unsigned int tsn0_txcrefclk_mux[] = {
+       TSN0_TXCREFCLK_MARK,
+};
+static const unsigned int tsn0_avtp_pps_pins[] = {
+       /* TSN0_AVTP_PPS0, TSN0_AVTP_PPS1 */
+       RCAR_GP_PIN(4, 8), RCAR_GP_PIN(4, 2),
+};
+static const unsigned int tsn0_avtp_pps_mux[] = {
+       TSN0_AVTP_PPS0_MARK, TSN0_AVTP_PPS1_MARK,
+};
+static const unsigned int tsn0_avtp_capture_pins[] = {
+       /* TSN0_AVTP_CAPTURE */
+       RCAR_GP_PIN(4, 6),
+};
+static const unsigned int tsn0_avtp_capture_mux[] = {
+       TSN0_AVTP_CAPTURE_MARK,
+};
+static const unsigned int tsn0_avtp_match_pins[] = {
+       /* TSN0_AVTP_MATCH */
+       RCAR_GP_PIN(4, 5),
+};
+static const unsigned int tsn0_avtp_match_mux[] = {
+       TSN0_AVTP_MATCH_MARK,
+};
+
+static const struct sh_pfc_pin_group pinmux_groups[] = {
+       SH_PFC_PIN_GROUP(avb0_link),
+       SH_PFC_PIN_GROUP(avb0_magic),
+       SH_PFC_PIN_GROUP(avb0_phy_int),
+       SH_PFC_PIN_GROUP(avb0_mdio),
+       SH_PFC_PIN_GROUP(avb0_rgmii),
+       SH_PFC_PIN_GROUP(avb0_txcrefclk),
+       SH_PFC_PIN_GROUP(avb0_avtp_pps),
+       SH_PFC_PIN_GROUP(avb0_avtp_capture),
+       SH_PFC_PIN_GROUP(avb0_avtp_match),
+
+       SH_PFC_PIN_GROUP(avb1_link),
+       SH_PFC_PIN_GROUP(avb1_magic),
+       SH_PFC_PIN_GROUP(avb1_phy_int),
+       SH_PFC_PIN_GROUP(avb1_mdio),
+       SH_PFC_PIN_GROUP(avb1_rgmii),
+       SH_PFC_PIN_GROUP(avb1_txcrefclk),
+       SH_PFC_PIN_GROUP(avb1_avtp_pps),
+       SH_PFC_PIN_GROUP(avb1_avtp_capture),
+       SH_PFC_PIN_GROUP(avb1_avtp_match),
+
+       SH_PFC_PIN_GROUP(avb2_link),
+       SH_PFC_PIN_GROUP(avb2_magic),
+       SH_PFC_PIN_GROUP(avb2_phy_int),
+       SH_PFC_PIN_GROUP(avb2_mdio),
+       SH_PFC_PIN_GROUP(avb2_rgmii),
+       SH_PFC_PIN_GROUP(avb2_txcrefclk),
+       SH_PFC_PIN_GROUP(avb2_avtp_pps),
+       SH_PFC_PIN_GROUP(avb2_avtp_capture),
+       SH_PFC_PIN_GROUP(avb2_avtp_match),
+
+       SH_PFC_PIN_GROUP(canfd0_data),
+       SH_PFC_PIN_GROUP(canfd1_data),
+       SH_PFC_PIN_GROUP(canfd2_data),
+       SH_PFC_PIN_GROUP(canfd3_data),
+       SH_PFC_PIN_GROUP(canfd4_data),
+       SH_PFC_PIN_GROUP(canfd5_data),          /* suffix might be updated */
+       SH_PFC_PIN_GROUP(canfd5_data_b),        /* suffix might be updated */
+       SH_PFC_PIN_GROUP(canfd6_data),
+       SH_PFC_PIN_GROUP(canfd7_data),
+       SH_PFC_PIN_GROUP(can_clk),
+
+       SH_PFC_PIN_GROUP(hscif0_data),
+       SH_PFC_PIN_GROUP(hscif0_clk),
+       SH_PFC_PIN_GROUP(hscif0_ctrl),
+       SH_PFC_PIN_GROUP(hscif1_data),          /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif1_clk),           /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif1_ctrl),          /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif1_data_x),        /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif1_clk_x),         /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif1_ctrl_x),        /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif2_data),
+       SH_PFC_PIN_GROUP(hscif2_clk),
+       SH_PFC_PIN_GROUP(hscif2_ctrl),
+       SH_PFC_PIN_GROUP(hscif3_data),          /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif3_clk),           /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif3_ctrl),          /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif3_data_a),        /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif3_clk_a),         /* suffix might be updated */
+       SH_PFC_PIN_GROUP(hscif3_ctrl_a),        /* suffix might be updated */
+
+       SH_PFC_PIN_GROUP(i2c0),
+       SH_PFC_PIN_GROUP(i2c1),
+       SH_PFC_PIN_GROUP(i2c2),
+       SH_PFC_PIN_GROUP(i2c3),
+       SH_PFC_PIN_GROUP(i2c4),
+       SH_PFC_PIN_GROUP(i2c5),
+
+       BUS_DATA_PIN_GROUP(mmc_data, 1),
+       BUS_DATA_PIN_GROUP(mmc_data, 4),
+       BUS_DATA_PIN_GROUP(mmc_data, 8),
+       SH_PFC_PIN_GROUP(mmc_ctrl),
+       SH_PFC_PIN_GROUP(mmc_cd),
+       SH_PFC_PIN_GROUP(mmc_wp),
+       SH_PFC_PIN_GROUP(mmc_ds),
+
+       SH_PFC_PIN_GROUP(msiof0_clk),
+       SH_PFC_PIN_GROUP(msiof0_sync),
+       SH_PFC_PIN_GROUP(msiof0_ss1),
+       SH_PFC_PIN_GROUP(msiof0_ss2),
+       SH_PFC_PIN_GROUP(msiof0_txd),
+       SH_PFC_PIN_GROUP(msiof0_rxd),
+
+       SH_PFC_PIN_GROUP(msiof1_clk),
+       SH_PFC_PIN_GROUP(msiof1_sync),
+       SH_PFC_PIN_GROUP(msiof1_ss1),
+       SH_PFC_PIN_GROUP(msiof1_ss2),
+       SH_PFC_PIN_GROUP(msiof1_txd),
+       SH_PFC_PIN_GROUP(msiof1_rxd),
+
+       SH_PFC_PIN_GROUP(msiof2_clk),
+       SH_PFC_PIN_GROUP(msiof2_sync),
+       SH_PFC_PIN_GROUP(msiof2_ss1),
+       SH_PFC_PIN_GROUP(msiof2_ss2),
+       SH_PFC_PIN_GROUP(msiof2_txd),
+       SH_PFC_PIN_GROUP(msiof2_rxd),
+
+       SH_PFC_PIN_GROUP(msiof3_clk),
+       SH_PFC_PIN_GROUP(msiof3_sync),
+       SH_PFC_PIN_GROUP(msiof3_ss1),
+       SH_PFC_PIN_GROUP(msiof3_ss2),
+       SH_PFC_PIN_GROUP(msiof3_txd),
+       SH_PFC_PIN_GROUP(msiof3_rxd),
+
+       SH_PFC_PIN_GROUP(msiof4_clk),
+       SH_PFC_PIN_GROUP(msiof4_sync),
+       SH_PFC_PIN_GROUP(msiof4_ss1),
+       SH_PFC_PIN_GROUP(msiof4_ss2),
+       SH_PFC_PIN_GROUP(msiof4_txd),
+       SH_PFC_PIN_GROUP(msiof4_rxd),
+
+       SH_PFC_PIN_GROUP(msiof5_clk),
+       SH_PFC_PIN_GROUP(msiof5_sync),
+       SH_PFC_PIN_GROUP(msiof5_ss1),
+       SH_PFC_PIN_GROUP(msiof5_ss2),
+       SH_PFC_PIN_GROUP(msiof5_txd),
+       SH_PFC_PIN_GROUP(msiof5_rxd),
+
+       SH_PFC_PIN_GROUP(pcie0_clkreq_n),
+       SH_PFC_PIN_GROUP(pcie1_clkreq_n),
+
+       SH_PFC_PIN_GROUP(pwm0_a),               /* suffix might be updated */
+       SH_PFC_PIN_GROUP(pwm1_a),
+       SH_PFC_PIN_GROUP(pwm1_b),
+       SH_PFC_PIN_GROUP(pwm2_b),               /* suffix might be updated */
+       SH_PFC_PIN_GROUP(pwm3_a),
+       SH_PFC_PIN_GROUP(pwm3_b),
+       SH_PFC_PIN_GROUP(pwm4),
+       SH_PFC_PIN_GROUP(pwm5),
+       SH_PFC_PIN_GROUP(pwm6),
+       SH_PFC_PIN_GROUP(pwm7),
+       SH_PFC_PIN_GROUP(pwm8_a),               /* suffix might be updated */
+       SH_PFC_PIN_GROUP(pwm9_a),               /* suffix might be updated */
+
+       SH_PFC_PIN_GROUP(qspi0_ctrl),
+       BUS_DATA_PIN_GROUP(qspi0_data, 2),
+       BUS_DATA_PIN_GROUP(qspi0_data, 4),
+       SH_PFC_PIN_GROUP(qspi1_ctrl),
+       BUS_DATA_PIN_GROUP(qspi1_data, 2),
+       BUS_DATA_PIN_GROUP(qspi1_data, 4),
+
+       SH_PFC_PIN_GROUP(scif0_data),
+       SH_PFC_PIN_GROUP(scif0_clk),
+       SH_PFC_PIN_GROUP(scif0_ctrl),
+       SH_PFC_PIN_GROUP(scif1_data),           /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif1_clk),            /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif1_ctrl),           /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif1_data_x),         /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif1_clk_x),          /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif1_ctrl_x),         /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif3_data),           /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif3_clk),            /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif3_ctrl),           /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif3_data_a),         /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif3_clk_a),          /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif3_ctrl_a),         /* suffix might be updated */
+       SH_PFC_PIN_GROUP(scif4_data),
+       SH_PFC_PIN_GROUP(scif4_clk),
+       SH_PFC_PIN_GROUP(scif4_ctrl),
+       SH_PFC_PIN_GROUP(scif_clk),
+
+       SH_PFC_PIN_GROUP(tpu_to0),              /* suffix might be updated */
+       SH_PFC_PIN_GROUP(tpu_to0_a),            /* suffix might be updated */
+       SH_PFC_PIN_GROUP(tpu_to1),              /* suffix might be updated */
+       SH_PFC_PIN_GROUP(tpu_to1_a),            /* suffix might be updated */
+       SH_PFC_PIN_GROUP(tpu_to2),              /* suffix might be updated */
+       SH_PFC_PIN_GROUP(tpu_to2_a),            /* suffix might be updated */
+       SH_PFC_PIN_GROUP(tpu_to3),              /* suffix might be updated */
+       SH_PFC_PIN_GROUP(tpu_to3_a),            /* suffix might be updated */
+
+       SH_PFC_PIN_GROUP(tsn0_link),
+       SH_PFC_PIN_GROUP(tsn0_phy_int),
+       SH_PFC_PIN_GROUP(tsn0_mdio),
+       SH_PFC_PIN_GROUP(tsn0_rgmii),
+       SH_PFC_PIN_GROUP(tsn0_txcrefclk),
+       SH_PFC_PIN_GROUP(tsn0_avtp_pps),
+       SH_PFC_PIN_GROUP(tsn0_avtp_capture),
+       SH_PFC_PIN_GROUP(tsn0_avtp_match),
+};
+
+static const char * const avb0_groups[] = {
+       "avb0_link",
+       "avb0_magic",
+       "avb0_phy_int",
+       "avb0_mdio",
+       "avb0_rgmii",
+       "avb0_txcrefclk",
+       "avb0_avtp_pps",
+       "avb0_avtp_capture",
+       "avb0_avtp_match",
+};
+
+static const char * const avb1_groups[] = {
+       "avb1_link",
+       "avb1_magic",
+       "avb1_phy_int",
+       "avb1_mdio",
+       "avb1_rgmii",
+       "avb1_txcrefclk",
+       "avb1_avtp_pps",
+       "avb1_avtp_capture",
+       "avb1_avtp_match",
+};
+
+static const char * const avb2_groups[] = {
+       "avb2_link",
+       "avb2_magic",
+       "avb2_phy_int",
+       "avb2_mdio",
+       "avb2_rgmii",
+       "avb2_txcrefclk",
+       "avb2_avtp_pps",
+       "avb2_avtp_capture",
+       "avb2_avtp_match",
+};
+
+static const char * const canfd0_groups[] = {
+       "canfd0_data",
+};
+
+static const char * const canfd1_groups[] = {
+       "canfd1_data",
+};
+
+static const char * const canfd2_groups[] = {
+       "canfd2_data",
+};
+
+static const char * const canfd3_groups[] = {
+       "canfd3_data",
+};
+
+static const char * const canfd4_groups[] = {
+       "canfd4_data",
+};
+
+static const char * const canfd5_groups[] = {
+       /* suffix might be updated */
+       "canfd5_data",
+       "canfd5_data_b",
+};
+
+static const char * const canfd6_groups[] = {
+       "canfd6_data",
+};
+
+static const char * const canfd7_groups[] = {
+       "canfd7_data",
+};
+
+static const char * const can_clk_groups[] = {
+       "can_clk",
+};
+
+static const char * const hscif0_groups[] = {
+       "hscif0_data",
+       "hscif0_clk",
+       "hscif0_ctrl",
+};
+
+static const char * const hscif1_groups[] = {
+       /* suffix might be updated */
+       "hscif1_data",
+       "hscif1_clk",
+       "hscif1_ctrl",
+       "hscif1_data_x",
+       "hscif1_clk_x",
+       "hscif1_ctrl_x",
+};
+
+static const char * const hscif2_groups[] = {
+       "hscif2_data",
+       "hscif2_clk",
+       "hscif2_ctrl",
+};
+
+static const char * const hscif3_groups[] = {
+       /* suffix might be updated */
+       "hscif3_data",
+       "hscif3_clk",
+       "hscif3_ctrl",
+       "hscif3_data_a",
+       "hscif3_clk_a",
+       "hscif3_ctrl_a",
+};
+
+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 i2c4_groups[] = {
+       "i2c4",
+};
+
+static const char * const i2c5_groups[] = {
+       "i2c5",
+};
+
+static const char * const mmc_groups[] = {
+       "mmc_data1",
+       "mmc_data4",
+       "mmc_data8",
+       "mmc_ctrl",
+       "mmc_cd",
+       "mmc_wp",
+       "mmc_ds",
+};
+
+static const char * const msiof0_groups[] = {
+       "msiof0_clk",
+       "msiof0_sync",
+       "msiof0_ss1",
+       "msiof0_ss2",
+       "msiof0_txd",
+       "msiof0_rxd",
+};
+
+static const char * const msiof1_groups[] = {
+       "msiof1_clk",
+       "msiof1_sync",
+       "msiof1_ss1",
+       "msiof1_ss2",
+       "msiof1_txd",
+       "msiof1_rxd",
+};
+
+static const char * const msiof2_groups[] = {
+       "msiof2_clk",
+       "msiof2_sync",
+       "msiof2_ss1",
+       "msiof2_ss2",
+       "msiof2_txd",
+       "msiof2_rxd",
+};
+
+static const char * const msiof3_groups[] = {
+       "msiof3_clk",
+       "msiof3_sync",
+       "msiof3_ss1",
+       "msiof3_ss2",
+       "msiof3_txd",
+       "msiof3_rxd",
+};
+
+static const char * const msiof4_groups[] = {
+       "msiof4_clk",
+       "msiof4_sync",
+       "msiof4_ss1",
+       "msiof4_ss2",
+       "msiof4_txd",
+       "msiof4_rxd",
+};
+
+static const char * const msiof5_groups[] = {
+       "msiof5_clk",
+       "msiof5_sync",
+       "msiof5_ss1",
+       "msiof5_ss2",
+       "msiof5_txd",
+       "msiof5_rxd",
+};
+
+static const char * const pcie_groups[] = {
+       "pcie0_clkreq_n",
+       "pcie1_clkreq_n",
+};
+
+static const char * const pwm0_groups[] = {
+       /* suffix might be updated */
+       "pwm0_a",
+};
+
+static const char * const pwm1_groups[] = {
+       "pwm1_a",
+       "pwm1_b",
+};
+
+static const char * const pwm2_groups[] = {
+       /* suffix might be updated */
+       "pwm2_b",
+};
+
+static const char * const pwm3_groups[] = {
+       "pwm3_a",
+       "pwm3_b",
+};
+
+static const char * const pwm4_groups[] = {
+       "pwm4",
+};
+
+static const char * const pwm5_groups[] = {
+       "pwm5",
+};
+
+static const char * const pwm6_groups[] = {
+       "pwm6",
+};
+
+static const char * const pwm7_groups[] = {
+       "pwm7",
+};
+
+static const char * const pwm8_groups[] = {
+       /* suffix might be updated */
+       "pwm8_a",
+};
+
+static const char * const pwm9_groups[] = {
+       /* suffix might be updated */
+       "pwm9_a",
+};
+
+static const char * const qspi0_groups[] = {
+       "qspi0_ctrl",
+       "qspi0_data2",
+       "qspi0_data4",
+};
+
+static const char * const qspi1_groups[] = {
+       "qspi1_ctrl",
+       "qspi1_data2",
+       "qspi1_data4",
+};
+
+static const char * const scif0_groups[] = {
+       "scif0_data",
+       "scif0_clk",
+       "scif0_ctrl",
+};
+
+static const char * const scif1_groups[] = {
+       /* suffix might be updated */
+       "scif1_data",
+       "scif1_clk",
+       "scif1_ctrl",
+       "scif1_data_x",
+       "scif1_clk_x",
+       "scif1_ctrl_x",
+};
+
+static const char * const scif3_groups[] = {
+       /* suffix might be updated */
+       "scif3_data",
+       "scif3_clk",
+       "scif3_ctrl",
+       "scif3_data_a",
+       "scif3_clk_a",
+       "scif3_ctrl_a",
+};
+
+static const char * const scif4_groups[] = {
+       "scif4_data",
+       "scif4_clk",
+       "scif4_ctrl",
+};
+
+static const char * const scif_clk_groups[] = {
+       "scif_clk",
+};
+
+static const char * const tpu_groups[] = {
+       /* suffix might be updated */
+       "tpu_to0",
+       "tpu_to0_a",
+       "tpu_to1",
+       "tpu_to1_a",
+       "tpu_to2",
+       "tpu_to2_a",
+       "tpu_to3",
+       "tpu_to3_a",
+};
+
+static const char * const tsn0_groups[] = {
+       "tsn0_link",
+       "tsn0_phy_int",
+       "tsn0_mdio",
+       "tsn0_rgmii",
+       "tsn0_txcrefclk",
+       "tsn0_avtp_pps",
+       "tsn0_avtp_capture",
+       "tsn0_avtp_match",
+};
+
+static const struct sh_pfc_function pinmux_functions[] = {
+       SH_PFC_FUNCTION(avb0),
+       SH_PFC_FUNCTION(avb1),
+       SH_PFC_FUNCTION(avb2),
+
+       SH_PFC_FUNCTION(canfd0),
+       SH_PFC_FUNCTION(canfd1),
+       SH_PFC_FUNCTION(canfd2),
+       SH_PFC_FUNCTION(canfd3),
+       SH_PFC_FUNCTION(canfd4),
+       SH_PFC_FUNCTION(canfd5),
+       SH_PFC_FUNCTION(canfd6),
+       SH_PFC_FUNCTION(canfd7),
+       SH_PFC_FUNCTION(can_clk),
+
+       SH_PFC_FUNCTION(hscif0),
+       SH_PFC_FUNCTION(hscif1),
+       SH_PFC_FUNCTION(hscif2),
+       SH_PFC_FUNCTION(hscif3),
+
+       SH_PFC_FUNCTION(i2c0),
+       SH_PFC_FUNCTION(i2c1),
+       SH_PFC_FUNCTION(i2c2),
+       SH_PFC_FUNCTION(i2c3),
+       SH_PFC_FUNCTION(i2c4),
+       SH_PFC_FUNCTION(i2c5),
+
+       SH_PFC_FUNCTION(mmc),
+
+       SH_PFC_FUNCTION(msiof0),
+       SH_PFC_FUNCTION(msiof1),
+       SH_PFC_FUNCTION(msiof2),
+       SH_PFC_FUNCTION(msiof3),
+       SH_PFC_FUNCTION(msiof4),
+       SH_PFC_FUNCTION(msiof5),
+
+       SH_PFC_FUNCTION(pcie),
+
+       SH_PFC_FUNCTION(pwm0),
+       SH_PFC_FUNCTION(pwm1),
+       SH_PFC_FUNCTION(pwm2),
+       SH_PFC_FUNCTION(pwm3),
+       SH_PFC_FUNCTION(pwm4),
+       SH_PFC_FUNCTION(pwm5),
+       SH_PFC_FUNCTION(pwm6),
+       SH_PFC_FUNCTION(pwm7),
+       SH_PFC_FUNCTION(pwm8),
+       SH_PFC_FUNCTION(pwm9),
+
+       SH_PFC_FUNCTION(qspi0),
+       SH_PFC_FUNCTION(qspi1),
+
+       SH_PFC_FUNCTION(scif0),
+       SH_PFC_FUNCTION(scif1),
+       SH_PFC_FUNCTION(scif3),
+       SH_PFC_FUNCTION(scif4),
+       SH_PFC_FUNCTION(scif_clk),
+
+       SH_PFC_FUNCTION(tpu),
+
+       SH_PFC_FUNCTION(tsn0),
+};
+
+static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+#define F_(x, y)       FN_##y
+#define FM(x)          FN_##x
+       { PINMUX_CFG_REG_VAR("GPSR0", 0xE6050040, 32,
+                            GROUP(-13, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+                            GROUP(
+               /* GP0_31_19 RESERVED */
+               GP_0_18_FN,     GPSR0_18,
+               GP_0_17_FN,     GPSR0_17,
+               GP_0_16_FN,     GPSR0_16,
+               GP_0_15_FN,     GPSR0_15,
+               GP_0_14_FN,     GPSR0_14,
+               GP_0_13_FN,     GPSR0_13,
+               GP_0_12_FN,     GPSR0_12,
+               GP_0_11_FN,     GPSR0_11,
+               GP_0_10_FN,     GPSR0_10,
+               GP_0_9_FN,      GPSR0_9,
+               GP_0_8_FN,      GPSR0_8,
+               GP_0_7_FN,      GPSR0_7,
+               GP_0_6_FN,      GPSR0_6,
+               GP_0_5_FN,      GPSR0_5,
+               GP_0_4_FN,      GPSR0_4,
+               GP_0_3_FN,      GPSR0_3,
+               GP_0_2_FN,      GPSR0_2,
+               GP_0_1_FN,      GPSR0_1,
+               GP_0_0_FN,      GPSR0_0, ))
+       },
+       { PINMUX_CFG_REG("GPSR1", 0xE6050840, 32, 1, GROUP(
+               0, 0,
+               0, 0,
+               0, 0,
+               GP_1_28_FN,     GPSR1_28,
+               GP_1_27_FN,     GPSR1_27,
+               GP_1_26_FN,     GPSR1_26,
+               GP_1_25_FN,     GPSR1_25,
+               GP_1_24_FN,     GPSR1_24,
+               GP_1_23_FN,     GPSR1_23,
+               GP_1_22_FN,     GPSR1_22,
+               GP_1_21_FN,     GPSR1_21,
+               GP_1_20_FN,     GPSR1_20,
+               GP_1_19_FN,     GPSR1_19,
+               GP_1_18_FN,     GPSR1_18,
+               GP_1_17_FN,     GPSR1_17,
+               GP_1_16_FN,     GPSR1_16,
+               GP_1_15_FN,     GPSR1_15,
+               GP_1_14_FN,     GPSR1_14,
+               GP_1_13_FN,     GPSR1_13,
+               GP_1_12_FN,     GPSR1_12,
+               GP_1_11_FN,     GPSR1_11,
+               GP_1_10_FN,     GPSR1_10,
+               GP_1_9_FN,      GPSR1_9,
+               GP_1_8_FN,      GPSR1_8,
+               GP_1_7_FN,      GPSR1_7,
+               GP_1_6_FN,      GPSR1_6,
+               GP_1_5_FN,      GPSR1_5,
+               GP_1_4_FN,      GPSR1_4,
+               GP_1_3_FN,      GPSR1_3,
+               GP_1_2_FN,      GPSR1_2,
+               GP_1_1_FN,      GPSR1_1,
+               GP_1_0_FN,      GPSR1_0, ))
+       },
+       { PINMUX_CFG_REG_VAR("GPSR2", 0xE6058040, 32,
+                            GROUP(-12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+                            GROUP(
+               /* GP2_31_20 RESERVED */
+               GP_2_19_FN,     GPSR2_19,
+               GP_2_18_FN,     GPSR2_18,
+               GP_2_17_FN,     GPSR2_17,
+               GP_2_16_FN,     GPSR2_16,
+               GP_2_15_FN,     GPSR2_15,
+               GP_2_14_FN,     GPSR2_14,
+               GP_2_13_FN,     GPSR2_13,
+               GP_2_12_FN,     GPSR2_12,
+               GP_2_11_FN,     GPSR2_11,
+               GP_2_10_FN,     GPSR2_10,
+               GP_2_9_FN,      GPSR2_9,
+               GP_2_8_FN,      GPSR2_8,
+               GP_2_7_FN,      GPSR2_7,
+               GP_2_6_FN,      GPSR2_6,
+               GP_2_5_FN,      GPSR2_5,
+               GP_2_4_FN,      GPSR2_4,
+               GP_2_3_FN,      GPSR2_3,
+               GP_2_2_FN,      GPSR2_2,
+               GP_2_1_FN,      GPSR2_1,
+               GP_2_0_FN,      GPSR2_0, ))
+       },
+       { PINMUX_CFG_REG("GPSR3", 0xE6058840, 32, 1, GROUP(
+               0, 0,
+               0, 0,
+               GP_3_29_FN,     GPSR3_29,
+               GP_3_28_FN,     GPSR3_28,
+               GP_3_27_FN,     GPSR3_27,
+               GP_3_26_FN,     GPSR3_26,
+               GP_3_25_FN,     GPSR3_25,
+               GP_3_24_FN,     GPSR3_24,
+               GP_3_23_FN,     GPSR3_23,
+               GP_3_22_FN,     GPSR3_22,
+               GP_3_21_FN,     GPSR3_21,
+               GP_3_20_FN,     GPSR3_20,
+               GP_3_19_FN,     GPSR3_19,
+               GP_3_18_FN,     GPSR3_18,
+               GP_3_17_FN,     GPSR3_17,
+               GP_3_16_FN,     GPSR3_16,
+               GP_3_15_FN,     GPSR3_15,
+               GP_3_14_FN,     GPSR3_14,
+               GP_3_13_FN,     GPSR3_13,
+               GP_3_12_FN,     GPSR3_12,
+               GP_3_11_FN,     GPSR3_11,
+               GP_3_10_FN,     GPSR3_10,
+               GP_3_9_FN,      GPSR3_9,
+               GP_3_8_FN,      GPSR3_8,
+               GP_3_7_FN,      GPSR3_7,
+               GP_3_6_FN,      GPSR3_6,
+               GP_3_5_FN,      GPSR3_5,
+               GP_3_4_FN,      GPSR3_4,
+               GP_3_3_FN,      GPSR3_3,
+               GP_3_2_FN,      GPSR3_2,
+               GP_3_1_FN,      GPSR3_1,
+               GP_3_0_FN,      GPSR3_0, ))
+       },
+       { PINMUX_CFG_REG("GPSR4", 0xE6060040, 32, 1, GROUP(
+               0, 0,
+               0, 0,
+               0, 0,
+               0, 0,
+               0, 0,
+               0, 0,
+               0, 0,
+               GP_4_24_FN,     GPSR4_24,
+               GP_4_23_FN,     GPSR4_23,
+               GP_4_22_FN,     GPSR4_22,
+               GP_4_21_FN,     GPSR4_21,
+               GP_4_20_FN,     GPSR4_20,
+               GP_4_19_FN,     GPSR4_19,
+               GP_4_18_FN,     GPSR4_18,
+               GP_4_17_FN,     GPSR4_17,
+               GP_4_16_FN,     GPSR4_16,
+               GP_4_15_FN,     GPSR4_15,
+               GP_4_14_FN,     GPSR4_14,
+               GP_4_13_FN,     GPSR4_13,
+               GP_4_12_FN,     GPSR4_12,
+               GP_4_11_FN,     GPSR4_11,
+               GP_4_10_FN,     GPSR4_10,
+               GP_4_9_FN,      GPSR4_9,
+               GP_4_8_FN,      GPSR4_8,
+               GP_4_7_FN,      GPSR4_7,
+               GP_4_6_FN,      GPSR4_6,
+               GP_4_5_FN,      GPSR4_5,
+               GP_4_4_FN,      GPSR4_4,
+               GP_4_3_FN,      GPSR4_3,
+               GP_4_2_FN,      GPSR4_2,
+               GP_4_1_FN,      GPSR4_1,
+               GP_4_0_FN,      GPSR4_0, ))
+       },
+       { PINMUX_CFG_REG_VAR("GPSR5", 0xE6060840, 32,
+                            GROUP(-11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+                            GROUP(
+               /* GP5_31_21 RESERVED */
+               GP_5_20_FN,     GPSR5_20,
+               GP_5_19_FN,     GPSR5_19,
+               GP_5_18_FN,     GPSR5_18,
+               GP_5_17_FN,     GPSR5_17,
+               GP_5_16_FN,     GPSR5_16,
+               GP_5_15_FN,     GPSR5_15,
+               GP_5_14_FN,     GPSR5_14,
+               GP_5_13_FN,     GPSR5_13,
+               GP_5_12_FN,     GPSR5_12,
+               GP_5_11_FN,     GPSR5_11,
+               GP_5_10_FN,     GPSR5_10,
+               GP_5_9_FN,      GPSR5_9,
+               GP_5_8_FN,      GPSR5_8,
+               GP_5_7_FN,      GPSR5_7,
+               GP_5_6_FN,      GPSR5_6,
+               GP_5_5_FN,      GPSR5_5,
+               GP_5_4_FN,      GPSR5_4,
+               GP_5_3_FN,      GPSR5_3,
+               GP_5_2_FN,      GPSR5_2,
+               GP_5_1_FN,      GPSR5_1,
+               GP_5_0_FN,      GPSR5_0, ))
+       },
+       { PINMUX_CFG_REG_VAR("GPSR6", 0xE6061040, 32,
+                            GROUP(-11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+                            GROUP(
+               /* GP6_31_21 RESERVED */
+               GP_6_20_FN,     GPSR6_20,
+               GP_6_19_FN,     GPSR6_19,
+               GP_6_18_FN,     GPSR6_18,
+               GP_6_17_FN,     GPSR6_17,
+               GP_6_16_FN,     GPSR6_16,
+               GP_6_15_FN,     GPSR6_15,
+               GP_6_14_FN,     GPSR6_14,
+               GP_6_13_FN,     GPSR6_13,
+               GP_6_12_FN,     GPSR6_12,
+               GP_6_11_FN,     GPSR6_11,
+               GP_6_10_FN,     GPSR6_10,
+               GP_6_9_FN,      GPSR6_9,
+               GP_6_8_FN,      GPSR6_8,
+               GP_6_7_FN,      GPSR6_7,
+               GP_6_6_FN,      GPSR6_6,
+               GP_6_5_FN,      GPSR6_5,
+               GP_6_4_FN,      GPSR6_4,
+               GP_6_3_FN,      GPSR6_3,
+               GP_6_2_FN,      GPSR6_2,
+               GP_6_1_FN,      GPSR6_1,
+               GP_6_0_FN,      GPSR6_0, ))
+       },
+       { PINMUX_CFG_REG_VAR("GPSR7", 0xE6061840, 32,
+                            GROUP(-11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+                            GROUP(
+               /* GP7_31_21 RESERVED */
+               GP_7_20_FN,     GPSR7_20,
+               GP_7_19_FN,     GPSR7_19,
+               GP_7_18_FN,     GPSR7_18,
+               GP_7_17_FN,     GPSR7_17,
+               GP_7_16_FN,     GPSR7_16,
+               GP_7_15_FN,     GPSR7_15,
+               GP_7_14_FN,     GPSR7_14,
+               GP_7_13_FN,     GPSR7_13,
+               GP_7_12_FN,     GPSR7_12,
+               GP_7_11_FN,     GPSR7_11,
+               GP_7_10_FN,     GPSR7_10,
+               GP_7_9_FN,      GPSR7_9,
+               GP_7_8_FN,      GPSR7_8,
+               GP_7_7_FN,      GPSR7_7,
+               GP_7_6_FN,      GPSR7_6,
+               GP_7_5_FN,      GPSR7_5,
+               GP_7_4_FN,      GPSR7_4,
+               GP_7_3_FN,      GPSR7_3,
+               GP_7_2_FN,      GPSR7_2,
+               GP_7_1_FN,      GPSR7_1,
+               GP_7_0_FN,      GPSR7_0, ))
+       },
+       { PINMUX_CFG_REG_VAR("GPSR8", 0xE6068040, 32,
+                            GROUP(-18, 1, 1, 1, 1,
+                                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+                            GROUP(
+               /* GP8_31_14 RESERVED */
+               GP_8_13_FN,     GPSR8_13,
+               GP_8_12_FN,     GPSR8_12,
+               GP_8_11_FN,     GPSR8_11,
+               GP_8_10_FN,     GPSR8_10,
+               GP_8_9_FN,      GPSR8_9,
+               GP_8_8_FN,      GPSR8_8,
+               GP_8_7_FN,      GPSR8_7,
+               GP_8_6_FN,      GPSR8_6,
+               GP_8_5_FN,      GPSR8_5,
+               GP_8_4_FN,      GPSR8_4,
+               GP_8_3_FN,      GPSR8_3,
+               GP_8_2_FN,      GPSR8_2,
+               GP_8_1_FN,      GPSR8_1,
+               GP_8_0_FN,      GPSR8_0, ))
+       },
+#undef F_
+#undef FM
+
+#define F_(x, y)       x,
+#define FM(x)          FN_##x,
+       { PINMUX_CFG_REG("IP0SR0", 0xE6050060, 32, 4, GROUP(
+               IP0SR0_31_28
+               IP0SR0_27_24
+               IP0SR0_23_20
+               IP0SR0_19_16
+               IP0SR0_15_12
+               IP0SR0_11_8
+               IP0SR0_7_4
+               IP0SR0_3_0))
+       },
+       { PINMUX_CFG_REG("IP1SR0", 0xE6050064, 32, 4, GROUP(
+               IP1SR0_31_28
+               IP1SR0_27_24
+               IP1SR0_23_20
+               IP1SR0_19_16
+               IP1SR0_15_12
+               IP1SR0_11_8
+               IP1SR0_7_4
+               IP1SR0_3_0))
+       },
+       { PINMUX_CFG_REG_VAR("IP2SR0", 0xE6050068, 32,
+                            GROUP(-20, 4, 4, 4),
+                            GROUP(
+               /* IP2SR0_31_12 RESERVED */
+               IP2SR0_11_8
+               IP2SR0_7_4
+               IP2SR0_3_0))
+       },
+       { PINMUX_CFG_REG("IP0SR1", 0xE6050860, 32, 4, GROUP(
+               IP0SR1_31_28
+               IP0SR1_27_24
+               IP0SR1_23_20
+               IP0SR1_19_16
+               IP0SR1_15_12
+               IP0SR1_11_8
+               IP0SR1_7_4
+               IP0SR1_3_0))
+       },
+       { PINMUX_CFG_REG("IP1SR1", 0xE6050864, 32, 4, GROUP(
+               IP1SR1_31_28
+               IP1SR1_27_24
+               IP1SR1_23_20
+               IP1SR1_19_16
+               IP1SR1_15_12
+               IP1SR1_11_8
+               IP1SR1_7_4
+               IP1SR1_3_0))
+       },
+       { PINMUX_CFG_REG("IP2SR1", 0xE6050868, 32, 4, GROUP(
+               IP2SR1_31_28
+               IP2SR1_27_24
+               IP2SR1_23_20
+               IP2SR1_19_16
+               IP2SR1_15_12
+               IP2SR1_11_8
+               IP2SR1_7_4
+               IP2SR1_3_0))
+       },
+       { PINMUX_CFG_REG_VAR("IP3SR1", 0xE605086C, 32,
+                            GROUP(-12, 4, 4, 4, 4, 4),
+                            GROUP(
+               /* IP3SR1_31_20 RESERVED */
+               IP3SR1_19_16
+               IP3SR1_15_12
+               IP3SR1_11_8
+               IP3SR1_7_4
+               IP3SR1_3_0))
+       },
+       { PINMUX_CFG_REG("IP0SR2", 0xE6058060, 32, 4, GROUP(
+               IP0SR2_31_28
+               IP0SR2_27_24
+               IP0SR2_23_20
+               IP0SR2_19_16
+               IP0SR2_15_12
+               IP0SR2_11_8
+               IP0SR2_7_4
+               IP0SR2_3_0))
+       },
+       { PINMUX_CFG_REG("IP1SR2", 0xE6058064, 32, 4, GROUP(
+               IP1SR2_31_28
+               IP1SR2_27_24
+               IP1SR2_23_20
+               IP1SR2_19_16
+               IP1SR2_15_12
+               IP1SR2_11_8
+               IP1SR2_7_4
+               IP1SR2_3_0))
+       },
+       { PINMUX_CFG_REG_VAR("IP2SR2", 0xE6058068, 32,
+                            GROUP(-16, 4, 4, 4, 4),
+                            GROUP(
+               /* IP2SR2_31_16 RESERVED */
+               IP2SR2_15_12
+               IP2SR2_11_8
+               IP2SR2_7_4
+               IP2SR2_3_0))
+       },
+       { PINMUX_CFG_REG("IP0SR3", 0xE6058860, 32, 4, GROUP(
+               IP0SR3_31_28
+               IP0SR3_27_24
+               IP0SR3_23_20
+               IP0SR3_19_16
+               IP0SR3_15_12
+               IP0SR3_11_8
+               IP0SR3_7_4
+               IP0SR3_3_0))
+       },
+       { PINMUX_CFG_REG("IP1SR3", 0xE6058864, 32, 4, GROUP(
+               IP1SR3_31_28
+               IP1SR3_27_24
+               IP1SR3_23_20
+               IP1SR3_19_16
+               IP1SR3_15_12
+               IP1SR3_11_8
+               IP1SR3_7_4
+               IP1SR3_3_0))
+       },
+       { PINMUX_CFG_REG("IP2SR3", 0xE6058868, 32, 4, GROUP(
+               IP2SR3_31_28
+               IP2SR3_27_24
+               IP2SR3_23_20
+               IP2SR3_19_16
+               IP2SR3_15_12
+               IP2SR3_11_8
+               IP2SR3_7_4
+               IP2SR3_3_0))
+       },
+       { PINMUX_CFG_REG_VAR("IP3SR3", 0xE605886C, 32,
+                            GROUP(-8, 4, 4, 4, 4, 4, 4),
+                            GROUP(
+               /* IP3SR3_31_24 RESERVED */
+               IP3SR3_23_20
+               IP3SR3_19_16
+               IP3SR3_15_12
+               IP3SR3_11_8
+               IP3SR3_7_4
+               IP3SR3_3_0))
+       },
+       { PINMUX_CFG_REG("IP0SR6", 0xE6061060, 32, 4, GROUP(
+               IP0SR6_31_28
+               IP0SR6_27_24
+               IP0SR6_23_20
+               IP0SR6_19_16
+               IP0SR6_15_12
+               IP0SR6_11_8
+               IP0SR6_7_4
+               IP0SR6_3_0))
+       },
+       { PINMUX_CFG_REG("IP1SR6", 0xE6061064, 32, 4, GROUP(
+               IP1SR6_31_28
+               IP1SR6_27_24
+               IP1SR6_23_20
+               IP1SR6_19_16
+               IP1SR6_15_12
+               IP1SR6_11_8
+               IP1SR6_7_4
+               IP1SR6_3_0))
+       },
+       { PINMUX_CFG_REG_VAR("IP2SR6", 0xE6061068, 32,
+                            GROUP(-12, 4, 4, 4, 4, 4),
+                            GROUP(
+               /* IP2SR6_31_20 RESERVED */
+               IP2SR6_19_16
+               IP2SR6_15_12
+               IP2SR6_11_8
+               IP2SR6_7_4
+               IP2SR6_3_0))
+       },
+       { PINMUX_CFG_REG("IP0SR7", 0xE6061860, 32, 4, GROUP(
+               IP0SR7_31_28
+               IP0SR7_27_24
+               IP0SR7_23_20
+               IP0SR7_19_16
+               IP0SR7_15_12
+               IP0SR7_11_8
+               IP0SR7_7_4
+               IP0SR7_3_0))
+       },
+       { PINMUX_CFG_REG("IP1SR7", 0xE6061864, 32, 4, GROUP(
+               IP1SR7_31_28
+               IP1SR7_27_24
+               IP1SR7_23_20
+               IP1SR7_19_16
+               IP1SR7_15_12
+               IP1SR7_11_8
+               IP1SR7_7_4
+               IP1SR7_3_0))
+       },
+       { PINMUX_CFG_REG_VAR("IP2SR7", 0xE6061868, 32,
+                            GROUP(-12, 4, 4, 4, 4, 4),
+                            GROUP(
+               /* IP2SR7_31_20 RESERVED */
+               IP2SR7_19_16
+               IP2SR7_15_12
+               IP2SR7_11_8
+               IP2SR7_7_4
+               IP2SR7_3_0))
+       },
+       { PINMUX_CFG_REG("IP0SR8", 0xE6068060, 32, 4, GROUP(
+               IP0SR8_31_28
+               IP0SR8_27_24
+               IP0SR8_23_20
+               IP0SR8_19_16
+               IP0SR8_15_12
+               IP0SR8_11_8
+               IP0SR8_7_4
+               IP0SR8_3_0))
+       },
+       { PINMUX_CFG_REG_VAR("IP1SR8", 0xE6068064, 32,
+                            GROUP(-8, 4, 4, 4, 4, 4, 4),
+                            GROUP(
+               /* IP1SR8_31_24 RESERVED */
+               IP1SR8_23_20
+               IP1SR8_19_16
+               IP1SR8_15_12
+               IP1SR8_11_8
+               IP1SR8_7_4
+               IP1SR8_3_0))
+       },
+#undef F_
+#undef FM
+
+#define F_(x, y)       x,
+#define FM(x)          FN_##x,
+       { PINMUX_CFG_REG_VAR("MOD_SEL4", 0xE6060100, 32,
+                            GROUP(-12, 1, 1, -2, 1, 1, -1, 1, -2, 1, 1, -2, 1,
+                                  -2, 1, 1, -1),
+                            GROUP(
+               /* RESERVED 31-20 */
+               MOD_SEL4_19
+               MOD_SEL4_18
+               /* RESERVED 17-16 */
+               MOD_SEL4_15
+               MOD_SEL4_14
+               /* RESERVED 13 */
+               MOD_SEL4_12
+               /* RESERVED 11-10 */
+               MOD_SEL4_9
+               MOD_SEL4_8
+               /* RESERVED 7-6 */
+               MOD_SEL4_5
+               /* RESERVED 4-3 */
+               MOD_SEL4_2
+               MOD_SEL4_1
+               /* RESERVED 0 */
+               ))
+       },
+       { PINMUX_CFG_REG_VAR("MOD_SEL5", 0xE6060900, 32,
+                            GROUP(-12, 1, -2, 1, 1, -2, 1, 1, -2, 1, -1,
+                                  1, 1, -2, 1, -1, 1),
+                            GROUP(
+               /* RESERVED 31-20 */
+               MOD_SEL5_19
+               /* RESERVED 18-17 */
+               MOD_SEL5_16
+               MOD_SEL5_15
+               /* RESERVED 14-13 */
+               MOD_SEL5_12
+               MOD_SEL5_11
+               /* RESERVED 10-9 */
+               MOD_SEL5_8
+               /* RESERVED 7 */
+               MOD_SEL5_6
+               MOD_SEL5_5
+               /* RESERVED 4-3 */
+               MOD_SEL5_2
+               /* RESERVED 1 */
+               MOD_SEL5_0))
+       },
+       { PINMUX_CFG_REG_VAR("MOD_SEL6", 0xE6061100, 32,
+                            GROUP(-13, 1, -1, 1, -2, 1, 1,
+                                  -1, 1, -2, 1, 1, 1, -2, 1, 1, -1),
+                            GROUP(
+               /* RESERVED 31-19 */
+               MOD_SEL6_18
+               /* RESERVED 17 */
+               MOD_SEL6_16
+               /* RESERVED 15-14 */
+               MOD_SEL6_13
+               MOD_SEL6_12
+               /* RESERVED 11 */
+               MOD_SEL6_10
+               /* RESERVED 9-8 */
+               MOD_SEL6_7
+               MOD_SEL6_6
+               MOD_SEL6_5
+               /* RESERVED 4-3 */
+               MOD_SEL6_2
+               MOD_SEL6_1
+               /* RESERVED 0 */
+               ))
+       },
+       { PINMUX_CFG_REG_VAR("MOD_SEL7", 0xE6061900, 32,
+                            GROUP(-15, 1, 1, -1, 1, -1, 1, 1, -2, 1, 1,
+                                  -2, 1, 1, -1, 1),
+                            GROUP(
+               /* RESERVED 31-17 */
+               MOD_SEL7_16
+               MOD_SEL7_15
+               /* RESERVED 14 */
+               MOD_SEL7_13
+               /* RESERVED 12 */
+               MOD_SEL7_11
+               MOD_SEL7_10
+               /* RESERVED 9-8 */
+               MOD_SEL7_7
+               MOD_SEL7_6
+               /* RESERVED 5-4 */
+               MOD_SEL7_3
+               MOD_SEL7_2
+               /* RESERVED 1 */
+               MOD_SEL7_0))
+       },
+       { PINMUX_CFG_REG_VAR("MOD_SEL8", 0xE6068100, 32,
+                            GROUP(-20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+                            GROUP(
+               /* RESERVED 31-12 */
+               MOD_SEL8_11
+               MOD_SEL8_10
+               MOD_SEL8_9
+               MOD_SEL8_8
+               MOD_SEL8_7
+               MOD_SEL8_6
+               MOD_SEL8_5
+               MOD_SEL8_4
+               MOD_SEL8_3
+               MOD_SEL8_2
+               MOD_SEL8_1
+               MOD_SEL8_0))
+       },
+       { },
+};
+
+static const struct pinmux_drive_reg pinmux_drive_regs[] = {
+       { PINMUX_DRIVE_REG("DRV0CTRL0", 0xE6050080) {
+               { RCAR_GP_PIN(0,  7), 28, 3 },  /* MSIOF5_SS2 */
+               { RCAR_GP_PIN(0,  6), 24, 3 },  /* IRQ0 */
+               { RCAR_GP_PIN(0,  5), 20, 3 },  /* IRQ1 */
+               { RCAR_GP_PIN(0,  4), 16, 3 },  /* IRQ2 */
+               { RCAR_GP_PIN(0,  3), 12, 3 },  /* IRQ3 */
+               { RCAR_GP_PIN(0,  2),  8, 3 },  /* GP0_02 */
+               { RCAR_GP_PIN(0,  1),  4, 3 },  /* GP0_01 */
+               { RCAR_GP_PIN(0,  0),  0, 3 },  /* GP0_00 */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL0", 0xE6050084) {
+               { RCAR_GP_PIN(0, 15), 28, 3 },  /* MSIOF2_SYNC */
+               { RCAR_GP_PIN(0, 14), 24, 3 },  /* MSIOF2_SS1 */
+               { RCAR_GP_PIN(0, 13), 20, 3 },  /* MSIOF2_SS2 */
+               { RCAR_GP_PIN(0, 12), 16, 3 },  /* MSIOF5_RXD */
+               { RCAR_GP_PIN(0, 11), 12, 3 },  /* MSIOF5_SCK */
+               { RCAR_GP_PIN(0, 10),  8, 3 },  /* MSIOF5_TXD */
+               { RCAR_GP_PIN(0,  9),  4, 3 },  /* MSIOF5_SYNC */
+               { RCAR_GP_PIN(0,  8),  0, 3 },  /* MSIOF5_SS1 */
+       } },
+       { PINMUX_DRIVE_REG("DRV2CTRL0", 0xE6050088) {
+               { RCAR_GP_PIN(0, 18),  8, 3 },  /* MSIOF2_RXD */
+               { RCAR_GP_PIN(0, 17),  4, 3 },  /* MSIOF2_SCK */
+               { RCAR_GP_PIN(0, 16),  0, 3 },  /* MSIOF2_TXD */
+       } },
+       { PINMUX_DRIVE_REG("DRV0CTRL1", 0xE6050880) {
+               { RCAR_GP_PIN(1,  7), 28, 3 },  /* MSIOF0_SS1 */
+               { RCAR_GP_PIN(1,  6), 24, 3 },  /* MSIOF0_SS2 */
+               { RCAR_GP_PIN(1,  5), 20, 3 },  /* MSIOF1_RXD */
+               { RCAR_GP_PIN(1,  4), 16, 3 },  /* MSIOF1_TXD */
+               { RCAR_GP_PIN(1,  3), 12, 3 },  /* MSIOF1_SCK */
+               { RCAR_GP_PIN(1,  2),  8, 3 },  /* MSIOF1_SYNC */
+               { RCAR_GP_PIN(1,  1),  4, 3 },  /* MSIOF1_SS1 */
+               { RCAR_GP_PIN(1,  0),  0, 3 },  /* MSIOF1_SS2 */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL1", 0xE6050884) {
+               { RCAR_GP_PIN(1, 15), 28, 3 },  /* HSCK0 */
+               { RCAR_GP_PIN(1, 14), 24, 3 },  /* HRTS0_N */
+               { RCAR_GP_PIN(1, 13), 20, 3 },  /* HCTS0_N */
+               { RCAR_GP_PIN(1, 12), 16, 3 },  /* HTX0 */
+               { RCAR_GP_PIN(1, 11), 12, 3 },  /* MSIOF0_RXD */
+               { RCAR_GP_PIN(1, 10),  8, 3 },  /* MSIOF0_SCK */
+               { RCAR_GP_PIN(1,  9),  4, 3 },  /* MSIOF0_TXD */
+               { RCAR_GP_PIN(1,  8),  0, 3 },  /* MSIOF0_SYNC */
+       } },
+       { PINMUX_DRIVE_REG("DRV2CTRL1", 0xE6050888) {
+               { RCAR_GP_PIN(1, 23), 28, 3 },  /* GP1_23 */
+               { RCAR_GP_PIN(1, 22), 24, 3 },  /* AUDIO_CLKIN */
+               { RCAR_GP_PIN(1, 21), 20, 3 },  /* AUDIO_CLKOUT */
+               { RCAR_GP_PIN(1, 20), 16, 3 },  /* SSI_SD */
+               { RCAR_GP_PIN(1, 19), 12, 3 },  /* SSI_WS */
+               { RCAR_GP_PIN(1, 18),  8, 3 },  /* SSI_SCK */
+               { RCAR_GP_PIN(1, 17),  4, 3 },  /* SCIF_CLK */
+               { RCAR_GP_PIN(1, 16),  0, 3 },  /* HRX0 */
+       } },
+       { PINMUX_DRIVE_REG("DRV3CTRL1", 0xE605088C) {
+               { RCAR_GP_PIN(1, 28), 16, 3 },  /* HTX3 */
+               { RCAR_GP_PIN(1, 27), 12, 3 },  /* HCTS3_N */
+               { RCAR_GP_PIN(1, 26),  8, 3 },  /* HRTS3_N */
+               { RCAR_GP_PIN(1, 25),  4, 3 },  /* HSCK3 */
+               { RCAR_GP_PIN(1, 24),  0, 3 },  /* HRX3 */
+       } },
+       { PINMUX_DRIVE_REG("DRV0CTRL2", 0xE6058080) {
+               { RCAR_GP_PIN(2,  7), 28, 3 },  /* TPU0TO1 */
+               { RCAR_GP_PIN(2,  6), 24, 3 },  /* FXR_TXDB */
+               { RCAR_GP_PIN(2,  5), 20, 3 },  /* FXR_TXENB_N */
+               { RCAR_GP_PIN(2,  4), 16, 3 },  /* RXDB_EXTFXR */
+               { RCAR_GP_PIN(2,  3), 12, 3 },  /* CLK_EXTFXR */
+               { RCAR_GP_PIN(2,  2),  8, 3 },  /* RXDA_EXTFXR */
+               { RCAR_GP_PIN(2,  1),  4, 3 },  /* FXR_TXENA_N */
+               { RCAR_GP_PIN(2,  0),  0, 3 },  /* FXR_TXDA */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL2", 0xE6058084) {
+               { RCAR_GP_PIN(2, 15), 28, 3 },  /* CANFD3_RX */
+               { RCAR_GP_PIN(2, 14), 24, 3 },  /* CANFD3_TX */
+               { RCAR_GP_PIN(2, 13), 20, 3 },  /* CANFD2_RX */
+               { RCAR_GP_PIN(2, 12), 16, 3 },  /* CANFD2_TX */
+               { RCAR_GP_PIN(2, 11), 12, 3 },  /* CANFD0_RX */
+               { RCAR_GP_PIN(2, 10),  8, 3 },  /* CANFD0_TX */
+               { RCAR_GP_PIN(2,  9),  4, 3 },  /* CAN_CLK */
+               { RCAR_GP_PIN(2,  8),  0, 3 },  /* TPU0TO0 */
+       } },
+       { PINMUX_DRIVE_REG("DRV2CTRL2", 0xE6058088) {
+               { RCAR_GP_PIN(2, 19), 12, 3 },  /* CANFD7_RX */
+               { RCAR_GP_PIN(2, 18),  8, 3 },  /* CANFD7_TX */
+               { RCAR_GP_PIN(2, 17),  4, 3 },  /* CANFD4_RX */
+               { RCAR_GP_PIN(2, 16),  0, 3 },  /* CANFD4_TX */
+       } },
+       { PINMUX_DRIVE_REG("DRV0CTRL3", 0xE6058880) {
+               { RCAR_GP_PIN(3,  7), 28, 3 },  /* MMC_D4 */
+               { RCAR_GP_PIN(3,  6), 24, 3 },  /* MMC_D5 */
+               { RCAR_GP_PIN(3,  5), 20, 3 },  /* MMC_SD_D3 */
+               { RCAR_GP_PIN(3,  4), 16, 3 },  /* MMC_DS */
+               { RCAR_GP_PIN(3,  3), 12, 3 },  /* MMC_SD_CLK */
+               { RCAR_GP_PIN(3,  2),  8, 3 },  /* MMC_SD_D2 */
+               { RCAR_GP_PIN(3,  1),  4, 3 },  /* MMC_SD_D0 */
+               { RCAR_GP_PIN(3,  0),  0, 3 },  /* MMC_SD_D1 */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL3", 0xE6058884) {
+               { RCAR_GP_PIN(3, 15), 28, 2 },  /* QSPI0_SSL */
+               { RCAR_GP_PIN(3, 14), 24, 2 },  /* IPC_CLKOUT */
+               { RCAR_GP_PIN(3, 13), 20, 2 },  /* IPC_CLKIN */
+               { RCAR_GP_PIN(3, 12), 16, 3 },  /* SD_WP */
+               { RCAR_GP_PIN(3, 11), 12, 3 },  /* SD_CD */
+               { RCAR_GP_PIN(3, 10),  8, 3 },  /* MMC_SD_CMD */
+               { RCAR_GP_PIN(3,  9),  4, 3 },  /* MMC_D6*/
+               { RCAR_GP_PIN(3,  8),  0, 3 },  /* MMC_D7 */
+       } },
+       { PINMUX_DRIVE_REG("DRV2CTRL3", 0xE6058888) {
+               { RCAR_GP_PIN(3, 23), 28, 2 },  /* QSPI1_MISO_IO1 */
+               { RCAR_GP_PIN(3, 22), 24, 2 },  /* QSPI1_SPCLK */
+               { RCAR_GP_PIN(3, 21), 20, 2 },  /* QSPI1_MOSI_IO0 */
+               { RCAR_GP_PIN(3, 20), 16, 2 },  /* QSPI0_SPCLK */
+               { RCAR_GP_PIN(3, 19), 12, 2 },  /* QSPI0_MOSI_IO0 */
+               { RCAR_GP_PIN(3, 18),  8, 2 },  /* QSPI0_MISO_IO1 */
+               { RCAR_GP_PIN(3, 17),  4, 2 },  /* QSPI0_IO2 */
+               { RCAR_GP_PIN(3, 16),  0, 2 },  /* QSPI0_IO3 */
+       } },
+       { PINMUX_DRIVE_REG("DRV3CTRL3", 0xE605888C) {
+               { RCAR_GP_PIN(3, 29), 20, 2 },  /* RPC_INT_N */
+               { RCAR_GP_PIN(3, 28), 16, 2 },  /* RPC_WP_N */
+               { RCAR_GP_PIN(3, 27), 12, 2 },  /* RPC_RESET_N */
+               { RCAR_GP_PIN(3, 26),  8, 2 },  /* QSPI1_IO3 */
+               { RCAR_GP_PIN(3, 25),  4, 2 },  /* QSPI1_SSL */
+               { RCAR_GP_PIN(3, 24),  0, 2 },  /* QSPI1_IO2 */
+       } },
+       { PINMUX_DRIVE_REG("DRV0CTRL4", 0xE6060080) {
+               { RCAR_GP_PIN(4,  7), 28, 3 },  /* TSN0_RX_CTL */
+               { RCAR_GP_PIN(4,  6), 24, 3 },  /* TSN0_AVTP_CAPTURE */
+               { RCAR_GP_PIN(4,  5), 20, 3 },  /* TSN0_AVTP_MATCH */
+               { RCAR_GP_PIN(4,  4), 16, 3 },  /* TSN0_LINK */
+               { RCAR_GP_PIN(4,  3), 12, 3 },  /* TSN0_PHY_INT */
+               { RCAR_GP_PIN(4,  2),  8, 3 },  /* TSN0_AVTP_PPS1 */
+               { RCAR_GP_PIN(4,  1),  4, 3 },  /* TSN0_MDC */
+               { RCAR_GP_PIN(4,  0),  0, 3 },  /* TSN0_MDIO */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL4", 0xE6060084) {
+               { RCAR_GP_PIN(4, 15), 28, 3 },  /* TSN0_TD0 */
+               { RCAR_GP_PIN(4, 14), 24, 3 },  /* TSN0_TD1 */
+               { RCAR_GP_PIN(4, 13), 20, 3 },  /* TSN0_RD1 */
+               { RCAR_GP_PIN(4, 12), 16, 3 },  /* TSN0_TXC */
+               { RCAR_GP_PIN(4, 11), 12, 3 },  /* TSN0_RXC */
+               { RCAR_GP_PIN(4, 10),  8, 3 },  /* TSN0_RD0 */
+               { RCAR_GP_PIN(4,  9),  4, 3 },  /* TSN0_TX_CTL */
+               { RCAR_GP_PIN(4,  8),  0, 3 },  /* TSN0_AVTP_PPS0 */
+       } },
+       { PINMUX_DRIVE_REG("DRV2CTRL4", 0xE6060088) {
+               { RCAR_GP_PIN(4, 23), 28, 3 },  /* AVS0 */
+               { RCAR_GP_PIN(4, 22), 24, 3 },  /* PCIE1_CLKREQ_N */
+               { RCAR_GP_PIN(4, 21), 20, 3 },  /* PCIE0_CLKREQ_N */
+               { RCAR_GP_PIN(4, 20), 16, 3 },  /* TSN0_TXCREFCLK */
+               { RCAR_GP_PIN(4, 19), 12, 3 },  /* TSN0_TD2 */
+               { RCAR_GP_PIN(4, 18),  8, 3 },  /* TSN0_TD3 */
+               { RCAR_GP_PIN(4, 17),  4, 3 },  /* TSN0_RD2 */
+               { RCAR_GP_PIN(4, 16),  0, 3 },  /* TSN0_RD3 */
+       } },
+       { PINMUX_DRIVE_REG("DRV3CTRL4", 0xE606008C) {
+               { RCAR_GP_PIN(4, 24),  0, 3 },  /* AVS1 */
+       } },
+       { PINMUX_DRIVE_REG("DRV0CTRL5", 0xE6060880) {
+               { RCAR_GP_PIN(5,  7), 28, 3 },  /* AVB2_TXCREFCLK */
+               { RCAR_GP_PIN(5,  6), 24, 3 },  /* AVB2_MDC */
+               { RCAR_GP_PIN(5,  5), 20, 3 },  /* AVB2_MAGIC */
+               { RCAR_GP_PIN(5,  4), 16, 3 },  /* AVB2_PHY_INT */
+               { RCAR_GP_PIN(5,  3), 12, 3 },  /* AVB2_LINK */
+               { RCAR_GP_PIN(5,  2),  8, 3 },  /* AVB2_AVTP_MATCH */
+               { RCAR_GP_PIN(5,  1),  4, 3 },  /* AVB2_AVTP_CAPTURE */
+               { RCAR_GP_PIN(5,  0),  0, 3 },  /* AVB2_AVTP_PPS */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL5", 0xE6060884) {
+               { RCAR_GP_PIN(5, 15), 28, 3 },  /* AVB2_TD0 */
+               { RCAR_GP_PIN(5, 14), 24, 3 },  /* AVB2_RD1 */
+               { RCAR_GP_PIN(5, 13), 20, 3 },  /* AVB2_RD2 */
+               { RCAR_GP_PIN(5, 12), 16, 3 },  /* AVB2_TD1 */
+               { RCAR_GP_PIN(5, 11), 12, 3 },  /* AVB2_TD2 */
+               { RCAR_GP_PIN(5, 10),  8, 3 },  /* AVB2_MDIO */
+               { RCAR_GP_PIN(5,  9),  4, 3 },  /* AVB2_RD3 */
+               { RCAR_GP_PIN(5,  8),  0, 3 },  /* AVB2_TD3 */
+       } },
+       { PINMUX_DRIVE_REG("DRV2CTRL5", 0xE6060888) {
+               { RCAR_GP_PIN(5, 20), 16, 3 },  /* AVB2_RX_CTL */
+               { RCAR_GP_PIN(5, 19), 12, 3 },  /* AVB2_TX_CTL */
+               { RCAR_GP_PIN(5, 18),  8, 3 },  /* AVB2_RXC */
+               { RCAR_GP_PIN(5, 17),  4, 3 },  /* AVB2_RD0 */
+               { RCAR_GP_PIN(5, 16),  0, 3 },  /* AVB2_TXC */
+       } },
+       { PINMUX_DRIVE_REG("DRV0CTRL6", 0xE6061080) {
+               { RCAR_GP_PIN(6,  7), 28, 3 },  /* AVB1_TX_CTL */
+               { RCAR_GP_PIN(6,  6), 24, 3 },  /* AVB1_TXC */
+               { RCAR_GP_PIN(6,  5), 20, 3 },  /* AVB1_AVTP_MATCH */
+               { RCAR_GP_PIN(6,  4), 16, 3 },  /* AVB1_LINK */
+               { RCAR_GP_PIN(6,  3), 12, 3 },  /* AVB1_PHY_INT */
+               { RCAR_GP_PIN(6,  2),  8, 3 },  /* AVB1_MDC */
+               { RCAR_GP_PIN(6,  1),  4, 3 },  /* AVB1_MAGIC */
+               { RCAR_GP_PIN(6,  0),  0, 3 },  /* AVB1_MDIO */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL6", 0xE6061084) {
+               { RCAR_GP_PIN(6, 15), 28, 3 },  /* AVB1_RD0 */
+               { RCAR_GP_PIN(6, 14), 24, 3 },  /* AVB1_RD1 */
+               { RCAR_GP_PIN(6, 13), 20, 3 },  /* AVB1_TD0 */
+               { RCAR_GP_PIN(6, 12), 16, 3 },  /* AVB1_TD1 */
+               { RCAR_GP_PIN(6, 11), 12, 3 },  /* AVB1_AVTP_CAPTURE */
+               { RCAR_GP_PIN(6, 10),  8, 3 },  /* AVB1_AVTP_PPS */
+               { RCAR_GP_PIN(6,  9),  4, 3 },  /* AVB1_RX_CTL */
+               { RCAR_GP_PIN(6,  8),  0, 3 },  /* AVB1_RXC */
+       } },
+       { PINMUX_DRIVE_REG("DRV2CTRL6", 0xE6061088) {
+               { RCAR_GP_PIN(6, 20), 16, 3 },  /* AVB1_TXCREFCLK */
+               { RCAR_GP_PIN(6, 19), 12, 3 },  /* AVB1_RD3 */
+               { RCAR_GP_PIN(6, 18),  8, 3 },  /* AVB1_TD3 */
+               { RCAR_GP_PIN(6, 17),  4, 3 },  /* AVB1_RD2 */
+               { RCAR_GP_PIN(6, 16),  0, 3 },  /* AVB1_TD2 */
+       } },
+       { PINMUX_DRIVE_REG("DRV0CTRL7", 0xE6061880) {
+               { RCAR_GP_PIN(7,  7), 28, 3 },  /* AVB0_TD1 */
+               { RCAR_GP_PIN(7,  6), 24, 3 },  /* AVB0_TD2 */
+               { RCAR_GP_PIN(7,  5), 20, 3 },  /* AVB0_PHY_INT */
+               { RCAR_GP_PIN(7,  4), 16, 3 },  /* AVB0_LINK */
+               { RCAR_GP_PIN(7,  3), 12, 3 },  /* AVB0_TD3 */
+               { RCAR_GP_PIN(7,  2),  8, 3 },  /* AVB0_AVTP_MATCH */
+               { RCAR_GP_PIN(7,  1),  4, 3 },  /* AVB0_AVTP_CAPTURE */
+               { RCAR_GP_PIN(7,  0),  0, 3 },  /* AVB0_AVTP_PPS */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL7", 0xE6061884) {
+               { RCAR_GP_PIN(7, 15), 28, 3 },  /* AVB0_TXC */
+               { RCAR_GP_PIN(7, 14), 24, 3 },  /* AVB0_MDIO */
+               { RCAR_GP_PIN(7, 13), 20, 3 },  /* AVB0_MDC */
+               { RCAR_GP_PIN(7, 12), 16, 3 },  /* AVB0_RD2 */
+               { RCAR_GP_PIN(7, 11), 12, 3 },  /* AVB0_TD0 */
+               { RCAR_GP_PIN(7, 10),  8, 3 },  /* AVB0_MAGIC */
+               { RCAR_GP_PIN(7,  9),  4, 3 },  /* AVB0_TXCREFCLK */
+               { RCAR_GP_PIN(7,  8),  0, 3 },  /* AVB0_RD3 */
+       } },
+       { PINMUX_DRIVE_REG("DRV2CTRL7", 0xE6061888) {
+               { RCAR_GP_PIN(7, 20), 16, 3 },  /* AVB0_RX_CTL */
+               { RCAR_GP_PIN(7, 19), 12, 3 },  /* AVB0_RXC */
+               { RCAR_GP_PIN(7, 18),  8, 3 },  /* AVB0_RD0 */
+               { RCAR_GP_PIN(7, 17),  4, 3 },  /* AVB0_RD1 */
+               { RCAR_GP_PIN(7, 16),  0, 3 },  /* AVB0_TX_CTL */
+       } },
+       { PINMUX_DRIVE_REG("DRV0CTRL8", 0xE6068080) {
+               { RCAR_GP_PIN(8,  7), 28, 3 },  /* SDA3 */
+               { RCAR_GP_PIN(8,  6), 24, 3 },  /* SCL3 */
+               { RCAR_GP_PIN(8,  5), 20, 3 },  /* SDA2 */
+               { RCAR_GP_PIN(8,  4), 16, 3 },  /* SCL2 */
+               { RCAR_GP_PIN(8,  3), 12, 3 },  /* SDA1 */
+               { RCAR_GP_PIN(8,  2),  8, 3 },  /* SCL1 */
+               { RCAR_GP_PIN(8,  1),  4, 3 },  /* SDA0 */
+               { RCAR_GP_PIN(8,  0),  0, 3 },  /* SCL0 */
+       } },
+       { PINMUX_DRIVE_REG("DRV1CTRL8", 0xE6068084) {
+               { RCAR_GP_PIN(8, 13), 20, 3 },  /* GP8_13 */
+               { RCAR_GP_PIN(8, 12), 16, 3 },  /* GP8_12 */
+               { RCAR_GP_PIN(8, 11), 12, 3 },  /* SDA5 */
+               { RCAR_GP_PIN(8, 10),  8, 3 },  /* SCL5 */
+               { RCAR_GP_PIN(8,  9),  4, 3 },  /* SDA4 */
+               { RCAR_GP_PIN(8,  8),  0, 3 },  /* SCL4 */
+       } },
+       { },
+};
+
+enum ioctrl_regs {
+       POC0,
+       POC1,
+       POC3,
+       POC4,
+       POC5,
+       POC6,
+       POC7,
+       POC8,
+};
+
+static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = {
+       [POC0]          = { 0xE60500A0, },
+       [POC1]          = { 0xE60508A0, },
+       [POC3]          = { 0xE60588A0, },
+       [POC4]          = { 0xE60600A0, },
+       [POC5]          = { 0xE60608A0, },
+       [POC6]          = { 0xE60610A0, },
+       [POC7]          = { 0xE60618A0, },
+       [POC8]          = { 0xE60680A0, },
+       { /* sentinel */ },
+};
+
+static int r8a779g0_pin_to_pocctrl(unsigned int pin, u32 *pocctrl)
+{
+       int bit = pin & 0x1f;
+
+       *pocctrl = pinmux_ioctrl_regs[POC0].reg;
+       if (pin >= RCAR_GP_PIN(0, 0) && pin <= RCAR_GP_PIN(0, 18))
+               return bit;
+
+       *pocctrl = pinmux_ioctrl_regs[POC1].reg;
+       if (pin >= RCAR_GP_PIN(1, 0) && pin <= RCAR_GP_PIN(1, 22))
+               return bit;
+
+       *pocctrl = pinmux_ioctrl_regs[POC3].reg;
+       if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 12))
+               return bit;
+
+       *pocctrl = pinmux_ioctrl_regs[POC8].reg;
+       if (pin >= RCAR_GP_PIN(8, 0) && pin <= RCAR_GP_PIN(8, 13))
+               return bit;
+
+       return -EINVAL;
+}
+
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+       { PINMUX_BIAS_REG("PUEN0", 0xE60500C0, "PUD0", 0xE60500E0) {
+               [ 0] = RCAR_GP_PIN(0,  0),      /* GP0_00 */
+               [ 1] = RCAR_GP_PIN(0,  1),      /* GP0_01 */
+               [ 2] = RCAR_GP_PIN(0,  2),      /* GP0_02 */
+               [ 3] = RCAR_GP_PIN(0,  3),      /* IRQ3 */
+               [ 4] = RCAR_GP_PIN(0,  4),      /* IRQ2 */
+               [ 5] = RCAR_GP_PIN(0,  5),      /* IRQ1 */
+               [ 6] = RCAR_GP_PIN(0,  6),      /* IRQ0 */
+               [ 7] = RCAR_GP_PIN(0,  7),      /* MSIOF5_SS2 */
+               [ 8] = RCAR_GP_PIN(0,  8),      /* MSIOF5_SS1 */
+               [ 9] = RCAR_GP_PIN(0,  9),      /* MSIOF5_SYNC */
+               [10] = RCAR_GP_PIN(0, 10),      /* MSIOF5_TXD */
+               [11] = RCAR_GP_PIN(0, 11),      /* MSIOF5_SCK */
+               [12] = RCAR_GP_PIN(0, 12),      /* MSIOF5_RXD */
+               [13] = RCAR_GP_PIN(0, 13),      /* MSIOF2_SS2 */
+               [14] = RCAR_GP_PIN(0, 14),      /* MSIOF2_SS1 */
+               [15] = RCAR_GP_PIN(0, 15),      /* MSIOF2_SYNC */
+               [16] = RCAR_GP_PIN(0, 16),      /* MSIOF2_TXD */
+               [17] = RCAR_GP_PIN(0, 17),      /* MSIOF2_SCK */
+               [18] = RCAR_GP_PIN(0, 18),      /* MSIOF2_RXD */
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { PINMUX_BIAS_REG("PUEN1", 0xE60508C0, "PUD1", 0xE60508E0) {
+               [ 0] = RCAR_GP_PIN(1,  0),      /* MSIOF1_SS2 */
+               [ 1] = RCAR_GP_PIN(1,  1),      /* MSIOF1_SS1 */
+               [ 2] = RCAR_GP_PIN(1,  2),      /* MSIOF1_SYNC */
+               [ 3] = RCAR_GP_PIN(1,  3),      /* MSIOF1_SCK */
+               [ 4] = RCAR_GP_PIN(1,  4),      /* MSIOF1_TXD */
+               [ 5] = RCAR_GP_PIN(1,  5),      /* MSIOF1_RXD */
+               [ 6] = RCAR_GP_PIN(1,  6),      /* MSIOF0_SS2 */
+               [ 7] = RCAR_GP_PIN(1,  7),      /* MSIOF0_SS1 */
+               [ 8] = RCAR_GP_PIN(1,  8),      /* MSIOF0_SYNC */
+               [ 9] = RCAR_GP_PIN(1,  9),      /* MSIOF0_TXD */
+               [10] = RCAR_GP_PIN(1, 10),      /* MSIOF0_SCK */
+               [11] = RCAR_GP_PIN(1, 11),      /* MSIOF0_RXD */
+               [12] = RCAR_GP_PIN(1, 12),      /* HTX0 */
+               [13] = RCAR_GP_PIN(1, 13),      /* HCTS0_N */
+               [14] = RCAR_GP_PIN(1, 14),      /* HRTS0_N */
+               [15] = RCAR_GP_PIN(1, 15),      /* HSCK0 */
+               [16] = RCAR_GP_PIN(1, 16),      /* HRX0 */
+               [17] = RCAR_GP_PIN(1, 17),      /* SCIF_CLK */
+               [18] = RCAR_GP_PIN(1, 18),      /* SSI_SCK */
+               [19] = RCAR_GP_PIN(1, 19),      /* SSI_WS */
+               [20] = RCAR_GP_PIN(1, 20),      /* SSI_SD */
+               [21] = RCAR_GP_PIN(1, 21),      /* AUDIO_CLKOUT */
+               [22] = RCAR_GP_PIN(1, 22),      /* AUDIO_CLKIN */
+               [23] = RCAR_GP_PIN(1, 23),      /* GP1_23 */
+               [24] = RCAR_GP_PIN(1, 24),      /* HRX3 */
+               [25] = RCAR_GP_PIN(1, 25),      /* HSCK3 */
+               [26] = RCAR_GP_PIN(1, 26),      /* HRTS3_N */
+               [27] = RCAR_GP_PIN(1, 27),      /* HCTS3_N */
+               [28] = RCAR_GP_PIN(1, 28),      /* HTX3 */
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { PINMUX_BIAS_REG("PUEN2", 0xE60580C0, "PUD2", 0xE60580E0) {
+               [ 0] = RCAR_GP_PIN(2,  0),      /* FXR_TXDA */
+               [ 1] = RCAR_GP_PIN(2,  1),      /* FXR_TXENA_N */
+               [ 2] = RCAR_GP_PIN(2,  2),      /* RXDA_EXTFXR */
+               [ 3] = RCAR_GP_PIN(2,  3),      /* CLK_EXTFXR */
+               [ 4] = RCAR_GP_PIN(2,  4),      /* RXDB_EXTFXR */
+               [ 5] = RCAR_GP_PIN(2,  5),      /* FXR_TXENB_N */
+               [ 6] = RCAR_GP_PIN(2,  6),      /* FXR_TXDB */
+               [ 7] = RCAR_GP_PIN(2,  7),      /* TPU0TO1 */
+               [ 8] = RCAR_GP_PIN(2,  8),      /* TPU0TO0 */
+               [ 9] = RCAR_GP_PIN(2,  9),      /* CAN_CLK */
+               [10] = RCAR_GP_PIN(2, 10),      /* CANFD0_TX */
+               [11] = RCAR_GP_PIN(2, 11),      /* CANFD0_RX */
+               [12] = RCAR_GP_PIN(2, 12),      /* CANFD2_TX */
+               [13] = RCAR_GP_PIN(2, 13),      /* CANFD2_RX */
+               [14] = RCAR_GP_PIN(2, 14),      /* CANFD3_TX */
+               [15] = RCAR_GP_PIN(2, 15),      /* CANFD3_RX */
+               [16] = RCAR_GP_PIN(2, 16),      /* CANFD4_TX */
+               [17] = RCAR_GP_PIN(2, 17),      /* CANFD4_RX */
+               [18] = RCAR_GP_PIN(2, 18),      /* CANFD7_TX */
+               [19] = RCAR_GP_PIN(2, 19),      /* CANFD7_RX */
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { PINMUX_BIAS_REG("PUEN3", 0xE60588C0, "PUD3", 0xE60588E0) {
+               [ 0] = RCAR_GP_PIN(3,  0),      /* MMC_SD_D1 */
+               [ 1] = RCAR_GP_PIN(3,  1),      /* MMC_SD_D0 */
+               [ 2] = RCAR_GP_PIN(3,  2),      /* MMC_SD_D2 */
+               [ 3] = RCAR_GP_PIN(3,  3),      /* MMC_SD_CLK */
+               [ 4] = RCAR_GP_PIN(3,  4),      /* MMC_DS */
+               [ 5] = RCAR_GP_PIN(3,  5),      /* MMC_SD_D3 */
+               [ 6] = RCAR_GP_PIN(3,  6),      /* MMC_D5 */
+               [ 7] = RCAR_GP_PIN(3,  7),      /* MMC_D4 */
+               [ 8] = RCAR_GP_PIN(3,  8),      /* MMC_D7 */
+               [ 9] = RCAR_GP_PIN(3,  9),      /* MMC_D6 */
+               [10] = RCAR_GP_PIN(3, 10),      /* MMC_SD_CMD */
+               [11] = RCAR_GP_PIN(3, 11),      /* SD_CD */
+               [12] = RCAR_GP_PIN(3, 12),      /* SD_WP */
+               [13] = RCAR_GP_PIN(3, 13),      /* IPC_CLKIN */
+               [14] = RCAR_GP_PIN(3, 14),      /* IPC_CLKOUT */
+               [15] = RCAR_GP_PIN(3, 15),      /* QSPI0_SSL */
+               [16] = RCAR_GP_PIN(3, 16),      /* QSPI0_IO3 */
+               [17] = RCAR_GP_PIN(3, 17),      /* QSPI0_IO2 */
+               [18] = RCAR_GP_PIN(3, 18),      /* QSPI0_MISO_IO1 */
+               [19] = RCAR_GP_PIN(3, 19),      /* QSPI0_MOSI_IO0 */
+               [20] = RCAR_GP_PIN(3, 20),      /* QSPI0_SPCLK */
+               [21] = RCAR_GP_PIN(3, 21),      /* QSPI1_MOSI_IO0 */
+               [22] = RCAR_GP_PIN(3, 22),      /* QSPI1_SPCLK */
+               [23] = RCAR_GP_PIN(3, 23),      /* QSPI1_MISO_IO1 */
+               [24] = RCAR_GP_PIN(3, 24),      /* QSPI1_IO2 */
+               [25] = RCAR_GP_PIN(3, 25),      /* QSPI1_SSL */
+               [26] = RCAR_GP_PIN(3, 26),      /* QSPI1_IO3 */
+               [27] = RCAR_GP_PIN(3, 27),      /* RPC_RESET_N */
+               [28] = RCAR_GP_PIN(3, 28),      /* RPC_WP_N */
+               [29] = RCAR_GP_PIN(3, 29),      /* RPC_INT_N */
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { PINMUX_BIAS_REG("PUEN4", 0xE60600C0, "PUD4", 0xE60600E0) {
+               [ 0] = RCAR_GP_PIN(4,  0),      /* TSN0_MDIO */
+               [ 1] = RCAR_GP_PIN(4,  1),      /* TSN0_MDC */
+               [ 2] = RCAR_GP_PIN(4,  2),      /* TSN0_AVTP_PPS1 */
+               [ 3] = RCAR_GP_PIN(4,  3),      /* TSN0_PHY_INT */
+               [ 4] = RCAR_GP_PIN(4,  4),      /* TSN0_LINK */
+               [ 5] = RCAR_GP_PIN(4,  5),      /* TSN0_AVTP_MATCH */
+               [ 6] = RCAR_GP_PIN(4,  6),      /* TSN0_AVTP_CAPTURE */
+               [ 7] = RCAR_GP_PIN(4,  7),      /* TSN0_RX_CTL */
+               [ 8] = RCAR_GP_PIN(4,  8),      /* TSN0_AVTP_PPS0 */
+               [ 9] = RCAR_GP_PIN(4,  9),      /* TSN0_TX_CTL */
+               [10] = RCAR_GP_PIN(4, 10),      /* TSN0_RD0 */
+               [11] = RCAR_GP_PIN(4, 11),      /* TSN0_RXC */
+               [12] = RCAR_GP_PIN(4, 12),      /* TSN0_TXC */
+               [13] = RCAR_GP_PIN(4, 13),      /* TSN0_RD1 */
+               [14] = RCAR_GP_PIN(4, 14),      /* TSN0_TD1 */
+               [15] = RCAR_GP_PIN(4, 15),      /* TSN0_TD0 */
+               [16] = RCAR_GP_PIN(4, 16),      /* TSN0_RD3 */
+               [17] = RCAR_GP_PIN(4, 17),      /* TSN0_RD2 */
+               [18] = RCAR_GP_PIN(4, 18),      /* TSN0_TD3 */
+               [19] = RCAR_GP_PIN(4, 19),      /* TSN0_TD2 */
+               [20] = RCAR_GP_PIN(4, 20),      /* TSN0_TXCREFCLK */
+               [21] = RCAR_GP_PIN(4, 21),      /* PCIE0_CLKREQ_N */
+               [22] = RCAR_GP_PIN(4, 22),      /* PCIE1_CLKREQ_N */
+               [23] = RCAR_GP_PIN(4, 23),      /* AVS0 */
+               [24] = RCAR_GP_PIN(4, 24),      /* AVS1 */
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { PINMUX_BIAS_REG("PUEN5", 0xE60608C0, "PUD5", 0xE60608E0) {
+               [ 0] = RCAR_GP_PIN(5,  0),      /* AVB2_AVTP_PPS */
+               [ 1] = RCAR_GP_PIN(5,  1),      /* AVB0_AVTP_CAPTURE */
+               [ 2] = RCAR_GP_PIN(5,  2),      /* AVB2_AVTP_MATCH */
+               [ 3] = RCAR_GP_PIN(5,  3),      /* AVB2_LINK */
+               [ 4] = RCAR_GP_PIN(5,  4),      /* AVB2_PHY_INT */
+               [ 5] = RCAR_GP_PIN(5,  5),      /* AVB2_MAGIC */
+               [ 6] = RCAR_GP_PIN(5,  6),      /* AVB2_MDC */
+               [ 7] = RCAR_GP_PIN(5,  7),      /* AVB2_TXCREFCLK */
+               [ 8] = RCAR_GP_PIN(5,  8),      /* AVB2_TD3 */
+               [ 9] = RCAR_GP_PIN(5,  9),      /* AVB2_RD3 */
+               [10] = RCAR_GP_PIN(5, 10),      /* AVB2_MDIO */
+               [11] = RCAR_GP_PIN(5, 11),      /* AVB2_TD2 */
+               [12] = RCAR_GP_PIN(5, 12),      /* AVB2_TD1 */
+               [13] = RCAR_GP_PIN(5, 13),      /* AVB2_RD2 */
+               [14] = RCAR_GP_PIN(5, 14),      /* AVB2_RD1 */
+               [15] = RCAR_GP_PIN(5, 15),      /* AVB2_TD0 */
+               [16] = RCAR_GP_PIN(5, 16),      /* AVB2_TXC */
+               [17] = RCAR_GP_PIN(5, 17),      /* AVB2_RD0 */
+               [18] = RCAR_GP_PIN(5, 18),      /* AVB2_RXC */
+               [19] = RCAR_GP_PIN(5, 19),      /* AVB2_TX_CTL */
+               [20] = RCAR_GP_PIN(5, 20),      /* AVB2_RX_CTL */
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { PINMUX_BIAS_REG("PUEN6", 0xE60610C0, "PUD6", 0xE60610E0) {
+               [ 0] = RCAR_GP_PIN(6,  0),      /* AVB1_MDIO */
+               [ 1] = RCAR_GP_PIN(6,  1),      /* AVB1_MAGIC */
+               [ 2] = RCAR_GP_PIN(6,  2),      /* AVB1_MDC */
+               [ 3] = RCAR_GP_PIN(6,  3),      /* AVB1_PHY_INT */
+               [ 4] = RCAR_GP_PIN(6,  4),      /* AVB1_LINK */
+               [ 5] = RCAR_GP_PIN(6,  5),      /* AVB1_AVTP_MATCH */
+               [ 6] = RCAR_GP_PIN(6,  6),      /* AVB1_TXC */
+               [ 7] = RCAR_GP_PIN(6,  7),      /* AVB1_TX_CTL */
+               [ 8] = RCAR_GP_PIN(6,  8),      /* AVB1_RXC */
+               [ 9] = RCAR_GP_PIN(6,  9),      /* AVB1_RX_CTL */
+               [10] = RCAR_GP_PIN(6, 10),      /* AVB1_AVTP_PPS */
+               [11] = RCAR_GP_PIN(6, 11),      /* AVB1_AVTP_CAPTURE */
+               [12] = RCAR_GP_PIN(6, 12),      /* AVB1_TD1 */
+               [13] = RCAR_GP_PIN(6, 13),      /* AVB1_TD0 */
+               [14] = RCAR_GP_PIN(6, 14),      /* AVB1_RD1*/
+               [15] = RCAR_GP_PIN(6, 15),      /* AVB1_RD0 */
+               [16] = RCAR_GP_PIN(6, 16),      /* AVB1_TD2 */
+               [17] = RCAR_GP_PIN(6, 17),      /* AVB1_RD2 */
+               [18] = RCAR_GP_PIN(6, 18),      /* AVB1_TD3 */
+               [19] = RCAR_GP_PIN(6, 19),      /* AVB1_RD3 */
+               [20] = RCAR_GP_PIN(6, 20),      /* AVB1_TXCREFCLK */
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { PINMUX_BIAS_REG("PUEN7", 0xE60618C0, "PUD7", 0xE60618E0) {
+               [ 0] = RCAR_GP_PIN(7,  0),      /* AVB0_AVTP_PPS */
+               [ 1] = RCAR_GP_PIN(7,  1),      /* AVB0_AVTP_CAPTURE */
+               [ 2] = RCAR_GP_PIN(7,  2),      /* AVB0_AVTP_MATCH */
+               [ 3] = RCAR_GP_PIN(7,  3),      /* AVB0_TD3 */
+               [ 4] = RCAR_GP_PIN(7,  4),      /* AVB0_LINK */
+               [ 5] = RCAR_GP_PIN(7,  5),      /* AVB0_PHY_INT */
+               [ 6] = RCAR_GP_PIN(7,  6),      /* AVB0_TD2 */
+               [ 7] = RCAR_GP_PIN(7,  7),      /* AVB0_TD1 */
+               [ 8] = RCAR_GP_PIN(7,  8),      /* AVB0_RD3 */
+               [ 9] = RCAR_GP_PIN(7,  9),      /* AVB0_TXCREFCLK */
+               [10] = RCAR_GP_PIN(7, 10),      /* AVB0_MAGIC */
+               [11] = RCAR_GP_PIN(7, 11),      /* AVB0_TD0 */
+               [12] = RCAR_GP_PIN(7, 12),      /* AVB0_RD2 */
+               [13] = RCAR_GP_PIN(7, 13),      /* AVB0_MDC */
+               [14] = RCAR_GP_PIN(7, 14),      /* AVB0_MDIO */
+               [15] = RCAR_GP_PIN(7, 15),      /* AVB0_TXC */
+               [16] = RCAR_GP_PIN(7, 16),      /* AVB0_TX_CTL */
+               [17] = RCAR_GP_PIN(7, 17),      /* AVB0_RD1 */
+               [18] = RCAR_GP_PIN(7, 18),      /* AVB0_RD0 */
+               [19] = RCAR_GP_PIN(7, 19),      /* AVB0_RXC */
+               [20] = RCAR_GP_PIN(7, 20),      /* AVB0_RX_CTL */
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { PINMUX_BIAS_REG("PUEN8", 0xE60680C0, "PUD8", 0xE60680E0) {
+               [ 0] = RCAR_GP_PIN(8,  0),      /* SCL0 */
+               [ 1] = RCAR_GP_PIN(8,  1),      /* SDA0 */
+               [ 2] = RCAR_GP_PIN(8,  2),      /* SCL1 */
+               [ 3] = RCAR_GP_PIN(8,  3),      /* SDA1 */
+               [ 4] = RCAR_GP_PIN(8,  4),      /* SCL2 */
+               [ 5] = RCAR_GP_PIN(8,  5),      /* SDA2 */
+               [ 6] = RCAR_GP_PIN(8,  6),      /* SCL3 */
+               [ 7] = RCAR_GP_PIN(8,  7),      /* SDA3 */
+               [ 8] = RCAR_GP_PIN(8,  8),      /* SCL4 */
+               [ 9] = RCAR_GP_PIN(8,  9),      /* SDA4 */
+               [10] = RCAR_GP_PIN(8, 10),      /* SCL5 */
+               [11] = RCAR_GP_PIN(8, 11),      /* SDA5 */
+               [12] = RCAR_GP_PIN(8, 12),      /* GP8_12 */
+               [13] = RCAR_GP_PIN(8, 13),      /* GP8_13 */
+               [14] = SH_PFC_PIN_NONE,
+               [15] = SH_PFC_PIN_NONE,
+               [16] = SH_PFC_PIN_NONE,
+               [17] = SH_PFC_PIN_NONE,
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
+       } },
+       { /* sentinel */ },
+};
+
+static const struct sh_pfc_soc_operations r8a779g0_pin_ops = {
+       .pin_to_pocctrl = r8a779g0_pin_to_pocctrl,
+       .get_bias = rcar_pinmux_get_bias,
+       .set_bias = rcar_pinmux_set_bias,
+};
+
+const struct sh_pfc_soc_info r8a779g0_pinmux_info = {
+       .name = "r8a779g0_pfc",
+       .ops = &r8a779g0_pin_ops,
+       .unlock_reg = 0x1ff,    /* PMMRn mask */
+
+       .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+       .pins = pinmux_pins,
+       .nr_pins = ARRAY_SIZE(pinmux_pins),
+       .groups = pinmux_groups,
+       .nr_groups = ARRAY_SIZE(pinmux_groups),
+       .functions = pinmux_functions,
+       .nr_functions = ARRAY_SIZE(pinmux_functions),
+
+       .cfg_regs = pinmux_config_regs,
+       .drive_regs = pinmux_drive_regs,
+       .bias_regs = pinmux_bias_regs,
+       .ioctrl_regs = pinmux_ioctrl_regs,
+
+       .pinmux_data = pinmux_data,
+       .pinmux_data_size = ARRAY_SIZE(pinmux_data),
+};
index c47eed9..a43824f 100644 (file)
@@ -527,6 +527,8 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
                if (!(cfg & PIN_CFG_IEN))
                        return -EINVAL;
                arg = rzg2l_read_pin_config(pctrl, IEN(port_offset), bit, IEN_MASK);
+               if (!arg)
+                       return -EINVAL;
                break;
 
        case PIN_CONFIG_POWER_SOURCE: {
diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
new file mode 100644 (file)
index 0000000..e8c1819
--- /dev/null
@@ -0,0 +1,1119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/V2M Pin Control and GPIO driver core
+ *
+ * Based on:
+ *   Renesas RZ/G2L Pin Control and GPIO driver core
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/pinctrl/rzv2m-pinctrl.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinmux.h"
+
+#define DRV_NAME       "pinctrl-rzv2m"
+
+/*
+ * Use 16 lower bits [15:0] for pin identifier
+ * Use 16 higher bits [31:16] for pin mux function
+ */
+#define MUX_PIN_ID_MASK                GENMASK(15, 0)
+#define MUX_FUNC_MASK          GENMASK(31, 16)
+#define MUX_FUNC(pinconf)      FIELD_GET(MUX_FUNC_MASK, (pinconf))
+
+/* PIN capabilities */
+#define PIN_CFG_GRP_1_8V_2             1
+#define PIN_CFG_GRP_1_8V_3             2
+#define PIN_CFG_GRP_SWIO_1             3
+#define PIN_CFG_GRP_SWIO_2             4
+#define PIN_CFG_GRP_3_3V               5
+#define PIN_CFG_GRP_MASK               GENMASK(2, 0)
+#define PIN_CFG_BIAS                   BIT(3)
+#define PIN_CFG_DRV                    BIT(4)
+#define PIN_CFG_SLEW                   BIT(5)
+
+#define RZV2M_MPXED_PIN_FUNCS          (PIN_CFG_BIAS | \
+                                        PIN_CFG_DRV | \
+                                        PIN_CFG_SLEW)
+
+/*
+ * n indicates number of pins in the port, a is the register index
+ * and f is pin configuration capabilities supported.
+ */
+#define RZV2M_GPIO_PORT_PACK(n, a, f)  (((n) << 24) | ((a) << 16) | (f))
+#define RZV2M_GPIO_PORT_GET_PINCNT(x)  FIELD_GET(GENMASK(31, 24), (x))
+#define RZV2M_GPIO_PORT_GET_INDEX(x)   FIELD_GET(GENMASK(23, 16), (x))
+#define RZV2M_GPIO_PORT_GET_CFGS(x)    FIELD_GET(GENMASK(15, 0), (x))
+
+#define RZV2M_DEDICATED_PORT_IDX       22
+
+/*
+ * BIT(31) indicates dedicated pin, b is the register bits (b * 16)
+ * and f is the pin configuration capabilities supported.
+ */
+#define RZV2M_SINGLE_PIN               BIT(31)
+#define RZV2M_SINGLE_PIN_PACK(b, f)    (RZV2M_SINGLE_PIN | \
+                                        ((RZV2M_DEDICATED_PORT_IDX) << 24) | \
+                                        ((b) << 16) | (f))
+#define RZV2M_SINGLE_PIN_GET_PORT(x)   FIELD_GET(GENMASK(30, 24), (x))
+#define RZV2M_SINGLE_PIN_GET_BIT(x)    FIELD_GET(GENMASK(23, 16), (x))
+#define RZV2M_SINGLE_PIN_GET_CFGS(x)   FIELD_GET(GENMASK(15, 0), (x))
+
+#define RZV2M_PIN_ID_TO_PORT(id)       ((id) / RZV2M_PINS_PER_PORT)
+#define RZV2M_PIN_ID_TO_PIN(id)                ((id) % RZV2M_PINS_PER_PORT)
+
+#define DO(n)          (0x00 + (n) * 0x40)
+#define OE(n)          (0x04 + (n) * 0x40)
+#define IE(n)          (0x08 + (n) * 0x40)
+#define PFSEL(n)       (0x10 + (n) * 0x40)
+#define DI(n)          (0x20 + (n) * 0x40)
+#define PUPD(n)                (0x24 + (n) * 0x40)
+#define DRV(n)         ((n) < RZV2M_DEDICATED_PORT_IDX ? (0x28 + (n) * 0x40) \
+                                                       : 0x590)
+#define SR(n)          ((n) < RZV2M_DEDICATED_PORT_IDX ? (0x2c + (n) * 0x40) \
+                                                       : 0x594)
+#define DI_MSK(n)      (0x30 + (n) * 0x40)
+#define EN_MSK(n)      (0x34 + (n) * 0x40)
+
+#define PFC_MASK       0x07
+#define PUPD_MASK      0x03
+#define DRV_MASK       0x03
+
+struct rzv2m_dedicated_configs {
+       const char *name;
+       u32 config;
+};
+
+struct rzv2m_pinctrl_data {
+       const char * const *port_pins;
+       const u32 *port_pin_configs;
+       const struct rzv2m_dedicated_configs *dedicated_pins;
+       unsigned int n_port_pins;
+       unsigned int n_dedicated_pins;
+};
+
+struct rzv2m_pinctrl {
+       struct pinctrl_dev              *pctl;
+       struct pinctrl_desc             desc;
+       struct pinctrl_pin_desc         *pins;
+
+       const struct rzv2m_pinctrl_data *data;
+       void __iomem                    *base;
+       struct device                   *dev;
+       struct clk                      *clk;
+
+       struct gpio_chip                gpio_chip;
+       struct pinctrl_gpio_range       gpio_range;
+
+       spinlock_t                      lock;
+};
+
+static const unsigned int drv_1_8V_group2_uA[] = { 1800, 3800, 7800, 11000 };
+static const unsigned int drv_1_8V_group3_uA[] = { 1600, 3200, 6400, 9600 };
+static const unsigned int drv_SWIO_group2_3_3V_uA[] = { 9000, 11000, 13000, 18000 };
+static const unsigned int drv_3_3V_group_uA[] = { 2000, 4000, 8000, 12000 };
+
+/* Helper for registers that have a write enable bit in the upper word */
+static void rzv2m_writel_we(void __iomem *addr, u8 shift, u8 value)
+{
+       writel((BIT(16) | value) << shift, addr);
+}
+
+static void rzv2m_pinctrl_set_pfc_mode(struct rzv2m_pinctrl *pctrl,
+                                      u8 port, u8 pin, u8 func)
+{
+       void __iomem *addr;
+
+       /* Mask input/output */
+       rzv2m_writel_we(pctrl->base + DI_MSK(port), pin, 1);
+       rzv2m_writel_we(pctrl->base + EN_MSK(port), pin, 1);
+
+       /* Select the function and set the write enable bits */
+       addr = pctrl->base + PFSEL(port) + (pin / 4) * 4;
+       writel(((PFC_MASK << 16) | func) << ((pin % 4) * 4), addr);
+
+       /* Unmask input/output */
+       rzv2m_writel_we(pctrl->base + EN_MSK(port), pin, 0);
+       rzv2m_writel_we(pctrl->base + DI_MSK(port), pin, 0);
+};
+
+static int rzv2m_pinctrl_set_mux(struct pinctrl_dev *pctldev,
+                                unsigned int func_selector,
+                                unsigned int group_selector)
+{
+       struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       struct function_desc *func;
+       unsigned int i, *psel_val;
+       struct group_desc *group;
+       int *pins;
+
+       func = pinmux_generic_get_function(pctldev, func_selector);
+       if (!func)
+               return -EINVAL;
+       group = pinctrl_generic_get_group(pctldev, group_selector);
+       if (!group)
+               return -EINVAL;
+
+       psel_val = func->data;
+       pins = group->pins;
+
+       for (i = 0; i < group->num_pins; i++) {
+               dev_dbg(pctrl->dev, "port:%u pin: %u PSEL:%u\n",
+                       RZV2M_PIN_ID_TO_PORT(pins[i]), RZV2M_PIN_ID_TO_PIN(pins[i]),
+                       psel_val[i]);
+               rzv2m_pinctrl_set_pfc_mode(pctrl, RZV2M_PIN_ID_TO_PORT(pins[i]),
+                                          RZV2M_PIN_ID_TO_PIN(pins[i]), psel_val[i]);
+       }
+
+       return 0;
+};
+
+static int rzv2m_map_add_config(struct pinctrl_map *map,
+                               const char *group_or_pin,
+                               enum pinctrl_map_type type,
+                               unsigned long *configs,
+                               unsigned int num_configs)
+{
+       unsigned long *cfgs;
+
+       cfgs = kmemdup(configs, num_configs * sizeof(*cfgs),
+                      GFP_KERNEL);
+       if (!cfgs)
+               return -ENOMEM;
+
+       map->type = type;
+       map->data.configs.group_or_pin = group_or_pin;
+       map->data.configs.configs = cfgs;
+       map->data.configs.num_configs = num_configs;
+
+       return 0;
+}
+
+static int rzv2m_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+                                  struct device_node *np,
+                                  struct pinctrl_map **map,
+                                  unsigned int *num_maps,
+                                  unsigned int *index)
+{
+       struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       struct pinctrl_map *maps = *map;
+       unsigned int nmaps = *num_maps;
+       unsigned long *configs = NULL;
+       unsigned int *pins, *psel_val;
+       unsigned int num_pinmux = 0;
+       unsigned int idx = *index;
+       unsigned int num_pins, i;
+       unsigned int num_configs;
+       struct property *pinmux;
+       struct property *prop;
+       int ret, gsel, fsel;
+       const char **pin_fn;
+       const char *pin;
+
+       pinmux = of_find_property(np, "pinmux", NULL);
+       if (pinmux)
+               num_pinmux = pinmux->length / sizeof(u32);
+
+       ret = of_property_count_strings(np, "pins");
+       if (ret == -EINVAL) {
+               num_pins = 0;
+       } else if (ret < 0) {
+               dev_err(pctrl->dev, "Invalid pins list in DT\n");
+               return ret;
+       } else {
+               num_pins = ret;
+       }
+
+       if (!num_pinmux && !num_pins)
+               return 0;
+
+       if (num_pinmux && num_pins) {
+               dev_err(pctrl->dev,
+                       "DT node must contain either a pinmux or pins and not both\n");
+               return -EINVAL;
+       }
+
+       ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs);
+       if (ret < 0)
+               return ret;
+
+       if (num_pins && !num_configs) {
+               dev_err(pctrl->dev, "DT node must contain a config\n");
+               ret = -ENODEV;
+               goto done;
+       }
+
+       if (num_pinmux)
+               nmaps += 1;
+
+       if (num_pins)
+               nmaps += num_pins;
+
+       maps = krealloc_array(maps, nmaps, sizeof(*maps), GFP_KERNEL);
+       if (!maps) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       *map = maps;
+       *num_maps = nmaps;
+       if (num_pins) {
+               of_property_for_each_string(np, "pins", prop, pin) {
+                       ret = rzv2m_map_add_config(&maps[idx], pin,
+                                                  PIN_MAP_TYPE_CONFIGS_PIN,
+                                                  configs, num_configs);
+                       if (ret < 0)
+                               goto done;
+
+                       idx++;
+               }
+               ret = 0;
+               goto done;
+       }
+
+       pins = devm_kcalloc(pctrl->dev, num_pinmux, sizeof(*pins), GFP_KERNEL);
+       psel_val = devm_kcalloc(pctrl->dev, num_pinmux, sizeof(*psel_val),
+                               GFP_KERNEL);
+       pin_fn = devm_kzalloc(pctrl->dev, sizeof(*pin_fn), GFP_KERNEL);
+       if (!pins || !psel_val || !pin_fn) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       /* Collect pin locations and mux settings from DT properties */
+       for (i = 0; i < num_pinmux; ++i) {
+               u32 value;
+
+               ret = of_property_read_u32_index(np, "pinmux", i, &value);
+               if (ret)
+                       goto done;
+               pins[i] = value & MUX_PIN_ID_MASK;
+               psel_val[i] = MUX_FUNC(value);
+       }
+
+       /* Register a single pin group listing all the pins we read from DT */
+       gsel = pinctrl_generic_add_group(pctldev, np->name, pins, num_pinmux, NULL);
+       if (gsel < 0) {
+               ret = gsel;
+               goto done;
+       }
+
+       /*
+        * Register a single group function where the 'data' is an array PSEL
+        * register values read from DT.
+        */
+       pin_fn[0] = np->name;
+       fsel = pinmux_generic_add_function(pctldev, np->name, pin_fn, 1,
+                                          psel_val);
+       if (fsel < 0) {
+               ret = fsel;
+               goto remove_group;
+       }
+
+       maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
+       maps[idx].data.mux.group = np->name;
+       maps[idx].data.mux.function = np->name;
+       idx++;
+
+       dev_dbg(pctrl->dev, "Parsed %pOF with %d pins\n", np, num_pinmux);
+       ret = 0;
+       goto done;
+
+remove_group:
+       pinctrl_generic_remove_group(pctldev, gsel);
+done:
+       *index = idx;
+       kfree(configs);
+       return ret;
+}
+
+static void rzv2m_dt_free_map(struct pinctrl_dev *pctldev,
+                             struct pinctrl_map *map,
+                             unsigned int num_maps)
+{
+       unsigned int i;
+
+       if (!map)
+               return;
+
+       for (i = 0; i < num_maps; ++i) {
+               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP ||
+                   map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+                       kfree(map[i].data.configs.configs);
+       }
+       kfree(map);
+}
+
+static int rzv2m_dt_node_to_map(struct pinctrl_dev *pctldev,
+                               struct device_node *np,
+                               struct pinctrl_map **map,
+                               unsigned int *num_maps)
+{
+       struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       struct device_node *child;
+       unsigned int index;
+       int ret;
+
+       *map = NULL;
+       *num_maps = 0;
+       index = 0;
+
+       for_each_child_of_node(np, child) {
+               ret = rzv2m_dt_subnode_to_map(pctldev, child, map,
+                                             num_maps, &index);
+               if (ret < 0) {
+                       of_node_put(child);
+                       goto done;
+               }
+       }
+
+       if (*num_maps == 0) {
+               ret = rzv2m_dt_subnode_to_map(pctldev, np, map,
+                                             num_maps, &index);
+               if (ret < 0)
+                       goto done;
+       }
+
+       if (*num_maps)
+               return 0;
+
+       dev_err(pctrl->dev, "no mapping found in node %pOF\n", np);
+       ret = -EINVAL;
+
+done:
+       if (ret < 0)
+               rzv2m_dt_free_map(pctldev, *map, *num_maps);
+
+       return ret;
+}
+
+static int rzv2m_validate_gpio_pin(struct rzv2m_pinctrl *pctrl,
+                                  u32 cfg, u32 port, u8 bit)
+{
+       u8 pincount = RZV2M_GPIO_PORT_GET_PINCNT(cfg);
+       u32 port_index = RZV2M_GPIO_PORT_GET_INDEX(cfg);
+       u32 data;
+
+       if (bit >= pincount || port >= pctrl->data->n_port_pins)
+               return -EINVAL;
+
+       data = pctrl->data->port_pin_configs[port];
+       if (port_index != RZV2M_GPIO_PORT_GET_INDEX(data))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void rzv2m_rmw_pin_config(struct rzv2m_pinctrl *pctrl, u32 offset,
+                                u8 shift, u32 mask, u32 val)
+{
+       void __iomem *addr = pctrl->base + offset;
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&pctrl->lock, flags);
+       reg = readl(addr) & ~(mask << shift);
+       writel(reg | (val << shift), addr);
+       spin_unlock_irqrestore(&pctrl->lock, flags);
+}
+
+static int rzv2m_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
+                                    unsigned int _pin,
+                                    unsigned long *config)
+{
+       struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
+       unsigned int *pin_data = pin->drv_data;
+       unsigned int arg = 0;
+       u32 port;
+       u32 cfg;
+       u8 bit;
+       u32 val;
+
+       if (!pin_data)
+               return -EINVAL;
+
+       if (*pin_data & RZV2M_SINGLE_PIN) {
+               port = RZV2M_SINGLE_PIN_GET_PORT(*pin_data);
+               cfg = RZV2M_SINGLE_PIN_GET_CFGS(*pin_data);
+               bit = RZV2M_SINGLE_PIN_GET_BIT(*pin_data);
+       } else {
+               cfg = RZV2M_GPIO_PORT_GET_CFGS(*pin_data);
+               port = RZV2M_PIN_ID_TO_PORT(_pin);
+               bit = RZV2M_PIN_ID_TO_PIN(_pin);
+
+               if (rzv2m_validate_gpio_pin(pctrl, *pin_data, RZV2M_PIN_ID_TO_PORT(_pin), bit))
+                       return -EINVAL;
+       }
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+       case PIN_CONFIG_BIAS_PULL_UP:
+       case PIN_CONFIG_BIAS_PULL_DOWN: {
+               enum pin_config_param bias;
+
+               if (!(cfg & PIN_CFG_BIAS))
+                       return -EINVAL;
+
+               /* PUPD uses 2-bits per pin */
+               bit *= 2;
+
+               switch ((readl(pctrl->base + PUPD(port)) >> bit) & PUPD_MASK) {
+               case 0:
+                       bias = PIN_CONFIG_BIAS_PULL_DOWN;
+                       break;
+               case 2:
+                       bias = PIN_CONFIG_BIAS_PULL_UP;
+                       break;
+               default:
+                       bias = PIN_CONFIG_BIAS_DISABLE;
+               }
+
+               if (bias != param)
+                       return -EINVAL;
+               break;
+       }
+
+       case PIN_CONFIG_DRIVE_STRENGTH_UA:
+               if (!(cfg & PIN_CFG_DRV))
+                       return -EINVAL;
+
+               /* DRV uses 2-bits per pin */
+               bit *= 2;
+
+               val = (readl(pctrl->base + DRV(port)) >> bit) & DRV_MASK;
+
+               switch (cfg & PIN_CFG_GRP_MASK) {
+               case PIN_CFG_GRP_1_8V_2:
+                       arg = drv_1_8V_group2_uA[val];
+                       break;
+               case PIN_CFG_GRP_1_8V_3:
+                       arg = drv_1_8V_group3_uA[val];
+                       break;
+               case PIN_CFG_GRP_SWIO_2:
+                       arg = drv_SWIO_group2_3_3V_uA[val];
+                       break;
+               case PIN_CFG_GRP_SWIO_1:
+               case PIN_CFG_GRP_3_3V:
+                       arg = drv_3_3V_group_uA[val];
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               break;
+
+       case PIN_CONFIG_SLEW_RATE:
+               if (!(cfg & PIN_CFG_SLEW))
+                       return -EINVAL;
+
+               arg = readl(pctrl->base + SR(port)) & BIT(bit);
+               break;
+
+       default:
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+};
+
+static int rzv2m_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
+                                    unsigned int _pin,
+                                    unsigned long *_configs,
+                                    unsigned int num_configs)
+{
+       struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
+       unsigned int *pin_data = pin->drv_data;
+       enum pin_config_param param;
+       u32 port;
+       unsigned int i;
+       u32 cfg;
+       u8 bit;
+       u32 val;
+
+       if (!pin_data)
+               return -EINVAL;
+
+       if (*pin_data & RZV2M_SINGLE_PIN) {
+               port = RZV2M_SINGLE_PIN_GET_PORT(*pin_data);
+               cfg = RZV2M_SINGLE_PIN_GET_CFGS(*pin_data);
+               bit = RZV2M_SINGLE_PIN_GET_BIT(*pin_data);
+       } else {
+               cfg = RZV2M_GPIO_PORT_GET_CFGS(*pin_data);
+               port = RZV2M_PIN_ID_TO_PORT(_pin);
+               bit = RZV2M_PIN_ID_TO_PIN(_pin);
+
+               if (rzv2m_validate_gpio_pin(pctrl, *pin_data, RZV2M_PIN_ID_TO_PORT(_pin), bit))
+                       return -EINVAL;
+       }
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(_configs[i]);
+               switch (param) {
+               case PIN_CONFIG_BIAS_DISABLE:
+               case PIN_CONFIG_BIAS_PULL_UP:
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       if (!(cfg & PIN_CFG_BIAS))
+                               return -EINVAL;
+
+                       /* PUPD uses 2-bits per pin */
+                       bit *= 2;
+
+                       switch (param) {
+                       case PIN_CONFIG_BIAS_PULL_DOWN:
+                               val = 0;
+                               break;
+                       case PIN_CONFIG_BIAS_PULL_UP:
+                               val = 2;
+                               break;
+                       default:
+                               val = 1;
+                       }
+
+                       rzv2m_rmw_pin_config(pctrl, PUPD(port), bit, PUPD_MASK, val);
+                       break;
+
+               case PIN_CONFIG_DRIVE_STRENGTH_UA: {
+                       unsigned int arg = pinconf_to_config_argument(_configs[i]);
+                       const unsigned int *drv_strengths;
+                       unsigned int index;
+
+                       if (!(cfg & PIN_CFG_DRV))
+                               return -EINVAL;
+
+                       switch (cfg & PIN_CFG_GRP_MASK) {
+                       case PIN_CFG_GRP_1_8V_2:
+                               drv_strengths = drv_1_8V_group2_uA;
+                               break;
+                       case PIN_CFG_GRP_1_8V_3:
+                               drv_strengths = drv_1_8V_group3_uA;
+                               break;
+                       case PIN_CFG_GRP_SWIO_2:
+                               drv_strengths = drv_SWIO_group2_3_3V_uA;
+                               break;
+                       case PIN_CFG_GRP_SWIO_1:
+                       case PIN_CFG_GRP_3_3V:
+                               drv_strengths = drv_3_3V_group_uA;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+
+                       for (index = 0; index < 4; index++) {
+                               if (arg == drv_strengths[index])
+                                       break;
+                       }
+                       if (index >= 4)
+                               return -EINVAL;
+
+                       /* DRV uses 2-bits per pin */
+                       bit *= 2;
+
+                       rzv2m_rmw_pin_config(pctrl, DRV(port), bit, DRV_MASK, index);
+                       break;
+               }
+
+               case PIN_CONFIG_SLEW_RATE: {
+                       unsigned int arg = pinconf_to_config_argument(_configs[i]);
+
+                       if (!(cfg & PIN_CFG_SLEW))
+                               return -EINVAL;
+
+                       rzv2m_writel_we(pctrl->base + SR(port), bit, !arg);
+                       break;
+               }
+
+               default:
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
+static int rzv2m_pinctrl_pinconf_group_set(struct pinctrl_dev *pctldev,
+                                          unsigned int group,
+                                          unsigned long *configs,
+                                          unsigned int num_configs)
+{
+       const unsigned int *pins;
+       unsigned int i, npins;
+       int ret;
+
+       ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < npins; i++) {
+               ret = rzv2m_pinctrl_pinconf_set(pctldev, pins[i], configs,
+                                               num_configs);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+};
+
+static int rzv2m_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev,
+                                          unsigned int group,
+                                          unsigned long *config)
+{
+       const unsigned int *pins;
+       unsigned int i, npins, prev_config = 0;
+       int ret;
+
+       ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < npins; i++) {
+               ret = rzv2m_pinctrl_pinconf_get(pctldev, pins[i], config);
+               if (ret)
+                       return ret;
+
+               /* Check config matches previous pins */
+               if (i && prev_config != *config)
+                       return -EOPNOTSUPP;
+
+               prev_config = *config;
+       }
+
+       return 0;
+};
+
+static const struct pinctrl_ops rzv2m_pinctrl_pctlops = {
+       .get_groups_count = pinctrl_generic_get_group_count,
+       .get_group_name = pinctrl_generic_get_group_name,
+       .get_group_pins = pinctrl_generic_get_group_pins,
+       .dt_node_to_map = rzv2m_dt_node_to_map,
+       .dt_free_map = rzv2m_dt_free_map,
+};
+
+static const struct pinmux_ops rzv2m_pinctrl_pmxops = {
+       .get_functions_count = pinmux_generic_get_function_count,
+       .get_function_name = pinmux_generic_get_function_name,
+       .get_function_groups = pinmux_generic_get_function_groups,
+       .set_mux = rzv2m_pinctrl_set_mux,
+       .strict = true,
+};
+
+static const struct pinconf_ops rzv2m_pinctrl_confops = {
+       .is_generic = true,
+       .pin_config_get = rzv2m_pinctrl_pinconf_get,
+       .pin_config_set = rzv2m_pinctrl_pinconf_set,
+       .pin_config_group_set = rzv2m_pinctrl_pinconf_group_set,
+       .pin_config_group_get = rzv2m_pinctrl_pinconf_group_get,
+       .pin_config_config_dbg_show = pinconf_generic_dump_config,
+};
+
+static int rzv2m_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+       struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+       u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+       u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+       int ret;
+
+       ret = pinctrl_gpio_request(chip->base + offset);
+       if (ret)
+               return ret;
+
+       rzv2m_pinctrl_set_pfc_mode(pctrl, port, bit, 0);
+
+       return 0;
+}
+
+static void rzv2m_gpio_set_direction(struct rzv2m_pinctrl *pctrl, u32 port,
+                                    u8 bit, bool output)
+{
+       rzv2m_writel_we(pctrl->base + OE(port), bit, output);
+       rzv2m_writel_we(pctrl->base + IE(port), bit, !output);
+}
+
+static int rzv2m_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+       struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+       u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+       u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+
+       if (!(readl(pctrl->base + IE(port)) & BIT(bit)))
+               return GPIO_LINE_DIRECTION_OUT;
+
+       return GPIO_LINE_DIRECTION_IN;
+}
+
+static int rzv2m_gpio_direction_input(struct gpio_chip *chip,
+                                     unsigned int offset)
+{
+       struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+       u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+       u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+
+       rzv2m_gpio_set_direction(pctrl, port, bit, false);
+
+       return 0;
+}
+
+static void rzv2m_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                          int value)
+{
+       struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+       u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+       u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+
+       rzv2m_writel_we(pctrl->base + DO(port), bit, !!value);
+}
+
+static int rzv2m_gpio_direction_output(struct gpio_chip *chip,
+                                      unsigned int offset, int value)
+{
+       struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+       u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+       u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+
+       rzv2m_gpio_set(chip, offset, value);
+       rzv2m_gpio_set_direction(pctrl, port, bit, true);
+
+       return 0;
+}
+
+static int rzv2m_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+       u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+       u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+       int direction = rzv2m_gpio_get_direction(chip, offset);
+
+       if (direction == GPIO_LINE_DIRECTION_IN)
+               return !!(readl(pctrl->base + DI(port)) & BIT(bit));
+       else
+               return !!(readl(pctrl->base + DO(port)) & BIT(bit));
+}
+
+static void rzv2m_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+       pinctrl_gpio_free(chip->base + offset);
+
+       /*
+        * Set the GPIO as an input to ensure that the next GPIO request won't
+        * drive the GPIO pin as an output.
+        */
+       rzv2m_gpio_direction_input(chip, offset);
+}
+
+static const char * const rzv2m_gpio_names[] = {
+       "P0_0", "P0_1", "P0_2", "P0_3", "P0_4", "P0_5", "P0_6", "P0_7",
+       "P0_8", "P0_9", "P0_10", "P0_11", "P0_12", "P0_13", "P0_14", "P0_15",
+       "P1_0", "P1_1", "P1_2", "P1_3", "P1_4", "P1_5", "P1_6", "P1_7",
+       "P1_8", "P1_9", "P1_10", "P1_11", "P1_12", "P1_13", "P1_14", "P1_15",
+       "P2_0", "P2_1", "P2_2", "P2_3", "P2_4", "P2_5", "P2_6", "P2_7",
+       "P2_8", "P2_9", "P2_10", "P2_11", "P2_12", "P2_13", "P2_14", "P2_15",
+       "P3_0", "P3_1", "P3_2", "P3_3", "P3_4", "P3_5", "P3_6", "P3_7",
+       "P3_8", "P3_9", "P3_10", "P3_11", "P3_12", "P3_13", "P3_14", "P3_15",
+       "P4_0", "P4_1", "P4_2", "P4_3", "P4_4", "P4_5", "P4_6", "P4_7",
+       "P4_8", "P4_9", "P4_10", "P4_11", "P4_12", "P4_13", "P4_14", "P4_15",
+       "P5_0", "P5_1", "P5_2", "P5_3", "P5_4", "P5_5", "P5_6", "P5_7",
+       "P5_8", "P5_9", "P5_10", "P5_11", "P5_12", "P5_13", "P5_14", "P5_15",
+       "P6_0", "P6_1", "P6_2", "P6_3", "P6_4", "P6_5", "P6_6", "P6_7",
+       "P6_8", "P6_9", "P6_10", "P6_11", "P6_12", "P6_13", "P6_14", "P6_15",
+       "P7_0", "P7_1", "P7_2", "P7_3", "P7_4", "P7_5", "P7_6", "P7_7",
+       "P7_8", "P7_9", "P7_10", "P7_11", "P7_12", "P7_13", "P7_14", "P7_15",
+       "P8_0", "P8_1", "P8_2", "P8_3", "P8_4", "P8_5", "P8_6", "P8_7",
+       "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15",
+       "P9_0", "P9_1", "P9_2", "P9_3", "P9_4", "P9_5", "P9_6", "P9_7",
+       "P9_8", "P9_9", "P9_10", "P9_11", "P9_12", "P9_13", "P9_14", "P9_15",
+       "P10_0", "P10_1", "P10_2", "P10_3", "P10_4", "P10_5", "P10_6", "P10_7",
+       "P10_8", "P10_9", "P10_10", "P10_11", "P10_12", "P10_13", "P10_14", "P10_15",
+       "P11_0", "P11_1", "P11_2", "P11_3", "P11_4", "P11_5", "P11_6", "P11_7",
+       "P11_8", "P11_9", "P11_10", "P11_11", "P11_12", "P11_13", "P11_14", "P11_15",
+       "P12_0", "P12_1", "P12_2", "P12_3", "P12_4", "P12_5", "P12_6", "P12_7",
+       "P12_8", "P12_9", "P12_10", "P12_11", "P12_12", "P12_13", "P12_14", "P12_15",
+       "P13_0", "P13_1", "P13_2", "P13_3", "P13_4", "P13_5", "P13_6", "P13_7",
+       "P13_8", "P13_9", "P13_10", "P13_11", "P13_12", "P13_13", "P13_14", "P13_15",
+       "P14_0", "P14_1", "P14_2", "P14_3", "P14_4", "P14_5", "P14_6", "P14_7",
+       "P14_8", "P14_9", "P14_10", "P14_11", "P14_12", "P14_13", "P14_14", "P14_15",
+       "P15_0", "P15_1", "P15_2", "P15_3", "P15_4", "P15_5", "P15_6", "P15_7",
+       "P15_8", "P15_9", "P15_10", "P15_11", "P15_12", "P15_13", "P15_14", "P15_15",
+       "P16_0", "P16_1", "P16_2", "P16_3", "P16_4", "P16_5", "P16_6", "P16_7",
+       "P16_8", "P16_9", "P16_10", "P16_11", "P16_12", "P16_13", "P16_14", "P16_15",
+       "P17_0", "P17_1", "P17_2", "P17_3", "P17_4", "P17_5", "P17_6", "P17_7",
+       "P17_8", "P17_9", "P17_10", "P17_11", "P17_12", "P17_13", "P17_14", "P17_15",
+       "P18_0", "P18_1", "P18_2", "P18_3", "P18_4", "P18_5", "P18_6", "P18_7",
+       "P18_8", "P18_9", "P18_10", "P18_11", "P18_12", "P18_13", "P18_14", "P18_15",
+       "P19_0", "P19_1", "P19_2", "P19_3", "P19_4", "P19_5", "P19_6", "P19_7",
+       "P19_8", "P19_9", "P19_10", "P19_11", "P19_12", "P19_13", "P19_14", "P19_15",
+       "P20_0", "P20_1", "P20_2", "P20_3", "P20_4", "P20_5", "P20_6", "P20_7",
+       "P20_8", "P20_9", "P20_10", "P20_11", "P20_12", "P20_13", "P20_14", "P20_15",
+       "P21_0", "P21_1", "P21_2", "P21_3", "P21_4", "P21_5", "P21_6", "P21_7",
+       "P21_8", "P21_9", "P21_10", "P21_11", "P21_12", "P21_13", "P21_14", "P21_15",
+};
+
+static const u32 rzv2m_gpio_configs[] = {
+       RZV2M_GPIO_PORT_PACK(14, 0, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(16, 1, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(8,  2, PIN_CFG_GRP_1_8V_3 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(16, 3, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(8,  4, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(4,  5, PIN_CFG_GRP_1_8V_3 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(12, 6, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(6,  7, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(8,  8, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(8,  9, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(9,  10, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(9,  11, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(4,  12, PIN_CFG_GRP_3_3V | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(12, 13, PIN_CFG_GRP_3_3V | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(8,  14, PIN_CFG_GRP_3_3V | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(16, 15, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(14, 16, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(1,  17, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+       RZV2M_GPIO_PORT_PACK(0,  18, 0),
+       RZV2M_GPIO_PORT_PACK(0,  19, 0),
+       RZV2M_GPIO_PORT_PACK(3,  20, PIN_CFG_GRP_1_8V_2 | PIN_CFG_DRV),
+       RZV2M_GPIO_PORT_PACK(1,  21, PIN_CFG_GRP_SWIO_1 | PIN_CFG_DRV | PIN_CFG_SLEW),
+};
+
+static const struct rzv2m_dedicated_configs rzv2m_dedicated_pins[] = {
+       { "NAWPN", RZV2M_SINGLE_PIN_PACK(0,
+               (PIN_CFG_GRP_SWIO_2 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+       { "IM0CLK", RZV2M_SINGLE_PIN_PACK(1,
+               (PIN_CFG_GRP_SWIO_1 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+       { "IM1CLK", RZV2M_SINGLE_PIN_PACK(2,
+               (PIN_CFG_GRP_SWIO_1 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+       { "DETDO", RZV2M_SINGLE_PIN_PACK(5,
+               (PIN_CFG_GRP_1_8V_3 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+       { "DETMS", RZV2M_SINGLE_PIN_PACK(6,
+               (PIN_CFG_GRP_1_8V_3 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+       { "PCRSTOUTB", RZV2M_SINGLE_PIN_PACK(12,
+               (PIN_CFG_GRP_3_3V | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+       { "USPWEN", RZV2M_SINGLE_PIN_PACK(14,
+               (PIN_CFG_GRP_3_3V | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+};
+
+static int rzv2m_gpio_register(struct rzv2m_pinctrl *pctrl)
+{
+       struct device_node *np = pctrl->dev->of_node;
+       struct gpio_chip *chip = &pctrl->gpio_chip;
+       const char *name = dev_name(pctrl->dev);
+       struct of_phandle_args of_args;
+       int ret;
+
+       ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &of_args);
+       if (ret) {
+               dev_err(pctrl->dev, "Unable to parse gpio-ranges\n");
+               return ret;
+       }
+
+       if (of_args.args[0] != 0 || of_args.args[1] != 0 ||
+           of_args.args[2] != pctrl->data->n_port_pins) {
+               dev_err(pctrl->dev, "gpio-ranges does not match selected SOC\n");
+               return -EINVAL;
+       }
+
+       chip->names = pctrl->data->port_pins;
+       chip->request = rzv2m_gpio_request;
+       chip->free = rzv2m_gpio_free;
+       chip->get_direction = rzv2m_gpio_get_direction;
+       chip->direction_input = rzv2m_gpio_direction_input;
+       chip->direction_output = rzv2m_gpio_direction_output;
+       chip->get = rzv2m_gpio_get;
+       chip->set = rzv2m_gpio_set;
+       chip->label = name;
+       chip->parent = pctrl->dev;
+       chip->owner = THIS_MODULE;
+       chip->base = -1;
+       chip->ngpio = of_args.args[2];
+
+       pctrl->gpio_range.id = 0;
+       pctrl->gpio_range.pin_base = 0;
+       pctrl->gpio_range.base = 0;
+       pctrl->gpio_range.npins = chip->ngpio;
+       pctrl->gpio_range.name = chip->label;
+       pctrl->gpio_range.gc = chip;
+       ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
+       if (ret) {
+               dev_err(pctrl->dev, "failed to add GPIO controller\n");
+               return ret;
+       }
+
+       dev_dbg(pctrl->dev, "Registered gpio controller\n");
+
+       return 0;
+}
+
+static int rzv2m_pinctrl_register(struct rzv2m_pinctrl *pctrl)
+{
+       struct pinctrl_pin_desc *pins;
+       unsigned int i, j;
+       u32 *pin_data;
+       int ret;
+
+       pctrl->desc.name = DRV_NAME;
+       pctrl->desc.npins = pctrl->data->n_port_pins + pctrl->data->n_dedicated_pins;
+       pctrl->desc.pctlops = &rzv2m_pinctrl_pctlops;
+       pctrl->desc.pmxops = &rzv2m_pinctrl_pmxops;
+       pctrl->desc.confops = &rzv2m_pinctrl_confops;
+       pctrl->desc.owner = THIS_MODULE;
+
+       pins = devm_kcalloc(pctrl->dev, pctrl->desc.npins, sizeof(*pins), GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       pin_data = devm_kcalloc(pctrl->dev, pctrl->desc.npins,
+                               sizeof(*pin_data), GFP_KERNEL);
+       if (!pin_data)
+               return -ENOMEM;
+
+       pctrl->pins = pins;
+       pctrl->desc.pins = pins;
+
+       for (i = 0, j = 0; i < pctrl->data->n_port_pins; i++) {
+               pins[i].number = i;
+               pins[i].name = pctrl->data->port_pins[i];
+               if (i && !(i % RZV2M_PINS_PER_PORT))
+                       j++;
+               pin_data[i] = pctrl->data->port_pin_configs[j];
+               pins[i].drv_data = &pin_data[i];
+       }
+
+       for (i = 0; i < pctrl->data->n_dedicated_pins; i++) {
+               unsigned int index = pctrl->data->n_port_pins + i;
+
+               pins[index].number = index;
+               pins[index].name = pctrl->data->dedicated_pins[i].name;
+               pin_data[index] = pctrl->data->dedicated_pins[i].config;
+               pins[index].drv_data = &pin_data[index];
+       }
+
+       ret = devm_pinctrl_register_and_init(pctrl->dev, &pctrl->desc, pctrl,
+                                            &pctrl->pctl);
+       if (ret) {
+               dev_err(pctrl->dev, "pinctrl registration failed\n");
+               return ret;
+       }
+
+       ret = pinctrl_enable(pctrl->pctl);
+       if (ret) {
+               dev_err(pctrl->dev, "pinctrl enable failed\n");
+               return ret;
+       }
+
+       ret = rzv2m_gpio_register(pctrl);
+       if (ret) {
+               dev_err(pctrl->dev, "failed to add GPIO chip: %i\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void rzv2m_pinctrl_clk_disable(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
+static int rzv2m_pinctrl_probe(struct platform_device *pdev)
+{
+       struct rzv2m_pinctrl *pctrl;
+       int ret;
+
+       pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+       if (!pctrl)
+               return -ENOMEM;
+
+       pctrl->dev = &pdev->dev;
+
+       pctrl->data = of_device_get_match_data(&pdev->dev);
+       if (!pctrl->data)
+               return -EINVAL;
+
+       pctrl->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(pctrl->base))
+               return PTR_ERR(pctrl->base);
+
+       pctrl->clk = devm_clk_get(pctrl->dev, NULL);
+       if (IS_ERR(pctrl->clk)) {
+               ret = PTR_ERR(pctrl->clk);
+               dev_err(pctrl->dev, "failed to get GPIO clk : %i\n", ret);
+               return ret;
+       }
+
+       spin_lock_init(&pctrl->lock);
+
+       platform_set_drvdata(pdev, pctrl);
+
+       ret = clk_prepare_enable(pctrl->clk);
+       if (ret) {
+               dev_err(pctrl->dev, "failed to enable GPIO clk: %i\n", ret);
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&pdev->dev, rzv2m_pinctrl_clk_disable,
+                                      pctrl->clk);
+       if (ret) {
+               dev_err(pctrl->dev,
+                       "failed to register GPIO clk disable action, %i\n",
+                       ret);
+               return ret;
+       }
+
+       ret = rzv2m_pinctrl_register(pctrl);
+       if (ret)
+               return ret;
+
+       dev_info(pctrl->dev, "%s support registered\n", DRV_NAME);
+       return 0;
+}
+
+static struct rzv2m_pinctrl_data r9a09g011_data = {
+       .port_pins = rzv2m_gpio_names,
+       .port_pin_configs = rzv2m_gpio_configs,
+       .dedicated_pins = rzv2m_dedicated_pins,
+       .n_port_pins = ARRAY_SIZE(rzv2m_gpio_configs) * RZV2M_PINS_PER_PORT,
+       .n_dedicated_pins = ARRAY_SIZE(rzv2m_dedicated_pins),
+};
+
+static const struct of_device_id rzv2m_pinctrl_of_table[] = {
+       {
+               .compatible = "renesas,r9a09g011-pinctrl",
+               .data = &r9a09g011_data,
+       },
+       { /* sentinel */ }
+};
+
+static struct platform_driver rzv2m_pinctrl_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = of_match_ptr(rzv2m_pinctrl_of_table),
+       },
+       .probe = rzv2m_pinctrl_probe,
+};
+
+static int __init rzv2m_pinctrl_init(void)
+{
+       return platform_driver_register(&rzv2m_pinctrl_driver);
+}
+core_initcall(rzv2m_pinctrl_init);
+
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_DESCRIPTION("Pin and gpio controller driver for RZ/V2M");
+MODULE_LICENSE("GPL");
index 12bc279..0fcb29a 100644 (file)
@@ -325,6 +325,7 @@ extern const struct sh_pfc_soc_info r8a77990_pinmux_info;
 extern const struct sh_pfc_soc_info r8a77995_pinmux_info;
 extern const struct sh_pfc_soc_info r8a779a0_pinmux_info;
 extern const struct sh_pfc_soc_info r8a779f0_pinmux_info;
+extern const struct sh_pfc_soc_info r8a779g0_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;
@@ -492,9 +493,13 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
        PORT_GP_CFG_1(bank, 11, fn, sfx, cfg)
 #define PORT_GP_12(bank, fn, sfx)      PORT_GP_CFG_12(bank, fn, sfx, 0)
 
-#define PORT_GP_CFG_14(bank, fn, sfx, cfg)                             \
+#define PORT_GP_CFG_13(bank, fn, sfx, cfg)                             \
        PORT_GP_CFG_12(bank, fn, sfx, cfg),                             \
-       PORT_GP_CFG_1(bank, 12, fn, sfx, cfg),                          \
+       PORT_GP_CFG_1(bank, 12, fn, sfx, cfg)
+#define PORT_GP_13(bank, fn, sfx)      PORT_GP_CFG_13(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_14(bank, fn, sfx, cfg)                             \
+       PORT_GP_CFG_13(bank, fn, sfx, cfg),                             \
        PORT_GP_CFG_1(bank, 13, fn, sfx, cfg)
 #define PORT_GP_14(bank, fn, sfx)      PORT_GP_CFG_14(bank, fn, sfx, 0)
 
index 6d7ca17..a8212fc 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/soc/samsung/exynos-pmu.h>
 #include <linux/soc/samsung/exynos-regs-pmu.h>
 
-#include <dt-bindings/pinctrl/samsung.h>
-
 #include "pinctrl-samsung.h"
 #include "pinctrl-exynos.h"
 
@@ -173,7 +171,7 @@ static int exynos_irq_request_resources(struct irq_data *irqd)
 
        con = readl(bank->pctl_base + reg_con);
        con &= ~(mask << shift);
-       con |= EXYNOS_PIN_FUNC_EINT << shift;
+       con |= EXYNOS_PIN_CON_FUNC_EINT << shift;
        writel(con, bank->pctl_base + reg_con);
 
        raw_spin_unlock_irqrestore(&bank->slock, flags);
@@ -196,7 +194,7 @@ static void exynos_irq_release_resources(struct irq_data *irqd)
 
        con = readl(bank->pctl_base + reg_con);
        con &= ~(mask << shift);
-       con |= EXYNOS_PIN_FUNC_INPUT << shift;
+       con |= PIN_CON_FUNC_INPUT << shift;
        writel(con, bank->pctl_base + reg_con);
 
        raw_spin_unlock_irqrestore(&bank->slock, flags);
index bfad1ce..7bd6d82 100644 (file)
@@ -16,6 +16,9 @@
 #ifndef __PINCTRL_SAMSUNG_EXYNOS_H
 #define __PINCTRL_SAMSUNG_EXYNOS_H
 
+/* Values for the pin CON register */
+#define EXYNOS_PIN_CON_FUNC_EINT       0xf
+
 /* External GPIO and wakeup interrupt related definitions */
 #define EXYNOS_GPIO_ECON_OFFSET                0x700
 #define EXYNOS_GPIO_EFLTCON_OFFSET     0x800
index 26d309d..4837bce 100644 (file)
@@ -26,8 +26,6 @@
 #include <linux/of_device.h>
 #include <linux/spinlock.h>
 
-#include <dt-bindings/pinctrl/samsung.h>
-
 #include "../core.h"
 #include "pinctrl-samsung.h"
 
@@ -614,7 +612,7 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,
        data = readl(reg);
        data &= ~(mask << shift);
        if (!input)
-               data |= EXYNOS_PIN_FUNC_OUTPUT << shift;
+               data |= PIN_CON_FUNC_OUTPUT << shift;
        writel(data, reg);
 
        return 0;
index fc6f519..9af93e3 100644 (file)
@@ -53,6 +53,14 @@ enum pincfg_type {
 #define PINCFG_UNPACK_TYPE(cfg)                ((cfg) & PINCFG_TYPE_MASK)
 #define PINCFG_UNPACK_VALUE(cfg)       (((cfg) & PINCFG_VALUE_MASK) >> \
                                                PINCFG_VALUE_SHIFT)
+/*
+ * Values for the pin CON register, choosing pin function.
+ * The basic set (input and output) are same between: S3C24xx, S3C64xx, S5PV210,
+ * Exynos ARMv7, Exynos ARMv8, Tesla FSD.
+ */
+#define PIN_CON_FUNC_INPUT             0x0
+#define PIN_CON_FUNC_OUTPUT            0x1
+
 /**
  * enum eint_type - possible external interrupt types.
  * @EINT_TYPE_NONE: bank does not support external interrupts
index 33751a6..a78fdbb 100644 (file)
@@ -29,7 +29,6 @@ config PINCTRL_SUN6I_A31
 config PINCTRL_SUN6I_A31_R
        bool "Support for the Allwinner A31 R-PIO"
        default MACH_SUN6I
-       depends on RESET_CONTROLLER
        select PINCTRL_SUNXI
 
 config PINCTRL_SUN8I_A23
@@ -55,7 +54,6 @@ config PINCTRL_SUN8I_A83T_R
 config PINCTRL_SUN8I_A23_R
        bool "Support for the Allwinner A23 and A33 R-PIO"
        default MACH_SUN8I
-       depends on RESET_CONTROLLER
        select PINCTRL_SUNXI
 
 config PINCTRL_SUN8I_H3
@@ -81,7 +79,11 @@ config PINCTRL_SUN9I_A80
 config PINCTRL_SUN9I_A80_R
        bool "Support for the Allwinner A80 R-PIO"
        default MACH_SUN9I
-       depends on RESET_CONTROLLER
+       select PINCTRL_SUNXI
+
+config PINCTRL_SUN20I_D1
+       bool "Support for the Allwinner D1 PIO"
+       default MACH_SUN8I || (RISCV && ARCH_SUNXI)
        select PINCTRL_SUNXI
 
 config PINCTRL_SUN50I_A64
index d3440c4..2ff5a55 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_PINCTRL_SUN8I_A83T_R)    += pinctrl-sun8i-a83t-r.o
 obj-$(CONFIG_PINCTRL_SUN8I_H3)         += pinctrl-sun8i-h3.o
 obj-$(CONFIG_PINCTRL_SUN8I_H3_R)       += pinctrl-sun8i-h3-r.o
 obj-$(CONFIG_PINCTRL_SUN8I_V3S)                += pinctrl-sun8i-v3s.o
+obj-$(CONFIG_PINCTRL_SUN20I_D1)                += pinctrl-sun20i-d1.o
 obj-$(CONFIG_PINCTRL_SUN50I_H5)                += pinctrl-sun50i-h5.o
 obj-$(CONFIG_PINCTRL_SUN50I_H6)                += pinctrl-sun50i-h6.o
 obj-$(CONFIG_PINCTRL_SUN50I_H6_R)      += pinctrl-sun50i-h6-r.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c b/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c
new file mode 100644 (file)
index 0000000..40858b8
--- /dev/null
@@ -0,0 +1,840 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner D1 SoC pinctrl driver.
+ *
+ * Copyright (c) 2020 wuyan@allwinnertech.com
+ * Copyright (c) 2021-2022 Samuel Holland <samuel@sholland.org>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin d1_pins[] = {
+       /* PB */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "pwm3"),
+               SUNXI_FUNCTION(0x3, "ir"),              /* TX */
+               SUNXI_FUNCTION(0x4, "i2c2"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "spi1"),            /* WP */
+               SUNXI_FUNCTION(0x6, "uart0"),           /* TX */
+               SUNXI_FUNCTION(0x7, "uart2"),           /* TX */
+               SUNXI_FUNCTION(0x8, "spdif"),           /* OUT */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 0)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "pwm4"),
+               SUNXI_FUNCTION(0x3, "i2s2_dout"),       /* DOUT3 */
+               SUNXI_FUNCTION(0x4, "i2c2"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "i2s2_din"),        /* DIN3 */
+               SUNXI_FUNCTION(0x6, "uart0"),           /* RX */
+               SUNXI_FUNCTION(0x7, "uart2"),           /* RX */
+               SUNXI_FUNCTION(0x8, "ir"),              /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 1)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D0 */
+               SUNXI_FUNCTION(0x3, "i2s2_dout"),       /* DOUT2 */
+               SUNXI_FUNCTION(0x4, "i2c0"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "i2s2_din"),        /* DIN2 */
+               SUNXI_FUNCTION(0x6, "lcd0"),            /* D18 */
+               SUNXI_FUNCTION(0x7, "uart4"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 2)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D1 */
+               SUNXI_FUNCTION(0x3, "i2s2_dout"),       /* DOUT1 */
+               SUNXI_FUNCTION(0x4, "i2c0"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "i2s2_din"),        /* DIN0 */
+               SUNXI_FUNCTION(0x6, "lcd0"),            /* D19 */
+               SUNXI_FUNCTION(0x7, "uart4"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 3)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D8 */
+               SUNXI_FUNCTION(0x3, "i2s2_dout"),       /* DOUT0 */
+               SUNXI_FUNCTION(0x4, "i2c1"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "i2s2_din"),        /* DIN1 */
+               SUNXI_FUNCTION(0x6, "lcd0"),            /* D20 */
+               SUNXI_FUNCTION(0x7, "uart5"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 4)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D9 */
+               SUNXI_FUNCTION(0x3, "i2s2"),            /* BCLK */
+               SUNXI_FUNCTION(0x4, "i2c1"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "pwm0"),
+               SUNXI_FUNCTION(0x6, "lcd0"),            /* D21 */
+               SUNXI_FUNCTION(0x7, "uart5"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 5)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D16 */
+               SUNXI_FUNCTION(0x3, "i2s2"),            /* LRCK */
+               SUNXI_FUNCTION(0x4, "i2c3"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "pwm1"),
+               SUNXI_FUNCTION(0x6, "lcd0"),            /* D22 */
+               SUNXI_FUNCTION(0x7, "uart3"),           /* TX */
+               SUNXI_FUNCTION(0x8, "bist0"),           /* BIST_RESULT0 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 6)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D17 */
+               SUNXI_FUNCTION(0x3, "i2s2"),            /* MCLK */
+               SUNXI_FUNCTION(0x4, "i2c3"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "ir"),              /* RX */
+               SUNXI_FUNCTION(0x6, "lcd0"),            /* D23 */
+               SUNXI_FUNCTION(0x7, "uart3"),           /* RX */
+               SUNXI_FUNCTION(0x8, "bist1"),           /* BIST_RESULT1 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 7)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "dmic"),            /* DATA3 */
+               SUNXI_FUNCTION(0x3, "pwm5"),
+               SUNXI_FUNCTION(0x4, "i2c2"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "spi1"),            /* HOLD */
+               SUNXI_FUNCTION(0x6, "uart0"),           /* TX */
+               SUNXI_FUNCTION(0x7, "uart1"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 8)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "dmic"),            /* DATA2 */
+               SUNXI_FUNCTION(0x3, "pwm6"),
+               SUNXI_FUNCTION(0x4, "i2c2"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "spi1"),            /* MISO */
+               SUNXI_FUNCTION(0x6, "uart0"),           /* RX */
+               SUNXI_FUNCTION(0x7, "uart1"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 9)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "dmic"),            /* DATA1 */
+               SUNXI_FUNCTION(0x3, "pwm7"),
+               SUNXI_FUNCTION(0x4, "i2c0"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "spi1"),            /* MOSI */
+               SUNXI_FUNCTION(0x6, "clk"),             /* FANOUT0 */
+               SUNXI_FUNCTION(0x7, "uart1"),           /* RTS */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 10)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 11),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "dmic"),            /* DATA0 */
+               SUNXI_FUNCTION(0x3, "pwm2"),
+               SUNXI_FUNCTION(0x4, "i2c0"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "spi1"),            /* CLK */
+               SUNXI_FUNCTION(0x6, "clk"),             /* FANOUT1 */
+               SUNXI_FUNCTION(0x7, "uart1"),           /* CTS */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 11)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 12),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "dmic"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "pwm0"),
+               SUNXI_FUNCTION(0x4, "spdif"),           /* IN */
+               SUNXI_FUNCTION(0x5, "spi1"),            /* CS0 */
+               SUNXI_FUNCTION(0x6, "clk"),             /* FANOUT2 */
+               SUNXI_FUNCTION(0x7, "ir"),              /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 12)),
+       /* PC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "uart2"),           /* TX */
+               SUNXI_FUNCTION(0x3, "i2c2"),            /* SCK */
+               SUNXI_FUNCTION(0x4, "ledc"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 0)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "uart2"),           /* RX */
+               SUNXI_FUNCTION(0x3, "i2c2"),            /* SDA */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 1)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "mmc2"),            /* CLK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 2)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* CS0 */
+               SUNXI_FUNCTION(0x3, "mmc2"),            /* CMD */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 3)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* MOSI */
+               SUNXI_FUNCTION(0x3, "mmc2"),            /* D2 */
+               SUNXI_FUNCTION(0x4, "boot"),            /* SEL0 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 4)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* MISO */
+               SUNXI_FUNCTION(0x3, "mmc2"),            /* D1 */
+               SUNXI_FUNCTION(0x4, "boot"),            /* SEL1 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 5)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* WP */
+               SUNXI_FUNCTION(0x3, "mmc2"),            /* D0 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* TX */
+               SUNXI_FUNCTION(0x5, "i2c3"),            /* SCK */
+               SUNXI_FUNCTION(0x6, "pll"),             /* DBG-CLK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 6)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* HOLD */
+               SUNXI_FUNCTION(0x3, "mmc2"),            /* D3 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* RX */
+               SUNXI_FUNCTION(0x5, "i2c3"),            /* SDA */
+               SUNXI_FUNCTION(0x6, "tcon"),            /* TRIG0 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 7)),
+       /* PD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D2 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* V0P */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* D0P */
+               SUNXI_FUNCTION(0x5, "i2c0"),            /* SCK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 0)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D3 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* V0N */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* D0N */
+               SUNXI_FUNCTION(0x5, "uart2"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 1)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D4 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* V1P */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* D1P */
+               SUNXI_FUNCTION(0x5, "uart2"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 2)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D5 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* V1N */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* D1N */
+               SUNXI_FUNCTION(0x5, "uart2"),           /* RTS */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 3)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D6 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* V2P */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* CKP */
+               SUNXI_FUNCTION(0x5, "uart2"),           /* CTS */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 4)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D7 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* V2N */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* CKN */
+               SUNXI_FUNCTION(0x5, "uart5"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 5)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D10 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* CKP */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* D2P */
+               SUNXI_FUNCTION(0x5, "uart5"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 6)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D11 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* CKN */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* D2N */
+               SUNXI_FUNCTION(0x5, "uart4"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 7)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D12 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* V3P */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* D3P */
+               SUNXI_FUNCTION(0x5, "uart4"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 8)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D13 */
+               SUNXI_FUNCTION(0x3, "lvds0"),           /* V3N */
+               SUNXI_FUNCTION(0x4, "dsi"),             /* D3N */
+               SUNXI_FUNCTION(0x5, "pwm6"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 9)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D14 */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* V0P */
+               SUNXI_FUNCTION(0x4, "spi1"),            /* CS0 */
+               SUNXI_FUNCTION(0x5, "uart3"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 10)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D15 */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* V0N */
+               SUNXI_FUNCTION(0x4, "spi1"),            /* CLK */
+               SUNXI_FUNCTION(0x5, "uart3"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 11)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D18 */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* V1P */
+               SUNXI_FUNCTION(0x4, "spi1"),            /* MOSI */
+               SUNXI_FUNCTION(0x5, "i2c0"),            /* SDA */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 12)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D19 */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* V1N */
+               SUNXI_FUNCTION(0x4, "spi1"),            /* MISO */
+               SUNXI_FUNCTION(0x5, "uart3"),           /* RTS */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 13)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D20 */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* V2P */
+               SUNXI_FUNCTION(0x4, "spi1"),            /* HOLD */
+               SUNXI_FUNCTION(0x5, "uart3"),           /* CTS */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 14)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D21 */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* V2N */
+               SUNXI_FUNCTION(0x4, "spi1"),            /* WP */
+               SUNXI_FUNCTION(0x5, "ir"),              /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 15)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D22 */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* CKP */
+               SUNXI_FUNCTION(0x4, "dmic"),            /* DATA3 */
+               SUNXI_FUNCTION(0x5, "pwm0"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 16)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D23 */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* CKN */
+               SUNXI_FUNCTION(0x4, "dmic"),            /* DATA2 */
+               SUNXI_FUNCTION(0x5, "pwm1"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 17)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* V3P */
+               SUNXI_FUNCTION(0x4, "dmic"),            /* DATA1 */
+               SUNXI_FUNCTION(0x5, "pwm2"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 18)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* DE */
+               SUNXI_FUNCTION(0x3, "lvds1"),           /* V3N */
+               SUNXI_FUNCTION(0x4, "dmic"),            /* DATA0 */
+               SUNXI_FUNCTION(0x5, "pwm3"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 19)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* HSYNC */
+               SUNXI_FUNCTION(0x3, "i2c2"),            /* SCK */
+               SUNXI_FUNCTION(0x4, "dmic"),            /* CLK */
+               SUNXI_FUNCTION(0x5, "pwm4"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 20)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* VSYNC */
+               SUNXI_FUNCTION(0x3, "i2c2"),            /* SDA */
+               SUNXI_FUNCTION(0x4, "uart1"),           /* TX */
+               SUNXI_FUNCTION(0x5, "pwm5"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 21)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spdif"),           /* OUT */
+               SUNXI_FUNCTION(0x3, "ir"),              /* RX */
+               SUNXI_FUNCTION(0x4, "uart1"),           /* RX */
+               SUNXI_FUNCTION(0x5, "pwm7"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 22)),
+       /* PE */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* HSYNC */
+               SUNXI_FUNCTION(0x3, "uart2"),           /* RTS */
+               SUNXI_FUNCTION(0x4, "i2c1"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "lcd0"),            /* HSYNC */
+               SUNXI_FUNCTION(0x8, "emac"),            /* RXCTL/CRS_DV */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 0)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* VSYNC */
+               SUNXI_FUNCTION(0x3, "uart2"),           /* CTS */
+               SUNXI_FUNCTION(0x4, "i2c1"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "lcd0"),            /* VSYNC */
+               SUNXI_FUNCTION(0x8, "emac"),            /* RXD0 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 1)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* PCLK */
+               SUNXI_FUNCTION(0x3, "uart2"),           /* TX */
+               SUNXI_FUNCTION(0x4, "i2c0"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT0 */
+               SUNXI_FUNCTION(0x6, "uart0"),           /* TX */
+               SUNXI_FUNCTION(0x8, "emac"),            /* RXD1 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 2)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* MCLK */
+               SUNXI_FUNCTION(0x3, "uart2"),           /* RX */
+               SUNXI_FUNCTION(0x4, "i2c0"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT1 */
+               SUNXI_FUNCTION(0x6, "uart0"),           /* RX */
+               SUNXI_FUNCTION(0x8, "emac"),            /* TXCK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 3)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* D0 */
+               SUNXI_FUNCTION(0x3, "uart4"),           /* TX */
+               SUNXI_FUNCTION(0x4, "i2c2"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT2 */
+               SUNXI_FUNCTION(0x6, "d_jtag"),          /* MS */
+               SUNXI_FUNCTION(0x7, "r_jtag"),          /* MS */
+               SUNXI_FUNCTION(0x8, "emac"),            /* TXD0 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 4)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* D1 */
+               SUNXI_FUNCTION(0x3, "uart4"),           /* RX */
+               SUNXI_FUNCTION(0x4, "i2c2"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "ledc"),
+               SUNXI_FUNCTION(0x6, "d_jtag"),          /* DI */
+               SUNXI_FUNCTION(0x7, "r_jtag"),          /* DI */
+               SUNXI_FUNCTION(0x8, "emac"),            /* TXD1 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 5)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* D2 */
+               SUNXI_FUNCTION(0x3, "uart5"),           /* TX */
+               SUNXI_FUNCTION(0x4, "i2c3"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "spdif"),           /* IN */
+               SUNXI_FUNCTION(0x6, "d_jtag"),          /* DO */
+               SUNXI_FUNCTION(0x7, "r_jtag"),          /* DO */
+               SUNXI_FUNCTION(0x8, "emac"),            /* TXCTL/TXEN */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 6)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* D3 */
+               SUNXI_FUNCTION(0x3, "uart5"),           /* RX */
+               SUNXI_FUNCTION(0x4, "i2c3"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "spdif"),           /* OUT */
+               SUNXI_FUNCTION(0x6, "d_jtag"),          /* CK */
+               SUNXI_FUNCTION(0x7, "r_jtag"),          /* CK */
+               SUNXI_FUNCTION(0x8, "emac"),            /* CK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 7)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* D4 */
+               SUNXI_FUNCTION(0x3, "uart1"),           /* RTS */
+               SUNXI_FUNCTION(0x4, "pwm2"),
+               SUNXI_FUNCTION(0x5, "uart3"),           /* TX */
+               SUNXI_FUNCTION(0x6, "jtag"),            /* MS */
+               SUNXI_FUNCTION(0x8, "emac"),            /* MDC */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 8)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* D5 */
+               SUNXI_FUNCTION(0x3, "uart1"),           /* CTS */
+               SUNXI_FUNCTION(0x4, "pwm3"),
+               SUNXI_FUNCTION(0x5, "uart3"),           /* RX */
+               SUNXI_FUNCTION(0x6, "jtag"),            /* DI */
+               SUNXI_FUNCTION(0x8, "emac"),            /* MDIO */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 9)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* D6 */
+               SUNXI_FUNCTION(0x3, "uart1"),           /* TX */
+               SUNXI_FUNCTION(0x4, "pwm4"),
+               SUNXI_FUNCTION(0x5, "ir"),              /* RX */
+               SUNXI_FUNCTION(0x6, "jtag"),            /* DO */
+               SUNXI_FUNCTION(0x8, "emac"),            /* EPHY-25M */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 10)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ncsi0"),           /* D7 */
+               SUNXI_FUNCTION(0x3, "uart1"),           /* RX */
+               SUNXI_FUNCTION(0x4, "i2s0_dout"),       /* DOUT3 */
+               SUNXI_FUNCTION(0x5, "i2s0_din"),        /* DIN3 */
+               SUNXI_FUNCTION(0x6, "jtag"),            /* CK */
+               SUNXI_FUNCTION(0x8, "emac"),            /* TXD2 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 11)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c2"),            /* SCK */
+               SUNXI_FUNCTION(0x3, "ncsi0"),           /* FIELD */
+               SUNXI_FUNCTION(0x4, "i2s0_dout"),       /* DOUT2 */
+               SUNXI_FUNCTION(0x5, "i2s0_din"),        /* DIN2 */
+               SUNXI_FUNCTION(0x8, "emac"),            /* TXD3 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 12)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c2"),            /* SDA */
+               SUNXI_FUNCTION(0x3, "pwm5"),
+               SUNXI_FUNCTION(0x4, "i2s0_dout"),       /* DOUT0 */
+               SUNXI_FUNCTION(0x5, "i2s0_din"),        /* DIN1 */
+               SUNXI_FUNCTION(0x6, "dmic"),            /* DATA3 */
+               SUNXI_FUNCTION(0x8, "emac"),            /* RXD2 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 13)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c1"),            /* SCK */
+               SUNXI_FUNCTION(0x3, "d_jtag"),          /* MS */
+               SUNXI_FUNCTION(0x4, "i2s0_dout"),       /* DOUT1 */
+               SUNXI_FUNCTION(0x5, "i2s0_din"),        /* DIN0 */
+               SUNXI_FUNCTION(0x6, "dmic"),            /* DATA2 */
+               SUNXI_FUNCTION(0x8, "emac"),            /* RXD3 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 14)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c1"),            /* SDA */
+               SUNXI_FUNCTION(0x3, "d_jtag"),          /* DI */
+               SUNXI_FUNCTION(0x4, "pwm6"),
+               SUNXI_FUNCTION(0x5, "i2s0"),            /* LRCK */
+               SUNXI_FUNCTION(0x6, "dmic"),            /* DATA1 */
+               SUNXI_FUNCTION(0x8, "emac"),            /* RXCK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 15)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c3"),            /* SCK */
+               SUNXI_FUNCTION(0x3, "d_jtag"),          /* DO */
+               SUNXI_FUNCTION(0x4, "pwm7"),
+               SUNXI_FUNCTION(0x5, "i2s0"),            /* BCLK */
+               SUNXI_FUNCTION(0x6, "dmic"),            /* DATA0 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 16)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c3"),            /* SDA */
+               SUNXI_FUNCTION(0x3, "d_jtag"),          /* CK */
+               SUNXI_FUNCTION(0x4, "ir"),              /* TX */
+               SUNXI_FUNCTION(0x5, "i2s0"),            /* MCLK */
+               SUNXI_FUNCTION(0x6, "dmic"),            /* CLK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 17)),
+       /* PF */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* D1 */
+               SUNXI_FUNCTION(0x3, "jtag"),            /* MS */
+               SUNXI_FUNCTION(0x4, "r_jtag"),          /* MS */
+               SUNXI_FUNCTION(0x5, "i2s2_dout"),       /* DOUT1 */
+               SUNXI_FUNCTION(0x6, "i2s2_din"),        /* DIN0 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 0)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* D0 */
+               SUNXI_FUNCTION(0x3, "jtag"),            /* DI */
+               SUNXI_FUNCTION(0x4, "r_jtag"),          /* DI */
+               SUNXI_FUNCTION(0x5, "i2s2_dout"),       /* DOUT0 */
+               SUNXI_FUNCTION(0x6, "i2s2_din"),        /* DIN1 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 1)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "uart0"),           /* TX */
+               SUNXI_FUNCTION(0x4, "i2c0"),            /* SCK */
+               SUNXI_FUNCTION(0x5, "ledc"),
+               SUNXI_FUNCTION(0x6, "spdif"),           /* IN */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 2)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* CMD */
+               SUNXI_FUNCTION(0x3, "jtag"),            /* DO */
+               SUNXI_FUNCTION(0x4, "r_jtag"),          /* DO */
+               SUNXI_FUNCTION(0x5, "i2s2"),            /* BCLK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 3)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* D3 */
+               SUNXI_FUNCTION(0x3, "uart0"),           /* RX */
+               SUNXI_FUNCTION(0x4, "i2c0"),            /* SDA */
+               SUNXI_FUNCTION(0x5, "pwm6"),
+               SUNXI_FUNCTION(0x6, "ir"),              /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 4)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* D2 */
+               SUNXI_FUNCTION(0x3, "jtag"),            /* CK */
+               SUNXI_FUNCTION(0x4, "r_jtag"),          /* CK */
+               SUNXI_FUNCTION(0x5, "i2s2"),            /* LRCK */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 5)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "spdif"),           /* OUT */
+               SUNXI_FUNCTION(0x4, "ir"),              /* RX */
+               SUNXI_FUNCTION(0x5, "i2s2"),            /* MCLK */
+               SUNXI_FUNCTION(0x6, "pwm5"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 6)),
+       /* PG */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc1"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "uart3"),           /* TX */
+               SUNXI_FUNCTION(0x4, "emac"),            /* RXCTRL/CRS_DV */
+               SUNXI_FUNCTION(0x5, "pwm7"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 0)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc1"),            /* CMD */
+               SUNXI_FUNCTION(0x3, "uart3"),           /* RX */
+               SUNXI_FUNCTION(0x4, "emac"),            /* RXD0 */
+               SUNXI_FUNCTION(0x5, "pwm6"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 1)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc1"),            /* D0 */
+               SUNXI_FUNCTION(0x3, "uart3"),           /* RTS */
+               SUNXI_FUNCTION(0x4, "emac"),            /* RXD1 */
+               SUNXI_FUNCTION(0x5, "uart4"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 2)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc1"),            /* D1 */
+               SUNXI_FUNCTION(0x3, "uart3"),           /* CTS */
+               SUNXI_FUNCTION(0x4, "emac"),            /* TXCK */
+               SUNXI_FUNCTION(0x5, "uart4"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 3)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc1"),            /* D2 */
+               SUNXI_FUNCTION(0x3, "uart5"),           /* TX */
+               SUNXI_FUNCTION(0x4, "emac"),            /* TXD0 */
+               SUNXI_FUNCTION(0x5, "pwm5"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 4)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc1"),            /* D3 */
+               SUNXI_FUNCTION(0x3, "uart5"),           /* RX */
+               SUNXI_FUNCTION(0x4, "emac"),            /* TXD1 */
+               SUNXI_FUNCTION(0x5, "pwm4"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 5)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "uart1"),           /* TX */
+               SUNXI_FUNCTION(0x3, "i2c2"),            /* SCK */
+               SUNXI_FUNCTION(0x4, "emac"),            /* TXD2 */
+               SUNXI_FUNCTION(0x5, "pwm1"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 6)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "uart1"),           /* RX */
+               SUNXI_FUNCTION(0x3, "i2c2"),            /* SDA */
+               SUNXI_FUNCTION(0x4, "emac"),            /* TXD3 */
+               SUNXI_FUNCTION(0x5, "spdif"),           /* IN */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 7)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "uart1"),           /* RTS */
+               SUNXI_FUNCTION(0x3, "i2c1"),            /* SCK */
+               SUNXI_FUNCTION(0x4, "emac"),            /* RXD2 */
+               SUNXI_FUNCTION(0x5, "uart3"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 8)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "uart1"),           /* CTS */
+               SUNXI_FUNCTION(0x3, "i2c1"),            /* SDA */
+               SUNXI_FUNCTION(0x4, "emac"),            /* RXD3 */
+               SUNXI_FUNCTION(0x5, "uart3"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 9)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "pwm3"),
+               SUNXI_FUNCTION(0x3, "i2c3"),            /* SCK */
+               SUNXI_FUNCTION(0x4, "emac"),            /* RXCK */
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT0 */
+               SUNXI_FUNCTION(0x6, "ir"),              /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 10)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s1"),            /* MCLK */
+               SUNXI_FUNCTION(0x3, "i2c3"),            /* SDA */
+               SUNXI_FUNCTION(0x4, "emac"),            /* EPHY-25M */
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT1 */
+               SUNXI_FUNCTION(0x6, "tcon"),            /* TRIG0 */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 11)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s1"),            /* LRCK */
+               SUNXI_FUNCTION(0x3, "i2c0"),            /* SCK */
+               SUNXI_FUNCTION(0x4, "emac"),            /* TXCTL/TXEN */
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT2 */
+               SUNXI_FUNCTION(0x6, "pwm0"),
+               SUNXI_FUNCTION(0x7, "uart1"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 12)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s1"),            /* BCLK */
+               SUNXI_FUNCTION(0x3, "i2c0"),            /* SDA */
+               SUNXI_FUNCTION(0x4, "emac"),            /* CLKIN/RXER */
+               SUNXI_FUNCTION(0x5, "pwm2"),
+               SUNXI_FUNCTION(0x6, "ledc"),
+               SUNXI_FUNCTION(0x7, "uart1"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 13)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 14),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s1_din"),        /* DIN0 */
+               SUNXI_FUNCTION(0x3, "i2c2"),            /* SCK */
+               SUNXI_FUNCTION(0x4, "emac"),            /* MDC */
+               SUNXI_FUNCTION(0x5, "i2s1_dout"),       /* DOUT1 */
+               SUNXI_FUNCTION(0x6, "spi0"),            /* WP */
+               SUNXI_FUNCTION(0x7, "uart1"),           /* RTS */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 14)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 15),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s1_dout"),       /* DOUT0 */
+               SUNXI_FUNCTION(0x3, "i2c2"),            /* SDA */
+               SUNXI_FUNCTION(0x4, "emac"),            /* MDIO */
+               SUNXI_FUNCTION(0x5, "i2s1_din"),        /* DIN1 */
+               SUNXI_FUNCTION(0x6, "spi0"),            /* HOLD */
+               SUNXI_FUNCTION(0x7, "uart1"),           /* CTS */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 15)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 16),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ir"),              /* RX */
+               SUNXI_FUNCTION(0x3, "tcon"),            /* TRIG0 */
+               SUNXI_FUNCTION(0x4, "pwm5"),
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT2 */
+               SUNXI_FUNCTION(0x6, "spdif"),           /* IN */
+               SUNXI_FUNCTION(0x7, "ledc"),
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 16)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 17),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "uart2"),           /* TX */
+               SUNXI_FUNCTION(0x3, "i2c3"),            /* SCK */
+               SUNXI_FUNCTION(0x4, "pwm7"),
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT0 */
+               SUNXI_FUNCTION(0x6, "ir"),              /* TX */
+               SUNXI_FUNCTION(0x7, "uart0"),           /* TX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 17)),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 18),
+               SUNXI_FUNCTION(0x0, "gpio_in"),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "uart2"),           /* RX */
+               SUNXI_FUNCTION(0x3, "i2c3"),            /* SDA */
+               SUNXI_FUNCTION(0x4, "pwm6"),
+               SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT1 */
+               SUNXI_FUNCTION(0x6, "spdif"),           /* OUT */
+               SUNXI_FUNCTION(0x7, "uart0"),           /* RX */
+               SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 18)),
+};
+
+static const unsigned int d1_irq_bank_map[] = { 1, 2, 3, 4, 5, 6 };
+
+static const struct sunxi_pinctrl_desc d1_pinctrl_data = {
+       .pins                   = d1_pins,
+       .npins                  = ARRAY_SIZE(d1_pins),
+       .irq_banks              = ARRAY_SIZE(d1_irq_bank_map),
+       .irq_bank_map           = d1_irq_bank_map,
+       .io_bias_cfg_variant    = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
+};
+
+static int d1_pinctrl_probe(struct platform_device *pdev)
+{
+       unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev);
+
+       return sunxi_pinctrl_init_with_variant(pdev, &d1_pinctrl_data, variant);
+}
+
+static const struct of_device_id d1_pinctrl_match[] = {
+       {
+               .compatible = "allwinner,sun20i-d1-pinctrl",
+               .data = (void *)PINCTRL_SUN20I_D1
+       },
+       {}
+};
+
+static struct platform_driver d1_pinctrl_driver = {
+       .probe  = d1_pinctrl_probe,
+       .driver = {
+               .name           = "sun20i-d1-pinctrl",
+               .of_match_table = d1_pinctrl_match,
+       },
+};
+builtin_platform_driver(d1_pinctrl_driver);
index 21054fc..afc1f5d 100644 (file)
@@ -82,6 +82,7 @@ static const struct sunxi_pinctrl_desc a100_r_pinctrl_data = {
        .npins = ARRAY_SIZE(a100_r_pins),
        .pin_base = PL_BASE,
        .irq_banks = 1,
+       .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
 };
 
 static int a100_r_pinctrl_probe(struct platform_device *pdev)
index e69f6da..f682e0e 100644 (file)
@@ -684,7 +684,7 @@ static const struct sunxi_pinctrl_desc a100_pinctrl_data = {
        .npins = ARRAY_SIZE(a100_pins),
        .irq_banks = 7,
        .irq_bank_map = a100_irq_bank_map,
-       .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+       .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
 };
 
 static int a100_pinctrl_probe(struct platform_device *pdev)
index e69c8da..ef261ec 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/platform_device.h>
-#include <linux/reset.h>
 
 #include "pinctrl-sunxi.h"
 
index c7d90c4..3aba0ae 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
 
 #include "pinctrl-sunxi.h"
 
@@ -107,6 +106,7 @@ static const struct sunxi_pinctrl_desc sun50i_h6_r_pinctrl_data = {
        .npins = ARRAY_SIZE(sun50i_h6_r_pins),
        .pin_base = PL_BASE,
        .irq_banks = 2,
+       .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
 };
 
 static int sun50i_h6_r_pinctrl_probe(struct platform_device *pdev)
index 8e4f10a..c39ea46 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
 
 #include "pinctrl-sunxi.h"
 
index 152b712..d6ca720 100644 (file)
@@ -525,7 +525,7 @@ static const struct sunxi_pinctrl_desc h616_pinctrl_data = {
        .irq_banks = ARRAY_SIZE(h616_irq_bank_map),
        .irq_bank_map = h616_irq_bank_map,
        .irq_read_needs_mux = true,
-       .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+       .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
 };
 
 static int h616_pinctrl_probe(struct platform_device *pdev)
index a00246d..2486cdf 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
 
 #include "pinctrl-sunxi.h"
 
@@ -111,26 +110,7 @@ static const struct sunxi_pinctrl_desc sun6i_a31_r_pinctrl_data = {
 
 static int sun6i_a31_r_pinctrl_probe(struct platform_device *pdev)
 {
-       struct reset_control *rstc;
-       int ret;
-
-       rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-       if (IS_ERR(rstc)) {
-               dev_err(&pdev->dev, "Reset controller missing\n");
-               return PTR_ERR(rstc);
-       }
-
-       ret = reset_control_deassert(rstc);
-       if (ret)
-               return ret;
-
-       ret = sunxi_pinctrl_init(pdev,
-                                &sun6i_a31_r_pinctrl_data);
-
-       if (ret)
-               reset_control_assert(rstc);
-
-       return ret;
+       return sunxi_pinctrl_init(pdev, &sun6i_a31_r_pinctrl_data);
 }
 
 static const struct of_device_id sun6i_a31_r_pinctrl_match[] = {
index 9e5b614..4fae12c 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
 
 #include "pinctrl-sunxi.h"
 
@@ -98,29 +97,7 @@ static const struct sunxi_pinctrl_desc sun8i_a23_r_pinctrl_data = {
 
 static int sun8i_a23_r_pinctrl_probe(struct platform_device *pdev)
 {
-       struct reset_control *rstc;
-       int ret;
-
-       rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-       if (IS_ERR(rstc)) {
-               ret = PTR_ERR(rstc);
-               if (ret == -EPROBE_DEFER)
-                       return ret;
-               dev_err(&pdev->dev, "Reset controller missing err=%d\n", ret);
-               return ret;
-       }
-
-       ret = reset_control_deassert(rstc);
-       if (ret)
-               return ret;
-
-       ret = sunxi_pinctrl_init(pdev,
-                                &sun8i_a23_r_pinctrl_data);
-
-       if (ret)
-               reset_control_assert(rstc);
-
-       return ret;
+       return sunxi_pinctrl_init(pdev, &sun8i_a23_r_pinctrl_data);
 }
 
 static const struct of_device_id sun8i_a23_r_pinctrl_match[] = {
index 6531cf6..0cb6c1a 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/platform_device.h>
-#include <linux/reset.h>
 
 #include "pinctrl-sunxi.h"
 
index a191a65..f11cb5b 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
 
 #include "pinctrl-sunxi.h"
 
index dd92840..6c04027 100644 (file)
@@ -46,6 +46,67 @@ static struct lock_class_key sunxi_pinctrl_irq_request_class;
 static struct irq_chip sunxi_pinctrl_edge_irq_chip;
 static struct irq_chip sunxi_pinctrl_level_irq_chip;
 
+/*
+ * The sunXi PIO registers are organized as a series of banks, with registers
+ * for each bank in the following order:
+ *  - Mux config
+ *  - Data value
+ *  - Drive level
+ *  - Pull direction
+ *
+ * Multiple consecutive registers are used for fields wider than one bit.
+ *
+ * The following functions calculate the register and the bit offset to access.
+ * They take a pin number which is relative to the start of the current device.
+ */
+static void sunxi_mux_reg(const struct sunxi_pinctrl *pctl,
+                         u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * MUX_FIELD_WIDTH;
+
+       *reg   = bank * pctl->bank_mem_size + MUX_REGS_OFFSET +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(MUX_FIELD_WIDTH) - 1) << *shift;
+}
+
+static void sunxi_data_reg(const struct sunxi_pinctrl *pctl,
+                          u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * DATA_FIELD_WIDTH;
+
+       *reg   = bank * pctl->bank_mem_size + DATA_REGS_OFFSET +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(DATA_FIELD_WIDTH) - 1) << *shift;
+}
+
+static void sunxi_dlevel_reg(const struct sunxi_pinctrl *pctl,
+                            u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * pctl->dlevel_field_width;
+
+       *reg   = bank * pctl->bank_mem_size + DLEVEL_REGS_OFFSET +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(pctl->dlevel_field_width) - 1) << *shift;
+}
+
+static void sunxi_pull_reg(const struct sunxi_pinctrl *pctl,
+                          u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * PULL_FIELD_WIDTH;
+
+       *reg   = bank * pctl->bank_mem_size + pctl->pull_regs_offset +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(PULL_FIELD_WIDTH) - 1) << *shift;
+}
+
 static struct sunxi_pinctrl_group *
 sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
 {
@@ -451,22 +512,19 @@ static const struct pinctrl_ops sunxi_pctrl_ops = {
        .get_group_pins         = sunxi_pctrl_get_group_pins,
 };
 
-static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
-                          u32 *offset, u32 *shift, u32 *mask)
+static int sunxi_pconf_reg(const struct sunxi_pinctrl *pctl,
+                          u32 pin, enum pin_config_param param,
+                          u32 *reg, u32 *shift, u32 *mask)
 {
        switch (param) {
        case PIN_CONFIG_DRIVE_STRENGTH:
-               *offset = sunxi_dlevel_reg(pin);
-               *shift = sunxi_dlevel_offset(pin);
-               *mask = DLEVEL_PINS_MASK;
+               sunxi_dlevel_reg(pctl, pin, reg, shift, mask);
                break;
 
        case PIN_CONFIG_BIAS_PULL_UP:
        case PIN_CONFIG_BIAS_PULL_DOWN:
        case PIN_CONFIG_BIAS_DISABLE:
-               *offset = sunxi_pull_reg(pin);
-               *shift = sunxi_pull_offset(pin);
-               *mask = PULL_PINS_MASK;
+               sunxi_pull_reg(pctl, pin, reg, shift, mask);
                break;
 
        default:
@@ -481,17 +539,17 @@ static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
 {
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param = pinconf_to_config_param(*config);
-       u32 offset, shift, mask, val;
+       u32 reg, shift, mask, val;
        u16 arg;
        int ret;
 
        pin -= pctl->desc->pin_base;
 
-       ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
+       ret = sunxi_pconf_reg(pctl, pin, param, &reg, &shift, &mask);
        if (ret < 0)
                return ret;
 
-       val = (readl(pctl->membase + offset) >> shift) & mask;
+       val = (readl(pctl->membase + reg) & mask) >> shift;
 
        switch (pinconf_to_config_param(*config)) {
        case PIN_CONFIG_DRIVE_STRENGTH:
@@ -547,16 +605,15 @@ static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
        pin -= pctl->desc->pin_base;
 
        for (i = 0; i < num_configs; i++) {
+               u32 arg, reg, shift, mask, val;
                enum pin_config_param param;
                unsigned long flags;
-               u32 offset, shift, mask, reg;
-               u32 arg, val;
                int ret;
 
                param = pinconf_to_config_param(configs[i]);
                arg = pinconf_to_config_argument(configs[i]);
 
-               ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
+               ret = sunxi_pconf_reg(pctl, pin, param, &reg, &shift, &mask);
                if (ret < 0)
                        return ret;
 
@@ -593,9 +650,8 @@ static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
                }
 
                raw_spin_lock_irqsave(&pctl->lock, flags);
-               reg = readl(pctl->membase + offset);
-               reg &= ~(mask << shift);
-               writel(reg | val << shift, pctl->membase + offset);
+               writel((readl(pctl->membase + reg) & ~mask) | val << shift,
+                      pctl->membase + reg);
                raw_spin_unlock_irqrestore(&pctl->lock, flags);
        } /* for each config */
 
@@ -624,7 +680,7 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
                                         unsigned pin,
                                         struct regulator *supply)
 {
-       unsigned short bank = pin / PINS_PER_BANK;
+       unsigned short bank;
        unsigned long flags;
        u32 val, reg;
        int uV;
@@ -640,6 +696,9 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
        if (uV == 0)
                return 0;
 
+       pin -= pctl->desc->pin_base;
+       bank = pin / PINS_PER_BANK;
+
        switch (pctl->desc->io_bias_cfg_variant) {
        case BIAS_VOLTAGE_GRP_CONFIG:
                /*
@@ -657,12 +716,20 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
                else
                        val = 0xD; /* 3.3V */
 
-               pin -= pctl->desc->pin_base;
-
                reg = readl(pctl->membase + sunxi_grp_config_reg(pin));
                reg &= ~IO_BIAS_MASK;
                writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin));
                return 0;
+       case BIAS_VOLTAGE_PIO_POW_MODE_CTL:
+               val = uV > 1800000 && uV <= 2500000 ? BIT(bank) : 0;
+
+               raw_spin_lock_irqsave(&pctl->lock, flags);
+               reg = readl(pctl->membase + PIO_POW_MOD_CTL_REG);
+               reg &= ~BIT(bank);
+               writel(reg | val, pctl->membase + PIO_POW_MOD_CTL_REG);
+               raw_spin_unlock_irqrestore(&pctl->lock, flags);
+
+               fallthrough;
        case BIAS_VOLTAGE_PIO_POW_MODE_SEL:
                val = uV <= 1800000 ? 1 : 0;
 
@@ -710,16 +777,16 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
                                 u8 config)
 {
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       u32 reg, shift, mask;
        unsigned long flags;
-       u32 val, mask;
+
+       pin -= pctl->desc->pin_base;
+       sunxi_mux_reg(pctl, pin, &reg, &shift, &mask);
 
        raw_spin_lock_irqsave(&pctl->lock, flags);
 
-       pin -= pctl->desc->pin_base;
-       val = readl(pctl->membase + sunxi_mux_reg(pin));
-       mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
-       writel((val & ~mask) | config << sunxi_mux_offset(pin),
-               pctl->membase + sunxi_mux_reg(pin));
+       writel((readl(pctl->membase + reg) & ~mask) | config << shift,
+              pctl->membase + reg);
 
        raw_spin_unlock_irqrestore(&pctl->lock, flags);
 }
@@ -852,43 +919,43 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
 static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
-       u32 reg = sunxi_data_reg(offset);
-       u8 index = sunxi_data_offset(offset);
        bool set_mux = pctl->desc->irq_read_needs_mux &&
                gpiochip_line_is_irq(chip, offset);
        u32 pin = offset + chip->base;
-       u32 val;
+       u32 reg, shift, mask, val;
+
+       sunxi_data_reg(pctl, offset, &reg, &shift, &mask);
 
        if (set_mux)
                sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT);
 
-       val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+       val = (readl(pctl->membase + reg) & mask) >> shift;
 
        if (set_mux)
                sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ);
 
-       return !!val;
+       return val;
 }
 
 static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
                                unsigned offset, int value)
 {
        struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
-       u32 reg = sunxi_data_reg(offset);
-       u8 index = sunxi_data_offset(offset);
+       u32 reg, shift, mask, val;
        unsigned long flags;
-       u32 regval;
+
+       sunxi_data_reg(pctl, offset, &reg, &shift, &mask);
 
        raw_spin_lock_irqsave(&pctl->lock, flags);
 
-       regval = readl(pctl->membase + reg);
+       val = readl(pctl->membase + reg);
 
        if (value)
-               regval |= BIT(index);
+               val |= mask;
        else
-               regval &= ~(BIT(index));
+               val &= ~mask;
 
-       writel(regval, pctl->membase + reg);
+       writel(val, pctl->membase + reg);
 
        raw_spin_unlock_irqrestore(&pctl->lock, flags);
 }
@@ -1232,11 +1299,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
 
        /*
         * Find an upper bound for the maximum number of functions: in
-        * the worst case we have gpio_in, gpio_out, irq and up to four
+        * the worst case we have gpio_in, gpio_out, irq and up to seven
         * special functions per pin, plus one entry for the sentinel.
         * We'll reallocate that later anyway.
         */
-       pctl->functions = kcalloc(4 * pctl->ngroups + 4,
+       pctl->functions = kcalloc(7 * pctl->ngroups + 4,
                                  sizeof(*pctl->functions),
                                  GFP_KERNEL);
        if (!pctl->functions)
@@ -1429,6 +1496,15 @@ int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
        pctl->dev = &pdev->dev;
        pctl->desc = desc;
        pctl->variant = variant;
+       if (pctl->variant >= PINCTRL_SUN20I_D1) {
+               pctl->bank_mem_size = D1_BANK_MEM_SIZE;
+               pctl->pull_regs_offset = D1_PULL_REGS_OFFSET;
+               pctl->dlevel_field_width = D1_DLEVEL_FIELD_WIDTH;
+       } else {
+               pctl->bank_mem_size = BANK_MEM_SIZE;
+               pctl->pull_regs_offset = PULL_REGS_OFFSET;
+               pctl->dlevel_field_width = DLEVEL_FIELD_WIDTH;
+       }
 
        pctl->irq_array = devm_kcalloc(&pdev->dev,
                                       IRQ_PER_BANK * pctl->desc->irq_banks,
index a32bb5b..a87a2f9 100644 (file)
 
 #define BANK_MEM_SIZE          0x24
 #define MUX_REGS_OFFSET                0x0
+#define MUX_FIELD_WIDTH                4
 #define DATA_REGS_OFFSET       0x10
+#define DATA_FIELD_WIDTH       1
 #define DLEVEL_REGS_OFFSET     0x14
+#define DLEVEL_FIELD_WIDTH     2
 #define PULL_REGS_OFFSET       0x1c
+#define PULL_FIELD_WIDTH       2
+
+#define D1_BANK_MEM_SIZE       0x30
+#define D1_DLEVEL_FIELD_WIDTH  4
+#define D1_PULL_REGS_OFFSET    0x24
 
 #define PINS_PER_BANK          32
-#define MUX_PINS_PER_REG       8
-#define MUX_PINS_BITS          4
-#define MUX_PINS_MASK          0x0f
-#define DATA_PINS_PER_REG      32
-#define DATA_PINS_BITS         1
-#define DATA_PINS_MASK         0x01
-#define DLEVEL_PINS_PER_REG    16
-#define DLEVEL_PINS_BITS       2
-#define DLEVEL_PINS_MASK       0x03
-#define PULL_PINS_PER_REG      16
-#define PULL_PINS_BITS         2
-#define PULL_PINS_MASK         0x03
 
 #define IRQ_PER_BANK           32
 
 #define PINCTRL_SUN8I_R40      BIT(8)
 #define PINCTRL_SUN8I_V3       BIT(9)
 #define PINCTRL_SUN8I_V3S      BIT(10)
+/* Variants below here have an updated register layout. */
+#define PINCTRL_SUN20I_D1      BIT(11)
 
 #define PIO_POW_MOD_SEL_REG    0x340
+#define PIO_POW_MOD_CTL_REG    0x344
 
 enum sunxi_desc_bias_voltage {
        BIAS_VOLTAGE_NONE,
@@ -111,6 +110,12 @@ enum sunxi_desc_bias_voltage {
         * register, as seen on H6 SoC, for example.
         */
        BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+       /*
+        * Bias voltage is set through PIO_POW_MOD_SEL_REG
+        * and PIO_POW_MOD_CTL_REG register, as seen on
+        * A100 and D1 SoC, for example.
+        */
+       BIAS_VOLTAGE_PIO_POW_MODE_CTL,
 };
 
 struct sunxi_desc_function {
@@ -170,6 +175,9 @@ struct sunxi_pinctrl {
        raw_spinlock_t                  lock;
        struct pinctrl_dev              *pctl_dev;
        unsigned long                   variant;
+       u32                             bank_mem_size;
+       u32                             pull_regs_offset;
+       u32                             dlevel_field_width;
 };
 
 #define SUNXI_PIN(_pin, ...)                                   \
@@ -215,83 +223,6 @@ struct sunxi_pinctrl {
                .irqnum = _irq,                                 \
        }
 
-/*
- * The sunXi PIO registers are organized as is:
- * 0x00 - 0x0c Muxing values.
- *             8 pins per register, each pin having a 4bits value
- * 0x10                Pin values
- *             32 bits per register, each pin corresponding to one bit
- * 0x14 - 0x18 Drive level
- *             16 pins per register, each pin having a 2bits value
- * 0x1c - 0x20 Pull-Up values
- *             16 pins per register, each pin having a 2bits value
- *
- * This is for the first bank. Each bank will have the same layout,
- * with an offset being a multiple of 0x24.
- *
- * The following functions calculate from the pin number the register
- * and the bit offset that we should access.
- */
-static inline u32 sunxi_mux_reg(u16 pin)
-{
-       u8 bank = pin / PINS_PER_BANK;
-       u32 offset = bank * BANK_MEM_SIZE;
-       offset += MUX_REGS_OFFSET;
-       offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04;
-       return round_down(offset, 4);
-}
-
-static inline u32 sunxi_mux_offset(u16 pin)
-{
-       u32 pin_num = pin % MUX_PINS_PER_REG;
-       return pin_num * MUX_PINS_BITS;
-}
-
-static inline u32 sunxi_data_reg(u16 pin)
-{
-       u8 bank = pin / PINS_PER_BANK;
-       u32 offset = bank * BANK_MEM_SIZE;
-       offset += DATA_REGS_OFFSET;
-       offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
-       return round_down(offset, 4);
-}
-
-static inline u32 sunxi_data_offset(u16 pin)
-{
-       u32 pin_num = pin % DATA_PINS_PER_REG;
-       return pin_num * DATA_PINS_BITS;
-}
-
-static inline u32 sunxi_dlevel_reg(u16 pin)
-{
-       u8 bank = pin / PINS_PER_BANK;
-       u32 offset = bank * BANK_MEM_SIZE;
-       offset += DLEVEL_REGS_OFFSET;
-       offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04;
-       return round_down(offset, 4);
-}
-
-static inline u32 sunxi_dlevel_offset(u16 pin)
-{
-       u32 pin_num = pin % DLEVEL_PINS_PER_REG;
-       return pin_num * DLEVEL_PINS_BITS;
-}
-
-static inline u32 sunxi_pull_reg(u16 pin)
-{
-       u8 bank = pin / PINS_PER_BANK;
-       u32 offset = bank * BANK_MEM_SIZE;
-       offset += PULL_REGS_OFFSET;
-       offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04;
-       return round_down(offset, 4);
-}
-
-static inline u32 sunxi_pull_offset(u16 pin)
-{
-       u32 pin_num = pin % PULL_PINS_PER_REG;
-       return pin_num * PULL_PINS_BITS;
-}
-
 static inline u32 sunxi_irq_hw_bank_num(const struct sunxi_pinctrl_desc *desc, u8 bank)
 {
        if (!desc->irq_bank_map)
index 4a33528..38383e7 100644 (file)
@@ -594,16 +594,17 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
 
                node = of_parse_phandle(np, "memory-region", a);
                /* Not map vdevbuffer, vdevring region */
-               if (!strncmp(node->name, "vdev", strlen("vdev")))
+               if (!strncmp(node->name, "vdev", strlen("vdev"))) {
+                       of_node_put(node);
                        continue;
+               }
                err = of_address_to_resource(node, 0, &res);
+               of_node_put(node);
                if (err) {
                        dev_err(dev, "unable to resolve memory region\n");
                        return err;
                }
 
-               of_node_put(node);
-
                if (b >= IMX_RPROC_MEM_MAX)
                        break;
 
index 54781f5..594a9b4 100644 (file)
@@ -410,10 +410,9 @@ static int keystone_rproc_probe(struct platform_device *pdev)
 
        /* enable clock for accessing DSP internal memories */
        pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0) {
                dev_err(dev, "failed to enable clock, status = %d\n", ret);
-               pm_runtime_put_noidle(dev);
                goto disable_rpm;
        }
 
index 47b2a40..d421a2c 100644 (file)
@@ -401,6 +401,14 @@ static int mt8186_scp_before_load(struct mtk_scp *scp)
        writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_P1);
        writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_p2);
 
+       /*
+        * Set I-cache and D-cache size before loading SCP FW.
+        * SCP SRAM logical address may change when cache size setting differs.
+        */
+       writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB,
+              scp->reg_base + MT8183_SCP_CACHE_CON);
+       writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON);
+
        return 0;
 }
 
@@ -943,7 +951,19 @@ static const struct mtk_scp_of_data mt8186_of_data = {
        .scp_da_to_va = mt8183_scp_da_to_va,
        .host_to_scp_reg = MT8183_HOST_TO_SCP,
        .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT,
-       .ipi_buf_offset = 0x7bdb0,
+       .ipi_buf_offset = 0x3bdb0,
+};
+
+static const struct mtk_scp_of_data mt8188_of_data = {
+       .scp_clk_get = mt8195_scp_clk_get,
+       .scp_before_load = mt8192_scp_before_load,
+       .scp_irq_handler = mt8192_scp_irq_handler,
+       .scp_reset_assert = mt8192_scp_reset_assert,
+       .scp_reset_deassert = mt8192_scp_reset_deassert,
+       .scp_stop = mt8192_scp_stop,
+       .scp_da_to_va = mt8192_scp_da_to_va,
+       .host_to_scp_reg = MT8192_GIPC_IN_SET,
+       .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT,
 };
 
 static const struct mtk_scp_of_data mt8192_of_data = {
@@ -973,6 +993,7 @@ static const struct mtk_scp_of_data mt8195_of_data = {
 static const struct of_device_id mtk_scp_of_match[] = {
        { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data },
        { .compatible = "mediatek,mt8186-scp", .data = &mt8186_of_data },
+       { .compatible = "mediatek,mt8188-scp", .data = &mt8188_of_data },
        { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data },
        { .compatible = "mediatek,mt8195-scp", .data = &mt8195_of_data },
        {},
index 32a588f..430fab0 100644 (file)
@@ -243,7 +243,7 @@ static inline int omap_rproc_get_timer_irq(struct omap_rproc_timer *timer)
  * omap_rproc_ack_timer_irq() - acknowledge a timer irq
  * @timer: handle to a OMAP rproc timer
  *
- * This function is used to clear the irq associated with a watchdog timer. The
+ * This function is used to clear the irq associated with a watchdog timer.
  * The function is called by the OMAP remoteproc upon a watchdog event on the
  * remote processor to clear the interrupt status of the watchdog timer.
  */
@@ -303,7 +303,7 @@ static irqreturn_t omap_rproc_watchdog_isr(int irq, void *data)
  * @configure: boolean flag used to acquire and configure the timer handle
  *
  * This function is used primarily to enable the timers associated with
- * a remoteproc. The configure flag is provided to allow the driver to
+ * a remoteproc. The configure flag is provided to allow the driver
  * to either acquire and start a timer (during device initialization) or
  * to just start a timer (during a resume operation).
  *
@@ -443,7 +443,7 @@ free_timers:
  * @configure: boolean flag used to release the timer handle
  *
  * This function is used primarily to disable the timers associated with
- * a remoteproc. The configure flag is provided to allow the driver to
+ * a remoteproc. The configure flag is provided to allow the driver
  * to either stop and release a timer (during device shutdown) or to just
  * stop a timer (during a suspend operation).
  *
index 1777a01..128bf99 100644 (file)
@@ -897,6 +897,7 @@ static const struct of_device_id pru_rproc_match[] = {
        { .compatible = "ti,j721e-pru",         .data = &k3_pru_data },
        { .compatible = "ti,j721e-rtu",         .data = &k3_rtu_data },
        { .compatible = "ti,j721e-tx-pru",      .data = &k3_tx_pru_data },
+       { .compatible = "ti,am625-pru",         .data = &k3_pru_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, pru_rproc_match);
index 4b91e3c..020349f 100644 (file)
@@ -50,7 +50,7 @@ struct minidump_region {
 };
 
 /**
- * struct minidump_subsystem_toc: Subsystem's SMEM Table of content
+ * struct minidump_subsystem - Subsystem's SMEM Table of content
  * @status : Subsystem toc init status
  * @enabled : if set to 1, this region would be copied during coredump
  * @encryption_status: Encryption status for this subsystem
@@ -68,7 +68,7 @@ struct minidump_subsystem {
 };
 
 /**
- * struct minidump_global_toc: Global Table of Content
+ * struct minidump_global_toc - Global Table of Content
  * @status : Global Minidump init status
  * @md_revision : Minidump revision
  * @enabled : Minidump enable status
index 5280ec9..497acfb 100644 (file)
@@ -112,6 +112,7 @@ static irqreturn_t q6v5_wdog_interrupt(int irq, void *data)
        else
                dev_err(q6v5->dev, "watchdog without message\n");
 
+       q6v5->running = false;
        rproc_report_crash(q6v5->rproc, RPROC_WATCHDOG);
 
        return IRQ_HANDLED;
@@ -123,6 +124,9 @@ static irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
        size_t len;
        char *msg;
 
+       if (!q6v5->running)
+               return IRQ_HANDLED;
+
        msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
        if (!IS_ERR(msg) && len > 0 && msg[0])
                dev_err(q6v5->dev, "fatal error received: %s\n", msg);
index 2f3b9f5..4c9a1b9 100644 (file)
@@ -175,9 +175,8 @@ static int qcom_rproc_pds_enable(struct qcom_adsp *adsp, struct device **pds,
 
        for (i = 0; i < pd_count; i++) {
                dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
-               ret = pm_runtime_get_sync(pds[i]);
+               ret = pm_runtime_resume_and_get(pds[i]);
                if (ret < 0) {
-                       pm_runtime_put_noidle(pds[i]);
                        dev_pm_genpd_set_performance_state(pds[i], 0);
                        goto unroll_pd_votes;
                }
index af217de..fddb63c 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/devcoredump.h>
+#include <linux/dma-map-ops.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -932,27 +933,52 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
 static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
                                const char *fw_name)
 {
-       unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
+       unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_KERNEL_MAPPING;
+       unsigned long flags = VM_DMA_COHERENT | VM_FLUSH_RESET_PERMS;
+       struct page **pages;
+       struct page *page;
        dma_addr_t phys;
        void *metadata;
        int mdata_perm;
        int xferop_ret;
        size_t size;
-       void *ptr;
+       void *vaddr;
+       int count;
        int ret;
+       int i;
 
        metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev);
        if (IS_ERR(metadata))
                return PTR_ERR(metadata);
 
-       ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
-       if (!ptr) {
+       page = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
+       if (!page) {
                kfree(metadata);
                dev_err(qproc->dev, "failed to allocate mdt buffer\n");
                return -ENOMEM;
        }
 
-       memcpy(ptr, metadata, size);
+       count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
+       if (!pages) {
+               ret = -ENOMEM;
+               goto free_dma_attrs;
+       }
+
+       for (i = 0; i < count; i++)
+               pages[i] = nth_page(page, i);
+
+       vaddr = vmap(pages, count, flags, pgprot_dmacoherent(PAGE_KERNEL));
+       kfree(pages);
+       if (!vaddr) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", &phys, size);
+               ret = -EBUSY;
+               goto free_dma_attrs;
+       }
+
+       memcpy(vaddr, metadata, size);
+
+       vunmap(vaddr);
 
        /* Hypervisor mapping to access metadata by modem */
        mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
@@ -982,7 +1008,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
                         "mdt buffer not reclaimed system may become unstable\n");
 
 free_dma_attrs:
-       dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
+       dma_free_attrs(qproc->dev, size, page, phys, dma_attrs);
        kfree(metadata);
 
        return ret < 0 ? ret : 0;
@@ -1102,6 +1128,9 @@ static int q6v5_mba_load(struct q6v5 *qproc)
        if (ret)
                goto reclaim_mba;
 
+       if (qproc->has_mba_logs)
+               qcom_pil_info_store("mba", qproc->mba_phys, MBA_LOG_SIZE);
+
        ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
        if (ret == -ETIMEDOUT) {
                dev_err(qproc->dev, "MBA boot timed out\n");
@@ -1594,11 +1623,19 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc,
        return ret;
 }
 
+static unsigned long q6v5_panic(struct rproc *rproc)
+{
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+
+       return qcom_q6v5_panic(&qproc->q6v5);
+}
+
 static const struct rproc_ops q6v5_ops = {
        .start = q6v5_start,
        .stop = q6v5_stop,
        .parse_fw = qcom_q6v5_register_dump_segments,
        .load = q6v5_load,
+       .panic = q6v5_panic,
 };
 
 static void qcom_msa_handover(struct qcom_q6v5 *q6v5)
@@ -2188,6 +2225,11 @@ static const struct rproc_hexagon_res msm8996_mss = {
                        "mnoc_axi",
                        NULL
        },
+       .proxy_pd_names = (char*[]){
+                       "mx",
+                       "cx",
+                       NULL
+       },
        .need_mem_protection = true,
        .has_alt_reset = false,
        .has_mba_logs = false,
index 6ae39c5..6afd094 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -29,6 +30,8 @@
 #include "qcom_q6v5.h"
 #include "remoteproc_internal.h"
 
+#define ADSP_DECRYPT_SHUTDOWN_DELAY_MS 100
+
 struct adsp_data {
        int crash_reason_smem;
        const char *firmware_name;
@@ -36,6 +39,7 @@ struct adsp_data {
        unsigned int minidump_id;
        bool has_aggre2_clk;
        bool auto_boot;
+       bool decrypt_shutdown;
 
        char **proxy_pd_names;
 
@@ -65,6 +69,7 @@ struct qcom_adsp {
        unsigned int minidump_id;
        int crash_reason_smem;
        bool has_aggre2_clk;
+       bool decrypt_shutdown;
        const char *info_name;
 
        struct completion start_done;
@@ -87,6 +92,9 @@ static void adsp_minidump(struct rproc *rproc)
 {
        struct qcom_adsp *adsp = rproc->priv;
 
+       if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)
+               return;
+
        qcom_minidump(rproc, adsp->minidump_id);
 }
 
@@ -128,6 +136,19 @@ static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds,
        }
 }
 
+static int adsp_shutdown_poll_decrypt(struct qcom_adsp *adsp)
+{
+       unsigned int retry_num = 50;
+       int ret;
+
+       do {
+               msleep(ADSP_DECRYPT_SHUTDOWN_DELAY_MS);
+               ret = qcom_scm_pas_shutdown(adsp->pas_id);
+       } while (ret == -EINVAL && --retry_num);
+
+       return ret;
+}
+
 static int adsp_unprepare(struct rproc *rproc)
 {
        struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
@@ -185,13 +206,17 @@ static int adsp_start(struct rproc *rproc)
        if (ret)
                goto disable_xo_clk;
 
-       ret = regulator_enable(adsp->cx_supply);
-       if (ret)
-               goto disable_aggre2_clk;
+       if (adsp->cx_supply) {
+               ret = regulator_enable(adsp->cx_supply);
+               if (ret)
+                       goto disable_aggre2_clk;
+       }
 
-       ret = regulator_enable(adsp->px_supply);
-       if (ret)
-               goto disable_cx_supply;
+       if (adsp->px_supply) {
+               ret = regulator_enable(adsp->px_supply);
+               if (ret)
+                       goto disable_cx_supply;
+       }
 
        ret = qcom_scm_pas_auth_and_reset(adsp->pas_id);
        if (ret) {
@@ -212,9 +237,11 @@ static int adsp_start(struct rproc *rproc)
        return 0;
 
 disable_px_supply:
-       regulator_disable(adsp->px_supply);
+       if (adsp->px_supply)
+               regulator_disable(adsp->px_supply);
 disable_cx_supply:
-       regulator_disable(adsp->cx_supply);
+       if (adsp->cx_supply)
+               regulator_disable(adsp->cx_supply);
 disable_aggre2_clk:
        clk_disable_unprepare(adsp->aggre2_clk);
 disable_xo_clk:
@@ -231,8 +258,10 @@ static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
 {
        struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
 
-       regulator_disable(adsp->px_supply);
-       regulator_disable(adsp->cx_supply);
+       if (adsp->px_supply)
+               regulator_disable(adsp->px_supply);
+       if (adsp->cx_supply)
+               regulator_disable(adsp->cx_supply);
        clk_disable_unprepare(adsp->aggre2_clk);
        clk_disable_unprepare(adsp->xo);
        adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
@@ -249,6 +278,9 @@ static int adsp_stop(struct rproc *rproc)
                dev_err(adsp->dev, "timed out on wait\n");
 
        ret = qcom_scm_pas_shutdown(adsp->pas_id);
+       if (ret && adsp->decrypt_shutdown)
+               ret = adsp_shutdown_poll_decrypt(adsp);
+
        if (ret)
                dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
 
@@ -268,6 +300,9 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iom
        if (offset < 0 || offset + len > adsp->mem_size)
                return NULL;
 
+       if (is_iomem)
+               *is_iomem = true;
+
        return adsp->mem_region + offset;
 }
 
@@ -326,14 +361,26 @@ static int adsp_init_clock(struct qcom_adsp *adsp)
 
 static int adsp_init_regulator(struct qcom_adsp *adsp)
 {
-       adsp->cx_supply = devm_regulator_get(adsp->dev, "cx");
-       if (IS_ERR(adsp->cx_supply))
-               return PTR_ERR(adsp->cx_supply);
+       adsp->cx_supply = devm_regulator_get_optional(adsp->dev, "cx");
+       if (IS_ERR(adsp->cx_supply)) {
+               if (PTR_ERR(adsp->cx_supply) == -ENODEV)
+                       adsp->cx_supply = NULL;
+               else
+                       return PTR_ERR(adsp->cx_supply);
+       }
 
-       regulator_set_load(adsp->cx_supply, 100000);
+       if (adsp->cx_supply)
+               regulator_set_load(adsp->cx_supply, 100000);
 
-       adsp->px_supply = devm_regulator_get(adsp->dev, "px");
-       return PTR_ERR_OR_ZERO(adsp->px_supply);
+       adsp->px_supply = devm_regulator_get_optional(adsp->dev, "px");
+       if (IS_ERR(adsp->px_supply)) {
+               if (PTR_ERR(adsp->px_supply) == -ENODEV)
+                       adsp->px_supply = NULL;
+               else
+                       return PTR_ERR(adsp->px_supply);
+       }
+
+       return 0;
 }
 
 static int adsp_pds_attach(struct device *dev, struct device **devs,
@@ -459,9 +506,12 @@ static int adsp_probe(struct platform_device *pdev)
        adsp->pas_id = desc->pas_id;
        adsp->has_aggre2_clk = desc->has_aggre2_clk;
        adsp->info_name = desc->sysmon_name;
+       adsp->decrypt_shutdown = desc->decrypt_shutdown;
        platform_set_drvdata(pdev, adsp);
 
-       device_wakeup_enable(adsp->dev);
+       ret = device_init_wakeup(adsp->dev, true);
+       if (ret)
+               goto free_rproc;
 
        ret = adsp_alloc_memory_region(adsp);
        if (ret)
@@ -877,6 +927,25 @@ static const struct adsp_data sdx55_mpss_resource = {
        .ssctl_id = 0x22,
 };
 
+static const struct adsp_data sm8450_mpss_resource = {
+       .crash_reason_smem = 421,
+       .firmware_name = "modem.mdt",
+       .pas_id = 4,
+       .minidump_id = 3,
+       .has_aggre2_clk = false,
+       .auto_boot = false,
+       .decrypt_shutdown = true,
+       .proxy_pd_names = (char*[]){
+               "cx",
+               "mss",
+               NULL
+       },
+       .load_state = "modem",
+       .ssr_name = "mpss",
+       .sysmon_name = "modem",
+       .ssctl_id = 0x12,
+};
+
 static const struct of_device_id adsp_of_match[] = {
        { .compatible = "qcom,msm8226-adsp-pil", .data = &adsp_resource_init},
        { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init},
@@ -916,7 +985,7 @@ static const struct of_device_id adsp_of_match[] = {
        { .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource},
        { .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource},
        { .compatible = "qcom,sm8450-slpi-pas", .data = &sm8350_slpi_resource},
-       { .compatible = "qcom,sm8450-mpss-pas", .data = &mpss_resource_init},
+       { .compatible = "qcom,sm8450-mpss-pas", .data = &sm8450_mpss_resource},
        { },
 };
 MODULE_DEVICE_TABLE(of, adsp_of_match);
index 9fca814..57dde2a 100644 (file)
@@ -41,6 +41,7 @@ struct qcom_sysmon {
        struct completion comp;
        struct completion ind_comp;
        struct completion shutdown_comp;
+       struct completion ssctl_comp;
        struct mutex lock;
 
        bool ssr_ack;
@@ -445,6 +446,8 @@ static int ssctl_new_server(struct qmi_handle *qmi, struct qmi_service *svc)
 
        svc->priv = sysmon;
 
+       complete(&sysmon->ssctl_comp);
+
        return 0;
 }
 
@@ -501,6 +504,7 @@ static int sysmon_start(struct rproc_subdev *subdev)
                .ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP
        };
 
+       reinit_completion(&sysmon->ssctl_comp);
        mutex_lock(&sysmon->state_lock);
        sysmon->state = SSCTL_SSR_EVENT_AFTER_POWERUP;
        blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event);
@@ -508,10 +512,12 @@ static int sysmon_start(struct rproc_subdev *subdev)
 
        mutex_lock(&sysmon_lock);
        list_for_each_entry(target, &sysmon_list, node) {
-               if (target == sysmon)
+               mutex_lock(&target->state_lock);
+               if (target == sysmon || target->state != SSCTL_SSR_EVENT_AFTER_POWERUP) {
+                       mutex_unlock(&target->state_lock);
                        continue;
+               }
 
-               mutex_lock(&target->state_lock);
                event.subsys_name = target->name;
                event.ssr_event = target->state;
 
@@ -545,6 +551,11 @@ static void sysmon_stop(struct rproc_subdev *subdev, bool crashed)
        if (crashed)
                return;
 
+       if (sysmon->ssctl_instance) {
+               if (!wait_for_completion_timeout(&sysmon->ssctl_comp, HZ / 2))
+                       dev_err(sysmon->dev, "timeout waiting for ssctl service\n");
+       }
+
        if (sysmon->ssctl_version)
                sysmon->shutdown_acked = ssctl_request_shutdown(sysmon);
        else if (sysmon->ept)
@@ -631,6 +642,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
        init_completion(&sysmon->comp);
        init_completion(&sysmon->ind_comp);
        init_completion(&sysmon->shutdown_comp);
+       init_completion(&sysmon->ssctl_comp);
        mutex_init(&sysmon->lock);
        mutex_init(&sysmon->state_lock);
 
index 9a223d3..68f3729 100644 (file)
@@ -467,6 +467,7 @@ static int wcnss_request_irq(struct qcom_wcnss *wcnss,
                             irq_handler_t thread_fn)
 {
        int ret;
+       int irq_number;
 
        ret = platform_get_irq_byname(pdev, name);
        if (ret < 0 && optional) {
@@ -477,14 +478,19 @@ static int wcnss_request_irq(struct qcom_wcnss *wcnss,
                return ret;
        }
 
+       irq_number = ret;
+
        ret = devm_request_threaded_irq(&pdev->dev, ret,
                                        NULL, thread_fn,
                                        IRQF_TRIGGER_RISING | IRQF_ONESHOT,
                                        "wcnss", wcnss);
-       if (ret)
+       if (ret) {
                dev_err(&pdev->dev, "request %s IRQ failed\n", name);
+               return ret;
+       }
 
-       return ret;
+       /* Return the IRQ number if the IRQ was successfully acquired */
+       return irq_number;
 }
 
 static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
index 02a04ab..8983239 100644 (file)
@@ -59,6 +59,7 @@ static int rproc_release_carveout(struct rproc *rproc,
 
 /* Unique indices for remoteproc devices */
 static DEFINE_IDA(rproc_dev_index);
+static struct workqueue_struct *rproc_recovery_wq;
 
 static const char * const rproc_crash_names[] = {
        [RPROC_MMUFAULT]        = "mmufault",
@@ -461,6 +462,7 @@ static void rproc_rvdev_release(struct device *dev)
        struct rproc_vdev *rvdev = container_of(dev, struct rproc_vdev, dev);
 
        of_reserved_mem_device_release(dev);
+       dma_release_coherent_memory(dev);
 
        kfree(rvdev);
 }
@@ -970,7 +972,7 @@ static int rproc_handle_carveout(struct rproc *rproc,
                return 0;
        }
 
-       /* Register carveout in in list */
+       /* Register carveout in list */
        carveout = rproc_mem_entry_init(dev, NULL, 0, rsc->len, rsc->da,
                                        rproc_alloc_carveout,
                                        rproc_release_carveout, rsc->name);
@@ -2434,7 +2436,7 @@ static void rproc_type_release(struct device *dev)
        idr_destroy(&rproc->notifyids);
 
        if (rproc->index >= 0)
-               ida_simple_remove(&rproc_dev_index, rproc->index);
+               ida_free(&rproc_dev_index, rproc->index);
 
        kfree_const(rproc->firmware);
        kfree_const(rproc->name);
@@ -2551,9 +2553,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
                goto put_device;
 
        /* Assign a unique device index and name */
-       rproc->index = ida_simple_get(&rproc_dev_index, 0, 0, GFP_KERNEL);
+       rproc->index = ida_alloc(&rproc_dev_index, GFP_KERNEL);
        if (rproc->index < 0) {
-               dev_err(dev, "ida_simple_get failed: %d\n", rproc->index);
+               dev_err(dev, "ida_alloc failed: %d\n", rproc->index);
                goto put_device;
        }
 
@@ -2762,8 +2764,7 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
        dev_err(&rproc->dev, "crash detected in %s: type %s\n",
                rproc->name, rproc_crash_to_string(type));
 
-       /* Have a worker handle the error; ensure system is not suspended */
-       queue_work(system_freezable_wq, &rproc->crash_handler);
+       queue_work(rproc_recovery_wq, &rproc->crash_handler);
 }
 EXPORT_SYMBOL(rproc_report_crash);
 
@@ -2812,6 +2813,13 @@ static void __exit rproc_exit_panic(void)
 
 static int __init remoteproc_init(void)
 {
+       rproc_recovery_wq = alloc_workqueue("rproc_recovery_wq",
+                                               WQ_UNBOUND | WQ_FREEZABLE, 0);
+       if (!rproc_recovery_wq) {
+               pr_err("remoteproc: creation of rproc_recovery_wq failed\n");
+               return -ENOMEM;
+       }
+
        rproc_init_sysfs();
        rproc_init_debugfs();
        rproc_init_cdev();
@@ -2825,9 +2833,13 @@ static void __exit remoteproc_exit(void)
 {
        ida_destroy(&rproc_dev_index);
 
+       if (!rproc_recovery_wq)
+               return;
+
        rproc_exit_panic();
        rproc_exit_debugfs();
        rproc_exit_sysfs();
+       destroy_workqueue(rproc_recovery_wq);
 }
 module_exit(remoteproc_exit);
 
index 4840ad9..0481926 100644 (file)
@@ -1655,6 +1655,7 @@ static int k3_r5_cluster_of_init(struct platform_device *pdev)
                if (!cpdev) {
                        ret = -ENODEV;
                        dev_err(dev, "could not get R5 core platform device\n");
+                       of_node_put(child);
                        goto fail;
                }
 
@@ -1663,6 +1664,7 @@ static int k3_r5_cluster_of_init(struct platform_device *pdev)
                        dev_err(dev, "k3_r5_core_of_init failed, ret = %d\n",
                                ret);
                        put_device(&cpdev->dev);
+                       of_node_put(child);
                        goto fail;
                }
 
index 5b4404b..d1213c3 100644 (file)
@@ -234,7 +234,9 @@ static void mtk_register_device_work_function(struct work_struct *register_work)
                if (info->registered)
                        continue;
 
+               mutex_unlock(&subdev->channels_lock);
                ret = mtk_rpmsg_register_device(subdev, &info->info);
+               mutex_lock(&subdev->channels_lock);
                if (ret) {
                        dev_err(&pdev->dev, "Can't create rpmsg_device\n");
                        continue;
index 0758651..115c0a1 100644 (file)
@@ -98,8 +98,6 @@ struct glink_core_rx_intent {
 struct qcom_glink {
        struct device *dev;
 
-       const char *name;
-
        struct mbox_client mbox_client;
        struct mbox_chan *mbox_chan;
 
@@ -1546,7 +1544,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
        cancel_work_sync(&channel->intent_work);
 
        if (channel->rpdev) {
-               strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
+               strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name));
                chinfo.src = RPMSG_ADDR_ANY;
                chinfo.dst = RPMSG_ADDR_ANY;
 
@@ -1674,7 +1672,7 @@ static ssize_t rpmsg_name_show(struct device *dev,
        if (ret < 0)
                name = dev->of_node->name;
 
-       return snprintf(buf, RPMSG_NAME_SIZE, "%s\n", name);
+       return sysfs_emit(buf, "%s\n", name);
 }
 static DEVICE_ATTR_RO(rpmsg_name);
 
@@ -1755,10 +1753,6 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
        if (ret)
                dev_err(dev, "failed to add groups\n");
 
-       ret = of_property_read_string(dev->of_node, "label", &glink->name);
-       if (ret < 0)
-               glink->name = dev->of_node->name;
-
        glink->mbox_client.dev = dev;
        glink->mbox_client.knows_txdone = true;
        glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
index dea929c..776d644 100644 (file)
@@ -39,7 +39,7 @@ struct cleanup_done_msg {
        __le32 seq_num;
 };
 
-/**
+/*
  * G-Link SSR protocol commands
  */
 #define GLINK_SSR_DO_CLEANUP   0
index 1957b27..1044cf0 100644 (file)
@@ -729,11 +729,11 @@ static int qcom_smd_write_fifo(struct qcom_smd_channel *channel,
 }
 
 /**
- * qcom_smd_send - write data to smd channel
+ * __qcom_smd_send - write data to smd channel
  * @channel:   channel handle
  * @data:      buffer of data to write
  * @len:       number of bytes to write
- * @wait:      flag to indicate if write has ca wait
+ * @wait:      flag to indicate if write can wait
  *
  * This is a blocking write of len bytes into the channel's tx ring buffer and
  * signal the remote end. It will sleep until there is enough space available
@@ -1089,7 +1089,7 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel)
 
        /* Assign public information to the rpmsg_device */
        rpdev = &qsdev->rpdev;
-       strncpy(rpdev->id.name, channel->name, RPMSG_NAME_SIZE);
+       strscpy_pad(rpdev->id.name, channel->name, RPMSG_NAME_SIZE);
        rpdev->src = RPMSG_ADDR_ANY;
        rpdev->dst = RPMSG_ADDR_ANY;
 
@@ -1323,7 +1323,7 @@ static void qcom_channel_state_worker(struct work_struct *work)
 
                spin_unlock_irqrestore(&edge->channels_lock, flags);
 
-               strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
+               strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name));
                chinfo.src = RPMSG_ADDR_ANY;
                chinfo.dst = RPMSG_ADDR_ANY;
                rpmsg_unregister_device(&edge->dev, &chinfo);
@@ -1383,6 +1383,7 @@ static int qcom_smd_parse_edge(struct device *dev,
                }
 
                edge->ipc_regmap = syscon_node_to_regmap(syscon_np);
+               of_node_put(syscon_np);
                if (IS_ERR(edge->ipc_regmap)) {
                        ret = PTR_ERR(edge->ipc_regmap);
                        goto put_node;
index b6183d4..4f21891 100644 (file)
@@ -120,8 +120,11 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
        struct rpmsg_device *rpdev = eptdev->rpdev;
        struct device *dev = &eptdev->dev;
 
-       if (eptdev->ept)
+       mutex_lock(&eptdev->ept_lock);
+       if (eptdev->ept) {
+               mutex_unlock(&eptdev->ept_lock);
                return -EBUSY;
+       }
 
        get_device(dev);
 
@@ -137,11 +140,13 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
        if (!ept) {
                dev_err(dev, "failed to open %s\n", eptdev->chinfo.name);
                put_device(dev);
+               mutex_unlock(&eptdev->ept_lock);
                return -EINVAL;
        }
 
        eptdev->ept = ept;
        filp->private_data = eptdev;
+       mutex_unlock(&eptdev->ept_lock);
 
        return 0;
 }
index 290c1f0..d6dde00 100644 (file)
@@ -604,7 +604,7 @@ int rpmsg_register_device_override(struct rpmsg_device *rpdev,
        int ret;
 
        if (driver_override)
-               strcpy(rpdev->id.name, driver_override);
+               strscpy_pad(rpdev->id.name, driver_override, RPMSG_NAME_SIZE);
 
        dev_set_name(dev, "%s.%s.%d.%d", dev_name(dev->parent),
                     rpdev->id.name, rpdev->src, rpdev->dst);
@@ -618,6 +618,7 @@ int rpmsg_register_device_override(struct rpmsg_device *rpdev,
                                          strlen(driver_override));
                if (ret) {
                        dev_err(dev, "device_set_override failed: %d\n", ret);
+                       put_device(dev);
                        return ret;
                }
        }
index a22cd4a..39b646d 100644 (file)
@@ -41,8 +41,8 @@ struct rpmsg_device_ops {
                                            rpmsg_rx_cb_t cb, void *priv,
                                            struct rpmsg_channel_info chinfo);
 
-       int (*announce_create)(struct rpmsg_device *ept);
-       int (*announce_destroy)(struct rpmsg_device *ept);
+       int (*announce_create)(struct rpmsg_device *rpdev);
+       int (*announce_destroy)(struct rpmsg_device *rpdev);
 };
 
 /**
index 32c346b..dff6d5e 100644 (file)
@@ -107,29 +107,46 @@ int devm_tegra_core_dev_init_opp_table(struct device *dev,
 {
        u32 hw_version;
        int err;
-
-       err = devm_pm_opp_set_clkname(dev, NULL);
-       if (err) {
-               dev_err(dev, "failed to set OPP clk: %d\n", err);
-               return err;
-       }
-
-       /* Tegra114+ doesn't support OPP yet */
-       if (!of_machine_is_compatible("nvidia,tegra20") &&
-           !of_machine_is_compatible("nvidia,tegra30"))
-               return -ENODEV;
-
-       if (of_machine_is_compatible("nvidia,tegra20"))
+       /*
+        * The clk's connection id to set is NULL and this is a NULL terminated
+        * array, hence two NULL entries.
+        */
+       const char *clk_names[] = { NULL, NULL };
+       struct dev_pm_opp_config config = {
+               /*
+                * For some devices we don't have any OPP table in the DT, and
+                * in order to use the same code path for all the devices, we
+                * create a dummy OPP table for them via this. The dummy OPP
+                * table is only capable of doing clk_set_rate() on invocation
+                * of dev_pm_opp_set_rate() and doesn't provide any other
+                * functionality.
+                */
+               .clk_names = clk_names,
+       };
+
+       if (of_machine_is_compatible("nvidia,tegra20")) {
                hw_version = BIT(tegra_sku_info.soc_process_id);
-       else
+               config.supported_hw = &hw_version;
+               config.supported_hw_count = 1;
+       } else if (of_machine_is_compatible("nvidia,tegra30")) {
                hw_version = BIT(tegra_sku_info.soc_speedo_id);
+               config.supported_hw = &hw_version;
+               config.supported_hw_count = 1;
+       }
 
-       err = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
+       err = devm_pm_opp_set_config(dev, &config);
        if (err) {
-               dev_err(dev, "failed to set OPP supported HW: %d\n", err);
+               dev_err(dev, "failed to set OPP config: %d\n", err);
                return err;
        }
 
+       /*
+        * Tegra114+ doesn't support OPP yet, return early for non tegra20/30
+        * case.
+        */
+       if (!config.supported_hw)
+               return -ENODEV;
+
        /*
         * Older device-trees have an empty OPP table, we will get
         * -ENODEV from devm_pm_opp_of_add_table() in this case.
index 5611d14..6a4b8f7 100644 (file)
@@ -1384,7 +1384,7 @@ tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
 static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
 {
        struct generic_pm_domain *genpd;
-       const char *rname = "core";
+       const char *rname[] = { "core", NULL};
        int err;
 
        genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
@@ -1395,7 +1395,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
        genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
        genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
 
-       err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1);
+       err = devm_pm_opp_set_regulators(pmc->dev, rname);
        if (err)
                return dev_err_probe(pmc->dev, err,
                                     "failed to set core OPP regulator\n");
index 0e5cc94..e052dae 100644 (file)
@@ -221,7 +221,7 @@ config THERMAL_EMULATION
 
 config THERMAL_MMIO
        tristate "Generic Thermal MMIO driver"
-       depends on OF || COMPILE_TEST
+       depends on OF
        depends on HAS_IOMEM
        help
          This option enables the generic thermal MMIO driver that will use
@@ -496,7 +496,7 @@ config SPRD_THERMAL
 
 config KHADAS_MCU_FAN_THERMAL
        tristate "Khadas MCU controller FAN cooling support"
-       depends on OF || COMPILE_TEST
+       depends on OF
        depends on MFD_KHADAS_MCU
        select MFD_CORE
        select REGMAP
index a9596e7..95adac4 100644 (file)
@@ -81,7 +81,9 @@ static const struct x86_cpu_id tcc_ids[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, NULL),
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
        {}
 };
 
index 5018459..3a8d6e7 100644 (file)
@@ -813,12 +813,13 @@ static const struct attribute_group cooling_device_stats_attr_group = {
 
 static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
 {
+       const struct attribute_group *stats_attr_group = NULL;
        struct cooling_dev_stats *stats;
        unsigned long states;
        int var;
 
        if (cdev->ops->get_max_state(cdev, &states))
-               return;
+               goto out;
 
        states++; /* Total number of states is highest state + 1 */
 
@@ -828,7 +829,7 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
 
        stats = kzalloc(var, GFP_KERNEL);
        if (!stats)
-               return;
+               goto out;
 
        stats->time_in_state = (ktime_t *)(stats + 1);
        stats->trans_table = (unsigned int *)(stats->time_in_state + states);
@@ -838,9 +839,12 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
 
        spin_lock_init(&stats->lock);
 
+       stats_attr_group = &cooling_device_stats_attr_group;
+
+out:
        /* Fill the empty slot left in cooling_device_attr_groups */
        var = ARRAY_SIZE(cooling_device_attr_groups) - 2;
-       cooling_device_attr_groups[var] = &cooling_device_stats_attr_group;
+       cooling_device_attr_groups[var] = stats_attr_group;
 }
 
 static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
index ffd9e6c..9b65509 100644 (file)
@@ -643,14 +643,12 @@ vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd,
        size_t offset;
        unsigned int npages = 0;
 
-       bytes = iov_iter_get_pages(iter, pages, LONG_MAX,
+       bytes = iov_iter_get_pages2(iter, pages, LONG_MAX,
                                VHOST_SCSI_PREALLOC_UPAGES, &offset);
        /* No pages were pinned */
        if (bytes <= 0)
                return bytes < 0 ? bytes : -EFAULT;
 
-       iov_iter_advance(iter, bytes);
-
        while (bytes) {
                unsigned n = min_t(unsigned, PAGE_SIZE - offset, bytes);
                sg_set_page(sg++, pages[npages++], n, offset);
index 1635f42..854b1cc 100644 (file)
@@ -274,6 +274,8 @@ static int armada_37xx_wdt_probe(struct platform_device *pdev)
        if (!res)
                return -ENODEV;
        dev->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!dev->reg)
+               return -ENOMEM;
 
        /* init clock */
        dev->clk = devm_clk_get(&pdev->dev, NULL);
index 1ffcf6a..9388838 100644 (file)
@@ -192,7 +192,6 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int bcm7038_wdt_suspend(struct device *dev)
 {
        struct bcm7038_watchdog *wdt = dev_get_drvdata(dev);
@@ -212,10 +211,9 @@ static int bcm7038_wdt_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(bcm7038_wdt_pm_ops, bcm7038_wdt_suspend,
-                        bcm7038_wdt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(bcm7038_wdt_pm_ops,
+                               bcm7038_wdt_suspend, bcm7038_wdt_resume);
 
 static const struct of_device_id bcm7038_wdt_match[] = {
        { .compatible = "brcm,bcm6345-wdt" },
@@ -236,7 +234,7 @@ static struct platform_driver bcm7038_wdt_driver = {
        .driver         = {
                .name           = "bcm7038-wdt",
                .of_match_table = bcm7038_wdt_match,
-               .pm             = &bcm7038_wdt_pm_ops,
+               .pm             = pm_sleep_ptr(&bcm7038_wdt_pm_ops),
        }
 };
 module_platform_driver(bcm7038_wdt_driver);
index 5e4dc1a..75da5cd 100644 (file)
@@ -74,7 +74,7 @@ static unsigned long long period_to_sec(unsigned int period)
 /*
  * This procedure will find the highest period which will give a timeout
  * greater than the one required. e.g. for a bus speed of 66666666 and
- * and a parameter of 2 secs, then this procedure will return a value of 38.
+ * a parameter of 2 secs, then this procedure will return a value of 38.
  */
 static unsigned int sec_to_period(unsigned int secs)
 {
index cd57884..52962e8 100644 (file)
@@ -218,7 +218,7 @@ static int dw_wdt_set_timeout(struct watchdog_device *wdd, unsigned int top_s)
 
        /*
         * Set the new value in the watchdog.  Some versions of dw_wdt
-        * have have TOPINIT in the TIMEOUT_RANGE register (as per
+        * have TOPINIT in the TIMEOUT_RANGE register (as per
         * CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1).  On those we
         * effectively get a pat of the watchdog right here.
         */
@@ -375,7 +375,6 @@ static irqreturn_t dw_wdt_irq(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int dw_wdt_suspend(struct device *dev)
 {
        struct dw_wdt *dw_wdt = dev_get_drvdata(dev);
@@ -410,9 +409,8 @@ static int dw_wdt_resume(struct device *dev)
 
        return 0;
 }
-#endif /* CONFIG_PM_SLEEP */
 
-static SIMPLE_DEV_PM_OPS(dw_wdt_pm_ops, dw_wdt_suspend, dw_wdt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(dw_wdt_pm_ops, dw_wdt_suspend, dw_wdt_resume);
 
 /*
  * In case if DW WDT IP core is synthesized with fixed TOP feature disabled the
@@ -710,7 +708,7 @@ static struct platform_driver dw_wdt_driver = {
        .driver         = {
                .name   = "dw_wdt",
                .of_match_table = of_match_ptr(dw_wdt_of_match),
-               .pm     = &dw_wdt_pm_ops,
+               .pm     = pm_sleep_ptr(&dw_wdt_pm_ops),
        },
 };
 
index 7f59c68..6a16d3d 100644 (file)
@@ -634,7 +634,9 @@ static int __init fintek_wdt_init(void)
 
        pdata.type = ret;
 
-       platform_driver_register(&fintek_wdt_driver);
+       ret = platform_driver_register(&fintek_wdt_driver);
+       if (ret)
+               return ret;
 
        wdt_res.name = "superio port";
        wdt_res.flags = IORESOURCE_IO;
index b76ad6b..33835c0 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 2022 Luca Ceresoli
  *
  * Author: Laxman Dewangan <ldewangan@nvidia.com>
- * Author: Luca Ceresoli <luca@lucaceresoli.net>
+ * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
  */
 
 #include <linux/err.h>
@@ -260,5 +260,5 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
        "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
+MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
 MODULE_LICENSE("GPL v2");
index f0d4e3c..e977875 100644 (file)
@@ -401,7 +401,6 @@ static int mtk_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int mtk_wdt_suspend(struct device *dev)
 {
        struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev);
@@ -423,7 +422,6 @@ static int mtk_wdt_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static const struct of_device_id mtk_wdt_dt_ids[] = {
        { .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data },
@@ -437,16 +435,14 @@ static const struct of_device_id mtk_wdt_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);
 
-static const struct dev_pm_ops mtk_wdt_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(mtk_wdt_suspend,
-                               mtk_wdt_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(mtk_wdt_pm_ops,
+                               mtk_wdt_suspend, mtk_wdt_resume);
 
 static struct platform_driver mtk_wdt_driver = {
        .probe          = mtk_wdt_probe,
        .driver         = {
                .name           = DRV_NAME,
-               .pm             = &mtk_wdt_pm_ops,
+               .pm             = pm_sleep_ptr(&mtk_wdt_pm_ops),
                .of_match_table = mtk_wdt_dt_ids,
        },
 };
index 9f9a340..c7f745c 100644 (file)
@@ -442,7 +442,7 @@ static long pc87413_ioctl(struct file *file, unsigned int cmd,
        }
 }
 
-/* -- Notifier funtions -----------------------------------------*/
+/* -- Notifier functions -----------------------------------------*/
 
 /**
  *     pc87413_notify_sys:
index 0937b8d..f4bfbff 100644 (file)
@@ -9,6 +9,12 @@
 #include <linux/regmap.h>
 #include <linux/watchdog.h>
 
+#define PON_POFF_REASON1               0x0c
+#define PON_POFF_REASON1_PMIC_WD       BIT(2)
+#define PON_POFF_REASON2               0x0d
+#define PON_POFF_REASON2_UVLO          BIT(5)
+#define PON_POFF_REASON2_OTST3         BIT(6)
+
 #define PON_INT_RT_STS                 0x10
 #define PMIC_WD_BARK_STS_BIT           BIT(6)
 
@@ -58,9 +64,8 @@ static int pm8916_wdt_ping(struct watchdog_device *wdev)
 {
        struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev);
 
-       return regmap_update_bits(wdt->regmap,
-                                 wdt->baseaddr + PON_PMIC_WD_RESET_PET,
-                                 WATCHDOG_PET_BIT, WATCHDOG_PET_BIT);
+       return regmap_write(wdt->regmap, wdt->baseaddr + PON_PMIC_WD_RESET_PET,
+                           WATCHDOG_PET_BIT);
 }
 
 static int pm8916_wdt_configure_timers(struct watchdog_device *wdev)
@@ -111,12 +116,14 @@ static irqreturn_t pm8916_wdt_isr(int irq, void *arg)
 }
 
 static const struct watchdog_info pm8916_wdt_ident = {
-       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE |
+                  WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_POWERUNDER,
        .identity = "QCOM PM8916 PON WDT",
 };
 
 static const struct watchdog_info pm8916_wdt_pt_ident = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE |
+                  WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_POWERUNDER |
                   WDIOF_PRETIMEOUT,
        .identity = "QCOM PM8916 PON WDT",
 };
@@ -135,7 +142,9 @@ static int pm8916_wdt_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct pm8916_wdt *wdt;
        struct device *parent;
+       unsigned int val;
        int err, irq;
+       u8 poff[2];
 
        wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
@@ -176,6 +185,30 @@ static int pm8916_wdt_probe(struct platform_device *pdev)
                wdt->wdev.info = &pm8916_wdt_ident;
        }
 
+       err = regmap_bulk_read(wdt->regmap, wdt->baseaddr + PON_POFF_REASON1,
+                              &poff, ARRAY_SIZE(poff));
+       if (err) {
+               dev_err(dev, "failed to read POFF reason: %d\n", err);
+               return err;
+       }
+
+       dev_dbg(dev, "POFF reason: %#x %#x\n", poff[0], poff[1]);
+       if (poff[0] & PON_POFF_REASON1_PMIC_WD)
+               wdt->wdev.bootstatus |= WDIOF_CARDRESET;
+       if (poff[1] & PON_POFF_REASON2_UVLO)
+               wdt->wdev.bootstatus |= WDIOF_POWERUNDER;
+       if (poff[1] & PON_POFF_REASON2_OTST3)
+               wdt->wdev.bootstatus |= WDIOF_OVERHEAT;
+
+       err = regmap_read(wdt->regmap, wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL2,
+                         &val);
+       if (err)  {
+               dev_err(dev, "failed to check if watchdog is active: %d\n", err);
+               return err;
+       }
+       if (val & S2_RESET_EN_BIT)
+               set_bit(WDOG_HW_RUNNING, &wdt->wdev.status);
+
        /* Configure watchdog to hard-reset mode */
        err = regmap_write(wdt->regmap,
                           wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL,
index 60058a0..2a5298c 100644 (file)
@@ -366,6 +366,7 @@ static const struct of_device_id otto_wdt_ids[] = {
        { .compatible = "realtek,rtl8380-wdt" },
        { .compatible = "realtek,rtl8390-wdt" },
        { .compatible = "realtek,rtl9300-wdt" },
+       { .compatible = "realtek,rtl9310-wdt" },
        { }
 };
 MODULE_DEVICE_TABLE(of, otto_wdt_ids);
index 6db22f2..9591939 100644 (file)
@@ -845,8 +845,6 @@ static void s3c2410wdt_shutdown(struct platform_device *dev)
        s3c2410wdt_stop(&wdt->wdt_device);
 }
 
-#ifdef CONFIG_PM_SLEEP
-
 static int s3c2410wdt_suspend(struct device *dev)
 {
        int ret;
@@ -885,10 +883,9 @@ static int s3c2410wdt_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend,
-                       s3c2410wdt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops,
+                               s3c2410wdt_suspend, s3c2410wdt_resume);
 
 static struct platform_driver s3c2410wdt_driver = {
        .probe          = s3c2410wdt_probe,
@@ -897,7 +894,7 @@ static struct platform_driver s3c2410wdt_driver = {
        .id_table       = s3c2410_wdt_ids,
        .driver         = {
                .name   = "s3c2410-wdt",
-               .pm     = &s3c2410wdt_pm_ops,
+               .pm     = pm_sleep_ptr(&s3c2410wdt_pm_ops),
                .of_match_table = of_match_ptr(s3c2410_wdt_match),
        },
 };
index ec20ad4..aeee934 100644 (file)
@@ -339,7 +339,6 @@ static const struct of_device_id sama5d4_wdt_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
 
-#ifdef CONFIG_PM_SLEEP
 static int sama5d4_wdt_suspend_late(struct device *dev)
 {
        struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
@@ -366,18 +365,17 @@ static int sama5d4_wdt_resume_early(struct device *dev)
 
        return 0;
 }
-#endif
 
 static const struct dev_pm_ops sama5d4_wdt_pm_ops = {
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late,
-                       sama5d4_wdt_resume_early)
+       LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late,
+                                sama5d4_wdt_resume_early)
 };
 
 static struct platform_driver sama5d4_wdt_driver = {
        .probe          = sama5d4_wdt_probe,
        .driver         = {
                .name   = "sama5d4_wdt",
-               .pm     = &sama5d4_wdt_pm_ops,
+               .pm     = pm_sleep_ptr(&sama5d4_wdt_pm_ops),
                .of_match_table = sama5d4_wdt_of_match,
        }
 };
index 86ffb58..ae54dd3 100644 (file)
@@ -402,6 +402,7 @@ out:
                iounmap(addr);
 
        release_resource(res);
+       kfree(res);
 
        return ret;
 }
index f9479a3..78ba366 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * drivers/char/watchdog/sp805-wdt.c
  *
@@ -341,6 +342,10 @@ static const struct amba_id sp805_wdt_ids[] = {
                .id     = 0x00141805,
                .mask   = 0x00ffffff,
        },
+       {
+               .id     = 0x001bb824,
+               .mask   = 0x00ffffff,
+       },
        { 0, 0 },
 };
 
index 14ab655..39abecd 100644 (file)
@@ -248,7 +248,6 @@ static int st_wdog_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int st_wdog_suspend(struct device *dev)
 {
        struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev);
@@ -285,16 +284,14 @@ static int st_wdog_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(st_wdog_pm_ops,
-                        st_wdog_suspend,
-                        st_wdog_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(st_wdog_pm_ops,
+                               st_wdog_suspend, st_wdog_resume);
 
 static struct platform_driver st_wdog_driver = {
        .driver = {
                .name = "st-lpc-wdt",
-               .pm = &st_wdog_pm_ops,
+               .pm = pm_sleep_ptr(&st_wdog_pm_ops),
                .of_match_table = st_wdog_match,
        },
        .probe = st_wdog_probe,
index dfe06e5..d5de6c0 100644 (file)
@@ -230,8 +230,7 @@ static int tegra_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int tegra_wdt_runtime_suspend(struct device *dev)
+static int tegra_wdt_suspend(struct device *dev)
 {
        struct tegra_wdt *wdt = dev_get_drvdata(dev);
 
@@ -241,7 +240,7 @@ static int tegra_wdt_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int tegra_wdt_runtime_resume(struct device *dev)
+static int tegra_wdt_resume(struct device *dev)
 {
        struct tegra_wdt *wdt = dev_get_drvdata(dev);
 
@@ -250,7 +249,6 @@ static int tegra_wdt_runtime_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static const struct of_device_id tegra_wdt_of_match[] = {
        { .compatible = "nvidia,tegra30-timer", },
@@ -258,16 +256,14 @@ static const struct of_device_id tegra_wdt_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_wdt_of_match);
 
-static const struct dev_pm_ops tegra_wdt_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(tegra_wdt_runtime_suspend,
-                               tegra_wdt_runtime_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(tegra_wdt_pm_ops,
+                               tegra_wdt_suspend, tegra_wdt_resume);
 
 static struct platform_driver tegra_wdt_driver = {
        .probe          = tegra_wdt_probe,
        .driver         = {
                .name   = "tegra-wdt",
-               .pm     = &tegra_wdt_pm_ops,
+               .pm     = pm_sleep_ptr(&tegra_wdt_pm_ops),
                .of_match_table = tegra_wdt_of_match,
        },
 };
index e6f95e9..aeadaa0 100644 (file)
@@ -467,7 +467,6 @@ static int wdat_wdt_probe(struct platform_device *pdev)
        return devm_watchdog_register_device(dev, &wdat->wdd);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int wdat_wdt_suspend_noirq(struct device *dev)
 {
        struct wdat_wdt *wdat = dev_get_drvdata(dev);
@@ -528,18 +527,16 @@ static int wdat_wdt_resume_noirq(struct device *dev)
 
        return wdat_wdt_start(&wdat->wdd);
 }
-#endif
 
 static const struct dev_pm_ops wdat_wdt_pm_ops = {
-       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(wdat_wdt_suspend_noirq,
-                                     wdat_wdt_resume_noirq)
+       NOIRQ_SYSTEM_SLEEP_PM_OPS(wdat_wdt_suspend_noirq, wdat_wdt_resume_noirq)
 };
 
 static struct platform_driver wdat_wdt_driver = {
        .probe = wdat_wdt_probe,
        .driver = {
                .name = "wdat_wdt",
-               .pm = &wdat_wdt_pm_ops,
+               .pm = pm_sleep_ptr(&wdat_wdt_pm_ops),
        },
 };
 
index 07ad744..988c2ac 100644 (file)
@@ -158,7 +158,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
                cell->name[i] = tolower(name[i]);
        cell->name[i] = 0;
 
-       atomic_set(&cell->ref, 1);
+       refcount_set(&cell->ref, 1);
        atomic_set(&cell->active, 0);
        INIT_WORK(&cell->manager, afs_manage_cell_work);
        cell->volumes = RB_ROOT;
@@ -287,7 +287,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
        cell = candidate;
        candidate = NULL;
        atomic_set(&cell->active, 2);
-       trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 2, afs_cell_trace_insert);
+       trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 2, afs_cell_trace_insert);
        rb_link_node_rcu(&cell->net_node, parent, pp);
        rb_insert_color(&cell->net_node, &net->cells);
        up_write(&net->cells_lock);
@@ -295,7 +295,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
        afs_queue_cell(cell, afs_cell_trace_get_queue_new);
 
 wait_for_cell:
-       trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), atomic_read(&cell->active),
+       trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), atomic_read(&cell->active),
                       afs_cell_trace_wait);
        _debug("wait_for_cell");
        wait_var_event(&cell->state,
@@ -490,13 +490,13 @@ static void afs_cell_destroy(struct rcu_head *rcu)
 {
        struct afs_cell *cell = container_of(rcu, struct afs_cell, rcu);
        struct afs_net *net = cell->net;
-       int u;
+       int r;
 
        _enter("%p{%s}", cell, cell->name);
 
-       u = atomic_read(&cell->ref);
-       ASSERTCMP(u, ==, 0);
-       trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), afs_cell_trace_free);
+       r = refcount_read(&cell->ref);
+       ASSERTCMP(r, ==, 0);
+       trace_afs_cell(cell->debug_id, r, atomic_read(&cell->active), afs_cell_trace_free);
 
        afs_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers));
        afs_unuse_cell(net, cell->alias_of, afs_cell_trace_unuse_alias);
@@ -539,13 +539,10 @@ void afs_cells_timer(struct timer_list *timer)
  */
 struct afs_cell *afs_get_cell(struct afs_cell *cell, enum afs_cell_trace reason)
 {
-       int u;
+       int r;
 
-       if (atomic_read(&cell->ref) <= 0)
-               BUG();
-
-       u = atomic_inc_return(&cell->ref);
-       trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), reason);
+       __refcount_inc(&cell->ref, &r);
+       trace_afs_cell(cell->debug_id, r + 1, atomic_read(&cell->active), reason);
        return cell;
 }
 
@@ -556,12 +553,14 @@ void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason)
 {
        if (cell) {
                unsigned int debug_id = cell->debug_id;
-               unsigned int u, a;
+               unsigned int a;
+               bool zero;
+               int r;
 
                a = atomic_read(&cell->active);
-               u = atomic_dec_return(&cell->ref);
-               trace_afs_cell(debug_id, u, a, reason);
-               if (u == 0) {
+               zero = __refcount_dec_and_test(&cell->ref, &r);
+               trace_afs_cell(debug_id, r - 1, a, reason);
+               if (zero) {
                        a = atomic_read(&cell->active);
                        WARN(a != 0, "Cell active count %u > 0\n", a);
                        call_rcu(&cell->rcu, afs_cell_destroy);
@@ -574,14 +573,12 @@ void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason)
  */
 struct afs_cell *afs_use_cell(struct afs_cell *cell, enum afs_cell_trace reason)
 {
-       int u, a;
-
-       if (atomic_read(&cell->ref) <= 0)
-               BUG();
+       int r, a;
 
-       u = atomic_read(&cell->ref);
+       r = refcount_read(&cell->ref);
+       WARN_ON(r == 0);
        a = atomic_inc_return(&cell->active);
-       trace_afs_cell(cell->debug_id, u, a, reason);
+       trace_afs_cell(cell->debug_id, r, a, reason);
        return cell;
 }
 
@@ -593,7 +590,7 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr
 {
        unsigned int debug_id;
        time64_t now, expire_delay;
-       int u, a;
+       int r, a;
 
        if (!cell)
                return;
@@ -607,9 +604,9 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr
                expire_delay = afs_cell_gc_delay;
 
        debug_id = cell->debug_id;
-       u = atomic_read(&cell->ref);
+       r = refcount_read(&cell->ref);
        a = atomic_dec_return(&cell->active);
-       trace_afs_cell(debug_id, u, a, reason);
+       trace_afs_cell(debug_id, r, a, reason);
        WARN_ON(a == 0);
        if (a == 1)
                /* 'cell' may now be garbage collected. */
@@ -621,11 +618,11 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr
  */
 void afs_see_cell(struct afs_cell *cell, enum afs_cell_trace reason)
 {
-       int u, a;
+       int r, a;
 
-       u = atomic_read(&cell->ref);
+       r = refcount_read(&cell->ref);
        a = atomic_read(&cell->active);
-       trace_afs_cell(cell->debug_id, u, a, reason);
+       trace_afs_cell(cell->debug_id, r, a, reason);
 }
 
 /*
@@ -739,7 +736,7 @@ again:
                active = 1;
                if (atomic_try_cmpxchg_relaxed(&cell->active, &active, 0)) {
                        rb_erase(&cell->net_node, &net->cells);
-                       trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 0,
+                       trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 0,
                                       afs_cell_trace_unuse_delete);
                        smp_store_release(&cell->state, AFS_CELL_REMOVED);
                }
@@ -866,7 +863,7 @@ void afs_manage_cells(struct work_struct *work)
                bool sched_cell = false;
 
                active = atomic_read(&cell->active);
-               trace_afs_cell(cell->debug_id, atomic_read(&cell->ref),
+               trace_afs_cell(cell->debug_id, refcount_read(&cell->ref),
                               active, afs_cell_trace_manage);
 
                ASSERTCMP(active, >=, 1);
@@ -874,7 +871,7 @@ void afs_manage_cells(struct work_struct *work)
                if (purging) {
                        if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) {
                                active = atomic_dec_return(&cell->active);
-                               trace_afs_cell(cell->debug_id, atomic_read(&cell->ref),
+                               trace_afs_cell(cell->debug_id, refcount_read(&cell->ref),
                                               active, afs_cell_trace_unuse_pin);
                        }
                }
index a3f5de2..0a090d6 100644 (file)
@@ -212,8 +212,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
         * to maintain cache coherency.
         */
        if (call->server) {
-               trace_afs_server(call->server,
-                                atomic_read(&call->server->ref),
+               trace_afs_server(call->server->debug_id,
+                                refcount_read(&call->server->ref),
                                 atomic_read(&call->server->active),
                                 afs_server_trace_callback);
                afs_break_callbacks(call->server, call->count, call->request);
index a6f25d9..64ad554 100644 (file)
@@ -122,7 +122,7 @@ struct afs_call {
        };
        struct afs_operation    *op;
        unsigned int            server_index;
-       atomic_t                usage;
+       refcount_t              ref;
        enum afs_call_state     state;
        spinlock_t              state_lock;
        int                     error;          /* error code */
@@ -365,7 +365,7 @@ struct afs_cell {
        struct hlist_node       proc_link;      /* /proc cell list link */
        time64_t                dns_expiry;     /* Time AFSDB/SRV record expires */
        time64_t                last_inactive;  /* Time of last drop of usage count */
-       atomic_t                ref;            /* Struct refcount */
+       refcount_t              ref;            /* Struct refcount */
        atomic_t                active;         /* Active usage counter */
        unsigned long           flags;
 #define AFS_CELL_FL_NO_GC      0               /* The cell was added manually, don't auto-gc */
@@ -410,7 +410,7 @@ struct afs_vlserver {
 #define AFS_VLSERVER_FL_IS_YFS 2               /* Server is YFS not AFS */
 #define AFS_VLSERVER_FL_RESPONDING 3           /* VL server is responding */
        rwlock_t                lock;           /* Lock on addresses */
-       atomic_t                usage;
+       refcount_t              ref;
        unsigned int            rtt;            /* Server's current RTT in uS */
 
        /* Probe state */
@@ -446,7 +446,7 @@ struct afs_vlserver_entry {
 
 struct afs_vlserver_list {
        struct rcu_head         rcu;
-       atomic_t                usage;
+       refcount_t              ref;
        u8                      nr_servers;
        u8                      index;          /* Server currently in use */
        u8                      preferred;      /* Preferred server */
@@ -517,7 +517,7 @@ struct afs_server {
 #define AFS_SERVER_FL_NO_IBULK 17              /* Fileserver doesn't support FS.InlineBulkStatus */
 #define AFS_SERVER_FL_NO_RM2   18              /* Fileserver doesn't support YFS.RemoveFile2 */
 #define AFS_SERVER_FL_HAS_FS64 19              /* Fileserver supports FS.{Fetch,Store}Data64 */
-       atomic_t                ref;            /* Object refcount */
+       refcount_t              ref;            /* Object refcount */
        atomic_t                active;         /* Active user count */
        u32                     addr_version;   /* Address list version */
        unsigned int            rtt;            /* Server's current RTT in uS */
@@ -571,7 +571,7 @@ struct afs_volume {
                struct rcu_head rcu;
                afs_volid_t     vid;            /* volume ID */
        };
-       atomic_t                usage;
+       refcount_t              ref;
        time64_t                update_at;      /* Time at which to next update */
        struct afs_cell         *cell;          /* Cell to which belongs (pins ref) */
        struct rb_node          cell_node;      /* Link in cell->volumes */
@@ -1493,14 +1493,14 @@ extern int afs_end_vlserver_operation(struct afs_vl_cursor *);
  */
 static inline struct afs_vlserver *afs_get_vlserver(struct afs_vlserver *vlserver)
 {
-       atomic_inc(&vlserver->usage);
+       refcount_inc(&vlserver->ref);
        return vlserver;
 }
 
 static inline struct afs_vlserver_list *afs_get_vlserverlist(struct afs_vlserver_list *vllist)
 {
        if (vllist)
-               atomic_inc(&vllist->usage);
+               refcount_inc(&vllist->ref);
        return vllist;
 }
 
index e1b8634..2a0c83d 100644 (file)
@@ -47,7 +47,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
 
        /* display one cell per line on subsequent lines */
        seq_printf(m, "%3u %3u %6lld %2u %2u %s\n",
-                  atomic_read(&cell->ref),
+                  refcount_read(&cell->ref),
                   atomic_read(&cell->active),
                   cell->dns_expiry - ktime_get_real_seconds(),
                   vllist ? vllist->nr_servers : 0,
@@ -217,7 +217,7 @@ static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
        }
 
        seq_printf(m, "%3d %08llx %s %s\n",
-                  atomic_read(&vol->usage), vol->vid,
+                  refcount_read(&vol->ref), vol->vid,
                   afs_vol_types[vol->type],
                   vol->name);
 
@@ -388,7 +388,7 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
        alist = rcu_dereference(server->addresses);
        seq_printf(m, "%pU %3d %3d\n",
                   &server->uuid,
-                  atomic_read(&server->ref),
+                  refcount_read(&server->ref),
                   atomic_read(&server->active));
        seq_printf(m, "  - info: fl=%lx rtt=%u brk=%x\n",
                   server->flags, server->rtt, server->cb_s_break);
index a5434f3..d5c4785 100644 (file)
@@ -145,14 +145,14 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
        call->type = type;
        call->net = net;
        call->debug_id = atomic_inc_return(&rxrpc_debug_id);
-       atomic_set(&call->usage, 1);
+       refcount_set(&call->ref, 1);
        INIT_WORK(&call->async_work, afs_process_async_call);
        init_waitqueue_head(&call->waitq);
        spin_lock_init(&call->state_lock);
        call->iter = &call->def_iter;
 
        o = atomic_inc_return(&net->nr_outstanding_calls);
-       trace_afs_call(call, afs_call_trace_alloc, 1, o,
+       trace_afs_call(call->debug_id, afs_call_trace_alloc, 1, o,
                       __builtin_return_address(0));
        return call;
 }
@@ -163,14 +163,16 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
 void afs_put_call(struct afs_call *call)
 {
        struct afs_net *net = call->net;
-       int n = atomic_dec_return(&call->usage);
-       int o = atomic_read(&net->nr_outstanding_calls);
+       unsigned int debug_id = call->debug_id;
+       bool zero;
+       int r, o;
 
-       trace_afs_call(call, afs_call_trace_put, n, o,
+       zero = __refcount_dec_and_test(&call->ref, &r);
+       o = atomic_read(&net->nr_outstanding_calls);
+       trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
                       __builtin_return_address(0));
 
-       ASSERTCMP(n, >=, 0);
-       if (n == 0) {
+       if (zero) {
                ASSERT(!work_pending(&call->async_work));
                ASSERT(call->type->name != NULL);
 
@@ -185,7 +187,7 @@ void afs_put_call(struct afs_call *call)
                afs_put_addrlist(call->alist);
                kfree(call->request);
 
-               trace_afs_call(call, afs_call_trace_free, 0, o,
+               trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
                               __builtin_return_address(0));
                kfree(call);
 
@@ -198,9 +200,11 @@ void afs_put_call(struct afs_call *call)
 static struct afs_call *afs_get_call(struct afs_call *call,
                                     enum afs_call_trace why)
 {
-       int u = atomic_inc_return(&call->usage);
+       int r;
 
-       trace_afs_call(call, why, u,
+       __refcount_inc(&call->ref, &r);
+
+       trace_afs_call(call->debug_id, why, r + 1,
                       atomic_read(&call->net->nr_outstanding_calls),
                       __builtin_return_address(0));
        return call;
@@ -668,14 +672,13 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
                                   unsigned long call_user_ID)
 {
        struct afs_call *call = (struct afs_call *)call_user_ID;
-       int u;
+       int r;
 
        trace_afs_notify_call(rxcall, call);
        call->need_attention = true;
 
-       u = atomic_fetch_add_unless(&call->usage, 1, 0);
-       if (u != 0) {
-               trace_afs_call(call, afs_call_trace_wake, u + 1,
+       if (__refcount_inc_not_zero(&call->ref, &r)) {
+               trace_afs_call(call->debug_id, afs_call_trace_wake, r + 1,
                               atomic_read(&call->net->nr_outstanding_calls),
                               __builtin_return_address(0));
 
index 6e5b9a1..4981baf 100644 (file)
@@ -228,7 +228,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
        if (!server)
                goto enomem;
 
-       atomic_set(&server->ref, 1);
+       refcount_set(&server->ref, 1);
        atomic_set(&server->active, 1);
        server->debug_id = atomic_inc_return(&afs_server_debug_id);
        RCU_INIT_POINTER(server->addresses, alist);
@@ -243,7 +243,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
        server->rtt = UINT_MAX;
 
        afs_inc_servers_outstanding(net);
-       trace_afs_server(server, 1, 1, afs_server_trace_alloc);
+       trace_afs_server(server->debug_id, 1, 1, afs_server_trace_alloc);
        _leave(" = %p", server);
        return server;
 
@@ -352,9 +352,12 @@ void afs_servers_timer(struct timer_list *timer)
 struct afs_server *afs_get_server(struct afs_server *server,
                                  enum afs_server_trace reason)
 {
-       unsigned int u = atomic_inc_return(&server->ref);
+       unsigned int a;
+       int r;
 
-       trace_afs_server(server, u, atomic_read(&server->active), reason);
+       __refcount_inc(&server->ref, &r);
+       a = atomic_read(&server->active);
+       trace_afs_server(server->debug_id, r + 1, a, reason);
        return server;
 }
 
@@ -364,14 +367,14 @@ struct afs_server *afs_get_server(struct afs_server *server,
 static struct afs_server *afs_maybe_use_server(struct afs_server *server,
                                               enum afs_server_trace reason)
 {
-       unsigned int r = atomic_fetch_add_unless(&server->ref, 1, 0);
        unsigned int a;
+       int r;
 
-       if (r == 0)
+       if (!__refcount_inc_not_zero(&server->ref, &r))
                return NULL;
 
        a = atomic_inc_return(&server->active);
-       trace_afs_server(server, r, a, reason);
+       trace_afs_server(server->debug_id, r + 1, a, reason);
        return server;
 }
 
@@ -380,10 +383,13 @@ static struct afs_server *afs_maybe_use_server(struct afs_server *server,
  */
 struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_trace reason)
 {
-       unsigned int r = atomic_inc_return(&server->ref);
-       unsigned int a = atomic_inc_return(&server->active);
+       unsigned int a;
+       int r;
 
-       trace_afs_server(server, r, a, reason);
+       __refcount_inc(&server->ref, &r);
+       a = atomic_inc_return(&server->active);
+
+       trace_afs_server(server->debug_id, r + 1, a, reason);
        return server;
 }
 
@@ -393,14 +399,17 @@ struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_tra
 void afs_put_server(struct afs_net *net, struct afs_server *server,
                    enum afs_server_trace reason)
 {
-       unsigned int usage;
+       unsigned int a, debug_id = server->debug_id;
+       bool zero;
+       int r;
 
        if (!server)
                return;
 
-       usage = atomic_dec_return(&server->ref);
-       trace_afs_server(server, usage, atomic_read(&server->active), reason);
-       if (unlikely(usage == 0))
+       a = atomic_inc_return(&server->active);
+       zero = __refcount_dec_and_test(&server->ref, &r);
+       trace_afs_server(debug_id, r - 1, a, reason);
+       if (unlikely(zero))
                __afs_put_server(net, server);
 }
 
@@ -436,7 +445,7 @@ static void afs_server_rcu(struct rcu_head *rcu)
 {
        struct afs_server *server = container_of(rcu, struct afs_server, rcu);
 
-       trace_afs_server(server, atomic_read(&server->ref),
+       trace_afs_server(server->debug_id, refcount_read(&server->ref),
                         atomic_read(&server->active), afs_server_trace_free);
        afs_put_addrlist(rcu_access_pointer(server->addresses));
        kfree(server);
@@ -487,7 +496,7 @@ static void afs_gc_servers(struct afs_net *net, struct afs_server *gc_list)
 
                active = atomic_read(&server->active);
                if (active == 0) {
-                       trace_afs_server(server, atomic_read(&server->ref),
+                       trace_afs_server(server->debug_id, refcount_read(&server->ref),
                                         active, afs_server_trace_gc);
                        next = rcu_dereference_protected(
                                server->uuid_next, lockdep_is_held(&net->fs_lock.lock));
@@ -553,7 +562,7 @@ void afs_manage_servers(struct work_struct *work)
                _debug("manage %pU %u", &server->uuid, active);
 
                if (purging) {
-                       trace_afs_server(server, atomic_read(&server->ref),
+                       trace_afs_server(server->debug_id, refcount_read(&server->ref),
                                         active, afs_server_trace_purging);
                        if (active != 0)
                                pr_notice("Can't purge s=%08x\n", server->debug_id);
@@ -633,7 +642,8 @@ static noinline bool afs_update_server_record(struct afs_operation *op,
 
        _enter("");
 
-       trace_afs_server(server, atomic_read(&server->ref), atomic_read(&server->active),
+       trace_afs_server(server->debug_id, refcount_read(&server->ref),
+                        atomic_read(&server->active),
                         afs_server_trace_update);
 
        alist = afs_vl_lookup_addrs(op->volume->cell, op->key, &server->uuid);
index 38b2ba1..acc4821 100644 (file)
@@ -17,7 +17,7 @@ struct afs_vlserver *afs_alloc_vlserver(const char *name, size_t name_len,
        vlserver = kzalloc(struct_size(vlserver, name, name_len + 1),
                           GFP_KERNEL);
        if (vlserver) {
-               atomic_set(&vlserver->usage, 1);
+               refcount_set(&vlserver->ref, 1);
                rwlock_init(&vlserver->lock);
                init_waitqueue_head(&vlserver->probe_wq);
                spin_lock_init(&vlserver->probe_lock);
@@ -39,13 +39,9 @@ static void afs_vlserver_rcu(struct rcu_head *rcu)
 
 void afs_put_vlserver(struct afs_net *net, struct afs_vlserver *vlserver)
 {
-       if (vlserver) {
-               unsigned int u = atomic_dec_return(&vlserver->usage);
-               //_debug("VL PUT %p{%u}", vlserver, u);
-
-               if (u == 0)
-                       call_rcu(&vlserver->rcu, afs_vlserver_rcu);
-       }
+       if (vlserver &&
+           refcount_dec_and_test(&vlserver->ref))
+               call_rcu(&vlserver->rcu, afs_vlserver_rcu);
 }
 
 struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
@@ -54,7 +50,7 @@ struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
 
        vllist = kzalloc(struct_size(vllist, servers, nr_servers), GFP_KERNEL);
        if (vllist) {
-               atomic_set(&vllist->usage, 1);
+               refcount_set(&vllist->ref, 1);
                rwlock_init(&vllist->lock);
        }
 
@@ -64,10 +60,7 @@ struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
 void afs_put_vlserverlist(struct afs_net *net, struct afs_vlserver_list *vllist)
 {
        if (vllist) {
-               unsigned int u = atomic_dec_return(&vllist->usage);
-
-               //_debug("VLLS PUT %p{%u}", vllist, u);
-               if (u == 0) {
+               if (refcount_dec_and_test(&vllist->ref)) {
                        int i;
 
                        for (i = 0; i < vllist->nr_servers; i++) {
index cc665ce..f493702 100644 (file)
@@ -52,7 +52,7 @@ static void afs_remove_volume_from_cell(struct afs_volume *volume)
        struct afs_cell *cell = volume->cell;
 
        if (!hlist_unhashed(&volume->proc_link)) {
-               trace_afs_volume(volume->vid, atomic_read(&volume->usage),
+               trace_afs_volume(volume->vid, refcount_read(&cell->ref),
                                 afs_volume_trace_remove);
                write_seqlock(&cell->volume_lock);
                hlist_del_rcu(&volume->proc_link);
@@ -87,7 +87,7 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
        volume->type_force      = params->force;
        volume->name_len        = vldb->name_len;
 
-       atomic_set(&volume->usage, 1);
+       refcount_set(&volume->ref, 1);
        INIT_HLIST_NODE(&volume->proc_link);
        rwlock_init(&volume->servers_lock);
        rwlock_init(&volume->cb_v_break_lock);
@@ -228,7 +228,7 @@ static void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume)
        afs_remove_volume_from_cell(volume);
        afs_put_serverlist(net, rcu_access_pointer(volume->servers));
        afs_put_cell(volume->cell, afs_cell_trace_put_vol);
-       trace_afs_volume(volume->vid, atomic_read(&volume->usage),
+       trace_afs_volume(volume->vid, refcount_read(&volume->ref),
                         afs_volume_trace_free);
        kfree_rcu(volume, rcu);
 
@@ -242,8 +242,10 @@ struct afs_volume *afs_get_volume(struct afs_volume *volume,
                                  enum afs_volume_trace reason)
 {
        if (volume) {
-               int u = atomic_inc_return(&volume->usage);
-               trace_afs_volume(volume->vid, u, reason);
+               int r;
+
+               __refcount_inc(&volume->ref, &r);
+               trace_afs_volume(volume->vid, r + 1, reason);
        }
        return volume;
 }
@@ -257,9 +259,12 @@ void afs_put_volume(struct afs_net *net, struct afs_volume *volume,
 {
        if (volume) {
                afs_volid_t vid = volume->vid;
-               int u = atomic_dec_return(&volume->usage);
-               trace_afs_volume(vid, u, reason);
-               if (u == 0)
+               bool zero;
+               int r;
+
+               zero = __refcount_dec_and_test(&volume->ref, &r);
+               trace_afs_volume(vid, r - 1, reason);
+               if (zero)
                        afs_destroy_volume(net, volume);
        }
 }
index d6e5916..2c3a9b5 100644 (file)
@@ -329,7 +329,7 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
 
        dout("%s: pos=%llu orig_len=%zu len=%llu\n", __func__, subreq->start, subreq->len, len);
        iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages, subreq->start, len);
-       err = iov_iter_get_pages_alloc(&iter, &pages, len, &page_off);
+       err = iov_iter_get_pages_alloc2(&iter, &pages, len, &page_off);
        if (err < 0) {
                dout("%s: iov_ter_get_pages_alloc returned %d\n", __func__, err);
                goto out;
index da59e83..284d2fd 100644 (file)
@@ -95,12 +95,11 @@ static ssize_t __iter_get_bvecs(struct iov_iter *iter, size_t maxsize,
                size_t start;
                int idx = 0;
 
-               bytes = iov_iter_get_pages(iter, pages, maxsize - size,
+               bytes = iov_iter_get_pages2(iter, pages, maxsize - size,
                                           ITER_GET_BVECS_PAGES, &start);
                if (bytes < 0)
                        return size ?: bytes;
 
-               iov_iter_advance(iter, bytes);
                size += bytes;
 
                for ( ; bytes; idx++, bvec_idx++) {
@@ -657,10 +656,6 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
                /* Directories always inherit the setgid bit. */
                if (S_ISDIR(mode))
                        mode |= S_ISGID;
-               else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
-                        !in_group_p(dir->i_gid) &&
-                        !capable_wrt_inode_uidgid(&init_user_ns, dir, CAP_FSETID))
-                       mode &= ~S_ISGID;
        } else {
                in.gid = cpu_to_le32(from_kgid(&init_user_ns, current_fsgid()));
        }
@@ -1262,7 +1257,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
        size_t count = iov_iter_count(iter);
        loff_t pos = iocb->ki_pos;
        bool write = iov_iter_rw(iter) == WRITE;
-       bool should_dirty = !write && iter_is_iovec(iter);
+       bool should_dirty = !write && user_backed_iter(iter);
 
        if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP)
                return -EROFS;
index 85f2abc..d5a4341 100644 (file)
@@ -3276,7 +3276,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
                if (ctx->direct_io) {
                        ssize_t result;
 
-                       result = iov_iter_get_pages_alloc(
+                       result = iov_iter_get_pages_alloc2(
                                from, &pagevec, cur_len, &start);
                        if (result < 0) {
                                cifs_dbg(VFS,
@@ -3290,7 +3290,6 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
                                break;
                        }
                        cur_len = (size_t)result;
-                       iov_iter_advance(from, cur_len);
 
                        nr_pages =
                                (cur_len + start + PAGE_SIZE - 1) / PAGE_SIZE;
@@ -4012,7 +4011,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                if (ctx->direct_io) {
                        ssize_t result;
 
-                       result = iov_iter_get_pages_alloc(
+                       result = iov_iter_get_pages_alloc2(
                                        &direct_iov, &pagevec,
                                        cur_len, &start);
                        if (result < 0) {
@@ -4028,7 +4027,6 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                                break;
                        }
                        cur_len = (size_t)result;
-                       iov_iter_advance(&direct_iov, cur_len);
 
                        rdata = cifs_readdata_direct_alloc(
                                        pagevec, cifs_uncached_readv_complete);
@@ -4258,7 +4256,7 @@ static ssize_t __cifs_readv(
        if (!is_sync_kiocb(iocb))
                ctx->iocb = iocb;
 
-       if (iter_is_iovec(to))
+       if (user_backed_iter(to))
                ctx->should_dirty = true;
 
        if (direct) {
index 7a90606..987f47f 100644 (file)
@@ -1022,7 +1022,7 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
        saved_len = count;
 
        while (count && npages < max_pages) {
-               rc = iov_iter_get_pages(iter, pages, count, max_pages, &start);
+               rc = iov_iter_get_pages2(iter, pages, count, max_pages, &start);
                if (rc < 0) {
                        cifs_dbg(VFS, "Couldn't get user pages (rc=%zd)\n", rc);
                        break;
@@ -1034,7 +1034,6 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
                        break;
                }
 
-               iov_iter_advance(iter, rc);
                count -= rc;
                rc += start;
                cur_npages = DIV_ROUND_UP(rc, PAGE_SIZE);
index df5e2d0..f669163 100644 (file)
@@ -169,7 +169,7 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio)
        const enum req_op dio_op = dio->opf & REQ_OP_MASK;
        ssize_t ret;
 
-       ret = iov_iter_get_pages(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES,
+       ret = iov_iter_get_pages2(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES,
                                &sdio->from);
 
        if (ret < 0 && sdio->blocks_available && dio_op == REQ_OP_WRITE) {
@@ -191,7 +191,6 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio)
        }
 
        if (ret >= 0) {
-               iov_iter_advance(sdio->iter, ret);
                ret += sdio->from;
                sdio->head = 0;
                sdio->tail = (ret + PAGE_SIZE - 1) / PAGE_SIZE;
@@ -1251,7 +1250,7 @@ ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
        spin_lock_init(&dio->bio_lock);
        dio->refcount = 1;
 
-       dio->should_dirty = iter_is_iovec(iter) && iov_iter_rw(iter) == READ;
+       dio->should_dirty = user_backed_iter(iter) && iov_iter_rw(iter) == READ;
        sdio.iter = iter;
        sdio.final_block_in_request = end >> blkbits;
 
index 7492082..451d8a0 100644 (file)
@@ -263,6 +263,8 @@ void fscache_caching_failed(struct fscache_cookie *cookie)
 {
        clear_bit(FSCACHE_COOKIE_IS_CACHING, &cookie->flags);
        fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_FAILED);
+       trace_fscache_cookie(cookie->debug_id, refcount_read(&cookie->ref),
+                               fscache_cookie_failed);
 }
 EXPORT_SYMBOL(fscache_caching_failed);
 
@@ -739,6 +741,9 @@ again_locked:
                fallthrough;
 
        case FSCACHE_COOKIE_STATE_FAILED:
+               if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+                       fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
+
                if (atomic_read(&cookie->n_accesses) != 0)
                        break;
                if (test_bit(FSCACHE_COOKIE_DO_RELINQUISH, &cookie->flags)) {
@@ -1063,8 +1068,8 @@ void __fscache_invalidate(struct fscache_cookie *cookie,
                return;
 
        case FSCACHE_COOKIE_STATE_LOOKING_UP:
-               __fscache_begin_cookie_access(cookie, fscache_access_invalidate_cookie);
-               set_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags);
+               if (!test_and_set_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+                       __fscache_begin_cookie_access(cookie, fscache_access_invalidate_cookie);
                fallthrough;
        case FSCACHE_COOKIE_STATE_CREATING:
                spin_unlock(&cookie->lock);
index 0e537e5..5189742 100644 (file)
@@ -730,14 +730,13 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
                }
        } else {
                size_t off;
-               err = iov_iter_get_pages(cs->iter, &page, PAGE_SIZE, 1, &off);
+               err = iov_iter_get_pages2(cs->iter, &page, PAGE_SIZE, 1, &off);
                if (err < 0)
                        return err;
                BUG_ON(!err);
                cs->len = err;
                cs->offset = off;
                cs->pg = page;
-               iov_iter_advance(cs->iter, err);
        }
 
        return lock_request(cs->req);
@@ -1356,7 +1355,7 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to)
        if (!fud)
                return -EPERM;
 
-       if (!iter_is_iovec(to))
+       if (!user_backed_iter(to))
                return -EINVAL;
 
        fuse_copy_init(&cs, 1, to);
@@ -1949,7 +1948,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
        if (!fud)
                return -EPERM;
 
-       if (!iter_is_iovec(from))
+       if (!user_backed_iter(from))
                return -EINVAL;
 
        fuse_copy_init(&cs, 0, from);
index 7154b95..1a3afd4 100644 (file)
@@ -1414,14 +1414,13 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
        while (nbytes < *nbytesp && ap->num_pages < max_pages) {
                unsigned npages;
                size_t start;
-               ret = iov_iter_get_pages(ii, &ap->pages[ap->num_pages],
+               ret = iov_iter_get_pages2(ii, &ap->pages[ap->num_pages],
                                        *nbytesp - nbytes,
                                        max_pages - ap->num_pages,
                                        &start);
                if (ret < 0)
                        break;
 
-               iov_iter_advance(ii, ret);
                nbytes += ret;
 
                ret += start;
@@ -1478,7 +1477,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
                        inode_unlock(inode);
        }
 
-       io->should_dirty = !write && iter_is_iovec(iter);
+       io->should_dirty = !write && user_backed_iter(iter);
        while (count) {
                ssize_t nres;
                fl_owner_t owner = current->files;
index d8f1239..892006f 100644 (file)
@@ -780,7 +780,7 @@ static inline bool should_fault_in_pages(struct iov_iter *i,
 
        if (!count)
                return false;
-       if (!iter_is_iovec(i))
+       if (!user_backed_iter(i))
                return false;
 
        size = PAGE_SIZE;
index fe0e374..f7a5b51 100644 (file)
@@ -282,35 +282,6 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 }
 #endif
 
-static size_t
-hugetlbfs_read_actor(struct page *page, unsigned long offset,
-                       struct iov_iter *to, unsigned long size)
-{
-       size_t copied = 0;
-       int i, chunksize;
-
-       /* Find which 4k chunk and offset with in that chunk */
-       i = offset >> PAGE_SHIFT;
-       offset = offset & ~PAGE_MASK;
-
-       while (size) {
-               size_t n;
-               chunksize = PAGE_SIZE;
-               if (offset)
-                       chunksize -= offset;
-               if (chunksize > size)
-                       chunksize = size;
-               n = copy_page_to_iter(&page[i], offset, chunksize, to);
-               copied += n;
-               if (n != chunksize)
-                       return copied;
-               offset = 0;
-               size -= chunksize;
-               i++;
-       }
-       return copied;
-}
-
 /*
  * Support for read() - Find the page attached to f_mapping and copy out the
  * data. This provides functionality similar to filemap_read().
@@ -360,7 +331,7 @@ static ssize_t hugetlbfs_read_iter(struct kiocb *iocb, struct iov_iter *to)
                        /*
                         * We have the page, copy it to user space buffer.
                         */
-                       copied = hugetlbfs_read_actor(page, offset, to, nr);
+                       copied = copy_page_to_iter(page, offset, nr, to);
                        put_page(page);
                }
                offset += copied;
index 524ee91..9c3cd54 100644 (file)
@@ -2326,10 +2326,6 @@ void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode,
                /* Directories are special, and always inherit S_ISGID */
                if (S_ISDIR(mode))
                        mode |= S_ISGID;
-               else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
-                        !in_group_p(i_gid_into_mnt(mnt_userns, dir)) &&
-                        !capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID))
-                       mode &= ~S_ISGID;
        } else
                inode_fsgid_set(inode, mnt_userns);
        inode->i_mode = mode;
@@ -2485,3 +2481,33 @@ struct timespec64 current_time(struct inode *inode)
        return timestamp_truncate(now, inode);
 }
 EXPORT_SYMBOL(current_time);
+
+/**
+ * mode_strip_sgid - handle the sgid bit for non-directories
+ * @mnt_userns: User namespace of the mount the inode was created from
+ * @dir: parent directory inode
+ * @mode: mode of the file to be created in @dir
+ *
+ * If the @mode of the new file has both the S_ISGID and S_IXGRP bit
+ * raised and @dir has the S_ISGID bit raised ensure that the caller is
+ * either in the group of the parent directory or they have CAP_FSETID
+ * in their user namespace and are privileged over the parent directory.
+ * In all other cases, strip the S_ISGID bit from @mode.
+ *
+ * Return: the new mode to use for the file
+ */
+umode_t mode_strip_sgid(struct user_namespace *mnt_userns,
+                       const struct inode *dir, umode_t mode)
+{
+       if ((mode & (S_ISGID | S_IXGRP)) != (S_ISGID | S_IXGRP))
+               return mode;
+       if (S_ISDIR(mode) || !dir || !(dir->i_mode & S_ISGID))
+               return mode;
+       if (in_group_p(i_gid_into_mnt(mnt_userns, dir)))
+               return mode;
+       if (capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID))
+               return mode;
+
+       return mode & ~S_ISGID;
+}
+EXPORT_SYMBOL(mode_strip_sgid);
index c75d33d..4eb559a 100644 (file)
@@ -533,7 +533,7 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
                        iomi.flags |= IOMAP_NOWAIT;
                }
 
-               if (iter_is_iovec(iter))
+               if (user_backed_iter(iter))
                        dio->flags |= IOMAP_DIO_DIRTY;
        } else {
                iomi.flags |= IOMAP_WRITE;
index 911444d..c5a5c7b 100644 (file)
@@ -121,8 +121,8 @@ out:
        return rc;
 }
 
-static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
-                           char *dname)
+static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+                           char *ntlmv2_hash, char *dname)
 {
        int ret, len, conv_len;
        wchar_t *domain = NULL;
@@ -158,7 +158,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
        }
 
        conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len,
-                                 sess->conn->local_nls);
+                                 conn->local_nls);
        if (conv_len < 0 || conv_len > len) {
                ret = -EINVAL;
                goto out;
@@ -182,7 +182,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
        }
 
        conv_len = smb_strtoUTF16((__le16 *)domain, dname, len,
-                                 sess->conn->local_nls);
+                                 conn->local_nls);
        if (conv_len < 0 || conv_len > len) {
                ret = -EINVAL;
                goto out;
@@ -215,8 +215,9 @@ out:
  *
  * Return:     0 on success, error number on error
  */
-int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
-                     int blen, char *domain_name, char *cryptkey)
+int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+                     struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
+                     char *cryptkey)
 {
        char ntlmv2_hash[CIFS_ENCPWD_SIZE];
        char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
@@ -230,7 +231,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
                return -ENOMEM;
        }
 
-       rc = calc_ntlmv2_hash(sess, ntlmv2_hash, domain_name);
+       rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name);
        if (rc) {
                ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc);
                goto out;
@@ -333,7 +334,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
        /* process NTLMv2 authentication */
        ksmbd_debug(AUTH, "decode_ntlmssp_authenticate_blob dname%s\n",
                    domain_name);
-       ret = ksmbd_auth_ntlmv2(sess, (struct ntlmv2_resp *)((char *)authblob + nt_off),
+       ret = ksmbd_auth_ntlmv2(conn, sess,
+                               (struct ntlmv2_resp *)((char *)authblob + nt_off),
                                nt_len - CIFS_ENCPWD_SIZE,
                                domain_name, conn->ntlmssp.cryptkey);
        kfree(domain_name);
@@ -659,8 +661,9 @@ struct derivation {
        bool binding;
 };
 
-static int generate_key(struct ksmbd_session *sess, struct kvec label,
-                       struct kvec context, __u8 *key, unsigned int key_size)
+static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+                       struct kvec label, struct kvec context, __u8 *key,
+                       unsigned int key_size)
 {
        unsigned char zero = 0x0;
        __u8 i[4] = {0, 0, 0, 1};
@@ -720,8 +723,8 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label,
                goto smb3signkey_ret;
        }
 
-       if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
-           sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
+       if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
+           conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
                rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4);
        else
                rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4);
@@ -756,17 +759,17 @@ static int generate_smb3signingkey(struct ksmbd_session *sess,
        if (!chann)
                return 0;
 
-       if (sess->conn->dialect >= SMB30_PROT_ID && signing->binding)
+       if (conn->dialect >= SMB30_PROT_ID && signing->binding)
                key = chann->smb3signingkey;
        else
                key = sess->smb3signingkey;
 
-       rc = generate_key(sess, signing->label, signing->context, key,
+       rc = generate_key(conn, sess, signing->label, signing->context, key,
                          SMB3_SIGN_KEY_SIZE);
        if (rc)
                return rc;
 
-       if (!(sess->conn->dialect >= SMB30_PROT_ID && signing->binding))
+       if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
                memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE);
 
        ksmbd_debug(AUTH, "dumping generated AES signing keys\n");
@@ -820,30 +823,31 @@ struct derivation_twin {
        struct derivation decryption;
 };
 
-static int generate_smb3encryptionkey(struct ksmbd_session *sess,
+static int generate_smb3encryptionkey(struct ksmbd_conn *conn,
+                                     struct ksmbd_session *sess,
                                      const struct derivation_twin *ptwin)
 {
        int rc;
 
-       rc = generate_key(sess, ptwin->encryption.label,
+       rc = generate_key(conn, sess, ptwin->encryption.label,
                          ptwin->encryption.context, sess->smb3encryptionkey,
                          SMB3_ENC_DEC_KEY_SIZE);
        if (rc)
                return rc;
 
-       rc = generate_key(sess, ptwin->decryption.label,
+       rc = generate_key(conn, sess, ptwin->decryption.label,
                          ptwin->decryption.context,
                          sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
        if (rc)
                return rc;
 
        ksmbd_debug(AUTH, "dumping generated AES encryption keys\n");
-       ksmbd_debug(AUTH, "Cipher type   %d\n", sess->conn->cipher_type);
+       ksmbd_debug(AUTH, "Cipher type   %d\n", conn->cipher_type);
        ksmbd_debug(AUTH, "Session Id    %llu\n", sess->id);
        ksmbd_debug(AUTH, "Session Key   %*ph\n",
                    SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
-       if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
-           sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
+       if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
+           conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
                ksmbd_debug(AUTH, "ServerIn Key  %*ph\n",
                            SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey);
                ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
@@ -857,7 +861,8 @@ static int generate_smb3encryptionkey(struct ksmbd_session *sess,
        return 0;
 }
 
-int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess)
+int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
+                                 struct ksmbd_session *sess)
 {
        struct derivation_twin twin;
        struct derivation *d;
@@ -874,10 +879,11 @@ int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess)
        d->context.iov_base = "ServerIn ";
        d->context.iov_len = 10;
 
-       return generate_smb3encryptionkey(sess, &twin);
+       return generate_smb3encryptionkey(conn, sess, &twin);
 }
 
-int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess)
+int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
+                                  struct ksmbd_session *sess)
 {
        struct derivation_twin twin;
        struct derivation *d;
@@ -894,7 +900,7 @@ int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess)
        d->context.iov_base = sess->Preauth_HashValue;
        d->context.iov_len = 64;
 
-       return generate_smb3encryptionkey(sess, &twin);
+       return generate_smb3encryptionkey(conn, sess, &twin);
 }
 
 int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
index 9562965..25b7726 100644 (file)
@@ -38,8 +38,9 @@ struct kvec;
 int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
                        unsigned int nvec, int enc);
 void ksmbd_copy_gss_neg_header(void *buf);
-int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
-                     int blen, char *domain_name, char *cryptkey);
+int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+                     struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
+                     char *cryptkey);
 int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
                                   int blob_len, struct ksmbd_conn *conn,
                                   struct ksmbd_session *sess);
@@ -58,8 +59,10 @@ int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
                               struct ksmbd_conn *conn);
 int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
                                struct ksmbd_conn *conn);
-int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess);
-int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess);
+int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
+                                 struct ksmbd_session *sess);
+int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
+                                  struct ksmbd_session *sess);
 int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
                                     __u8 *pi_hash);
 int ksmbd_gen_sd_hash(struct ksmbd_conn *conn, char *sd_buf, int len,
index e8f476c..756ad63 100644 (file)
@@ -36,6 +36,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
        list_del(&conn->conns_list);
        write_unlock(&conn_list_lock);
 
+       xa_destroy(&conn->sessions);
        kvfree(conn->request_buf);
        kfree(conn->preauth_info);
        kfree(conn);
@@ -65,13 +66,14 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
        conn->outstanding_credits = 0;
 
        init_waitqueue_head(&conn->req_running_q);
+       init_waitqueue_head(&conn->r_count_q);
        INIT_LIST_HEAD(&conn->conns_list);
-       INIT_LIST_HEAD(&conn->sessions);
        INIT_LIST_HEAD(&conn->requests);
        INIT_LIST_HEAD(&conn->async_requests);
        spin_lock_init(&conn->request_lock);
        spin_lock_init(&conn->credits_lock);
        ida_init(&conn->async_ida);
+       xa_init(&conn->sessions);
 
        spin_lock_init(&conn->llist_lock);
        INIT_LIST_HEAD(&conn->lock_list);
@@ -164,7 +166,6 @@ int ksmbd_conn_write(struct ksmbd_work *work)
        struct kvec iov[3];
        int iov_idx = 0;
 
-       ksmbd_conn_try_dequeue_request(work);
        if (!work->response_buf) {
                pr_err("NULL response header\n");
                return -EINVAL;
@@ -346,8 +347,8 @@ int ksmbd_conn_handler_loop(void *p)
 
 out:
        /* Wait till all reference dropped to the Server object*/
-       while (atomic_read(&conn->r_count) > 0)
-               schedule_timeout(HZ);
+       wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
+
 
        unload_nls(conn->local_nls);
        if (default_conn_ops.terminate_fn)
index 98c1cbe..e7f7d57 100644 (file)
 
 #define KSMBD_SOCKET_BACKLOG           16
 
-/*
- * WARNING
- *
- * This is nothing but a HACK. Session status should move to channel
- * or to session. As of now we have 1 tcp_conn : 1 ksmbd_session, but
- * we need to change it to 1 tcp_conn : N ksmbd_sessions.
- */
 enum {
        KSMBD_SESS_NEW = 0,
        KSMBD_SESS_GOOD,
@@ -55,7 +48,7 @@ struct ksmbd_conn {
        struct nls_table                *local_nls;
        struct list_head                conns_list;
        /* smb session 1 per user */
-       struct list_head                sessions;
+       struct xarray                   sessions;
        unsigned long                   last_active;
        /* How many request are running currently */
        atomic_t                        req_running;
@@ -65,6 +58,7 @@ struct ksmbd_conn {
        unsigned int                    outstanding_credits;
        spinlock_t                      credits_lock;
        wait_queue_head_t               req_running_q;
+       wait_queue_head_t               r_count_q;
        /* Lock to protect requests list*/
        spinlock_t                      request_lock;
        struct list_head                requests;
index cb72d30..70655af 100644 (file)
@@ -222,17 +222,3 @@ bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
        }
        return false;
 }
-
-void ksmbd_share_configs_cleanup(void)
-{
-       struct ksmbd_share_config *share;
-       struct hlist_node *tmp;
-       int i;
-
-       down_write(&shares_table_lock);
-       hash_for_each_safe(shares_table, i, tmp, share, hlist) {
-               hash_del(&share->hlist);
-               kill_share(share);
-       }
-       up_write(&shares_table_lock);
-}
index 953befc..28bf351 100644 (file)
@@ -76,6 +76,4 @@ static inline void ksmbd_share_config_put(struct ksmbd_share_config *share)
 struct ksmbd_share_config *ksmbd_share_config_get(char *name);
 bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
                               const char *filename);
-void ksmbd_share_configs_cleanup(void);
-
 #endif /* __SHARE_CONFIG_MANAGEMENT_H__ */
index 0d28e72..b35ea6a 100644 (file)
@@ -16,7 +16,8 @@
 #include "user_session.h"
 
 struct ksmbd_tree_conn_status
-ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name)
+ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+                       char *share_name)
 {
        struct ksmbd_tree_conn_status status = {-EINVAL, NULL};
        struct ksmbd_tree_connect_response *resp = NULL;
@@ -41,7 +42,7 @@ ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name)
                goto out_error;
        }
 
-       peer_addr = KSMBD_TCP_PEER_SOCKADDR(sess->conn);
+       peer_addr = KSMBD_TCP_PEER_SOCKADDR(conn);
        resp = ksmbd_ipc_tree_connect_request(sess,
                                              sc,
                                              tree_conn,
index 18e2a99..71e5027 100644 (file)
@@ -12,6 +12,7 @@
 
 struct ksmbd_share_config;
 struct ksmbd_user;
+struct ksmbd_conn;
 
 struct ksmbd_tree_connect {
        int                             id;
@@ -40,7 +41,8 @@ static inline int test_tree_conn_flag(struct ksmbd_tree_connect *tree_conn,
 struct ksmbd_session;
 
 struct ksmbd_tree_conn_status
-ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name);
+ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+                       char *share_name);
 
 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
                               struct ksmbd_tree_connect *tree_conn);
index 8d8ffd8..3fa2139 100644 (file)
@@ -32,11 +32,13 @@ static void free_channel_list(struct ksmbd_session *sess)
 {
        struct channel *chann, *tmp;
 
+       write_lock(&sess->chann_lock);
        list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
                                 chann_list) {
                list_del(&chann->chann_list);
                kfree(chann);
        }
+       write_unlock(&sess->chann_lock);
 }
 
 static void __session_rpc_close(struct ksmbd_session *sess,
@@ -149,11 +151,6 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
        if (!sess)
                return;
 
-       if (!atomic_dec_and_test(&sess->refcnt))
-               return;
-
-       list_del(&sess->sessions_entry);
-
        down_write(&sessions_table_lock);
        hash_del(&sess->hlist);
        up_write(&sessions_table_lock);
@@ -181,53 +178,70 @@ static struct ksmbd_session *__session_lookup(unsigned long long id)
        return NULL;
 }
 
-void ksmbd_session_register(struct ksmbd_conn *conn,
-                           struct ksmbd_session *sess)
+int ksmbd_session_register(struct ksmbd_conn *conn,
+                          struct ksmbd_session *sess)
 {
-       sess->conn = conn;
-       list_add(&sess->sessions_entry, &conn->sessions);
+       sess->dialect = conn->dialect;
+       memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
+       return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
 }
 
-void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
+static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
 {
-       struct ksmbd_session *sess;
-
-       while (!list_empty(&conn->sessions)) {
-               sess = list_entry(conn->sessions.next,
-                                 struct ksmbd_session,
-                                 sessions_entry);
+       struct channel *chann, *tmp;
 
-               ksmbd_session_destroy(sess);
+       write_lock(&sess->chann_lock);
+       list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
+                                chann_list) {
+               if (chann->conn == conn) {
+                       list_del(&chann->chann_list);
+                       kfree(chann);
+                       write_unlock(&sess->chann_lock);
+                       return 0;
+               }
        }
-}
+       write_unlock(&sess->chann_lock);
 
-static bool ksmbd_session_id_match(struct ksmbd_session *sess,
-                                  unsigned long long id)
-{
-       return sess->id == id;
+       return -ENOENT;
 }
 
-struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
-                                          unsigned long long id)
+void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
 {
-       struct ksmbd_session *sess = NULL;
+       struct ksmbd_session *sess;
 
-       list_for_each_entry(sess, &conn->sessions, sessions_entry) {
-               if (ksmbd_session_id_match(sess, id))
-                       return sess;
+       if (conn->binding) {
+               int bkt;
+
+               down_write(&sessions_table_lock);
+               hash_for_each(sessions_table, bkt, sess, hlist) {
+                       if (!ksmbd_chann_del(conn, sess)) {
+                               up_write(&sessions_table_lock);
+                               goto sess_destroy;
+                       }
+               }
+               up_write(&sessions_table_lock);
+       } else {
+               unsigned long id;
+
+               xa_for_each(&conn->sessions, id, sess) {
+                       if (!ksmbd_chann_del(conn, sess))
+                               goto sess_destroy;
+               }
        }
-       return NULL;
-}
 
-int get_session(struct ksmbd_session *sess)
-{
-       return atomic_inc_not_zero(&sess->refcnt);
+       return;
+
+sess_destroy:
+       if (list_empty(&sess->ksmbd_chann_list)) {
+               xa_erase(&conn->sessions, sess->id);
+               ksmbd_session_destroy(sess);
+       }
 }
 
-void put_session(struct ksmbd_session *sess)
+struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
+                                          unsigned long long id)
 {
-       if (atomic_dec_and_test(&sess->refcnt))
-               pr_err("get/%s seems to be mismatched.", __func__);
+       return xa_load(&conn->sessions, id);
 }
 
 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
@@ -236,10 +250,6 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
 
        down_read(&sessions_table_lock);
        sess = __session_lookup(id);
-       if (sess) {
-               if (!get_session(sess))
-                       sess = NULL;
-       }
        up_read(&sessions_table_lock);
 
        return sess;
@@ -253,6 +263,8 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
        sess = ksmbd_session_lookup(conn, id);
        if (!sess && conn->binding)
                sess = ksmbd_session_lookup_slowpath(id);
+       if (sess && sess->state != SMB2_SESSION_VALID)
+               sess = NULL;
        return sess;
 }
 
@@ -314,12 +326,11 @@ static struct ksmbd_session *__session_create(int protocol)
                goto error;
 
        set_session_flag(sess, protocol);
-       INIT_LIST_HEAD(&sess->sessions_entry);
        xa_init(&sess->tree_conns);
        INIT_LIST_HEAD(&sess->ksmbd_chann_list);
        INIT_LIST_HEAD(&sess->rpc_handle_list);
        sess->sequence_number = 1;
-       atomic_set(&sess->refcnt, 1);
+       rwlock_init(&sess->chann_lock);
 
        switch (protocol) {
        case CIFDS_SESSION_FLAG_SMB2:
index e241f16..8934b8e 100644 (file)
@@ -33,8 +33,10 @@ struct preauth_session {
 struct ksmbd_session {
        u64                             id;
 
+       __u16                           dialect;
+       char                            ClientGUID[SMB2_CLIENT_GUID_SIZE];
+
        struct ksmbd_user               *user;
-       struct ksmbd_conn               *conn;
        unsigned int                    sequence_number;
        unsigned int                    flags;
 
@@ -48,6 +50,7 @@ struct ksmbd_session {
        char                            sess_key[CIFS_KEY_SIZE];
 
        struct hlist_node               hlist;
+       rwlock_t                        chann_lock;
        struct list_head                ksmbd_chann_list;
        struct xarray                   tree_conns;
        struct ida                      tree_conn_ida;
@@ -57,9 +60,7 @@ struct ksmbd_session {
        __u8                            smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
        __u8                            smb3signingkey[SMB3_SIGN_KEY_SIZE];
 
-       struct list_head                sessions_entry;
        struct ksmbd_file_table         file_table;
-       atomic_t                        refcnt;
 };
 
 static inline int test_session_flag(struct ksmbd_session *sess, int bit)
@@ -84,8 +85,8 @@ void ksmbd_session_destroy(struct ksmbd_session *sess);
 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
                                           unsigned long long id);
-void ksmbd_session_register(struct ksmbd_conn *conn,
-                           struct ksmbd_session *sess);
+int ksmbd_session_register(struct ksmbd_conn *conn,
+                          struct ksmbd_session *sess);
 void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
                                               unsigned long long id);
@@ -100,6 +101,4 @@ void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id);
 int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name);
 void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id);
 int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id);
-int get_session(struct ksmbd_session *sess);
-void put_session(struct ksmbd_session *sess);
 #endif /* __USER_SESSION_MANAGEMENT_H__ */
index 8b55605..9046cff 100644 (file)
@@ -30,6 +30,7 @@ static DEFINE_RWLOCK(lease_list_lock);
 static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
                                        u64 id, __u16 Tid)
 {
+       struct ksmbd_conn *conn = work->conn;
        struct ksmbd_session *sess = work->sess;
        struct oplock_info *opinfo;
 
@@ -38,7 +39,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
                return NULL;
 
        opinfo->sess = sess;
-       opinfo->conn = sess->conn;
+       opinfo->conn = conn;
        opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
        opinfo->op_state = OPLOCK_STATE_NONE;
        opinfo->pending_break = 0;
@@ -615,18 +616,13 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
        struct ksmbd_file *fp;
 
        fp = ksmbd_lookup_durable_fd(br_info->fid);
-       if (!fp) {
-               atomic_dec(&conn->r_count);
-               ksmbd_free_work_struct(work);
-               return;
-       }
+       if (!fp)
+               goto out;
 
        if (allocate_oplock_break_buf(work)) {
                pr_err("smb2_allocate_rsp_buf failed! ");
-               atomic_dec(&conn->r_count);
                ksmbd_fd_put(work, fp);
-               ksmbd_free_work_struct(work);
-               return;
+               goto out;
        }
 
        rsp_hdr = smb2_get_msg(work->response_buf);
@@ -667,8 +663,16 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
 
        ksmbd_fd_put(work, fp);
        ksmbd_conn_write(work);
+
+out:
        ksmbd_free_work_struct(work);
-       atomic_dec(&conn->r_count);
+       /*
+        * Checking waitqueue to dropping pending requests on
+        * disconnection. waitqueue_active is safe because it
+        * uses atomic operation for condition.
+        */
+       if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+               wake_up(&conn->r_count_q);
 }
 
 /**
@@ -731,9 +735,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
 
        if (allocate_oplock_break_buf(work)) {
                ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! ");
-               ksmbd_free_work_struct(work);
-               atomic_dec(&conn->r_count);
-               return;
+               goto out;
        }
 
        rsp_hdr = smb2_get_msg(work->response_buf);
@@ -771,8 +773,16 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
        inc_rfc1001_len(work->response_buf, 44);
 
        ksmbd_conn_write(work);
+
+out:
        ksmbd_free_work_struct(work);
-       atomic_dec(&conn->r_count);
+       /*
+        * Checking waitqueue to dropping pending requests on
+        * disconnection. waitqueue_active is safe because it
+        * uses atomic operation for condition.
+        */
+       if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+               wake_up(&conn->r_count_q);
 }
 
 /**
@@ -972,7 +982,7 @@ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
        }
 
        list_for_each_entry(lb, &lease_table_list, l_entry) {
-               if (!memcmp(lb->client_guid, sess->conn->ClientGUID,
+               if (!memcmp(lb->client_guid, sess->ClientGUID,
                            SMB2_CLIENT_GUID_SIZE))
                        goto found;
        }
@@ -988,7 +998,7 @@ found:
                rcu_read_unlock();
                if (opinfo->o_fp->f_ci == ci)
                        goto op_next;
-               err = compare_guid_key(opinfo, sess->conn->ClientGUID,
+               err = compare_guid_key(opinfo, sess->ClientGUID,
                                       lctx->lease_key);
                if (err) {
                        err = -EINVAL;
@@ -1122,7 +1132,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
                struct oplock_info *m_opinfo;
 
                /* is lease already granted ? */
-               m_opinfo = same_client_has_lease(ci, sess->conn->ClientGUID,
+               m_opinfo = same_client_has_lease(ci, sess->ClientGUID,
                                                 lctx);
                if (m_opinfo) {
                        copy_lease(m_opinfo, opinfo);
@@ -1240,7 +1250,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
 {
        struct oplock_info *op, *brk_op;
        struct ksmbd_inode *ci;
-       struct ksmbd_conn *conn = work->sess->conn;
+       struct ksmbd_conn *conn = work->conn;
 
        if (!test_share_config_flag(work->tcon->share_conf,
                                    KSMBD_SHARE_FLAG_OPLOCKS))
index 4cd03d6..ce42bff 100644 (file)
@@ -261,7 +261,13 @@ static void handle_ksmbd_work(struct work_struct *wk)
 
        ksmbd_conn_try_dequeue_request(work);
        ksmbd_free_work_struct(work);
-       atomic_dec(&conn->r_count);
+       /*
+        * Checking waitqueue to dropping pending requests on
+        * disconnection. waitqueue_active is safe because it
+        * uses atomic operation for condition.
+        */
+       if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+               wake_up(&conn->r_count_q);
 }
 
 /**
index f8f4563..6e25ace 100644 (file)
@@ -90,11 +90,6 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
        *off = 0;
        *len = 0;
 
-       /* error reqeusts do not have data area */
-       if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
-           (((struct smb2_err_rsp *)hdr)->StructureSize) == SMB2_ERROR_STRUCTURE_SIZE2_LE)
-               return ret;
-
        /*
         * Following commands have data areas so we have to get the location
         * of the data buffer offset and data buffer length for the particular
@@ -136,8 +131,11 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
                *len = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoLength);
                break;
        case SMB2_WRITE:
-               if (((struct smb2_write_req *)hdr)->DataOffset) {
-                       *off = le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset);
+               if (((struct smb2_write_req *)hdr)->DataOffset ||
+                   ((struct smb2_write_req *)hdr)->Length) {
+                       *off = max_t(unsigned int,
+                                    le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset),
+                                    offsetof(struct smb2_write_req, Buffer));
                        *len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length);
                        break;
                }
index 353f047..9751cc9 100644 (file)
@@ -535,9 +535,10 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
                struct smb2_query_info_req *req;
 
                req = smb2_get_msg(work->request_buf);
-               if (req->InfoType == SMB2_O_INFO_FILE &&
-                   (req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
-                    req->FileInfoClass == FILE_ALL_INFORMATION))
+               if ((req->InfoType == SMB2_O_INFO_FILE &&
+                    (req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
+                    req->FileInfoClass == FILE_ALL_INFORMATION)) ||
+                   req->InfoType == SMB2_O_INFO_SECURITY)
                        sz = large_sz;
        }
 
@@ -588,10 +589,12 @@ int smb2_check_user_session(struct ksmbd_work *work)
        return -EINVAL;
 }
 
-static void destroy_previous_session(struct ksmbd_user *user, u64 id)
+static void destroy_previous_session(struct ksmbd_conn *conn,
+                                    struct ksmbd_user *user, u64 id)
 {
        struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
        struct ksmbd_user *prev_user;
+       struct channel *chann;
 
        if (!prev_sess)
                return;
@@ -601,13 +604,14 @@ static void destroy_previous_session(struct ksmbd_user *user, u64 id)
        if (!prev_user ||
            strcmp(user->name, prev_user->name) ||
            user->passkey_sz != prev_user->passkey_sz ||
-           memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) {
-               put_session(prev_sess);
+           memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
                return;
-       }
 
-       put_session(prev_sess);
-       ksmbd_session_destroy(prev_sess);
+       prev_sess->state = SMB2_SESSION_EXPIRED;
+       write_lock(&prev_sess->chann_lock);
+       list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list)
+               chann->conn->status = KSMBD_SESS_EXITING;
+       write_unlock(&prev_sess->chann_lock);
 }
 
 /**
@@ -1139,12 +1143,16 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
                               status);
                        rsp->hdr.Status = status;
                        rc = -EINVAL;
+                       kfree(conn->preauth_info);
+                       conn->preauth_info = NULL;
                        goto err_out;
                }
 
                rc = init_smb3_11_server(conn);
                if (rc < 0) {
                        rsp->hdr.Status = STATUS_INVALID_PARAMETER;
+                       kfree(conn->preauth_info);
+                       conn->preauth_info = NULL;
                        goto err_out;
                }
 
@@ -1439,7 +1447,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
        /* Check for previous session */
        prev_id = le64_to_cpu(req->PreviousSessionId);
        if (prev_id && prev_id != sess->id)
-               destroy_previous_session(user, prev_id);
+               destroy_previous_session(conn, user, prev_id);
 
        if (sess->state == SMB2_SESSION_VALID) {
                /*
@@ -1493,7 +1501,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
 
        if (smb3_encryption_negotiated(conn) &&
                        !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
-               rc = conn->ops->generate_encryptionkey(sess);
+               rc = conn->ops->generate_encryptionkey(conn, sess);
                if (rc) {
                        ksmbd_debug(SMB,
                                        "SMB3 encryption key generation failed\n");
@@ -1510,7 +1518,9 @@ static int ntlm_authenticate(struct ksmbd_work *work)
 
 binding_session:
        if (conn->dialect >= SMB30_PROT_ID) {
+               read_lock(&sess->chann_lock);
                chann = lookup_chann_list(sess, conn);
+               read_unlock(&sess->chann_lock);
                if (!chann) {
                        chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
                        if (!chann)
@@ -1518,7 +1528,9 @@ binding_session:
 
                        chann->conn = conn;
                        INIT_LIST_HEAD(&chann->chann_list);
+                       write_lock(&sess->chann_lock);
                        list_add(&chann->chann_list, &sess->ksmbd_chann_list);
+                       write_unlock(&sess->chann_lock);
                }
        }
 
@@ -1561,7 +1573,7 @@ static int krb5_authenticate(struct ksmbd_work *work)
        /* Check previous session */
        prev_sess_id = le64_to_cpu(req->PreviousSessionId);
        if (prev_sess_id && prev_sess_id != sess->id)
-               destroy_previous_session(sess->user, prev_sess_id);
+               destroy_previous_session(conn, sess->user, prev_sess_id);
 
        if (sess->state == SMB2_SESSION_VALID)
                ksmbd_free_user(sess->user);
@@ -1580,7 +1592,7 @@ static int krb5_authenticate(struct ksmbd_work *work)
                sess->sign = true;
 
        if (smb3_encryption_negotiated(conn)) {
-               retval = conn->ops->generate_encryptionkey(sess);
+               retval = conn->ops->generate_encryptionkey(conn, sess);
                if (retval) {
                        ksmbd_debug(SMB,
                                    "SMB3 encryption key generation failed\n");
@@ -1592,7 +1604,9 @@ static int krb5_authenticate(struct ksmbd_work *work)
        }
 
        if (conn->dialect >= SMB30_PROT_ID) {
+               read_lock(&sess->chann_lock);
                chann = lookup_chann_list(sess, conn);
+               read_unlock(&sess->chann_lock);
                if (!chann) {
                        chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
                        if (!chann)
@@ -1600,7 +1614,9 @@ static int krb5_authenticate(struct ksmbd_work *work)
 
                        chann->conn = conn;
                        INIT_LIST_HEAD(&chann->chann_list);
+                       write_lock(&sess->chann_lock);
                        list_add(&chann->chann_list, &sess->ksmbd_chann_list);
+                       write_unlock(&sess->chann_lock);
                }
        }
 
@@ -1650,7 +1666,9 @@ int smb2_sess_setup(struct ksmbd_work *work)
                        goto out_err;
                }
                rsp->hdr.SessionId = cpu_to_le64(sess->id);
-               ksmbd_session_register(conn, sess);
+               rc = ksmbd_session_register(conn, sess);
+               if (rc)
+                       goto out_err;
        } else if (conn->dialect >= SMB30_PROT_ID &&
                   (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
                   req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) {
@@ -1662,7 +1680,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
                        goto out_err;
                }
 
-               if (conn->dialect != sess->conn->dialect) {
+               if (conn->dialect != sess->dialect) {
                        rc = -EINVAL;
                        goto out_err;
                }
@@ -1672,7 +1690,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
                        goto out_err;
                }
 
-               if (strncmp(conn->ClientGUID, sess->conn->ClientGUID,
+               if (strncmp(conn->ClientGUID, sess->ClientGUID,
                            SMB2_CLIENT_GUID_SIZE)) {
                        rc = -ENOENT;
                        goto out_err;
@@ -1828,6 +1846,7 @@ out_err:
                        if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
                                try_delay = true;
 
+                       xa_erase(&conn->sessions, sess->id);
                        ksmbd_session_destroy(sess);
                        work->sess = NULL;
                        if (try_delay)
@@ -1873,7 +1892,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
        ksmbd_debug(SMB, "tree connect request for tree %s treename %s\n",
                    name, treename);
 
-       status = ksmbd_tree_conn_connect(sess, name);
+       status = ksmbd_tree_conn_connect(conn, sess, name);
        if (status.ret == KSMBD_TREE_CONN_STATUS_OK)
                rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id);
        else
@@ -2039,6 +2058,7 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
 
        ksmbd_close_tree_conn_fds(work);
        ksmbd_tree_conn_disconnect(sess, tcon);
+       work->tcon = NULL;
        return 0;
 }
 
@@ -2969,7 +2989,7 @@ int smb2_open(struct ksmbd_work *work)
                                                goto err_out;
 
                                        rc = build_sec_desc(user_ns,
-                                                           pntsd, NULL,
+                                                           pntsd, NULL, 0,
                                                            OWNER_SECINFO |
                                                            GROUP_SECINFO |
                                                            DACL_SECINFO,
@@ -3814,6 +3834,15 @@ static int verify_info_level(int info_level)
        return 0;
 }
 
+static int smb2_resp_buf_len(struct ksmbd_work *work, unsigned short hdr2_len)
+{
+       int free_len;
+
+       free_len = (int)(work->response_sz -
+               (get_rfc1002_len(work->response_buf) + 4)) - hdr2_len;
+       return free_len;
+}
+
 static int smb2_calc_max_out_buf_len(struct ksmbd_work *work,
                                     unsigned short hdr2_len,
                                     unsigned int out_buf_len)
@@ -3823,9 +3852,7 @@ static int smb2_calc_max_out_buf_len(struct ksmbd_work *work,
        if (out_buf_len > work->conn->vals->max_trans_size)
                return -EINVAL;
 
-       free_len = (int)(work->response_sz -
-                        (get_rfc1002_len(work->response_buf) + 4)) -
-               hdr2_len;
+       free_len = smb2_resp_buf_len(work, hdr2_len);
        if (free_len < 0)
                return -EINVAL;
 
@@ -4858,7 +4885,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
                                    struct smb2_query_info_rsp *rsp)
 {
        struct ksmbd_session *sess = work->sess;
-       struct ksmbd_conn *conn = sess->conn;
+       struct ksmbd_conn *conn = work->conn;
        struct ksmbd_share_config *share = work->tcon->share_conf;
        int fsinfoclass = 0;
        struct kstatfs stfs;
@@ -5088,10 +5115,10 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
        struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd = NULL;
        struct smb_fattr fattr = {{0}};
        struct inode *inode;
-       __u32 secdesclen;
+       __u32 secdesclen = 0;
        unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
        int addition_info = le32_to_cpu(req->AdditionalInformation);
-       int rc;
+       int rc = 0, ppntsd_size = 0;
 
        if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |
                              PROTECTED_DACL_SECINFO |
@@ -5137,11 +5164,14 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
 
        if (test_share_config_flag(work->tcon->share_conf,
                                   KSMBD_SHARE_FLAG_ACL_XATTR))
-               ksmbd_vfs_get_sd_xattr(work->conn, user_ns,
-                                      fp->filp->f_path.dentry, &ppntsd);
-
-       rc = build_sec_desc(user_ns, pntsd, ppntsd, addition_info,
-                           &secdesclen, &fattr);
+               ppntsd_size = ksmbd_vfs_get_sd_xattr(work->conn, user_ns,
+                                                    fp->filp->f_path.dentry,
+                                                    &ppntsd);
+
+       /* Check if sd buffer size exceeds response buffer size */
+       if (smb2_resp_buf_len(work, 8) > ppntsd_size)
+               rc = build_sec_desc(user_ns, pntsd, ppntsd, ppntsd_size,
+                                   addition_info, &secdesclen, &fattr);
        posix_acl_release(fattr.cf_acls);
        posix_acl_release(fattr.cf_dacls);
        kfree(ppntsd);
@@ -5776,7 +5806,7 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
        }
 next:
        return smb2_rename(work, fp, user_ns, rename_info,
-                          work->sess->conn->local_nls);
+                          work->conn->local_nls);
 }
 
 static int set_file_disposition_info(struct ksmbd_file *fp,
@@ -5908,7 +5938,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                return smb2_create_link(work, work->tcon->share_conf,
                                        (struct smb2_file_link_info *)req->Buffer,
                                        buf_len, fp->filp,
-                                       work->sess->conn->local_nls);
+                                       work->conn->local_nls);
        }
        case FILE_DISPOSITION_INFORMATION:
        {
@@ -6495,14 +6525,12 @@ int smb2_write(struct ksmbd_work *work)
                writethrough = true;
 
        if (is_rdma_channel == false) {
-               if ((u64)le16_to_cpu(req->DataOffset) + length >
-                   get_rfc1002_len(work->request_buf)) {
-                       pr_err("invalid write data offset %u, smb_len %u\n",
-                              le16_to_cpu(req->DataOffset),
-                              get_rfc1002_len(work->request_buf));
+               if (le16_to_cpu(req->DataOffset) <
+                   offsetof(struct smb2_write_req, Buffer)) {
                        err = -EINVAL;
                        goto out;
                }
+
                data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
                                    le16_to_cpu(req->DataOffset));
 
@@ -8356,10 +8384,14 @@ int smb3_check_sign_req(struct ksmbd_work *work)
        if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
                signing_key = work->sess->smb3signingkey;
        } else {
+               read_lock(&work->sess->chann_lock);
                chann = lookup_chann_list(work->sess, conn);
-               if (!chann)
+               if (!chann) {
+                       read_unlock(&work->sess->chann_lock);
                        return 0;
+               }
                signing_key = chann->smb3signingkey;
+               read_unlock(&work->sess->chann_lock);
        }
 
        if (!signing_key) {
@@ -8419,10 +8451,14 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
            le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
                signing_key = work->sess->smb3signingkey;
        } else {
+               read_lock(&work->sess->chann_lock);
                chann = lookup_chann_list(work->sess, work->conn);
-               if (!chann)
+               if (!chann) {
+                       read_unlock(&work->sess->chann_lock);
                        return;
+               }
                signing_key = chann->smb3signingkey;
+               read_unlock(&work->sess->chann_lock);
        }
 
        if (!signing_key)
index e1369b4..318c16f 100644 (file)
@@ -421,7 +421,7 @@ struct smb_version_ops {
        int (*check_sign_req)(struct ksmbd_work *work);
        void (*set_sign_rsp)(struct ksmbd_work *work);
        int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn);
-       int (*generate_encryptionkey)(struct ksmbd_session *sess);
+       int (*generate_encryptionkey)(struct ksmbd_conn *conn, struct ksmbd_session *sess);
        bool (*is_transform_hdr)(void *buf);
        int (*decrypt_req)(struct ksmbd_work *work);
        int (*encrypt_resp)(struct ksmbd_work *work);
index 38f23bf..3781bca 100644 (file)
@@ -690,6 +690,7 @@ posix_default_acl:
 static void set_ntacl_dacl(struct user_namespace *user_ns,
                           struct smb_acl *pndacl,
                           struct smb_acl *nt_dacl,
+                          unsigned int aces_size,
                           const struct smb_sid *pownersid,
                           const struct smb_sid *pgrpsid,
                           struct smb_fattr *fattr)
@@ -703,9 +704,19 @@ static void set_ntacl_dacl(struct user_namespace *user_ns,
        if (nt_num_aces) {
                ntace = (struct smb_ace *)((char *)nt_dacl + sizeof(struct smb_acl));
                for (i = 0; i < nt_num_aces; i++) {
-                       memcpy((char *)pndace + size, ntace, le16_to_cpu(ntace->size));
-                       size += le16_to_cpu(ntace->size);
-                       ntace = (struct smb_ace *)((char *)ntace + le16_to_cpu(ntace->size));
+                       unsigned short nt_ace_size;
+
+                       if (offsetof(struct smb_ace, access_req) > aces_size)
+                               break;
+
+                       nt_ace_size = le16_to_cpu(ntace->size);
+                       if (nt_ace_size > aces_size)
+                               break;
+
+                       memcpy((char *)pndace + size, ntace, nt_ace_size);
+                       size += nt_ace_size;
+                       aces_size -= nt_ace_size;
+                       ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
                        num_aces++;
                }
        }
@@ -878,7 +889,7 @@ int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
 /* Convert permission bits from mode to equivalent CIFS ACL */
 int build_sec_desc(struct user_namespace *user_ns,
                   struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd,
-                  int addition_info, __u32 *secdesclen,
+                  int ppntsd_size, int addition_info, __u32 *secdesclen,
                   struct smb_fattr *fattr)
 {
        int rc = 0;
@@ -938,15 +949,25 @@ int build_sec_desc(struct user_namespace *user_ns,
 
                if (!ppntsd) {
                        set_mode_dacl(user_ns, dacl_ptr, fattr);
-               } else if (!ppntsd->dacloffset) {
-                       goto out;
                } else {
                        struct smb_acl *ppdacl_ptr;
+                       unsigned int dacl_offset = le32_to_cpu(ppntsd->dacloffset);
+                       int ppdacl_size, ntacl_size = ppntsd_size - dacl_offset;
+
+                       if (!dacl_offset ||
+                           (dacl_offset + sizeof(struct smb_acl) > ppntsd_size))
+                               goto out;
+
+                       ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + dacl_offset);
+                       ppdacl_size = le16_to_cpu(ppdacl_ptr->size);
+                       if (ppdacl_size > ntacl_size ||
+                           ppdacl_size < sizeof(struct smb_acl))
+                               goto out;
 
-                       ppdacl_ptr = (struct smb_acl *)((char *)ppntsd +
-                                               le32_to_cpu(ppntsd->dacloffset));
                        set_ntacl_dacl(user_ns, dacl_ptr, ppdacl_ptr,
-                                      nowner_sid_ptr, ngroup_sid_ptr, fattr);
+                                      ntacl_size - sizeof(struct smb_acl),
+                                      nowner_sid_ptr, ngroup_sid_ptr,
+                                      fattr);
                }
                pntsd->dacloffset = cpu_to_le32(offset);
                offset += le16_to_cpu(dacl_ptr->size);
@@ -980,24 +1001,31 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
        struct smb_sid owner_sid, group_sid;
        struct dentry *parent = path->dentry->d_parent;
        struct user_namespace *user_ns = mnt_user_ns(path->mnt);
-       int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0;
-       int rc = 0, num_aces, dacloffset, pntsd_type, acl_len;
+       int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size;
+       int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
        char *aces_base;
        bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
 
-       acl_len = ksmbd_vfs_get_sd_xattr(conn, user_ns,
-                                        parent, &parent_pntsd);
-       if (acl_len <= 0)
+       pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
+                                           parent, &parent_pntsd);
+       if (pntsd_size <= 0)
                return -ENOENT;
        dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
-       if (!dacloffset) {
+       if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) {
                rc = -EINVAL;
                goto free_parent_pntsd;
        }
 
        parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
+       acl_len = pntsd_size - dacloffset;
        num_aces = le32_to_cpu(parent_pdacl->num_aces);
        pntsd_type = le16_to_cpu(parent_pntsd->type);
+       pdacl_size = le16_to_cpu(parent_pdacl->size);
+
+       if (pdacl_size > acl_len || pdacl_size < sizeof(struct smb_acl)) {
+               rc = -EINVAL;
+               goto free_parent_pntsd;
+       }
 
        aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL);
        if (!aces_base) {
@@ -1008,11 +1036,23 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
        aces = (struct smb_ace *)aces_base;
        parent_aces = (struct smb_ace *)((char *)parent_pdacl +
                        sizeof(struct smb_acl));
+       aces_size = acl_len - sizeof(struct smb_acl);
 
        if (pntsd_type & DACL_AUTO_INHERITED)
                inherited_flags = INHERITED_ACE;
 
        for (i = 0; i < num_aces; i++) {
+               int pace_size;
+
+               if (offsetof(struct smb_ace, access_req) > aces_size)
+                       break;
+
+               pace_size = le16_to_cpu(parent_aces->size);
+               if (pace_size > aces_size)
+                       break;
+
+               aces_size -= pace_size;
+
                flags = parent_aces->flags;
                if (!smb_inherit_flags(flags, is_dir))
                        goto pass;
@@ -1057,8 +1097,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
                aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size));
                ace_cnt++;
 pass:
-               parent_aces =
-                       (struct smb_ace *)((char *)parent_aces + le16_to_cpu(parent_aces->size));
+               parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size);
        }
 
        if (nt_size > 0) {
@@ -1153,7 +1192,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
        struct smb_ntsd *pntsd = NULL;
        struct smb_acl *pdacl;
        struct posix_acl *posix_acls;
-       int rc = 0, acl_size;
+       int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset;
        struct smb_sid sid;
        int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE);
        struct smb_ace *ace;
@@ -1162,37 +1201,33 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
        struct smb_ace *others_ace = NULL;
        struct posix_acl_entry *pa_entry;
        unsigned int sid_type = SIDOWNER;
-       char *end_of_acl;
+       unsigned short ace_size;
 
        ksmbd_debug(SMB, "check permission using windows acl\n");
-       acl_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
-                                         path->dentry, &pntsd);
-       if (acl_size <= 0 || !pntsd || !pntsd->dacloffset) {
-               kfree(pntsd);
-               return 0;
-       }
+       pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
+                                           path->dentry, &pntsd);
+       if (pntsd_size <= 0 || !pntsd)
+               goto err_out;
+
+       dacl_offset = le32_to_cpu(pntsd->dacloffset);
+       if (!dacl_offset ||
+           (dacl_offset + sizeof(struct smb_acl) > pntsd_size))
+               goto err_out;
 
        pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));
-       end_of_acl = ((char *)pntsd) + acl_size;
-       if (end_of_acl <= (char *)pdacl) {
-               kfree(pntsd);
-               return 0;
-       }
+       acl_size = pntsd_size - dacl_offset;
+       pdacl_size = le16_to_cpu(pdacl->size);
 
-       if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size) ||
-           le16_to_cpu(pdacl->size) < sizeof(struct smb_acl)) {
-               kfree(pntsd);
-               return 0;
-       }
+       if (pdacl_size > acl_size || pdacl_size < sizeof(struct smb_acl))
+               goto err_out;
 
        if (!pdacl->num_aces) {
-               if (!(le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) &&
+               if (!(pdacl_size - sizeof(struct smb_acl)) &&
                    *pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) {
                        rc = -EACCES;
                        goto err_out;
                }
-               kfree(pntsd);
-               return 0;
+               goto err_out;
        }
 
        if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) {
@@ -1200,11 +1235,16 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
                        DELETE;
 
                ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+               aces_size = acl_size - sizeof(struct smb_acl);
                for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
+                       if (offsetof(struct smb_ace, access_req) > aces_size)
+                               break;
+                       ace_size = le16_to_cpu(ace->size);
+                       if (ace_size > aces_size)
+                               break;
+                       aces_size -= ace_size;
                        granted |= le32_to_cpu(ace->access_req);
                        ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
-                       if (end_of_acl < (char *)ace)
-                               goto err_out;
                }
 
                if (!pdacl->num_aces)
@@ -1216,7 +1256,15 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
        id_to_sid(uid, sid_type, &sid);
 
        ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+       aces_size = acl_size - sizeof(struct smb_acl);
        for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
+               if (offsetof(struct smb_ace, access_req) > aces_size)
+                       break;
+               ace_size = le16_to_cpu(ace->size);
+               if (ace_size > aces_size)
+                       break;
+               aces_size -= ace_size;
+
                if (!compare_sids(&sid, &ace->sid) ||
                    !compare_sids(&sid_unix_NFS_mode, &ace->sid)) {
                        found = 1;
@@ -1226,8 +1274,6 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
                        others_ace = ace;
 
                ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
-               if (end_of_acl < (char *)ace)
-                       goto err_out;
        }
 
        if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) {
index 811af33..fcb2c83 100644 (file)
@@ -193,7 +193,7 @@ struct posix_acl_state {
 int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
                   int acl_len, struct smb_fattr *fattr);
 int build_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
-                  struct smb_ntsd *ppntsd, int addition_info,
+                  struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info,
                   __u32 *secdesclen, struct smb_fattr *fattr);
 int init_acl_state(struct posix_acl_state *state, int cnt);
 void free_acl_state(struct posix_acl_state *state);
index 7c84902..78d0103 100644 (file)
@@ -481,12 +481,11 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
                    char *buf, size_t count, loff_t *pos, bool sync,
                    ssize_t *written)
 {
-       struct ksmbd_session *sess = work->sess;
        struct file *filp;
        loff_t  offset = *pos;
        int err = 0;
 
-       if (sess->conn->connection_type) {
+       if (work->conn->connection_type) {
                if (!(fp->daccess & FILE_WRITE_DATA_LE)) {
                        pr_err("no right to write(%pd)\n",
                               fp->filp->f_path.dentry);
@@ -1540,6 +1539,11 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
        }
 
        *pntsd = acl.sd_buf;
+       if (acl.sd_size < sizeof(struct smb_ntsd)) {
+               pr_err("sd size is invalid\n");
+               goto out_free;
+       }
+
        (*pntsd)->osidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->osidoffset) -
                                           NDR_NTSD_OFFSETOF);
        (*pntsd)->gsidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->gsidoffset) -
index c4d59d2..da9163b 100644 (file)
@@ -569,7 +569,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
        atomic_set(&fp->refcount, 1);
 
        fp->filp                = filp;
-       fp->conn                = work->sess->conn;
+       fp->conn                = work->conn;
        fp->tcon                = work->tcon;
        fp->volatile_id         = KSMBD_NO_FID;
        fp->persistent_id       = KSMBD_NO_FID;
index 176b468..bf274f2 100644 (file)
@@ -32,6 +32,10 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
        if (!nlmsvc_ops)
                return nlm_lck_denied_nolocks;
 
+       if (lock->lock_start > OFFSET_MAX ||
+           (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start))))
+               return nlm4_fbig;
+
        /* Obtain host handle */
        if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
         || (argp->monitor && nsm_monitor(host) < 0))
@@ -50,6 +54,10 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
                /* Set up the missing parts of the file_lock structure */
                lock->fl.fl_file  = file->f_file[mode];
                lock->fl.fl_pid = current->tgid;
+               lock->fl.fl_start = (loff_t)lock->lock_start;
+               lock->fl.fl_end = lock->lock_len ?
+                                  (loff_t)(lock->lock_start + lock->lock_len - 1) :
+                                  OFFSET_MAX;
                lock->fl.fl_lmops = &nlmsvc_lock_operations;
                nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
                if (!lock->fl.fl_owner) {
@@ -87,6 +95,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
        struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
+       struct nlm_lockowner *test_owner;
        __be32 rc = rpc_success;
 
        dprintk("lockd: TEST4        called\n");
@@ -96,6 +105,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
+       test_owner = argp->lock.fl.fl_owner;
        /* Now check for conflicting locks */
        resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie);
        if (resp->status == nlm_drop_reply)
@@ -103,7 +113,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
        else
                dprintk("lockd: TEST4        status %d\n", ntohl(resp->status));
 
-       nlmsvc_release_lockowner(&argp->lock);
+       nlmsvc_put_lockowner(test_owner);
        nlmsvc_release_host(host);
        nlm_release_file(file);
        return rc;
index cb3658a..9c1aa75 100644 (file)
@@ -340,7 +340,7 @@ nlmsvc_get_lockowner(struct nlm_lockowner *lockowner)
        return lockowner;
 }
 
-static void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner)
+void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner)
 {
        if (!refcount_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
                return;
@@ -590,7 +590,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
        int                     error;
        int                     mode;
        __be32                  ret;
-       struct nlm_lockowner    *test_owner;
 
        dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
                                nlmsvc_file_inode(file)->i_sb->s_id,
@@ -604,9 +603,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
                goto out;
        }
 
-       /* If there's a conflicting lock, remember to clean up the test lock */
-       test_owner = (struct nlm_lockowner *)lock->fl.fl_owner;
-
        mode = lock_to_openmode(&lock->fl);
        error = vfs_test_lock(file->f_file[mode], &lock->fl);
        if (error) {
@@ -635,10 +631,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
        conflock->fl.fl_end = lock->fl.fl_end;
        locks_release_private(&lock->fl);
 
-       /* Clean up the test lock */
-       lock->fl.fl_owner = NULL;
-       nlmsvc_put_lockowner(test_owner);
-
        ret = nlm_lck_denied;
 out:
        return ret;
index 4dc1b40..b09ca35 100644 (file)
@@ -116,6 +116,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
        struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
+       struct nlm_lockowner *test_owner;
        __be32 rc = rpc_success;
 
        dprintk("lockd: TEST          called\n");
@@ -125,6 +126,8 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
+       test_owner = argp->lock.fl.fl_owner;
+
        /* Now check for conflicting locks */
        resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie));
        if (resp->status == nlm_drop_reply)
@@ -133,7 +136,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
                dprintk("lockd: TEST          status %d vers %d\n",
                        ntohl(resp->status), rqstp->rq_vers);
 
-       nlmsvc_release_lockowner(&argp->lock);
+       nlmsvc_put_lockowner(test_owner);
        nlmsvc_release_host(host);
        nlm_release_file(file);
        return rc;
index 856267c..712fdfe 100644 (file)
 
 #include "svcxdr.h"
 
-static inline loff_t
-s64_to_loff_t(__s64 offset)
-{
-       return (loff_t)offset;
-}
-
-
 static inline s64
 loff_t_to_s64(loff_t offset)
 {
@@ -70,8 +63,6 @@ static bool
 svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
 {
        struct file_lock *fl = &lock->fl;
-       u64 len, start;
-       s64 end;
 
        if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
                return false;
@@ -81,20 +72,14 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
                return false;
        if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
                return false;
-       if (xdr_stream_decode_u64(xdr, &start) < 0)
+       if (xdr_stream_decode_u64(xdr, &lock->lock_start) < 0)
                return false;
-       if (xdr_stream_decode_u64(xdr, &len) < 0)
+       if (xdr_stream_decode_u64(xdr, &lock->lock_len) < 0)
                return false;
 
        locks_init_lock(fl);
        fl->fl_flags = FL_POSIX;
        fl->fl_type  = F_RDLCK;
-       end = start + len - 1;
-       fl->fl_start = s64_to_loff_t(start);
-       if (len == 0 || end < 0)
-               fl->fl_end = OFFSET_MAX;
-       else
-               fl->fl_end = s64_to_loff_t(end);
 
        return true;
 }
index ed3ffd9..53b4bc0 100644 (file)
@@ -3023,6 +3023,65 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
 }
 EXPORT_SYMBOL(unlock_rename);
 
+/**
+ * mode_strip_umask - handle vfs umask stripping
+ * @dir:       parent directory of the new inode
+ * @mode:      mode of the new inode to be created in @dir
+ *
+ * Umask stripping depends on whether or not the filesystem supports POSIX
+ * ACLs. If the filesystem doesn't support it umask stripping is done directly
+ * in here. If the filesystem does support POSIX ACLs umask stripping is
+ * deferred until the filesystem calls posix_acl_create().
+ *
+ * Returns: mode
+ */
+static inline umode_t mode_strip_umask(const struct inode *dir, umode_t mode)
+{
+       if (!IS_POSIXACL(dir))
+               mode &= ~current_umask();
+       return mode;
+}
+
+/**
+ * vfs_prepare_mode - prepare the mode to be used for a new inode
+ * @mnt_userns:                user namespace of the mount the inode was found from
+ * @dir:       parent directory of the new inode
+ * @mode:      mode of the new inode
+ * @mask_perms:        allowed permission by the vfs
+ * @type:      type of file to be created
+ *
+ * This helper consolidates and enforces vfs restrictions on the @mode of a new
+ * object to be created.
+ *
+ * Umask stripping depends on whether the filesystem supports POSIX ACLs (see
+ * the kernel documentation for mode_strip_umask()). Moving umask stripping
+ * after setgid stripping allows the same ordering for both non-POSIX ACL and
+ * POSIX ACL supporting filesystems.
+ *
+ * Note that it's currently valid for @type to be 0 if a directory is created.
+ * Filesystems raise that flag individually and we need to check whether each
+ * filesystem can deal with receiving S_IFDIR from the vfs before we enforce a
+ * non-zero type.
+ *
+ * Returns: mode to be passed to the filesystem
+ */
+static inline umode_t vfs_prepare_mode(struct user_namespace *mnt_userns,
+                                      const struct inode *dir, umode_t mode,
+                                      umode_t mask_perms, umode_t type)
+{
+       mode = mode_strip_sgid(mnt_userns, dir, mode);
+       mode = mode_strip_umask(dir, mode);
+
+       /*
+        * Apply the vfs mandated allowed permission mask and set the type of
+        * file to be created before we call into the filesystem.
+        */
+       mode &= (mask_perms & ~S_IFMT);
+       mode |= (type & S_IFMT);
+
+       return mode;
+}
+
 /**
  * vfs_create - create new file
  * @mnt_userns:        user namespace of the mount the inode was found from
@@ -3048,8 +3107,8 @@ int vfs_create(struct user_namespace *mnt_userns, struct inode *dir,
 
        if (!dir->i_op->create)
                return -EACCES; /* shouldn't it be ENOSYS? */
-       mode &= S_IALLUGO;
-       mode |= S_IFREG;
+
+       mode = vfs_prepare_mode(mnt_userns, dir, mode, S_IALLUGO, S_IFREG);
        error = security_inode_create(dir, dentry, mode);
        if (error)
                return error;
@@ -3312,8 +3371,7 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
        if (open_flag & O_CREAT) {
                if (open_flag & O_EXCL)
                        open_flag &= ~O_TRUNC;
-               if (!IS_POSIXACL(dir->d_inode))
-                       mode &= ~current_umask();
+               mode = vfs_prepare_mode(mnt_userns, dir->d_inode, mode, mode, mode);
                if (likely(got_write))
                        create_error = may_o_create(mnt_userns, &nd->path,
                                                    dentry, mode);
@@ -3544,6 +3602,7 @@ struct dentry *vfs_tmpfile(struct user_namespace *mnt_userns,
        child = d_alloc(dentry, &slash_name);
        if (unlikely(!child))
                goto out_err;
+       mode = vfs_prepare_mode(mnt_userns, dir, mode, mode, mode);
        error = dir->i_op->tmpfile(mnt_userns, dir, child, mode);
        if (error)
                goto out_err;
@@ -3821,6 +3880,7 @@ int vfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
        if (!dir->i_op->mknod)
                return -EPERM;
 
+       mode = vfs_prepare_mode(mnt_userns, dir, mode, mode, mode);
        error = devcgroup_inode_mknod(mode, dev);
        if (error)
                return error;
@@ -3871,9 +3931,8 @@ retry:
        if (IS_ERR(dentry))
                goto out1;
 
-       if (!IS_POSIXACL(path.dentry->d_inode))
-               mode &= ~current_umask();
-       error = security_path_mknod(&path, dentry, mode, dev);
+       error = security_path_mknod(&path, dentry,
+                       mode_strip_umask(path.dentry->d_inode, mode), dev);
        if (error)
                goto out2;
 
@@ -3943,7 +4002,7 @@ int vfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
        if (!dir->i_op->mkdir)
                return -EPERM;
 
-       mode &= (S_IRWXUGO|S_ISVTX);
+       mode = vfs_prepare_mode(mnt_userns, dir, mode, S_IRWXUGO | S_ISVTX, 0);
        error = security_inode_mkdir(dir, dentry, mode);
        if (error)
                return error;
@@ -3971,9 +4030,8 @@ retry:
        if (IS_ERR(dentry))
                goto out_putname;
 
-       if (!IS_POSIXACL(path.dentry->d_inode))
-               mode &= ~current_umask();
-       error = security_path_mkdir(&path, dentry, mode);
+       error = security_path_mkdir(&path, dentry,
+                       mode_strip_umask(path.dentry->d_inode, mode));
        if (!error) {
                struct user_namespace *mnt_userns;
                mnt_userns = mnt_user_ns(path.mnt);
index 4eb2a83..c275c83 100644 (file)
@@ -364,13 +364,12 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
                size_t pgbase;
                unsigned npages, i;
 
-               result = iov_iter_get_pages_alloc(iter, &pagevec, 
+               result = iov_iter_get_pages_alloc2(iter, &pagevec,
                                                  rsize, &pgbase);
                if (result < 0)
                        break;
        
                bytes = result;
-               iov_iter_advance(iter, bytes);
                npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE;
                for (i = 0; i < npages; i++) {
                        struct nfs_page *req;
@@ -478,7 +477,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
-       if (iter_is_iovec(iter))
+       if (user_backed_iter(iter))
                dreq->flags = NFS_ODIRECT_SHOULD_DIRTY;
 
        if (!swap)
@@ -812,13 +811,12 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
                size_t pgbase;
                unsigned npages, i;
 
-               result = iov_iter_get_pages_alloc(iter, &pagevec, 
+               result = iov_iter_get_pages_alloc2(iter, &pagevec,
                                                  wsize, &pgbase);
                if (result < 0)
                        break;
 
                bytes = result;
-               iov_iter_advance(iter, bytes);
                npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE;
                for (i = 0; i < npages; i++) {
                        struct nfs_page *req;
index ba14d2f..4b73244 100644 (file)
@@ -38,6 +38,8 @@
 struct nfs4_acl;
 struct svc_fh;
 struct svc_rqst;
+struct nfsd_attrs;
+enum nfs_ftype4;
 
 int nfs4_acl_bytes(int entries);
 int nfs4_acl_get_whotype(char *, u32);
@@ -45,7 +47,7 @@ __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who);
 
 int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
                struct nfs4_acl **acl);
-__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               struct nfs4_acl *acl);
+__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
+                        struct nfsd_attrs *attr);
 
 #endif /* LINUX_NFS4_ACL_H */
index a605c0e..eeed4ae 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/fsnotify_backend.h>
 #include <linux/fsnotify.h>
 #include <linux/seq_file.h>
+#include <linux/rhashtable.h>
 
 #include "vfs.h"
 #include "nfsd.h"
 #include "filecache.h"
 #include "trace.h"
 
-#define NFSDDBG_FACILITY       NFSDDBG_FH
-
-/* FIXME: dynamically size this for the machine somehow? */
-#define NFSD_FILE_HASH_BITS                   12
-#define NFSD_FILE_HASH_SIZE                  (1 << NFSD_FILE_HASH_BITS)
 #define NFSD_LAUNDRETTE_DELAY               (2 * HZ)
 
-#define NFSD_FILE_SHUTDOWN                  (1)
-#define NFSD_FILE_LRU_THRESHOLD                     (4096UL)
-#define NFSD_FILE_LRU_LIMIT                 (NFSD_FILE_LRU_THRESHOLD << 2)
+#define NFSD_FILE_CACHE_UP                  (0)
 
 /* We only care about NFSD_MAY_READ/WRITE for this cache */
 #define NFSD_FILE_MAY_MASK     (NFSD_MAY_READ|NFSD_MAY_WRITE)
 
-struct nfsd_fcache_bucket {
-       struct hlist_head       nfb_head;
-       spinlock_t              nfb_lock;
-       unsigned int            nfb_count;
-       unsigned int            nfb_maxcount;
-};
-
 static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_releases);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_pages_flushed);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions);
 
 struct nfsd_fcache_disposal {
        struct work_struct work;
@@ -54,21 +46,146 @@ static struct workqueue_struct *nfsd_filecache_wq __read_mostly;
 
 static struct kmem_cache               *nfsd_file_slab;
 static struct kmem_cache               *nfsd_file_mark_slab;
-static struct nfsd_fcache_bucket       *nfsd_file_hashtbl;
 static struct list_lru                 nfsd_file_lru;
-static long                            nfsd_file_lru_flags;
+static unsigned long                   nfsd_file_flags;
 static struct fsnotify_group           *nfsd_file_fsnotify_group;
-static atomic_long_t                   nfsd_filecache_count;
 static struct delayed_work             nfsd_filecache_laundrette;
+static struct rhashtable               nfsd_file_rhash_tbl
+                                               ____cacheline_aligned_in_smp;
+
+enum nfsd_file_lookup_type {
+       NFSD_FILE_KEY_INODE,
+       NFSD_FILE_KEY_FULL,
+};
+
+struct nfsd_file_lookup_key {
+       struct inode                    *inode;
+       struct net                      *net;
+       const struct cred               *cred;
+       unsigned char                   need;
+       enum nfsd_file_lookup_type      type;
+};
+
+/*
+ * The returned hash value is based solely on the address of an in-code
+ * inode, a pointer to a slab-allocated object. The entropy in such a
+ * pointer is concentrated in its middle bits.
+ */
+static u32 nfsd_file_inode_hash(const struct inode *inode, u32 seed)
+{
+       unsigned long ptr = (unsigned long)inode;
+       u32 k;
+
+       k = ptr >> L1_CACHE_SHIFT;
+       k &= 0x00ffffff;
+       return jhash2(&k, 1, seed);
+}
+
+/**
+ * nfsd_file_key_hashfn - Compute the hash value of a lookup key
+ * @data: key on which to compute the hash value
+ * @len: rhash table's key_len parameter (unused)
+ * @seed: rhash table's random seed of the day
+ *
+ * Return value:
+ *   Computed 32-bit hash value
+ */
+static u32 nfsd_file_key_hashfn(const void *data, u32 len, u32 seed)
+{
+       const struct nfsd_file_lookup_key *key = data;
+
+       return nfsd_file_inode_hash(key->inode, seed);
+}
+
+/**
+ * nfsd_file_obj_hashfn - Compute the hash value of an nfsd_file
+ * @data: object on which to compute the hash value
+ * @len: rhash table's key_len parameter (unused)
+ * @seed: rhash table's random seed of the day
+ *
+ * Return value:
+ *   Computed 32-bit hash value
+ */
+static u32 nfsd_file_obj_hashfn(const void *data, u32 len, u32 seed)
+{
+       const struct nfsd_file *nf = data;
+
+       return nfsd_file_inode_hash(nf->nf_inode, seed);
+}
 
-static void nfsd_file_gc(void);
+static bool
+nfsd_match_cred(const struct cred *c1, const struct cred *c2)
+{
+       int i;
+
+       if (!uid_eq(c1->fsuid, c2->fsuid))
+               return false;
+       if (!gid_eq(c1->fsgid, c2->fsgid))
+               return false;
+       if (c1->group_info == NULL || c2->group_info == NULL)
+               return c1->group_info == c2->group_info;
+       if (c1->group_info->ngroups != c2->group_info->ngroups)
+               return false;
+       for (i = 0; i < c1->group_info->ngroups; i++) {
+               if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
+                       return false;
+       }
+       return true;
+}
+
+/**
+ * nfsd_file_obj_cmpfn - Match a cache item against search criteria
+ * @arg: search criteria
+ * @ptr: cache item to check
+ *
+ * Return values:
+ *   %0 - Item matches search criteria
+ *   %1 - Item does not match search criteria
+ */
+static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg,
+                              const void *ptr)
+{
+       const struct nfsd_file_lookup_key *key = arg->key;
+       const struct nfsd_file *nf = ptr;
+
+       switch (key->type) {
+       case NFSD_FILE_KEY_INODE:
+               if (nf->nf_inode != key->inode)
+                       return 1;
+               break;
+       case NFSD_FILE_KEY_FULL:
+               if (nf->nf_inode != key->inode)
+                       return 1;
+               if (nf->nf_may != key->need)
+                       return 1;
+               if (nf->nf_net != key->net)
+                       return 1;
+               if (!nfsd_match_cred(nf->nf_cred, key->cred))
+                       return 1;
+               if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0)
+                       return 1;
+               break;
+       }
+       return 0;
+}
+
+static const struct rhashtable_params nfsd_file_rhash_params = {
+       .key_len                = sizeof_field(struct nfsd_file, nf_inode),
+       .key_offset             = offsetof(struct nfsd_file, nf_inode),
+       .head_offset            = offsetof(struct nfsd_file, nf_rhash),
+       .hashfn                 = nfsd_file_key_hashfn,
+       .obj_hashfn             = nfsd_file_obj_hashfn,
+       .obj_cmpfn              = nfsd_file_obj_cmpfn,
+       /* Reduce resizing churn on light workloads */
+       .min_size               = 512,          /* buckets */
+       .automatic_shrinking    = true,
+};
 
 static void
 nfsd_file_schedule_laundrette(void)
 {
-       long count = atomic_long_read(&nfsd_filecache_count);
-
-       if (count == 0 || test_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags))
+       if ((atomic_read(&nfsd_file_rhash_tbl.nelems) == 0) ||
+           test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0)
                return;
 
        queue_delayed_work(system_wq, &nfsd_filecache_laundrette,
@@ -111,12 +228,11 @@ nfsd_file_mark_put(struct nfsd_file_mark *nfm)
 }
 
 static struct nfsd_file_mark *
-nfsd_file_mark_find_or_create(struct nfsd_file *nf)
+nfsd_file_mark_find_or_create(struct nfsd_file *nf, struct inode *inode)
 {
        int                     err;
        struct fsnotify_mark    *mark;
        struct nfsd_file_mark   *nfm = NULL, *new;
-       struct inode *inode = nf->nf_inode;
 
        do {
                fsnotify_group_lock(nfsd_file_fsnotify_group);
@@ -167,31 +283,25 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf)
 }
 
 static struct nfsd_file *
-nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval,
-               struct net *net)
+nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may)
 {
        struct nfsd_file *nf;
 
        nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL);
        if (nf) {
-               INIT_HLIST_NODE(&nf->nf_node);
                INIT_LIST_HEAD(&nf->nf_lru);
+               nf->nf_birthtime = ktime_get();
                nf->nf_file = NULL;
                nf->nf_cred = get_current_cred();
-               nf->nf_net = net;
+               nf->nf_net = key->net;
                nf->nf_flags = 0;
-               nf->nf_inode = inode;
-               nf->nf_hashval = hashval;
-               refcount_set(&nf->nf_ref, 1);
-               nf->nf_may = may & NFSD_FILE_MAY_MASK;
-               if (may & NFSD_MAY_NOT_BREAK_LEASE) {
-                       if (may & NFSD_MAY_WRITE)
-                               __set_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags);
-                       if (may & NFSD_MAY_READ)
-                               __set_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags);
-               }
+               __set_bit(NFSD_FILE_HASHED, &nf->nf_flags);
+               __set_bit(NFSD_FILE_PENDING, &nf->nf_flags);
+               nf->nf_inode = key->inode;
+               /* nf_ref is pre-incremented for hash table */
+               refcount_set(&nf->nf_ref, 2);
+               nf->nf_may = key->need;
                nf->nf_mark = NULL;
-               trace_nfsd_file_alloc(nf);
        }
        return nf;
 }
@@ -199,8 +309,12 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval,
 static bool
 nfsd_file_free(struct nfsd_file *nf)
 {
+       s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime));
        bool flush = false;
 
+       this_cpu_inc(nfsd_file_releases);
+       this_cpu_add(nfsd_file_total_age, age);
+
        trace_nfsd_file_put_final(nf);
        if (nf->nf_mark)
                nfsd_file_mark_put(nf->nf_mark);
@@ -210,6 +324,14 @@ nfsd_file_free(struct nfsd_file *nf)
                fput(nf->nf_file);
                flush = true;
        }
+
+       /*
+        * If this item is still linked via nf_lru, that's a bug.
+        * WARN and leak it to preserve system stability.
+        */
+       if (WARN_ON_ONCE(!list_empty(&nf->nf_lru)))
+               return flush;
+
        call_rcu(&nf->nf_rcu, nfsd_file_slab_free);
        return flush;
 }
@@ -240,31 +362,44 @@ nfsd_file_check_write_error(struct nfsd_file *nf)
 static void
 nfsd_file_flush(struct nfsd_file *nf)
 {
-       if (nf->nf_file && vfs_fsync(nf->nf_file, 1) != 0)
+       struct file *file = nf->nf_file;
+
+       if (!file || !(file->f_mode & FMODE_WRITE))
+               return;
+       this_cpu_add(nfsd_file_pages_flushed, file->f_mapping->nrpages);
+       if (vfs_fsync(file, 1) != 0)
                nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
 }
 
-static void
-nfsd_file_do_unhash(struct nfsd_file *nf)
+static void nfsd_file_lru_add(struct nfsd_file *nf)
 {
-       lockdep_assert_held(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
+       set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
+       if (list_lru_add(&nfsd_file_lru, &nf->nf_lru))
+               trace_nfsd_file_lru_add(nf);
+}
 
+static void nfsd_file_lru_remove(struct nfsd_file *nf)
+{
+       if (list_lru_del(&nfsd_file_lru, &nf->nf_lru))
+               trace_nfsd_file_lru_del(nf);
+}
+
+static void
+nfsd_file_hash_remove(struct nfsd_file *nf)
+{
        trace_nfsd_file_unhash(nf);
 
        if (nfsd_file_check_write_error(nf))
                nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
-       --nfsd_file_hashtbl[nf->nf_hashval].nfb_count;
-       hlist_del_rcu(&nf->nf_node);
-       atomic_long_dec(&nfsd_filecache_count);
+       rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash,
+                              nfsd_file_rhash_params);
 }
 
 static bool
 nfsd_file_unhash(struct nfsd_file *nf)
 {
        if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
-               nfsd_file_do_unhash(nf);
-               if (!list_empty(&nf->nf_lru))
-                       list_lru_del(&nfsd_file_lru, &nf->nf_lru);
+               nfsd_file_hash_remove(nf);
                return true;
        }
        return false;
@@ -274,17 +409,16 @@ nfsd_file_unhash(struct nfsd_file *nf)
  * Return true if the file was unhashed.
  */
 static bool
-nfsd_file_unhash_and_release_locked(struct nfsd_file *nf, struct list_head *dispose)
+nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose)
 {
-       lockdep_assert_held(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
-
-       trace_nfsd_file_unhash_and_release_locked(nf);
+       trace_nfsd_file_unhash_and_dispose(nf);
        if (!nfsd_file_unhash(nf))
                return false;
        /* keep final reference for nfsd_file_lru_dispose */
        if (refcount_dec_not_one(&nf->nf_ref))
                return true;
 
+       nfsd_file_lru_remove(nf);
        list_add(&nf->nf_lru, dispose);
        return true;
 }
@@ -296,6 +430,7 @@ nfsd_file_put_noref(struct nfsd_file *nf)
 
        if (refcount_dec_and_test(&nf->nf_ref)) {
                WARN_ON(test_bit(NFSD_FILE_HASHED, &nf->nf_flags));
+               nfsd_file_lru_remove(nf);
                nfsd_file_free(nf);
        }
 }
@@ -305,7 +440,7 @@ nfsd_file_put(struct nfsd_file *nf)
 {
        might_sleep();
 
-       set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
+       nfsd_file_lru_add(nf);
        if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) {
                nfsd_file_flush(nf);
                nfsd_file_put_noref(nf);
@@ -314,9 +449,24 @@ nfsd_file_put(struct nfsd_file *nf)
                nfsd_file_schedule_laundrette();
        } else
                nfsd_file_put_noref(nf);
+}
 
-       if (atomic_long_read(&nfsd_filecache_count) >= NFSD_FILE_LRU_LIMIT)
-               nfsd_file_gc();
+/**
+ * nfsd_file_close - Close an nfsd_file
+ * @nf: nfsd_file to close
+ *
+ * If this is the final reference for @nf, free it immediately.
+ * This reflects an on-the-wire CLOSE or DELEGRETURN into the
+ * VFS and exported filesystem.
+ */
+void nfsd_file_close(struct nfsd_file *nf)
+{
+       nfsd_file_put(nf);
+       if (refcount_dec_if_one(&nf->nf_ref)) {
+               nfsd_file_unhash(nf);
+               nfsd_file_lru_remove(nf);
+               nfsd_file_free(nf);
+       }
 }
 
 struct nfsd_file *
@@ -334,7 +484,7 @@ nfsd_file_dispose_list(struct list_head *dispose)
 
        while(!list_empty(dispose)) {
                nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
-               list_del(&nf->nf_lru);
+               list_del_init(&nf->nf_lru);
                nfsd_file_flush(nf);
                nfsd_file_put_noref(nf);
        }
@@ -348,7 +498,7 @@ nfsd_file_dispose_list_sync(struct list_head *dispose)
 
        while(!list_empty(dispose)) {
                nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
-               list_del(&nf->nf_lru);
+               list_del_init(&nf->nf_lru);
                nfsd_file_flush(nf);
                if (!refcount_dec_and_test(&nf->nf_ref))
                        continue;
@@ -405,8 +555,19 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose)
        }
 }
 
-/*
+/**
+ * nfsd_file_lru_cb - Examine an entry on the LRU list
+ * @item: LRU entry to examine
+ * @lru: controlling LRU
+ * @lock: LRU list lock (unused)
+ * @arg: dispose list
+ *
  * Note this can deadlock with nfsd_file_cache_purge.
+ *
+ * Return values:
+ *   %LRU_REMOVED: @item was removed from the LRU
+ *   %LRU_ROTATE: @item is to be moved to the LRU tail
+ *   %LRU_SKIP: @item cannot be evicted
  */
 static enum lru_status
 nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
@@ -427,55 +588,65 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
         * counter. Here we check the counter and then test and clear the flag.
         * That order is deliberate to ensure that we can do this locklessly.
         */
-       if (refcount_read(&nf->nf_ref) > 1)
-               goto out_skip;
+       if (refcount_read(&nf->nf_ref) > 1) {
+               list_lru_isolate(lru, &nf->nf_lru);
+               trace_nfsd_file_gc_in_use(nf);
+               return LRU_REMOVED;
+       }
 
        /*
         * Don't throw out files that are still undergoing I/O or
         * that have uncleared errors pending.
         */
-       if (nfsd_file_check_writeback(nf))
-               goto out_skip;
+       if (nfsd_file_check_writeback(nf)) {
+               trace_nfsd_file_gc_writeback(nf);
+               return LRU_SKIP;
+       }
 
-       if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags))
-               goto out_skip;
+       if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) {
+               trace_nfsd_file_gc_referenced(nf);
+               return LRU_ROTATE;
+       }
 
-       if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags))
-               goto out_skip;
+       if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
+               trace_nfsd_file_gc_hashed(nf);
+               return LRU_SKIP;
+       }
 
        list_lru_isolate_move(lru, &nf->nf_lru, head);
+       this_cpu_inc(nfsd_file_evictions);
+       trace_nfsd_file_gc_disposed(nf);
        return LRU_REMOVED;
-out_skip:
-       return LRU_SKIP;
 }
 
-static unsigned long
-nfsd_file_lru_walk_list(struct shrink_control *sc)
+/*
+ * Unhash items on @dispose immediately, then queue them on the
+ * disposal workqueue to finish releasing them in the background.
+ *
+ * cel: Note that between the time list_lru_shrink_walk runs and
+ * now, these items are in the hash table but marked unhashed.
+ * Why release these outside of lru_cb ? There's no lock ordering
+ * problem since lru_cb currently takes no lock.
+ */
+static void nfsd_file_gc_dispose_list(struct list_head *dispose)
 {
-       LIST_HEAD(head);
        struct nfsd_file *nf;
-       unsigned long ret;
 
-       if (sc)
-               ret = list_lru_shrink_walk(&nfsd_file_lru, sc,
-                               nfsd_file_lru_cb, &head);
-       else
-               ret = list_lru_walk(&nfsd_file_lru,
-                               nfsd_file_lru_cb,
-                               &head, LONG_MAX);
-       list_for_each_entry(nf, &head, nf_lru) {
-               spin_lock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
-               nfsd_file_do_unhash(nf);
-               spin_unlock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
-       }
-       nfsd_file_dispose_list_delayed(&head);
-       return ret;
+       list_for_each_entry(nf, dispose, nf_lru)
+               nfsd_file_hash_remove(nf);
+       nfsd_file_dispose_list_delayed(dispose);
 }
 
 static void
 nfsd_file_gc(void)
 {
-       nfsd_file_lru_walk_list(NULL);
+       LIST_HEAD(dispose);
+       unsigned long ret;
+
+       ret = list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb,
+                           &dispose, list_lru_count(&nfsd_file_lru));
+       trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru));
+       nfsd_file_gc_dispose_list(&dispose);
 }
 
 static void
@@ -494,7 +665,14 @@ nfsd_file_lru_count(struct shrinker *s, struct shrink_control *sc)
 static unsigned long
 nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
 {
-       return nfsd_file_lru_walk_list(sc);
+       LIST_HEAD(dispose);
+       unsigned long ret;
+
+       ret = list_lru_shrink_walk(&nfsd_file_lru, sc,
+                                  nfsd_file_lru_cb, &dispose);
+       trace_nfsd_file_shrinker_removed(ret, list_lru_count(&nfsd_file_lru));
+       nfsd_file_gc_dispose_list(&dispose);
+       return ret;
 }
 
 static struct shrinker nfsd_file_shrinker = {
@@ -503,39 +681,47 @@ static struct shrinker    nfsd_file_shrinker = {
        .seeks = 1,
 };
 
-static void
-__nfsd_file_close_inode(struct inode *inode, unsigned int hashval,
-                       struct list_head *dispose)
+/*
+ * Find all cache items across all net namespaces that match @inode and
+ * move them to @dispose. The lookup is atomic wrt nfsd_file_acquire().
+ */
+static unsigned int
+__nfsd_file_close_inode(struct inode *inode, struct list_head *dispose)
 {
-       struct nfsd_file        *nf;
-       struct hlist_node       *tmp;
+       struct nfsd_file_lookup_key key = {
+               .type   = NFSD_FILE_KEY_INODE,
+               .inode  = inode,
+       };
+       unsigned int count = 0;
+       struct nfsd_file *nf;
 
-       spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
-       hlist_for_each_entry_safe(nf, tmp, &nfsd_file_hashtbl[hashval].nfb_head, nf_node) {
-               if (inode == nf->nf_inode)
-                       nfsd_file_unhash_and_release_locked(nf, dispose);
-       }
-       spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
+       rcu_read_lock();
+       do {
+               nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key,
+                                      nfsd_file_rhash_params);
+               if (!nf)
+                       break;
+               nfsd_file_unhash_and_dispose(nf, dispose);
+               count++;
+       } while (1);
+       rcu_read_unlock();
+       return count;
 }
 
 /**
  * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file
  * @inode: inode of the file to attempt to remove
  *
- * Walk the whole hash bucket, looking for any files that correspond to "inode".
- * If any do, then unhash them and put the hashtable reference to them and
- * destroy any that had their last reference put. Also ensure that any of the
- * fputs also have their final __fput done as well.
+ * Unhash and put, then flush and fput all cache items associated with @inode.
  */
 void
 nfsd_file_close_inode_sync(struct inode *inode)
 {
-       unsigned int            hashval = (unsigned int)hash_long(inode->i_ino,
-                                               NFSD_FILE_HASH_BITS);
        LIST_HEAD(dispose);
+       unsigned int count;
 
-       __nfsd_file_close_inode(inode, hashval, &dispose);
-       trace_nfsd_file_close_inode_sync(inode, hashval, !list_empty(&dispose));
+       count = __nfsd_file_close_inode(inode, &dispose);
+       trace_nfsd_file_close_inode_sync(inode, count);
        nfsd_file_dispose_list_sync(&dispose);
 }
 
@@ -543,19 +729,16 @@ nfsd_file_close_inode_sync(struct inode *inode)
  * nfsd_file_close_inode - attempt a delayed close of a nfsd_file
  * @inode: inode of the file to attempt to remove
  *
- * Walk the whole hash bucket, looking for any files that correspond to "inode".
- * If any do, then unhash them and put the hashtable reference to them and
- * destroy any that had their last reference put.
+ * Unhash and put all cache item associated with @inode.
  */
 static void
 nfsd_file_close_inode(struct inode *inode)
 {
-       unsigned int            hashval = (unsigned int)hash_long(inode->i_ino,
-                                               NFSD_FILE_HASH_BITS);
        LIST_HEAD(dispose);
+       unsigned int count;
 
-       __nfsd_file_close_inode(inode, hashval, &dispose);
-       trace_nfsd_file_close_inode(inode, hashval, !list_empty(&dispose));
+       count = __nfsd_file_close_inode(inode, &dispose);
+       trace_nfsd_file_close_inode(inode, count);
        nfsd_file_dispose_list_delayed(&dispose);
 }
 
@@ -630,25 +813,21 @@ static const struct fsnotify_ops nfsd_file_fsnotify_ops = {
 int
 nfsd_file_cache_init(void)
 {
-       int             ret = -ENOMEM;
-       unsigned int    i;
+       int ret;
 
-       clear_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags);
-
-       if (nfsd_file_hashtbl)
+       lockdep_assert_held(&nfsd_mutex);
+       if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)
                return 0;
 
+       ret = rhashtable_init(&nfsd_file_rhash_tbl, &nfsd_file_rhash_params);
+       if (ret)
+               return ret;
+
+       ret = -ENOMEM;
        nfsd_filecache_wq = alloc_workqueue("nfsd_filecache", 0, 0);
        if (!nfsd_filecache_wq)
                goto out;
 
-       nfsd_file_hashtbl = kvcalloc(NFSD_FILE_HASH_SIZE,
-                               sizeof(*nfsd_file_hashtbl), GFP_KERNEL);
-       if (!nfsd_file_hashtbl) {
-               pr_err("nfsd: unable to allocate nfsd_file_hashtbl\n");
-               goto out_err;
-       }
-
        nfsd_file_slab = kmem_cache_create("nfsd_file",
                                sizeof(struct nfsd_file), 0, 0, NULL);
        if (!nfsd_file_slab) {
@@ -692,11 +871,6 @@ nfsd_file_cache_init(void)
                goto out_notifier;
        }
 
-       for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
-               INIT_HLIST_HEAD(&nfsd_file_hashtbl[i].nfb_head);
-               spin_lock_init(&nfsd_file_hashtbl[i].nfb_lock);
-       }
-
        INIT_DELAYED_WORK(&nfsd_filecache_laundrette, nfsd_file_gc_worker);
 out:
        return ret;
@@ -711,46 +885,47 @@ out_err:
        nfsd_file_slab = NULL;
        kmem_cache_destroy(nfsd_file_mark_slab);
        nfsd_file_mark_slab = NULL;
-       kvfree(nfsd_file_hashtbl);
-       nfsd_file_hashtbl = NULL;
        destroy_workqueue(nfsd_filecache_wq);
        nfsd_filecache_wq = NULL;
+       rhashtable_destroy(&nfsd_file_rhash_tbl);
        goto out;
 }
 
 /*
  * Note this can deadlock with nfsd_file_lru_cb.
  */
-void
-nfsd_file_cache_purge(struct net *net)
+static void
+__nfsd_file_cache_purge(struct net *net)
 {
-       unsigned int            i;
-       struct nfsd_file        *nf;
-       struct hlist_node       *next;
+       struct rhashtable_iter iter;
+       struct nfsd_file *nf;
        LIST_HEAD(dispose);
        bool del;
 
-       if (!nfsd_file_hashtbl)
-               return;
-
-       for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
-               struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i];
+       rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter);
+       do {
+               rhashtable_walk_start(&iter);
 
-               spin_lock(&nfb->nfb_lock);
-               hlist_for_each_entry_safe(nf, next, &nfb->nfb_head, nf_node) {
+               nf = rhashtable_walk_next(&iter);
+               while (!IS_ERR_OR_NULL(nf)) {
                        if (net && nf->nf_net != net)
                                continue;
-                       del = nfsd_file_unhash_and_release_locked(nf, &dispose);
+                       del = nfsd_file_unhash_and_dispose(nf, &dispose);
 
                        /*
                         * Deadlock detected! Something marked this entry as
                         * unhased, but hasn't removed it from the hash list.
                         */
                        WARN_ON_ONCE(!del);
+
+                       nf = rhashtable_walk_next(&iter);
                }
-               spin_unlock(&nfb->nfb_lock);
-               nfsd_file_dispose_list(&dispose);
-       }
+
+               rhashtable_walk_stop(&iter);
+       } while (nf == ERR_PTR(-EAGAIN));
+       rhashtable_walk_exit(&iter);
+
+       nfsd_file_dispose_list(&dispose);
 }
 
 static struct nfsd_fcache_disposal *
@@ -793,6 +968,19 @@ nfsd_file_cache_start_net(struct net *net)
        return nn->fcache_disposal ? 0 : -ENOMEM;
 }
 
+/**
+ * nfsd_file_cache_purge - Remove all cache items associated with @net
+ * @net: target net namespace
+ *
+ */
+void
+nfsd_file_cache_purge(struct net *net)
+{
+       lockdep_assert_held(&nfsd_mutex);
+       if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)
+               __nfsd_file_cache_purge(net);
+}
+
 void
 nfsd_file_cache_shutdown_net(struct net *net)
 {
@@ -803,7 +991,11 @@ nfsd_file_cache_shutdown_net(struct net *net)
 void
 nfsd_file_cache_shutdown(void)
 {
-       set_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags);
+       int i;
+
+       lockdep_assert_held(&nfsd_mutex);
+       if (test_and_clear_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0)
+               return;
 
        lease_unregister_notifier(&nfsd_file_lease_notifier);
        unregister_shrinker(&nfsd_file_shrinker);
@@ -812,7 +1004,7 @@ nfsd_file_cache_shutdown(void)
         * calling nfsd_file_cache_purge
         */
        cancel_delayed_work_sync(&nfsd_filecache_laundrette);
-       nfsd_file_cache_purge(NULL);
+       __nfsd_file_cache_purge(NULL);
        list_lru_destroy(&nfsd_file_lru);
        rcu_barrier();
        fsnotify_put_group(nfsd_file_fsnotify_group);
@@ -822,124 +1014,96 @@ nfsd_file_cache_shutdown(void)
        fsnotify_wait_marks_destroyed();
        kmem_cache_destroy(nfsd_file_mark_slab);
        nfsd_file_mark_slab = NULL;
-       kvfree(nfsd_file_hashtbl);
-       nfsd_file_hashtbl = NULL;
        destroy_workqueue(nfsd_filecache_wq);
        nfsd_filecache_wq = NULL;
-}
-
-static bool
-nfsd_match_cred(const struct cred *c1, const struct cred *c2)
-{
-       int i;
-
-       if (!uid_eq(c1->fsuid, c2->fsuid))
-               return false;
-       if (!gid_eq(c1->fsgid, c2->fsgid))
-               return false;
-       if (c1->group_info == NULL || c2->group_info == NULL)
-               return c1->group_info == c2->group_info;
-       if (c1->group_info->ngroups != c2->group_info->ngroups)
-               return false;
-       for (i = 0; i < c1->group_info->ngroups; i++) {
-               if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
-                       return false;
-       }
-       return true;
-}
-
-static struct nfsd_file *
-nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
-                       unsigned int hashval, struct net *net)
-{
-       struct nfsd_file *nf;
-       unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
-
-       hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head,
-                                nf_node, lockdep_is_held(&nfsd_file_hashtbl[hashval].nfb_lock)) {
-               if (nf->nf_may != need)
-                       continue;
-               if (nf->nf_inode != inode)
-                       continue;
-               if (nf->nf_net != net)
-                       continue;
-               if (!nfsd_match_cred(nf->nf_cred, current_cred()))
-                       continue;
-               if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags))
-                       continue;
-               if (nfsd_file_get(nf) != NULL)
-                       return nf;
+       rhashtable_destroy(&nfsd_file_rhash_tbl);
+
+       for_each_possible_cpu(i) {
+               per_cpu(nfsd_file_cache_hits, i) = 0;
+               per_cpu(nfsd_file_acquisitions, i) = 0;
+               per_cpu(nfsd_file_releases, i) = 0;
+               per_cpu(nfsd_file_total_age, i) = 0;
+               per_cpu(nfsd_file_pages_flushed, i) = 0;
+               per_cpu(nfsd_file_evictions, i) = 0;
        }
-       return NULL;
 }
 
 /**
- * nfsd_file_is_cached - are there any cached open files for this fh?
- * @inode: inode of the file to check
+ * nfsd_file_is_cached - are there any cached open files for this inode?
+ * @inode: inode to check
+ *
+ * The lookup matches inodes in all net namespaces and is atomic wrt
+ * nfsd_file_acquire().
  *
- * Scan the hashtable for open files that match this fh. Returns true if there
- * are any, and false if not.
+ * Return values:
+ *   %true: filecache contains at least one file matching this inode
+ *   %false: filecache contains no files matching this inode
  */
 bool
 nfsd_file_is_cached(struct inode *inode)
 {
-       bool                    ret = false;
-       struct nfsd_file        *nf;
-       unsigned int            hashval;
-
-        hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS);
-
-       rcu_read_lock();
-       hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head,
-                                nf_node) {
-               if (inode == nf->nf_inode) {
-                       ret = true;
-                       break;
-               }
-       }
-       rcu_read_unlock();
-       trace_nfsd_file_is_cached(inode, hashval, (int)ret);
+       struct nfsd_file_lookup_key key = {
+               .type   = NFSD_FILE_KEY_INODE,
+               .inode  = inode,
+       };
+       bool ret = false;
+
+       if (rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key,
+                                  nfsd_file_rhash_params) != NULL)
+               ret = true;
+       trace_nfsd_file_is_cached(inode, (int)ret);
        return ret;
 }
 
 static __be32
-nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
+nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
                     unsigned int may_flags, struct nfsd_file **pnf, bool open)
 {
-       __be32  status;
-       struct net *net = SVC_NET(rqstp);
+       struct nfsd_file_lookup_key key = {
+               .type   = NFSD_FILE_KEY_FULL,
+               .need   = may_flags & NFSD_FILE_MAY_MASK,
+               .net    = SVC_NET(rqstp),
+       };
        struct nfsd_file *nf, *new;
-       struct inode *inode;
-       unsigned int hashval;
        bool retry = true;
+       __be32 status;
 
-       /* FIXME: skip this if fh_dentry is already set? */
        status = fh_verify(rqstp, fhp, S_IFREG,
                                may_flags|NFSD_MAY_OWNER_OVERRIDE);
        if (status != nfs_ok)
                return status;
+       key.inode = d_inode(fhp->fh_dentry);
+       key.cred = get_current_cred();
 
-       inode = d_inode(fhp->fh_dentry);
-       hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS);
 retry:
-       rcu_read_lock();
-       nf = nfsd_file_find_locked(inode, may_flags, hashval, net);
-       rcu_read_unlock();
+       /* Avoid allocation if the item is already in cache */
+       nf = rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key,
+                                   nfsd_file_rhash_params);
+       if (nf)
+               nf = nfsd_file_get(nf);
        if (nf)
                goto wait_for_construction;
 
-       new = nfsd_file_alloc(inode, may_flags, hashval, net);
+       new = nfsd_file_alloc(&key, may_flags);
        if (!new) {
-               trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags,
-                                       NULL, nfserr_jukebox);
-               return nfserr_jukebox;
+               status = nfserr_jukebox;
+               goto out_status;
        }
 
-       spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
-       nf = nfsd_file_find_locked(inode, may_flags, hashval, net);
-       if (nf == NULL)
+       nf = rhashtable_lookup_get_insert_key(&nfsd_file_rhash_tbl,
+                                             &key, &new->nf_rhash,
+                                             nfsd_file_rhash_params);
+       if (!nf) {
+               nf = new;
                goto open_file;
-       spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
+       }
+       if (IS_ERR(nf))
+               goto insert_err;
+       nf = nfsd_file_get(nf);
+       if (nf == NULL) {
+               nf = new;
+               goto open_file;
+       }
        nfsd_file_slab_free(&new->nf_rcu);
 
 wait_for_construction:
@@ -947,6 +1111,7 @@ wait_for_construction:
 
        /* Did construction of this file fail? */
        if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
+               trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf);
                if (!retry) {
                        status = nfserr_jukebox;
                        goto out;
@@ -956,49 +1121,29 @@ wait_for_construction:
                goto retry;
        }
 
+       nfsd_file_lru_remove(nf);
        this_cpu_inc(nfsd_file_cache_hits);
 
-       if (!(may_flags & NFSD_MAY_NOT_BREAK_LEASE)) {
-               bool write = (may_flags & NFSD_MAY_WRITE);
-
-               if (test_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags) ||
-                   (test_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags) && write)) {
-                       status = nfserrno(nfsd_open_break_lease(
-                                       file_inode(nf->nf_file), may_flags));
-                       if (status == nfs_ok) {
-                               clear_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags);
-                               if (write)
-                                       clear_bit(NFSD_FILE_BREAK_WRITE,
-                                                 &nf->nf_flags);
-                       }
-               }
-       }
+       status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags));
 out:
        if (status == nfs_ok) {
+               if (open)
+                       this_cpu_inc(nfsd_file_acquisitions);
                *pnf = nf;
        } else {
                nfsd_file_put(nf);
                nf = NULL;
        }
 
-       trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags, nf, status);
+out_status:
+       put_cred(key.cred);
+       if (open)
+               trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
        return status;
+
 open_file:
-       nf = new;
-       /* Take reference for the hashtable */
-       refcount_inc(&nf->nf_ref);
-       __set_bit(NFSD_FILE_HASHED, &nf->nf_flags);
-       __set_bit(NFSD_FILE_PENDING, &nf->nf_flags);
-       list_lru_add(&nfsd_file_lru, &nf->nf_lru);
-       hlist_add_head_rcu(&nf->nf_node, &nfsd_file_hashtbl[hashval].nfb_head);
-       ++nfsd_file_hashtbl[hashval].nfb_count;
-       nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount,
-                       nfsd_file_hashtbl[hashval].nfb_count);
-       spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
-       if (atomic_long_inc_return(&nfsd_filecache_count) >= NFSD_FILE_LRU_THRESHOLD)
-               nfsd_file_gc();
-
-       nf->nf_mark = nfsd_file_mark_find_or_create(nf);
+       trace_nfsd_file_alloc(nf);
+       nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode);
        if (nf->nf_mark) {
                if (open) {
                        status = nfsd_open_verified(rqstp, fhp, may_flags,
@@ -1012,18 +1157,20 @@ open_file:
         * If construction failed, or we raced with a call to unlink()
         * then unhash.
         */
-       if (status != nfs_ok || inode->i_nlink == 0) {
-               bool do_free;
-               spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
-               do_free = nfsd_file_unhash(nf);
-               spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
-               if (do_free)
+       if (status != nfs_ok || key.inode->i_nlink == 0)
+               if (nfsd_file_unhash(nf))
                        nfsd_file_put_noref(nf);
-       }
        clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags);
        smp_mb__after_atomic();
        wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING);
        goto out;
+
+insert_err:
+       nfsd_file_slab_free(&new->nf_rcu);
+       trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, PTR_ERR(nf));
+       nf = NULL;
+       status = nfserr_jukebox;
+       goto out_status;
 }
 
 /**
@@ -1040,7 +1187,7 @@ __be32
 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
                  unsigned int may_flags, struct nfsd_file **pnf)
 {
-       return nfsd_do_file_acquire(rqstp, fhp, may_flags, pnf, true);
+       return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true);
 }
 
 /**
@@ -1057,7 +1204,7 @@ __be32
 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                 unsigned int may_flags, struct nfsd_file **pnf)
 {
-       return nfsd_do_file_acquire(rqstp, fhp, may_flags, pnf, false);
+       return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false);
 }
 
 /*
@@ -1067,29 +1214,49 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
  */
 static int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
 {
-       unsigned int i, count = 0, longest = 0;
-       unsigned long hits = 0;
+       unsigned long releases = 0, pages_flushed = 0, evictions = 0;
+       unsigned long hits = 0, acquisitions = 0;
+       unsigned int i, count = 0, buckets = 0;
+       unsigned long lru = 0, total_age = 0;
 
-       /*
-        * No need for spinlocks here since we're not terribly interested in
-        * accuracy. We do take the nfsd_mutex simply to ensure that we
-        * don't end up racing with server shutdown
-        */
+       /* Serialize with server shutdown */
        mutex_lock(&nfsd_mutex);
-       if (nfsd_file_hashtbl) {
-               for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
-                       count += nfsd_file_hashtbl[i].nfb_count;
-                       longest = max(longest, nfsd_file_hashtbl[i].nfb_count);
-               }
+       if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) {
+               struct bucket_table *tbl;
+               struct rhashtable *ht;
+
+               lru = list_lru_count(&nfsd_file_lru);
+
+               rcu_read_lock();
+               ht = &nfsd_file_rhash_tbl;
+               count = atomic_read(&ht->nelems);
+               tbl = rht_dereference_rcu(ht->tbl, ht);
+               buckets = tbl->size;
+               rcu_read_unlock();
        }
        mutex_unlock(&nfsd_mutex);
 
-       for_each_possible_cpu(i)
+       for_each_possible_cpu(i) {
                hits += per_cpu(nfsd_file_cache_hits, i);
+               acquisitions += per_cpu(nfsd_file_acquisitions, i);
+               releases += per_cpu(nfsd_file_releases, i);
+               total_age += per_cpu(nfsd_file_total_age, i);
+               evictions += per_cpu(nfsd_file_evictions, i);
+               pages_flushed += per_cpu(nfsd_file_pages_flushed, i);
+       }
 
        seq_printf(m, "total entries: %u\n", count);
-       seq_printf(m, "longest chain: %u\n", longest);
+       seq_printf(m, "hash buckets:  %u\n", buckets);
+       seq_printf(m, "lru entries:   %lu\n", lru);
        seq_printf(m, "cache hits:    %lu\n", hits);
+       seq_printf(m, "acquisitions:  %lu\n", acquisitions);
+       seq_printf(m, "releases:      %lu\n", releases);
+       seq_printf(m, "evictions:     %lu\n", evictions);
+       if (releases)
+               seq_printf(m, "mean age (ms): %ld\n", total_age / releases);
+       else
+               seq_printf(m, "mean age (ms): -\n");
+       seq_printf(m, "pages flushed: %lu\n", pages_flushed);
        return 0;
 }
 
index 1da0c79..8e8c0c4 100644 (file)
@@ -29,7 +29,7 @@ struct nfsd_file_mark {
  * never be dereferenced, only used for comparison.
  */
 struct nfsd_file {
-       struct hlist_node       nf_node;
+       struct rhash_head       nf_rhash;
        struct list_head        nf_lru;
        struct rcu_head         nf_rcu;
        struct file             *nf_file;
@@ -37,15 +37,13 @@ struct nfsd_file {
        struct net              *nf_net;
 #define NFSD_FILE_HASHED       (0)
 #define NFSD_FILE_PENDING      (1)
-#define NFSD_FILE_BREAK_READ   (2)
-#define NFSD_FILE_BREAK_WRITE  (3)
-#define NFSD_FILE_REFERENCED   (4)
+#define NFSD_FILE_REFERENCED   (2)
        unsigned long           nf_flags;
-       struct inode            *nf_inode;
-       unsigned int            nf_hashval;
+       struct inode            *nf_inode;      /* don't deref */
        refcount_t              nf_ref;
        unsigned char           nf_may;
        struct nfsd_file_mark   *nf_mark;
+       ktime_t                 nf_birthtime;
 };
 
 int nfsd_file_cache_init(void);
@@ -54,6 +52,7 @@ void nfsd_file_cache_shutdown(void);
 int nfsd_file_cache_start_net(struct net *net);
 void nfsd_file_cache_shutdown_net(struct net *net);
 void nfsd_file_put(struct nfsd_file *nf);
+void nfsd_file_close(struct nfsd_file *nf);
 struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
 void nfsd_file_close_inode_sync(struct inode *inode);
 bool nfsd_file_is_cached(struct inode *inode);
index 1b1a962..ffe1774 100644 (file)
@@ -189,6 +189,9 @@ struct nfsd_net {
        struct nfsd_fcache_disposal *fcache_disposal;
 
        siphash_key_t           siphash_key;
+
+       atomic_t                nfs4_client_count;
+       int                     nfs4_max_clients;
 };
 
 /* Simple check to find out if a given net was properly initialized */
index b576080..9edd3c1 100644 (file)
@@ -111,7 +111,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
        if (error)
                goto out_errno;
 
-       fh_lock(fh);
+       inode_lock(inode);
 
        error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
                              argp->acl_access);
@@ -122,7 +122,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
        if (error)
                goto out_drop_lock;
 
-       fh_unlock(fh);
+       inode_unlock(inode);
 
        fh_drop_write(fh);
 
@@ -136,7 +136,7 @@ out:
        return rpc_success;
 
 out_drop_lock:
-       fh_unlock(fh);
+       inode_unlock(inode);
        fh_drop_write(fh);
 out_errno:
        resp->status = nfserrno(error);
index 35b2ebd..9446c67 100644 (file)
@@ -101,7 +101,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
        if (error)
                goto out_errno;
 
-       fh_lock(fh);
+       inode_lock(inode);
 
        error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
                              argp->acl_access);
@@ -111,7 +111,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
                              argp->acl_default);
 
 out_drop_lock:
-       fh_unlock(fh);
+       inode_unlock(inode);
        fh_drop_write(fh);
 out_errno:
        resp->status = nfserrno(error);
index 981a3a7..a41cca6 100644 (file)
@@ -67,12 +67,15 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp)
 {
        struct nfsd3_sattrargs *argp = rqstp->rq_argp;
        struct nfsd3_attrstat *resp = rqstp->rq_resp;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &argp->attrs,
+       };
 
        dprintk("nfsd: SETATTR(3)  %s\n",
                                SVCFH_fmt(&argp->fh));
 
        fh_copy(&resp->fh, &argp->fh);
-       resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
+       resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs,
                                    argp->check_guard, argp->guardtime);
        return rpc_success;
 }
@@ -233,6 +236,9 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 {
        struct iattr *iap = &argp->attrs;
        struct dentry *parent, *child;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = iap,
+       };
        __u32 v_mtime, v_atime;
        struct inode *inode;
        __be32 status;
@@ -254,7 +260,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (host_err)
                return nfserrno(host_err);
 
-       fh_lock_nested(fhp, I_MUTEX_PARENT);
+       inode_lock_nested(inode, I_MUTEX_PARENT);
 
        child = lookup_one_len(argp->name, parent, argp->len);
        if (IS_ERR(child)) {
@@ -312,11 +318,13 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (!IS_POSIXACL(inode))
                iap->ia_mode &= ~current_umask();
 
+       fh_fill_pre_attrs(fhp);
        host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true);
        if (host_err < 0) {
                status = nfserrno(host_err);
                goto out;
        }
+       fh_fill_post_attrs(fhp);
 
        /* A newly created file already has a file size of zero. */
        if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
@@ -331,10 +339,10 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
        }
 
 set_attr:
-       status = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
+       status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
 
 out:
-       fh_unlock(fhp);
+       inode_unlock(inode);
        if (child && !IS_ERR(child))
                dput(child);
        fh_drop_write(fhp);
@@ -368,6 +376,9 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
 {
        struct nfsd3_createargs *argp = rqstp->rq_argp;
        struct nfsd3_diropres *resp = rqstp->rq_resp;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &argp->attrs,
+       };
 
        dprintk("nfsd: MKDIR(3)    %s %.*s\n",
                                SVCFH_fmt(&argp->fh),
@@ -378,8 +389,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
        fh_copy(&resp->dirfh, &argp->fh);
        fh_init(&resp->fh, NFS3_FHSIZE);
        resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
-                                  &argp->attrs, S_IFDIR, 0, &resp->fh);
-       fh_unlock(&resp->dirfh);
+                                  &attrs, S_IFDIR, 0, &resp->fh);
        return rpc_success;
 }
 
@@ -388,6 +398,9 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
 {
        struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
        struct nfsd3_diropres *resp = rqstp->rq_resp;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &argp->attrs,
+       };
 
        if (argp->tlen == 0) {
                resp->status = nfserr_inval;
@@ -414,7 +427,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
        fh_copy(&resp->dirfh, &argp->ffh);
        fh_init(&resp->fh, NFS3_FHSIZE);
        resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
-                                   argp->flen, argp->tname, &resp->fh);
+                                   argp->flen, argp->tname, &attrs, &resp->fh);
        kfree(argp->tname);
 out:
        return rpc_success;
@@ -428,6 +441,9 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
 {
        struct nfsd3_mknodargs *argp = rqstp->rq_argp;
        struct nfsd3_diropres  *resp = rqstp->rq_resp;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &argp->attrs,
+       };
        int type;
        dev_t   rdev = 0;
 
@@ -453,8 +469,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
 
        type = nfs3_ftypes[argp->ftype];
        resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
-                                  &argp->attrs, type, rdev, &resp->fh);
-       fh_unlock(&resp->dirfh);
+                                  &attrs, type, rdev, &resp->fh);
 out:
        return rpc_success;
 }
@@ -477,7 +492,6 @@ nfsd3_proc_remove(struct svc_rqst *rqstp)
        fh_copy(&resp->fh, &argp->fh);
        resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
                                   argp->name, argp->len);
-       fh_unlock(&resp->fh);
        return rpc_success;
 }
 
@@ -498,7 +512,6 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp)
        fh_copy(&resp->fh, &argp->fh);
        resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
                                   argp->name, argp->len);
-       fh_unlock(&resp->fh);
        return rpc_success;
 }
 
index eaa3a0c..bb8e2f6 100644 (file)
@@ -751,58 +751,26 @@ out_estate:
        return ret;
 }
 
-__be32
-nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               struct nfs4_acl *acl)
+__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
+                        struct nfsd_attrs *attr)
 {
-       __be32 error;
        int host_error;
-       struct dentry *dentry;
-       struct inode *inode;
-       struct posix_acl *pacl = NULL, *dpacl = NULL;
        unsigned int flags = 0;
 
-       /* Get inode */
-       error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
-       if (error)
-               return error;
-
-       dentry = fhp->fh_dentry;
-       inode = d_inode(dentry);
+       if (!acl)
+               return nfs_ok;
 
-       if (S_ISDIR(inode->i_mode))
+       if (type == NF4DIR)
                flags = NFS4_ACL_DIR;
 
-       host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
+       host_error = nfs4_acl_nfsv4_to_posix(acl, &attr->na_pacl,
+                                            &attr->na_dpacl, flags);
        if (host_error == -EINVAL)
                return nfserr_attrnotsupp;
-       if (host_error < 0)
-               goto out_nfserr;
-
-       fh_lock(fhp);
-
-       host_error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS, pacl);
-       if (host_error < 0)
-               goto out_drop_lock;
-
-       if (S_ISDIR(inode->i_mode)) {
-               host_error = set_posix_acl(&init_user_ns, inode,
-                                          ACL_TYPE_DEFAULT, dpacl);
-       }
-
-out_drop_lock:
-       fh_unlock(fhp);
-
-       posix_acl_release(pacl);
-       posix_acl_release(dpacl);
-out_nfserr:
-       if (host_error == -EOPNOTSUPP)
-               return nfserr_attrnotsupp;
        else
                return nfserrno(host_error);
 }
 
-
 static short
 ace2type(struct nfs4_ace *ace)
 {
index 11f8715..4ce3282 100644 (file)
@@ -679,7 +679,7 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,
  *     case NFS4_OK:
  *             write_response4 coa_resok4;
  *     default:
- *     length4         coa_bytes_copied;
+ *             length4         coa_bytes_copied;
  * };
  * struct CB_OFFLOAD4args {
  *     nfs_fh4         coa_fh;
@@ -688,21 +688,22 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,
  * };
  */
 static void encode_offload_info4(struct xdr_stream *xdr,
-                                __be32 nfserr,
-                                const struct nfsd4_copy *cp)
+                                const struct nfsd4_cb_offload *cbo)
 {
        __be32 *p;
 
        p = xdr_reserve_space(xdr, 4);
-       *p++ = nfserr;
-       if (!nfserr) {
+       *p = cbo->co_nfserr;
+       switch (cbo->co_nfserr) {
+       case nfs_ok:
                p = xdr_reserve_space(xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE);
                p = xdr_encode_empty_array(p);
-               p = xdr_encode_hyper(p, cp->cp_res.wr_bytes_written);
-               *p++ = cpu_to_be32(cp->cp_res.wr_stable_how);
-               p = xdr_encode_opaque_fixed(p, cp->cp_res.wr_verifier.data,
+               p = xdr_encode_hyper(p, cbo->co_res.wr_bytes_written);
+               *p++ = cpu_to_be32(cbo->co_res.wr_stable_how);
+               p = xdr_encode_opaque_fixed(p, cbo->co_res.wr_verifier.data,
                                            NFS4_VERIFIER_SIZE);
-       } else {
+               break;
+       default:
                p = xdr_reserve_space(xdr, 8);
                /* We always return success if bytes were written */
                p = xdr_encode_hyper(p, 0);
@@ -710,18 +711,16 @@ static void encode_offload_info4(struct xdr_stream *xdr,
 }
 
 static void encode_cb_offload4args(struct xdr_stream *xdr,
-                                  __be32 nfserr,
-                                  const struct knfsd_fh *fh,
-                                  const struct nfsd4_copy *cp,
+                                  const struct nfsd4_cb_offload *cbo,
                                   struct nfs4_cb_compound_hdr *hdr)
 {
        __be32 *p;
 
        p = xdr_reserve_space(xdr, 4);
-       *p++ = cpu_to_be32(OP_CB_OFFLOAD);
-       encode_nfs_fh4(xdr, fh);
-       encode_stateid4(xdr, &cp->cp_res.cb_stateid);
-       encode_offload_info4(xdr, nfserr, cp);
+       *p = cpu_to_be32(OP_CB_OFFLOAD);
+       encode_nfs_fh4(xdr, &cbo->co_fh);
+       encode_stateid4(xdr, &cbo->co_res.cb_stateid);
+       encode_offload_info4(xdr, cbo);
 
        hdr->nops++;
 }
@@ -731,8 +730,8 @@ static void nfs4_xdr_enc_cb_offload(struct rpc_rqst *req,
                                    const void *data)
 {
        const struct nfsd4_callback *cb = data;
-       const struct nfsd4_copy *cp =
-               container_of(cb, struct nfsd4_copy, cp_cb);
+       const struct nfsd4_cb_offload *cbo =
+               container_of(cb, struct nfsd4_cb_offload, co_cb);
        struct nfs4_cb_compound_hdr hdr = {
                .ident = 0,
                .minorversion = cb->cb_clp->cl_minorversion,
@@ -740,7 +739,7 @@ static void nfs4_xdr_enc_cb_offload(struct rpc_rqst *req,
 
        encode_cb_compound4args(xdr, &hdr);
        encode_cb_sequence4args(xdr, cb, &hdr);
-       encode_cb_offload4args(xdr, cp->nfserr, &cp->fh, cp, &hdr);
+       encode_cb_offload4args(xdr, cbo, &hdr);
        encode_cb_nops(&hdr);
 }
 
index 3895eb5..a72ab97 100644 (file)
@@ -64,36 +64,6 @@ MODULE_PARM_DESC(nfsd4_ssc_umount_timeout,
                "idle msecs before unmount export from source server");
 #endif
 
-#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-#include <linux/security.h>
-
-static inline void
-nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
-{
-       struct inode *inode = d_inode(resfh->fh_dentry);
-       int status;
-
-       inode_lock(inode);
-       status = security_inode_setsecctx(resfh->fh_dentry,
-               label->data, label->len);
-       inode_unlock(inode);
-
-       if (status)
-               /*
-                * XXX: We should really fail the whole open, but we may
-                * already have created a new file, so it may be too
-                * late.  For now this seems the least of evils:
-                */
-               bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
-
-       return;
-}
-#else
-static inline void
-nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
-{ }
-#endif
-
 #define NFSDDBG_FACILITY               NFSDDBG_PROC
 
 static u32 nfsd_attrmask[] = {
@@ -158,26 +128,6 @@ is_create_with_attrs(struct nfsd4_open *open)
                    || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
 }
 
-/*
- * if error occurs when setting the acl, just clear the acl bit
- * in the returned attr bitmap.
- */
-static void
-do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               struct nfs4_acl *acl, u32 *bmval)
-{
-       __be32 status;
-
-       status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
-       if (status)
-               /*
-                * We should probably fail the whole open at this point,
-                * but we've already created the file, so it's too late;
-                * So this seems the least of evils:
-                */
-               bmval[0] &= ~FATTR4_WORD0_ACL;
-}
-
 static inline void
 fh_dup2(struct svc_fh *dst, struct svc_fh *src)
 {
@@ -286,6 +236,10 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
                  struct svc_fh *resfhp, struct nfsd4_open *open)
 {
        struct iattr *iap = &open->op_iattr;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = iap,
+               .na_seclabel    = &open->op_label,
+       };
        struct dentry *parent, *child;
        __u32 v_mtime, v_atime;
        struct inode *inode;
@@ -307,7 +261,10 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (host_err)
                return nfserrno(host_err);
 
-       fh_lock_nested(fhp, I_MUTEX_PARENT);
+       if (is_create_with_attrs(open))
+               nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs);
+
+       inode_lock_nested(inode, I_MUTEX_PARENT);
 
        child = lookup_one_len(open->op_fname, parent, open->op_fnamelen);
        if (IS_ERR(child)) {
@@ -345,6 +302,11 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (d_really_is_positive(child)) {
                status = nfs_ok;
 
+               /* NFSv4 protocol requires change attributes even though
+                * no change happened.
+                */
+               fh_fill_both_attrs(fhp);
+
                switch (open->op_createmode) {
                case NFS4_CREATE_UNCHECKED:
                        if (!d_is_reg(child))
@@ -386,10 +348,12 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (!IS_POSIXACL(inode))
                iap->ia_mode &= ~current_umask();
 
+       fh_fill_pre_attrs(fhp);
        status = nfsd4_vfs_create(fhp, child, open);
        if (status != nfs_ok)
                goto out;
        open->op_created = true;
+       fh_fill_post_attrs(fhp);
 
        /* A newly created file already has a file size of zero. */
        if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
@@ -404,10 +368,15 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
        }
 
 set_attr:
-       status = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
+       status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
 
+       if (attrs.na_labelerr)
+               open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+       if (attrs.na_aclerr)
+               open->op_bmval[0] &= ~FATTR4_WORD0_ACL;
 out:
-       fh_unlock(fhp);
+       inode_unlock(inode);
+       nfsd_attrs_free(&attrs);
        if (child && !IS_ERR(child))
                dput(child);
        fh_drop_write(fhp);
@@ -447,9 +416,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
                status = nfsd4_create_file(rqstp, current_fh, *resfh, open);
                current->fs->umask = 0;
 
-               if (!status && open->op_label.len)
-                       nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval);
-
                /*
                 * Following rfc 3530 14.2.16, and rfc 5661 18.16.4
                 * use the returned bitmask to indicate which attributes
@@ -458,24 +424,21 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
                if (nfsd4_create_is_exclusive(open->op_createmode) && status == 0)
                        open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
                                                FATTR4_WORD1_TIME_MODIFY);
-       } else
-               /*
-                * Note this may exit with the parent still locked.
-                * We will hold the lock until nfsd4_open's final
-                * lookup, to prevent renames or unlinks until we've had
-                * a chance to an acquire a delegation if appropriate.
-                */
+       } else {
                status = nfsd_lookup(rqstp, current_fh,
                                     open->op_fname, open->op_fnamelen, *resfh);
+               if (!status)
+                       /* NFSv4 protocol requires change attributes even though
+                        * no change happened.
+                        */
+                       fh_fill_both_attrs(current_fh);
+       }
        if (status)
                goto out;
        status = nfsd_check_obj_isreg(*resfh);
        if (status)
                goto out;
 
-       if (is_create_with_attrs(open) && open->op_acl != NULL)
-               do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
-
        nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
        accmode = NFSD_MAY_NOP;
        if (open->op_created ||
@@ -547,6 +510,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                open->op_openowner);
 
        open->op_filp = NULL;
+       open->op_rqstp = rqstp;
 
        /* This check required by spec. */
        if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
@@ -630,9 +594,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        }
 
        status = nfsd4_process_open2(rqstp, resfh, open);
-       WARN(status && open->op_created,
-            "nfsd4_process_open2 failed to open newly-created file! status=%u\n",
-            be32_to_cpu(status));
+       if (status && open->op_created)
+               pr_warn("nfsd4_process_open2 failed to open newly-created file: status=%u\n",
+                       be32_to_cpu(status));
        if (reclaim && !status)
                nn->somebody_reclaimed = true;
 out:
@@ -786,6 +750,10 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
             union nfsd4_op_u *u)
 {
        struct nfsd4_create *create = &u->create;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &create->cr_iattr,
+               .na_seclabel    = &create->cr_label,
+       };
        struct svc_fh resfh;
        __be32 status;
        dev_t rdev;
@@ -801,12 +769,13 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        if (status)
                return status;
 
+       status = nfsd4_acl_to_attr(create->cr_type, create->cr_acl, &attrs);
        current->fs->umask = create->cr_umask;
        switch (create->cr_type) {
        case NF4LNK:
                status = nfsd_symlink(rqstp, &cstate->current_fh,
                                      create->cr_name, create->cr_namelen,
-                                     create->cr_data, &resfh);
+                                     create->cr_data, &attrs, &resfh);
                break;
 
        case NF4BLK:
@@ -817,7 +786,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out_umask;
                status = nfsd_create(rqstp, &cstate->current_fh,
                                     create->cr_name, create->cr_namelen,
-                                    &create->cr_iattr, S_IFBLK, rdev, &resfh);
+                                    &attrs, S_IFBLK, rdev, &resfh);
                break;
 
        case NF4CHR:
@@ -828,26 +797,26 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out_umask;
                status = nfsd_create(rqstp, &cstate->current_fh,
                                     create->cr_name, create->cr_namelen,
-                                    &create->cr_iattr,S_IFCHR, rdev, &resfh);
+                                    &attrs, S_IFCHR, rdev, &resfh);
                break;
 
        case NF4SOCK:
                status = nfsd_create(rqstp, &cstate->current_fh,
                                     create->cr_name, create->cr_namelen,
-                                    &create->cr_iattr, S_IFSOCK, 0, &resfh);
+                                    &attrs, S_IFSOCK, 0, &resfh);
                break;
 
        case NF4FIFO:
                status = nfsd_create(rqstp, &cstate->current_fh,
                                     create->cr_name, create->cr_namelen,
-                                    &create->cr_iattr, S_IFIFO, 0, &resfh);
+                                    &attrs, S_IFIFO, 0, &resfh);
                break;
 
        case NF4DIR:
                create->cr_iattr.ia_valid &= ~ATTR_SIZE;
                status = nfsd_create(rqstp, &cstate->current_fh,
                                     create->cr_name, create->cr_namelen,
-                                    &create->cr_iattr, S_IFDIR, 0, &resfh);
+                                    &attrs, S_IFDIR, 0, &resfh);
                break;
 
        default:
@@ -857,20 +826,17 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        if (status)
                goto out;
 
-       if (create->cr_label.len)
-               nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval);
-
-       if (create->cr_acl != NULL)
-               do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
-                               create->cr_bmval);
-
-       fh_unlock(&cstate->current_fh);
+       if (attrs.na_labelerr)
+               create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+       if (attrs.na_aclerr)
+               create->cr_bmval[0] &= ~FATTR4_WORD0_ACL;
        set_change_info(&create->cr_cinfo, &cstate->current_fh);
        fh_dup2(&cstate->current_fh, &resfh);
 out:
        fh_put(&resfh);
 out_umask:
        current->fs->umask = 0;
+       nfsd_attrs_free(&attrs);
        return status;
 }
 
@@ -1043,10 +1009,8 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                return nfserr_grace;
        status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
                             remove->rm_name, remove->rm_namelen);
-       if (!status) {
-               fh_unlock(&cstate->current_fh);
+       if (!status)
                set_change_info(&remove->rm_cinfo, &cstate->current_fh);
-       }
        return status;
 }
 
@@ -1086,7 +1050,6 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                    &exp, &dentry);
        if (err)
                return err;
-       fh_unlock(&cstate->current_fh);
        if (d_really_is_negative(dentry)) {
                exp_put(exp);
                err = nfserr_noent;
@@ -1141,6 +1104,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
              union nfsd4_op_u *u)
 {
        struct nfsd4_setattr *setattr = &u->setattr;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &setattr->sa_iattr,
+               .na_seclabel    = &setattr->sa_label,
+       };
+       struct inode *inode;
        __be32 status = nfs_ok;
        int err;
 
@@ -1163,19 +1131,18 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        if (status)
                goto out;
 
-       if (setattr->sa_acl != NULL)
-               status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
-                                           setattr->sa_acl);
-       if (status)
-               goto out;
-       if (setattr->sa_label.len)
-               status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
-                               &setattr->sa_label);
+       inode = cstate->current_fh.fh_dentry->d_inode;
+       status = nfsd4_acl_to_attr(S_ISDIR(inode->i_mode) ? NF4DIR : NF4REG,
+                                  setattr->sa_acl, &attrs);
+
        if (status)
                goto out;
-       status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
+       status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs,
                                0, (time64_t)0);
+       if (!status)
+               status = nfserrno(attrs.na_labelerr);
 out:
+       nfsd_attrs_free(&attrs);
        fh_drop_write(&cstate->current_fh);
        return status;
 }
@@ -1285,30 +1252,17 @@ out:
        return status;
 }
 
-void nfs4_put_copy(struct nfsd4_copy *copy)
+static void nfs4_put_copy(struct nfsd4_copy *copy)
 {
        if (!refcount_dec_and_test(&copy->refcount))
                return;
+       kfree(copy->cp_src);
        kfree(copy);
 }
 
-static bool
-check_and_set_stop_copy(struct nfsd4_copy *copy)
-{
-       bool value;
-
-       spin_lock(&copy->cp_clp->async_lock);
-       value = copy->stopped;
-       if (!copy->stopped)
-               copy->stopped = true;
-       spin_unlock(&copy->cp_clp->async_lock);
-       return value;
-}
-
 static void nfsd4_stop_copy(struct nfsd4_copy *copy)
 {
-       /* only 1 thread should stop the copy */
-       if (!check_and_set_stop_copy(copy))
+       if (!test_and_set_bit(NFSD4_COPY_F_STOPPED, &copy->cp_flags))
                kthread_stop(copy->copy_task);
        nfs4_put_copy(copy);
 }
@@ -1389,7 +1343,7 @@ try_again:
                return 0;
        }
        if (work) {
-               strncpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr));
+               strlcpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr) - 1);
                refcount_set(&work->nsui_refcnt, 2);
                work->nsui_busy = true;
                list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list);
@@ -1549,7 +1503,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
        if (status)
                goto out;
 
-       status = nfsd4_interssc_connect(&copy->cp_src, rqstp, mount);
+       status = nfsd4_interssc_connect(copy->cp_src, rqstp, mount);
        if (status)
                goto out;
 
@@ -1567,7 +1521,7 @@ out:
 }
 
 static void
-nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
+nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp,
                        struct nfsd_file *dst)
 {
        bool found = false;
@@ -1576,9 +1530,9 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
        struct nfsd4_ssc_umount_item *ni = NULL;
        struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id);
 
-       nfs42_ssc_close(src->nf_file);
+       nfs42_ssc_close(filp);
        nfsd_file_put(dst);
-       fput(src->nf_file);
+       fput(filp);
 
        if (!nn) {
                mntput(ss_mnt);
@@ -1621,7 +1575,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
 }
 
 static void
-nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
+nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp,
                        struct nfsd_file *dst)
 {
 }
@@ -1658,9 +1612,10 @@ nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst)
 
 static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
 {
-       struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb);
+       struct nfsd4_cb_offload *cbo =
+               container_of(cb, struct nfsd4_cb_offload, co_cb);
 
-       nfs4_put_copy(copy);
+       kfree(cbo);
 }
 
 static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
@@ -1677,15 +1632,16 @@ static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = {
 static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync)
 {
        copy->cp_res.wr_stable_how =
-               copy->committed ? NFS_FILE_SYNC : NFS_UNSTABLE;
-       copy->cp_synchronous = sync;
+               test_bit(NFSD4_COPY_F_COMMITTED, &copy->cp_flags) ?
+                       NFS_FILE_SYNC : NFS_UNSTABLE;
+       nfsd4_copy_set_sync(copy, sync);
        gen_boot_verifier(&copy->cp_res.wr_verifier, copy->cp_clp->net);
 }
 
-static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
+static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy,
+                                    struct file *dst,
+                                    struct file *src)
 {
-       struct file *dst = copy->nf_dst->nf_file;
-       struct file *src = copy->nf_src->nf_file;
        errseq_t since;
        ssize_t bytes_copied = 0;
        u64 bytes_total = copy->cp_count;
@@ -1707,26 +1663,29 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
                copy->cp_res.wr_bytes_written += bytes_copied;
                src_pos += bytes_copied;
                dst_pos += bytes_copied;
-       } while (bytes_total > 0 && !copy->cp_synchronous);
+       } while (bytes_total > 0 && nfsd4_copy_is_async(copy));
        /* for a non-zero asynchronous copy do a commit of data */
-       if (!copy->cp_synchronous && copy->cp_res.wr_bytes_written > 0) {
+       if (nfsd4_copy_is_async(copy) && copy->cp_res.wr_bytes_written > 0) {
                since = READ_ONCE(dst->f_wb_err);
                status = vfs_fsync_range(dst, copy->cp_dst_pos,
                                         copy->cp_res.wr_bytes_written, 0);
                if (!status)
                        status = filemap_check_wb_err(dst->f_mapping, since);
                if (!status)
-                       copy->committed = true;
+                       set_bit(NFSD4_COPY_F_COMMITTED, &copy->cp_flags);
        }
        return bytes_copied;
 }
 
-static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
+static __be32 nfsd4_do_copy(struct nfsd4_copy *copy,
+                           struct file *src, struct file *dst,
+                           bool sync)
 {
        __be32 status;
        ssize_t bytes;
 
-       bytes = _nfsd_copy_file_range(copy);
+       bytes = _nfsd_copy_file_range(copy, dst, src);
+
        /* for async copy, we ignore the error, client can always retry
         * to get the error
         */
@@ -1736,13 +1695,6 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
                nfsd4_init_copy_res(copy, sync);
                status = nfs_ok;
        }
-
-       if (!copy->cp_intra) /* Inter server SSC */
-               nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src,
-                                       copy->nf_dst);
-       else
-               nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
-
        return status;
 }
 
@@ -1751,17 +1703,17 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
        dst->cp_src_pos = src->cp_src_pos;
        dst->cp_dst_pos = src->cp_dst_pos;
        dst->cp_count = src->cp_count;
-       dst->cp_synchronous = src->cp_synchronous;
+       dst->cp_flags = src->cp_flags;
        memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res));
        memcpy(&dst->fh, &src->fh, sizeof(src->fh));
        dst->cp_clp = src->cp_clp;
        dst->nf_dst = nfsd_file_get(src->nf_dst);
-       dst->cp_intra = src->cp_intra;
-       if (src->cp_intra) /* for inter, file_src doesn't exist yet */
+       /* for inter, nf_src doesn't exist yet */
+       if (!nfsd4_ssc_is_inter(src))
                dst->nf_src = nfsd_file_get(src->nf_src);
 
        memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
-       memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server));
+       memcpy(dst->cp_src, src->cp_src, sizeof(struct nl4_server));
        memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
        memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh));
        dst->ss_mnt = src->ss_mnt;
@@ -1771,7 +1723,7 @@ static void cleanup_async_copy(struct nfsd4_copy *copy)
 {
        nfs4_free_copy_state(copy);
        nfsd_file_put(copy->nf_dst);
-       if (copy->cp_intra)
+       if (!nfsd4_ssc_is_inter(copy))
                nfsd_file_put(copy->nf_src);
        spin_lock(&copy->cp_clp->async_lock);
        list_del(&copy->copies);
@@ -1779,45 +1731,58 @@ static void cleanup_async_copy(struct nfsd4_copy *copy)
        nfs4_put_copy(copy);
 }
 
+static void nfsd4_send_cb_offload(struct nfsd4_copy *copy, __be32 nfserr)
+{
+       struct nfsd4_cb_offload *cbo;
+
+       cbo = kzalloc(sizeof(*cbo), GFP_KERNEL);
+       if (!cbo)
+               return;
+
+       memcpy(&cbo->co_res, &copy->cp_res, sizeof(copy->cp_res));
+       memcpy(&cbo->co_fh, &copy->fh, sizeof(copy->fh));
+       cbo->co_nfserr = nfserr;
+
+       nfsd4_init_cb(&cbo->co_cb, copy->cp_clp, &nfsd4_cb_offload_ops,
+                     NFSPROC4_CLNT_CB_OFFLOAD);
+       trace_nfsd_cb_offload(copy->cp_clp, &cbo->co_res.cb_stateid,
+                             &cbo->co_fh, copy->cp_count, nfserr);
+       nfsd4_run_cb(&cbo->co_cb);
+}
+
+/**
+ * nfsd4_do_async_copy - kthread function for background server-side COPY
+ * @data: arguments for COPY operation
+ *
+ * Return values:
+ *   %0: Copy operation is done.
+ */
 static int nfsd4_do_async_copy(void *data)
 {
        struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
-       struct nfsd4_copy *cb_copy;
+       __be32 nfserr;
 
-       if (!copy->cp_intra) { /* Inter server SSC */
-               copy->nf_src = kzalloc(sizeof(struct nfsd_file), GFP_KERNEL);
-               if (!copy->nf_src) {
-                       copy->nfserr = nfserr_serverfault;
-                       nfsd4_interssc_disconnect(copy->ss_mnt);
-                       goto do_callback;
-               }
-               copy->nf_src->nf_file = nfs42_ssc_open(copy->ss_mnt, &copy->c_fh,
-                                             &copy->stateid);
-               if (IS_ERR(copy->nf_src->nf_file)) {
-                       copy->nfserr = nfserr_offload_denied;
+       if (nfsd4_ssc_is_inter(copy)) {
+               struct file *filp;
+
+               filp = nfs42_ssc_open(copy->ss_mnt, &copy->c_fh,
+                                     &copy->stateid);
+               if (IS_ERR(filp)) {
+                       nfserr = nfserr_offload_denied;
                        nfsd4_interssc_disconnect(copy->ss_mnt);
                        goto do_callback;
                }
+               nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file,
+                                      false);
+               nfsd4_cleanup_inter_ssc(copy->ss_mnt, filp, copy->nf_dst);
+       } else {
+               nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file,
+                                      copy->nf_dst->nf_file, false);
+               nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
        }
 
-       copy->nfserr = nfsd4_do_copy(copy, 0);
 do_callback:
-       cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
-       if (!cb_copy)
-               goto out;
-       refcount_set(&cb_copy->refcount, 1);
-       memcpy(&cb_copy->cp_res, &copy->cp_res, sizeof(copy->cp_res));
-       cb_copy->cp_clp = copy->cp_clp;
-       cb_copy->nfserr = copy->nfserr;
-       memcpy(&cb_copy->fh, &copy->fh, sizeof(copy->fh));
-       nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp,
-                       &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD);
-       trace_nfsd_cb_offload(copy->cp_clp, &copy->cp_res.cb_stateid,
-                             &copy->fh, copy->cp_count, copy->nfserr);
-       nfsd4_run_cb(&cb_copy->cp_cb);
-out:
-       if (!copy->cp_intra)
-               kfree(copy->nf_src);
+       nfsd4_send_cb_offload(copy, nfserr);
        cleanup_async_copy(copy);
        return 0;
 }
@@ -1830,8 +1795,8 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        __be32 status;
        struct nfsd4_copy *async_copy = NULL;
 
-       if (!copy->cp_intra) { /* Inter server SSC */
-               if (!inter_copy_offload_enable || copy->cp_synchronous) {
+       if (nfsd4_ssc_is_inter(copy)) {
+               if (!inter_copy_offload_enable || nfsd4_copy_is_sync(copy)) {
                        status = nfserr_notsupp;
                        goto out;
                }
@@ -1848,13 +1813,16 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        copy->cp_clp = cstate->clp;
        memcpy(&copy->fh, &cstate->current_fh.fh_handle,
                sizeof(struct knfsd_fh));
-       if (!copy->cp_synchronous) {
+       if (nfsd4_copy_is_async(copy)) {
                struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
                status = nfserrno(-ENOMEM);
                async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
                if (!async_copy)
                        goto out_err;
+               async_copy->cp_src = kmalloc(sizeof(*async_copy->cp_src), GFP_KERNEL);
+               if (!async_copy->cp_src)
+                       goto out_err;
                if (!nfs4_init_copy_state(nn, copy))
                        goto out_err;
                refcount_set(&async_copy->refcount, 1);
@@ -1872,7 +1840,9 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                wake_up_process(async_copy->copy_task);
                status = nfs_ok;
        } else {
-               status = nfsd4_do_copy(copy, 1);
+               status = nfsd4_do_copy(copy, copy->nf_src->nf_file,
+                                      copy->nf_dst->nf_file, true);
+               nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
        }
 out:
        return status;
@@ -1880,7 +1850,7 @@ out_err:
        if (async_copy)
                cleanup_async_copy(async_copy);
        status = nfserrno(-ENOMEM);
-       if (!copy->cp_intra)
+       if (nfsd4_ssc_is_inter(copy))
                nfsd4_interssc_disconnect(copy->ss_mnt);
        goto out;
 }
@@ -1953,9 +1923,9 @@ nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        /* For now, only return one server address in cpn_src, the
         * address used by the client to connect to this server.
         */
-       cn->cpn_src.nl4_type = NL4_NETADDR;
+       cn->cpn_src->nl4_type = NL4_NETADDR;
        status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr,
-                                &cn->cpn_src.u.nl4_addr);
+                                &cn->cpn_src->u.nl4_addr);
        WARN_ON_ONCE(status);
        if (status) {
                nfs4_put_cpntf_state(nn, cps);
@@ -2609,7 +2579,7 @@ check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
                                return;
                        }
                        putfh = (struct nfsd4_putfh *)&saved_op->u;
-                       if (!copy->cp_intra)
+                       if (nfsd4_ssc_is_inter(copy))
                                putfh->no_verify = true;
                }
        }
@@ -2711,7 +2681,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
                if (op->opdesc->op_flags & OP_MODIFIES_SOMETHING) {
                        /*
                         * Don't execute this op if we couldn't encode a
-                        * succesful reply:
+                        * successful reply:
                         */
                        u32 plen = op->opdesc->op_rsize_bop(rqstp, op);
                        /*
index 9409a0d..c5d199d 100644 (file)
@@ -820,9 +820,9 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
                        swap(f2, fp->fi_fds[O_RDWR]);
                spin_unlock(&fp->fi_lock);
                if (f1)
-                       nfsd_file_put(f1);
+                       nfsd_file_close(f1);
                if (f2)
-                       nfsd_file_put(f2);
+                       nfsd_file_close(f2);
        }
 }
 
@@ -1131,7 +1131,6 @@ static void block_delegations(struct knfsd_fh *fh)
 
 static struct nfs4_delegation *
 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
-                struct svc_fh *current_fh,
                 struct nfs4_clnt_odstate *odstate)
 {
        struct nfs4_delegation *dp;
@@ -1141,7 +1140,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
        n = atomic_long_inc_return(&num_delegations);
        if (n < 0 || n > max_delegations)
                goto out_dec;
-       if (delegation_blocked(&current_fh->fh_handle))
+       if (delegation_blocked(&fp->fi_fhandle))
                goto out_dec;
        dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
        if (dp == NULL)
@@ -2053,11 +2052,16 @@ STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
  * This type of memory management is somewhat inefficient, but we use it
  * anyway since SETCLIENTID is not a common operation.
  */
-static struct nfs4_client *alloc_client(struct xdr_netobj name)
+static struct nfs4_client *alloc_client(struct xdr_netobj name,
+                               struct nfsd_net *nn)
 {
        struct nfs4_client *clp;
        int i;
 
+       if (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) {
+               mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
+               return NULL;
+       }
        clp = kmem_cache_zalloc(client_slab, GFP_KERNEL);
        if (clp == NULL)
                return NULL;
@@ -2076,6 +2080,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
        atomic_set(&clp->cl_rpc_users, 0);
        clp->cl_cb_state = NFSD4_CB_UNKNOWN;
        clp->cl_state = NFSD4_ACTIVE;
+       atomic_inc(&nn->nfs4_client_count);
        atomic_set(&clp->cl_delegs_in_recall, 0);
        INIT_LIST_HEAD(&clp->cl_idhash);
        INIT_LIST_HEAD(&clp->cl_openowners);
@@ -2183,6 +2188,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
 static void
 __destroy_client(struct nfs4_client *clp)
 {
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
        int i;
        struct nfs4_openowner *oo;
        struct nfs4_delegation *dp;
@@ -2226,6 +2232,7 @@ __destroy_client(struct nfs4_client *clp)
        nfsd4_shutdown_callback(clp);
        if (clp->cl_cb_conn.cb_xprt)
                svc_xprt_put(clp->cl_cb_conn.cb_xprt);
+       atomic_add_unless(&nn->nfs4_client_count, -1, 0);
        free_client(clp);
        wake_up_all(&expiry_wq);
 }
@@ -2564,7 +2571,7 @@ static void nfs4_show_fname(struct seq_file *s, struct nfsd_file *f)
 
 static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f)
 {
-       struct inode *inode = f->nf_inode;
+       struct inode *inode = file_inode(f->nf_file);
 
        seq_printf(s, "superblock: \"%02x:%02x:%ld\"",
                                        MAJOR(inode->i_sb->s_dev),
@@ -2848,7 +2855,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        struct dentry *dentries[ARRAY_SIZE(client_files)];
 
-       clp = alloc_client(name);
+       clp = alloc_client(name, nn);
        if (clp == NULL)
                return NULL;
 
@@ -4330,6 +4337,27 @@ out:
        return -ENOMEM;
 }
 
+void nfsd4_init_leases_net(struct nfsd_net *nn)
+{
+       struct sysinfo si;
+       u64 max_clients;
+
+       nn->nfsd4_lease = 90;   /* default lease time */
+       nn->nfsd4_grace = 90;
+       nn->somebody_reclaimed = false;
+       nn->track_reclaim_completes = false;
+       nn->clverifier_counter = prandom_u32();
+       nn->clientid_base = prandom_u32();
+       nn->clientid_counter = nn->clientid_base + 1;
+       nn->s2s_cp_cl_id = nn->clientid_counter++;
+
+       atomic_set(&nn->nfs4_client_count, 0);
+       si_meminfo(&si);
+       max_clients = (u64)si.totalram * si.mem_unit / (1024 * 1024 * 1024);
+       max_clients *= NFS4_CLIENTS_PER_GB;
+       nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB);
+}
+
 static void init_nfs4_replay(struct nfs4_replay *rp)
 {
        rp->rp_status = nfserr_serverfault;
@@ -5032,11 +5060,14 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
                .ia_valid = ATTR_SIZE,
                .ia_size = 0,
        };
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &iattr,
+       };
        if (!open->op_truncate)
                return 0;
        if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
                return nfserr_inval;
-       return nfsd_setattr(rqstp, fh, &iattr, 0, (time64_t)0);
+       return nfsd_setattr(rqstp, fh, &attrs, 0, (time64_t)0);
 }
 
 static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
@@ -5104,6 +5135,7 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
                                goto out_put_access;
                        nf->nf_file = open->op_filp;
                        open->op_filp = NULL;
+                       trace_nfsd_file_create(rqstp, access, nf);
                }
 
                spin_lock(&fp->fi_lock);
@@ -5259,11 +5291,41 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
        return 0;
 }
 
+/*
+ * It's possible that between opening the dentry and setting the delegation,
+ * that it has been renamed or unlinked. Redo the lookup to verify that this
+ * hasn't happened.
+ */
+static int
+nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp,
+                         struct svc_fh *parent)
+{
+       struct svc_export *exp;
+       struct dentry *child;
+       __be32 err;
+
+       err = nfsd_lookup_dentry(open->op_rqstp, parent,
+                                open->op_fname, open->op_fnamelen,
+                                &exp, &child);
+
+       if (err)
+               return -EAGAIN;
+
+       dput(child);
+       if (child != file_dentry(fp->fi_deleg_file->nf_file))
+               return -EAGAIN;
+
+       return 0;
+}
+
 static struct nfs4_delegation *
-nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
-                   struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
+nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
+                   struct svc_fh *parent)
 {
        int status = 0;
+       struct nfs4_client *clp = stp->st_stid.sc_client;
+       struct nfs4_file *fp = stp->st_stid.sc_file;
+       struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
        struct nfs4_delegation *dp;
        struct nfsd_file *nf;
        struct file_lock *fl;
@@ -5305,7 +5367,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
                return ERR_PTR(status);
 
        status = -ENOMEM;
-       dp = alloc_init_deleg(clp, fp, fh, odstate);
+       dp = alloc_init_deleg(clp, fp, odstate);
        if (!dp)
                goto out_delegees;
 
@@ -5318,6 +5380,13 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
                locks_free_lock(fl);
        if (status)
                goto out_clnt_odstate;
+
+       if (parent) {
+               status = nfsd4_verify_deleg_dentry(open, fp, parent);
+               if (status)
+                       goto out_unlock;
+       }
+
        status = nfsd4_check_conflicting_opens(clp, fp);
        if (status)
                goto out_unlock;
@@ -5373,12 +5442,13 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
  * proper support for them.
  */
 static void
-nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
-                       struct nfs4_ol_stateid *stp)
+nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
+                    struct svc_fh *currentfh)
 {
        struct nfs4_delegation *dp;
        struct nfs4_openowner *oo = openowner(stp->st_stateowner);
        struct nfs4_client *clp = stp->st_stid.sc_client;
+       struct svc_fh *parent = NULL;
        int cb_up;
        int status = 0;
 
@@ -5392,6 +5462,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
                                goto out_no_deleg;
                        break;
                case NFS4_OPEN_CLAIM_NULL:
+                       parent = currentfh;
+                       fallthrough;
                case NFS4_OPEN_CLAIM_FH:
                        /*
                         * Let's not give out any delegations till everyone's
@@ -5406,7 +5478,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
                default:
                        goto out_no_deleg;
        }
-       dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate);
+       dp = nfs4_set_delegation(open, stp, parent);
        if (IS_ERR(dp))
                goto out_no_deleg;
 
@@ -5538,7 +5610,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
        * Attempt to hand out a delegation. No error return, because the
        * OPEN succeeds even if we fail.
        */
-       nfs4_open_delegation(current_fh, open, stp);
+       nfs4_open_delegation(open, stp, &resp->cstate.current_fh);
 nodeleg:
        status = nfs_ok;
        trace_nfsd_open(&stp->st_stid.sc_stateid);
@@ -5792,9 +5864,12 @@ static void
 nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
                                struct laundry_time *lt)
 {
+       unsigned int maxreap, reapcnt = 0;
        struct list_head *pos, *next;
        struct nfs4_client *clp;
 
+       maxreap = (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) ?
+                       NFSD_CLIENT_MAX_TRIM_PER_RUN : 0;
        INIT_LIST_HEAD(reaplist);
        spin_lock(&nn->client_lock);
        list_for_each_safe(pos, next, &nn->client_lru) {
@@ -5805,14 +5880,15 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
                        break;
                if (!atomic_read(&clp->cl_rpc_users))
                        clp->cl_state = NFSD4_COURTESY;
-               if (!client_has_state(clp) ||
-                               ktime_get_boottime_seconds() >=
-                               (clp->cl_time + NFSD_COURTESY_CLIENT_TIMEOUT))
+               if (!client_has_state(clp))
                        goto exp_client;
-               if (nfs4_anylock_blockers(clp)) {
+               if (!nfs4_anylock_blockers(clp))
+                       if (reapcnt >= maxreap)
+                               continue;
 exp_client:
-                       if (!mark_client_expired_locked(clp))
-                               list_add(&clp->cl_lru, reaplist);
+               if (!mark_client_expired_locked(clp)) {
+                       list_add(&clp->cl_lru, reaplist);
+                       reapcnt++;
                }
        }
        spin_unlock(&nn->client_lock);
@@ -7321,21 +7397,22 @@ out:
 static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
 {
        struct nfsd_file *nf;
+       struct inode *inode;
        __be32 err;
 
        err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf);
        if (err)
                return err;
-       fh_lock(fhp); /* to block new leases till after test_lock: */
-       err = nfserrno(nfsd_open_break_lease(fhp->fh_dentry->d_inode,
-                                                       NFSD_MAY_READ));
+       inode = fhp->fh_dentry->d_inode;
+       inode_lock(inode); /* to block new leases till after test_lock: */
+       err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
        if (err)
                goto out;
        lock->fl_file = nf->nf_file;
        err = nfserrno(vfs_test_lock(nf->nf_file, lock));
        lock->fl_file = NULL;
 out:
-       fh_unlock(fhp);
+       inode_unlock(inode);
        nfsd_file_put(nf);
        return err;
 }
index 2acea77..1e9690a 100644 (file)
@@ -1810,7 +1810,7 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta
        for (i = 0; i < test_stateid->ts_num_ids; i++) {
                stateid = svcxdr_tmpalloc(argp, sizeof(*stateid));
                if (!stateid)
-                       return nfserrno(-ENOMEM);       /* XXX: not jukebox? */
+                       return nfserr_jukebox;
                INIT_LIST_HEAD(&stateid->ts_id_list);
                list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
                status = nfsd4_decode_stateid4(argp, &stateid->ts_id_stateid);
@@ -1896,8 +1896,8 @@ static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
 static __be32
 nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
 {
+       u32 consecutive, i, count, sync;
        struct nl4_server *ns_dummy;
-       u32 consecutive, i, count;
        __be32 status;
 
        status = nfsd4_decode_stateid4(argp, &copy->cp_src_stateid);
@@ -1915,25 +1915,28 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
        /* ca_consecutive: we always do consecutive copies */
        if (xdr_stream_decode_u32(argp->xdr, &consecutive) < 0)
                return nfserr_bad_xdr;
-       if (xdr_stream_decode_u32(argp->xdr, &copy->cp_synchronous) < 0)
+       if (xdr_stream_decode_bool(argp->xdr, &sync) < 0)
                return nfserr_bad_xdr;
+       nfsd4_copy_set_sync(copy, sync);
 
        if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
                return nfserr_bad_xdr;
-       copy->cp_intra = false;
+       copy->cp_src = svcxdr_tmpalloc(argp, sizeof(*copy->cp_src));
+       if (copy->cp_src == NULL)
+               return nfserr_jukebox;
        if (count == 0) { /* intra-server copy */
-               copy->cp_intra = true;
+               __set_bit(NFSD4_COPY_F_INTRA, &copy->cp_flags);
                return nfs_ok;
        }
 
        /* decode all the supplied server addresses but use only the first */
-       status = nfsd4_decode_nl4_server(argp, &copy->cp_src);
+       status = nfsd4_decode_nl4_server(argp, copy->cp_src);
        if (status)
                return status;
 
        ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL);
        if (ns_dummy == NULL)
-               return nfserrno(-ENOMEM);       /* XXX: jukebox? */
+               return nfserr_jukebox;
        for (i = 0; i < count - 1; i++) {
                status = nfsd4_decode_nl4_server(argp, ns_dummy);
                if (status) {
@@ -1952,10 +1955,17 @@ nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
 {
        __be32 status;
 
+       cn->cpn_src = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_src));
+       if (cn->cpn_src == NULL)
+               return nfserr_jukebox;
+       cn->cpn_dst = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_dst));
+       if (cn->cpn_dst == NULL)
+               return nfserr_jukebox;
+
        status = nfsd4_decode_stateid4(argp, &cn->cpn_src_stateid);
        if (status)
                return status;
-       return nfsd4_decode_nl4_server(argp, &cn->cpn_dst);
+       return nfsd4_decode_nl4_server(argp, cn->cpn_dst);
 }
 
 static __be32
@@ -2828,10 +2838,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        struct kstat stat;
        struct svc_fh *tempfh = NULL;
        struct kstatfs statfs;
-       __be32 *p;
+       __be32 *p, *attrlen_p;
        int starting_len = xdr->buf->len;
        int attrlen_offset;
-       __be32 attrlen;
        u32 dummy;
        u64 dummy64;
        u32 rdattr_err = 0;
@@ -2919,10 +2928,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
                goto out;
 
        attrlen_offset = xdr->buf->len;
-       p = xdr_reserve_space(xdr, 4);
-       if (!p)
+       attrlen_p = xdr_reserve_space(xdr, XDR_UNIT);
+       if (!attrlen_p)
                goto out_resource;
-       p++;                /* to be backfilled later */
 
        if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
                u32 supp[3];
@@ -3344,8 +3352,7 @@ out_acl:
                *p++ = cpu_to_be32(err == 0);
        }
 
-       attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
-       write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
+       *attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT);
        status = nfs_ok;
 
 out:
@@ -3882,16 +3889,15 @@ static __be32 nfsd4_encode_splice_read(
        struct xdr_stream *xdr = resp->xdr;
        struct xdr_buf *buf = xdr->buf;
        int status, space_left;
-       u32 eof;
        __be32 nfserr;
-       __be32 *p = xdr->p - 2;
 
        /* Make sure there will be room for padding if needed */
        if (xdr->end - xdr->p < 1)
                return nfserr_resource;
 
        nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
-                                 file, read->rd_offset, &maxcount, &eof);
+                                 file, read->rd_offset, &maxcount,
+                                 &read->rd_eof);
        read->rd_length = maxcount;
        if (nfserr)
                goto out_err;
@@ -3902,9 +3908,6 @@ static __be32 nfsd4_encode_splice_read(
                goto out_err;
        }
 
-       *(p++) = htonl(eof);
-       *(p++) = htonl(maxcount);
-
        buf->page_len = maxcount;
        buf->len += maxcount;
        xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1)
@@ -3946,11 +3949,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
                                 struct file *file, unsigned long maxcount)
 {
        struct xdr_stream *xdr = resp->xdr;
-       u32 eof;
-       int starting_len = xdr->buf->len - 8;
+       unsigned int starting_len = xdr->buf->len;
+       __be32 zero = xdr_zero;
        __be32 nfserr;
-       __be32 tmp;
-       int pad;
 
        read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount);
        if (read->rd_vlen < 0)
@@ -3958,31 +3959,24 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
 
        nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
                            resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
-                           &eof);
+                           &read->rd_eof);
        read->rd_length = maxcount;
        if (nfserr)
                return nfserr;
-       if (svc_encode_result_payload(resp->rqstp, starting_len + 8, maxcount))
+       if (svc_encode_result_payload(resp->rqstp, starting_len, maxcount))
                return nfserr_io;
-       xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount));
-
-       tmp = htonl(eof);
-       write_bytes_to_xdr_buf(xdr->buf, starting_len    , &tmp, 4);
-       tmp = htonl(maxcount);
-       write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
-
-       tmp = xdr_zero;
-       pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
-       write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
-                                                               &tmp, pad);
-       return 0;
+       xdr_truncate_encode(xdr, starting_len + xdr_align_size(maxcount));
 
+       write_bytes_to_xdr_buf(xdr->buf, starting_len + maxcount, &zero,
+                              xdr_pad_size(maxcount));
+       return nfs_ok;
 }
 
 static __be32
 nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
                  struct nfsd4_read *read)
 {
+       bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
        unsigned long maxcount;
        struct xdr_stream *xdr = resp->xdr;
        struct file *file;
@@ -3995,11 +3989,10 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
 
        p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
        if (!p) {
-               WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
+               WARN_ON_ONCE(splice_ok);
                return nfserr_resource;
        }
-       if (resp->xdr->buf->page_len &&
-           test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
+       if (resp->xdr->buf->page_len && splice_ok) {
                WARN_ON_ONCE(1);
                return nfserr_resource;
        }
@@ -4008,31 +4001,30 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
        maxcount = min_t(unsigned long, read->rd_length,
                         (xdr->buf->buflen - xdr->buf->len));
 
-       if (file->f_op->splice_read &&
-           test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
+       if (file->f_op->splice_read && splice_ok)
                nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
        else
                nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
-
-       if (nfserr)
+       if (nfserr) {
                xdr_truncate_encode(xdr, starting_len);
+               return nfserr;
+       }
 
-       return nfserr;
+       p = xdr_encode_bool(p, read->rd_eof);
+       *p = cpu_to_be32(read->rd_length);
+       return nfs_ok;
 }
 
 static __be32
 nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
 {
-       int maxcount;
-       __be32 wire_count;
-       int zero = 0;
+       __be32 *p, *maxcount_p, zero = xdr_zero;
        struct xdr_stream *xdr = resp->xdr;
        int length_offset = xdr->buf->len;
-       int status;
-       __be32 *p;
+       int maxcount, status;
 
-       p = xdr_reserve_space(xdr, 4);
-       if (!p)
+       maxcount_p = xdr_reserve_space(xdr, XDR_UNIT);
+       if (!maxcount_p)
                return nfserr_resource;
        maxcount = PAGE_SIZE;
 
@@ -4057,14 +4049,11 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
                nfserr = nfserrno(status);
                goto out_err;
        }
-
-       wire_count = htonl(maxcount);
-       write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4);
-       xdr_truncate_encode(xdr, length_offset + 4 + ALIGN(maxcount, 4));
-       if (maxcount & 3)
-               write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
-                                               &zero, 4 - (maxcount&3));
-       return 0;
+       *maxcount_p = cpu_to_be32(maxcount);
+       xdr_truncate_encode(xdr, length_offset + 4 + xdr_align_size(maxcount));
+       write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, &zero,
+                              xdr_pad_size(maxcount));
+       return nfs_ok;
 
 out_err:
        xdr_truncate_encode(xdr, length_offset);
@@ -4715,13 +4704,13 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
        __be32 *p;
 
        nfserr = nfsd42_encode_write_res(resp, &copy->cp_res,
-                                        !!copy->cp_synchronous);
+                                        nfsd4_copy_is_sync(copy));
        if (nfserr)
                return nfserr;
 
        p = xdr_reserve_space(resp->xdr, 4 + 4);
        *p++ = xdr_one; /* cr_consecutive */
-       *p++ = cpu_to_be32(copy->cp_synchronous);
+       *p = nfsd4_copy_is_sync(copy) ? xdr_one : xdr_zero;
        return 0;
 }
 
@@ -4919,7 +4908,8 @@ nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
 
        *p++ = cpu_to_be32(1);
 
-       return nfsd42_encode_nl4_server(resp, &cn->cpn_src);
+       nfserr = nfsd42_encode_nl4_server(resp, cn->cpn_src);
+       return nfserr;
 }
 
 static __be32
@@ -5373,8 +5363,7 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
                                                so->so_replay.rp_buf, len);
        }
 status:
-       /* Note that op->status is already in network byte order: */
-       write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4);
+       *p = op->status;
 }
 
 /* 
index 0621c2f..917fa18 100644 (file)
@@ -25,6 +25,7 @@
 #include "state.h"
 #include "netns.h"
 #include "pnfs.h"
+#include "filecache.h"
 
 /*
  *     We have a single directory with several nodes in it.
@@ -45,6 +46,7 @@ enum {
        NFSD_Ports,
        NFSD_MaxBlkSize,
        NFSD_MaxConnections,
+       NFSD_Filecache,
        NFSD_SupportedEnctypes,
        /*
         * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
@@ -229,6 +231,13 @@ static const struct file_operations reply_cache_stats_operations = {
        .release        = single_release,
 };
 
+static const struct file_operations filecache_ops = {
+       .open           = nfsd_file_cache_stats_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*----------------------------------------------------------------------------*/
 /*
  * payload - write methods
@@ -633,7 +642,6 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
        }
 
        /* Now write current state into reply buffer */
-       len = 0;
        sep = "";
        remaining = SIMPLE_TRANSACTION_LIMIT;
        for (num=2 ; num <= 4 ; num++) {
@@ -1371,6 +1379,7 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc)
                [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
                [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
                [NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO},
+               [NFSD_Filecache] = {"filecache", &filecache_ops, S_IRUGO},
 #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
                [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
 #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
@@ -1475,14 +1484,7 @@ static __net_init int nfsd_init_net(struct net *net)
        retval = nfsd_reply_cache_init(nn);
        if (retval)
                goto out_drc_error;
-       nn->nfsd4_lease = 90;   /* default lease time */
-       nn->nfsd4_grace = 90;
-       nn->somebody_reclaimed = false;
-       nn->track_reclaim_completes = false;
-       nn->clverifier_counter = prandom_u32();
-       nn->clientid_base = prandom_u32();
-       nn->clientid_counter = nn->clientid_base + 1;
-       nn->s2s_cp_cl_id = nn->clientid_counter++;
+       nfsd4_init_leases_net(nn);
 
        get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
        seqlock_init(&nn->writeverf_lock);
@@ -1517,7 +1519,6 @@ static struct pernet_operations nfsd_net_ops = {
 static int __init init_nfsd(void)
 {
        int retval;
-       printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
        retval = nfsd4_init_slabs();
        if (retval)
index 9a8b09a..57a468e 100644 (file)
@@ -341,6 +341,8 @@ void                nfsd_lockd_shutdown(void);
 
 #define NFSD_LAUNDROMAT_MINTIMEOUT      1   /* seconds */
 #define        NFSD_COURTESY_CLIENT_TIMEOUT    (24 * 60 * 60)  /* seconds */
+#define        NFSD_CLIENT_MAX_TRIM_PER_RUN    128
+#define        NFS4_CLIENTS_PER_GB             1024
 
 /*
  * The following attributes are currently not supported by the NFSv4 server:
@@ -496,12 +498,16 @@ extern void unregister_cld_notifier(void);
 extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn);
 #endif
 
+extern void nfsd4_init_leases_net(struct nfsd_net *nn);
+
 #else /* CONFIG_NFSD_V4 */
 static inline int nfsd4_is_junction(struct dentry *dentry)
 {
        return 0;
 }
 
+static inline void nfsd4_init_leases_net(struct nfsd_net *nn) {};
+
 #define register_cld_notifier() 0
 #define unregister_cld_notifier() do { } while(0)
 
index c29baa0..a5b7152 100644 (file)
@@ -331,8 +331,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
        struct dentry   *dentry;
        __be32          error;
 
-       dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
-
        if (!fhp->fh_dentry) {
                error = nfsd_set_fh_dentry(rqstp, fhp);
                if (error)
@@ -340,6 +338,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
        }
        dentry = fhp->fh_dentry;
        exp = fhp->fh_export;
+
+       trace_nfsd_fh_verify(rqstp, fhp, type, access);
+
        /*
         * We still have to do all these permission checks, even when
         * fh_dentry is already set:
@@ -548,7 +549,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
        if (ref_fh == fhp)
                fh_put(ref_fh);
 
-       if (fhp->fh_locked || fhp->fh_dentry) {
+       if (fhp->fh_dentry) {
                printk(KERN_ERR "fh_compose: fh %pd2 not initialized!\n",
                       dentry);
        }
@@ -671,6 +672,25 @@ void fh_fill_post_attrs(struct svc_fh *fhp)
                        nfsd4_change_attribute(&fhp->fh_post_attr, inode);
 }
 
+/**
+ * fh_fill_both_attrs - Fill pre-op and post-op attributes
+ * @fhp: file handle to be updated
+ *
+ * This is used when the directory wasn't changed, but wcc attributes
+ * are needed anyway.
+ */
+void fh_fill_both_attrs(struct svc_fh *fhp)
+{
+       fh_fill_post_attrs(fhp);
+       if (!fhp->fh_post_saved)
+               return;
+       fhp->fh_pre_change = fhp->fh_post_change;
+       fhp->fh_pre_mtime = fhp->fh_post_attr.mtime;
+       fhp->fh_pre_ctime = fhp->fh_post_attr.ctime;
+       fhp->fh_pre_size = fhp->fh_post_attr.size;
+       fhp->fh_pre_saved = true;
+}
+
 /*
  * Release a file handle.
  */
@@ -680,7 +700,6 @@ fh_put(struct svc_fh *fhp)
        struct dentry * dentry = fhp->fh_dentry;
        struct svc_export * exp = fhp->fh_export;
        if (dentry) {
-               fh_unlock(fhp);
                fhp->fh_dentry = NULL;
                dput(dentry);
                fh_clear_pre_post_attrs(fhp);
index fb9d358..c3ae641 100644 (file)
@@ -81,7 +81,6 @@ typedef struct svc_fh {
        struct dentry *         fh_dentry;      /* validated dentry */
        struct svc_export *     fh_export;      /* export pointer */
 
-       bool                    fh_locked;      /* inode locked by us */
        bool                    fh_want_write;  /* remount protection taken */
        bool                    fh_no_wcc;      /* no wcc data needed */
        bool                    fh_no_atomic_attr;
@@ -93,7 +92,7 @@ typedef struct svc_fh {
        bool                    fh_post_saved;  /* post-op attrs saved */
        bool                    fh_pre_saved;   /* pre-op attrs saved */
 
-       /* Pre-op attributes saved during fh_lock */
+       /* Pre-op attributes saved when inode is locked */
        __u64                   fh_pre_size;    /* size before operation */
        struct timespec64       fh_pre_mtime;   /* mtime before oper */
        struct timespec64       fh_pre_ctime;   /* ctime before oper */
@@ -103,7 +102,7 @@ typedef struct svc_fh {
         */
        u64                     fh_pre_change;
 
-       /* Post-op attributes saved in fh_unlock */
+       /* Post-op attributes saved in fh_fill_post_attrs() */
        struct kstat            fh_post_attr;   /* full attrs after operation */
        u64                     fh_post_change; /* nfsv4 change; see above */
 } svc_fh;
@@ -223,8 +222,8 @@ void        fh_put(struct svc_fh *);
 static __inline__ struct svc_fh *
 fh_copy(struct svc_fh *dst, struct svc_fh *src)
 {
-       WARN_ON(src->fh_dentry || src->fh_locked);
-                       
+       WARN_ON(src->fh_dentry);
+
        *dst = *src;
        return dst;
 }
@@ -322,52 +321,5 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
 
 extern void fh_fill_pre_attrs(struct svc_fh *fhp);
 extern void fh_fill_post_attrs(struct svc_fh *fhp);
-
-
-/*
- * Lock a file handle/inode
- * NOTE: both fh_lock and fh_unlock are done "by hand" in
- * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once
- * so, any changes here should be reflected there.
- */
-
-static inline void
-fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
-{
-       struct dentry   *dentry = fhp->fh_dentry;
-       struct inode    *inode;
-
-       BUG_ON(!dentry);
-
-       if (fhp->fh_locked) {
-               printk(KERN_WARNING "fh_lock: %pd2 already locked!\n",
-                       dentry);
-               return;
-       }
-
-       inode = d_inode(dentry);
-       inode_lock_nested(inode, subclass);
-       fh_fill_pre_attrs(fhp);
-       fhp->fh_locked = true;
-}
-
-static inline void
-fh_lock(struct svc_fh *fhp)
-{
-       fh_lock_nested(fhp, I_MUTEX_NORMAL);
-}
-
-/*
- * Unlock a file handle/inode
- */
-static inline void
-fh_unlock(struct svc_fh *fhp)
-{
-       if (fhp->fh_locked) {
-               fh_fill_post_attrs(fhp);
-               inode_unlock(d_inode(fhp->fh_dentry));
-               fhp->fh_locked = false;
-       }
-}
-
+extern void fh_fill_both_attrs(struct svc_fh *fhp);
 #endif /* _LINUX_NFSD_NFSFH_H */
index fcdab8a..7381972 100644 (file)
@@ -51,6 +51,9 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
        struct nfsd_sattrargs *argp = rqstp->rq_argp;
        struct nfsd_attrstat *resp = rqstp->rq_resp;
        struct iattr *iap = &argp->attrs;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = iap,
+       };
        struct svc_fh *fhp;
 
        dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
@@ -100,7 +103,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
                }
        }
 
-       resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
+       resp->status = nfsd_setattr(rqstp, fhp, &attrs, 0, (time64_t)0);
        if (resp->status != nfs_ok)
                goto out;
 
@@ -260,6 +263,9 @@ nfsd_proc_create(struct svc_rqst *rqstp)
        svc_fh          *dirfhp = &argp->fh;
        svc_fh          *newfhp = &resp->fh;
        struct iattr    *attr = &argp->attrs;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = attr,
+       };
        struct inode    *inode;
        struct dentry   *dchild;
        int             type, mode;
@@ -285,7 +291,7 @@ nfsd_proc_create(struct svc_rqst *rqstp)
                goto done;
        }
 
-       fh_lock_nested(dirfhp, I_MUTEX_PARENT);
+       inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT);
        dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
        if (IS_ERR(dchild)) {
                resp->status = nfserrno(PTR_ERR(dchild));
@@ -385,7 +391,7 @@ nfsd_proc_create(struct svc_rqst *rqstp)
        if (!inode) {
                /* File doesn't exist. Create it and set attrs */
                resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
-                                                 argp->len, attr, type, rdev,
+                                                 argp->len, &attrs, type, rdev,
                                                  newfhp);
        } else if (type == S_IFREG) {
                dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
@@ -396,13 +402,12 @@ nfsd_proc_create(struct svc_rqst *rqstp)
                 */
                attr->ia_valid &= ATTR_SIZE;
                if (attr->ia_valid)
-                       resp->status = nfsd_setattr(rqstp, newfhp, attr, 0,
+                       resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 0,
                                                    (time64_t)0);
        }
 
 out_unlock:
-       /* We don't really need to unlock, as fh_put does it. */
-       fh_unlock(dirfhp);
+       inode_unlock(dirfhp->fh_dentry->d_inode);
        fh_drop_write(dirfhp);
 done:
        fh_put(dirfhp);
@@ -472,6 +477,9 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
 {
        struct nfsd_symlinkargs *argp = rqstp->rq_argp;
        struct nfsd_stat *resp = rqstp->rq_resp;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &argp->attrs,
+       };
        struct svc_fh   newfh;
 
        if (argp->tlen > NFS_MAXPATHLEN) {
@@ -493,7 +501,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
 
        fh_init(&newfh, NFS_FHSIZE);
        resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
-                                   argp->tname, &newfh);
+                                   argp->tname, &attrs, &newfh);
 
        kfree(argp->tname);
        fh_put(&argp->ffh);
@@ -511,6 +519,9 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
 {
        struct nfsd_createargs *argp = rqstp->rq_argp;
        struct nfsd_diropres *resp = rqstp->rq_resp;
+       struct nfsd_attrs attrs = {
+               .na_iattr       = &argp->attrs,
+       };
 
        dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
 
@@ -522,7 +533,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
        argp->attrs.ia_valid &= ~ATTR_SIZE;
        fh_init(&resp->fh, NFS_FHSIZE);
        resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
-                                  &argp->attrs, S_IFDIR, 0, &resp->fh);
+                                  &attrs, S_IFDIR, 0, &resp->fh);
        fh_put(&argp->fh);
        if (resp->status != nfs_ok)
                goto out;
index f3d6313..ae596db 100644 (file)
@@ -703,7 +703,6 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
 extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);
 
 void put_nfs4_file(struct nfs4_file *fi);
-extern void nfs4_put_copy(struct nfsd4_copy *copy);
 extern struct nfsd4_copy *
 find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
 extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
index a60ead3..9ebd67d 100644 (file)
@@ -171,6 +171,52 @@ TRACE_EVENT(nfsd_compound_encode_err,
                __entry->opnum, __entry->status)
 );
 
+#define show_fs_file_type(x) \
+       __print_symbolic(x, \
+               { S_IFLNK,              "LNK" }, \
+               { S_IFREG,              "REG" }, \
+               { S_IFDIR,              "DIR" }, \
+               { S_IFCHR,              "CHR" }, \
+               { S_IFBLK,              "BLK" }, \
+               { S_IFIFO,              "FIFO" }, \
+               { S_IFSOCK,             "SOCK" })
+
+TRACE_EVENT(nfsd_fh_verify,
+       TP_PROTO(
+               const struct svc_rqst *rqstp,
+               const struct svc_fh *fhp,
+               umode_t type,
+               int access
+       ),
+       TP_ARGS(rqstp, fhp, type, access),
+       TP_STRUCT__entry(
+               __field(unsigned int, netns_ino)
+               __sockaddr(server, rqstp->rq_xprt->xpt_remotelen)
+               __sockaddr(client, rqstp->rq_xprt->xpt_remotelen)
+               __field(u32, xid)
+               __field(u32, fh_hash)
+               __field(void *, inode)
+               __field(unsigned long, type)
+               __field(unsigned long, access)
+       ),
+       TP_fast_assign(
+               __entry->netns_ino = SVC_NET(rqstp)->ns.inum;
+               __assign_sockaddr(server, &rqstp->rq_xprt->xpt_local,
+                      rqstp->rq_xprt->xpt_locallen);
+               __assign_sockaddr(client, &rqstp->rq_xprt->xpt_remote,
+                                 rqstp->rq_xprt->xpt_remotelen);
+               __entry->xid = be32_to_cpu(rqstp->rq_xid);
+               __entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
+               __entry->inode = d_inode(fhp->fh_dentry);
+               __entry->type = type;
+               __entry->access = access;
+       ),
+       TP_printk("xid=0x%08x fh_hash=0x%08x inode=%p type=%s access=%s",
+               __entry->xid, __entry->fh_hash, __entry->inode,
+               show_fs_file_type(__entry->type),
+               show_nfsd_may_flags(__entry->access)
+       )
+);
 
 DECLARE_EVENT_CLASS(nfsd_fh_err_class,
        TP_PROTO(struct svc_rqst *rqstp,
@@ -696,15 +742,12 @@ DEFINE_CLID_EVENT(confirmed_r);
        __print_flags(val, "|",                                         \
                { 1 << NFSD_FILE_HASHED,        "HASHED" },             \
                { 1 << NFSD_FILE_PENDING,       "PENDING" },            \
-               { 1 << NFSD_FILE_BREAK_READ,    "BREAK_READ" },         \
-               { 1 << NFSD_FILE_BREAK_WRITE,   "BREAK_WRITE" },        \
                { 1 << NFSD_FILE_REFERENCED,    "REFERENCED"})
 
 DECLARE_EVENT_CLASS(nfsd_file_class,
        TP_PROTO(struct nfsd_file *nf),
        TP_ARGS(nf),
        TP_STRUCT__entry(
-               __field(unsigned int, nf_hashval)
                __field(void *, nf_inode)
                __field(int, nf_ref)
                __field(unsigned long, nf_flags)
@@ -712,15 +755,13 @@ DECLARE_EVENT_CLASS(nfsd_file_class,
                __field(struct file *, nf_file)
        ),
        TP_fast_assign(
-               __entry->nf_hashval = nf->nf_hashval;
                __entry->nf_inode = nf->nf_inode;
                __entry->nf_ref = refcount_read(&nf->nf_ref);
                __entry->nf_flags = nf->nf_flags;
                __entry->nf_may = nf->nf_may;
                __entry->nf_file = nf->nf_file;
        ),
-       TP_printk("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p",
-               __entry->nf_hashval,
+       TP_printk("inode=%p ref=%d flags=%s may=%s nf_file=%p",
                __entry->nf_inode,
                __entry->nf_ref,
                show_nf_flags(__entry->nf_flags),
@@ -733,34 +774,59 @@ DEFINE_EVENT(nfsd_file_class, name, \
        TP_PROTO(struct nfsd_file *nf), \
        TP_ARGS(nf))
 
-DEFINE_NFSD_FILE_EVENT(nfsd_file_alloc);
 DEFINE_NFSD_FILE_EVENT(nfsd_file_put_final);
 DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash);
 DEFINE_NFSD_FILE_EVENT(nfsd_file_put);
-DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_release_locked);
+DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_dispose);
+
+TRACE_EVENT(nfsd_file_alloc,
+       TP_PROTO(
+               const struct nfsd_file *nf
+       ),
+       TP_ARGS(nf),
+       TP_STRUCT__entry(
+               __field(const void *, nf_inode)
+               __field(unsigned long, nf_flags)
+               __field(unsigned long, nf_may)
+               __field(unsigned int, nf_ref)
+       ),
+       TP_fast_assign(
+               __entry->nf_inode = nf->nf_inode;
+               __entry->nf_flags = nf->nf_flags;
+               __entry->nf_ref = refcount_read(&nf->nf_ref);
+               __entry->nf_may = nf->nf_may;
+       ),
+       TP_printk("inode=%p ref=%u flags=%s may=%s",
+               __entry->nf_inode, __entry->nf_ref,
+               show_nf_flags(__entry->nf_flags),
+               show_nfsd_may_flags(__entry->nf_may)
+       )
+);
 
 TRACE_EVENT(nfsd_file_acquire,
-       TP_PROTO(struct svc_rqst *rqstp, unsigned int hash,
-                struct inode *inode, unsigned int may_flags,
-                struct nfsd_file *nf, __be32 status),
+       TP_PROTO(
+               const struct svc_rqst *rqstp,
+               const struct inode *inode,
+               unsigned int may_flags,
+               const struct nfsd_file *nf,
+               __be32 status
+       ),
 
-       TP_ARGS(rqstp, hash, inode, may_flags, nf, status),
+       TP_ARGS(rqstp, inode, may_flags, nf, status),
 
        TP_STRUCT__entry(
                __field(u32, xid)
-               __field(unsigned int, hash)
-               __field(void *, inode)
+               __field(const void *, inode)
                __field(unsigned long, may_flags)
-               __field(int, nf_ref)
+               __field(unsigned int, nf_ref)
                __field(unsigned long, nf_flags)
                __field(unsigned long, nf_may)
-               __field(struct file *, nf_file)
+               __field(const void *, nf_file)
                __field(u32, status)
        ),
 
        TP_fast_assign(
                __entry->xid = be32_to_cpu(rqstp->rq_xid);
-               __entry->hash = hash;
                __entry->inode = inode;
                __entry->may_flags = may_flags;
                __entry->nf_ref = nf ? refcount_read(&nf->nf_ref) : 0;
@@ -770,19 +836,117 @@ TRACE_EVENT(nfsd_file_acquire,
                __entry->status = be32_to_cpu(status);
        ),
 
-       TP_printk("xid=0x%x hash=0x%x inode=%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=%p status=%u",
-                       __entry->xid, __entry->hash, __entry->inode,
+       TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p status=%u",
+                       __entry->xid, __entry->inode,
                        show_nfsd_may_flags(__entry->may_flags),
                        __entry->nf_ref, show_nf_flags(__entry->nf_flags),
                        show_nfsd_may_flags(__entry->nf_may),
-                       __entry->nf_file, __entry->status)
+                       __entry->nf_file, __entry->status
+       )
+);
+
+TRACE_EVENT(nfsd_file_create,
+       TP_PROTO(
+               const struct svc_rqst *rqstp,
+               unsigned int may_flags,
+               const struct nfsd_file *nf
+       ),
+
+       TP_ARGS(rqstp, may_flags, nf),
+
+       TP_STRUCT__entry(
+               __field(const void *, nf_inode)
+               __field(const void *, nf_file)
+               __field(unsigned long, may_flags)
+               __field(unsigned long, nf_flags)
+               __field(unsigned long, nf_may)
+               __field(unsigned int, nf_ref)
+               __field(u32, xid)
+       ),
+
+       TP_fast_assign(
+               __entry->nf_inode = nf->nf_inode;
+               __entry->nf_file = nf->nf_file;
+               __entry->may_flags = may_flags;
+               __entry->nf_flags = nf->nf_flags;
+               __entry->nf_may = nf->nf_may;
+               __entry->nf_ref = refcount_read(&nf->nf_ref);
+               __entry->xid = be32_to_cpu(rqstp->rq_xid);
+       ),
+
+       TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p",
+               __entry->xid, __entry->nf_inode,
+               show_nfsd_may_flags(__entry->may_flags),
+               __entry->nf_ref, show_nf_flags(__entry->nf_flags),
+               show_nfsd_may_flags(__entry->nf_may), __entry->nf_file
+       )
+);
+
+TRACE_EVENT(nfsd_file_insert_err,
+       TP_PROTO(
+               const struct svc_rqst *rqstp,
+               const struct inode *inode,
+               unsigned int may_flags,
+               long error
+       ),
+       TP_ARGS(rqstp, inode, may_flags, error),
+       TP_STRUCT__entry(
+               __field(u32, xid)
+               __field(const void *, inode)
+               __field(unsigned long, may_flags)
+               __field(long, error)
+       ),
+       TP_fast_assign(
+               __entry->xid = be32_to_cpu(rqstp->rq_xid);
+               __entry->inode = inode;
+               __entry->may_flags = may_flags;
+               __entry->error = error;
+       ),
+       TP_printk("xid=0x%x inode=%p may_flags=%s error=%ld",
+               __entry->xid, __entry->inode,
+               show_nfsd_may_flags(__entry->may_flags),
+               __entry->error
+       )
+);
+
+TRACE_EVENT(nfsd_file_cons_err,
+       TP_PROTO(
+               const struct svc_rqst *rqstp,
+               const struct inode *inode,
+               unsigned int may_flags,
+               const struct nfsd_file *nf
+       ),
+       TP_ARGS(rqstp, inode, may_flags, nf),
+       TP_STRUCT__entry(
+               __field(u32, xid)
+               __field(const void *, inode)
+               __field(unsigned long, may_flags)
+               __field(unsigned int, nf_ref)
+               __field(unsigned long, nf_flags)
+               __field(unsigned long, nf_may)
+               __field(const void *, nf_file)
+       ),
+       TP_fast_assign(
+               __entry->xid = be32_to_cpu(rqstp->rq_xid);
+               __entry->inode = inode;
+               __entry->may_flags = may_flags;
+               __entry->nf_ref = refcount_read(&nf->nf_ref);
+               __entry->nf_flags = nf->nf_flags;
+               __entry->nf_may = nf->nf_may;
+               __entry->nf_file = nf->nf_file;
+       ),
+       TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p",
+               __entry->xid, __entry->inode,
+               show_nfsd_may_flags(__entry->may_flags), __entry->nf_ref,
+               show_nf_flags(__entry->nf_flags),
+               show_nfsd_may_flags(__entry->nf_may), __entry->nf_file
+       )
 );
 
 TRACE_EVENT(nfsd_file_open,
        TP_PROTO(struct nfsd_file *nf, __be32 status),
        TP_ARGS(nf, status),
        TP_STRUCT__entry(
-               __field(unsigned int, nf_hashval)
                __field(void *, nf_inode)       /* cannot be dereferenced */
                __field(int, nf_ref)
                __field(unsigned long, nf_flags)
@@ -790,15 +954,13 @@ TRACE_EVENT(nfsd_file_open,
                __field(void *, nf_file)        /* cannot be dereferenced */
        ),
        TP_fast_assign(
-               __entry->nf_hashval = nf->nf_hashval;
                __entry->nf_inode = nf->nf_inode;
                __entry->nf_ref = refcount_read(&nf->nf_ref);
                __entry->nf_flags = nf->nf_flags;
                __entry->nf_may = nf->nf_may;
                __entry->nf_file = nf->nf_file;
        ),
-       TP_printk("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p",
-               __entry->nf_hashval,
+       TP_printk("inode=%p ref=%d flags=%s may=%s file=%p",
                __entry->nf_inode,
                __entry->nf_ref,
                show_nf_flags(__entry->nf_flags),
@@ -807,30 +969,53 @@ TRACE_EVENT(nfsd_file_open,
 )
 
 DECLARE_EVENT_CLASS(nfsd_file_search_class,
-       TP_PROTO(struct inode *inode, unsigned int hash, int found),
-       TP_ARGS(inode, hash, found),
+       TP_PROTO(
+               const struct inode *inode,
+               unsigned int count
+       ),
+       TP_ARGS(inode, count),
        TP_STRUCT__entry(
-               __field(struct inode *, inode)
-               __field(unsigned int, hash)
-               __field(int, found)
+               __field(const struct inode *, inode)
+               __field(unsigned int, count)
        ),
        TP_fast_assign(
                __entry->inode = inode;
-               __entry->hash = hash;
-               __entry->found = found;
+               __entry->count = count;
        ),
-       TP_printk("hash=0x%x inode=%p found=%d", __entry->hash,
-                       __entry->inode, __entry->found)
+       TP_printk("inode=%p count=%u",
+               __entry->inode, __entry->count)
 );
 
 #define DEFINE_NFSD_FILE_SEARCH_EVENT(name)                            \
 DEFINE_EVENT(nfsd_file_search_class, name,                             \
-       TP_PROTO(struct inode *inode, unsigned int hash, int found),    \
-       TP_ARGS(inode, hash, found))
+       TP_PROTO(                                                       \
+               const struct inode *inode,                              \
+               unsigned int count                                      \
+       ),                                                              \
+       TP_ARGS(inode, count))
 
 DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode_sync);
 DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode);
-DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_is_cached);
+
+TRACE_EVENT(nfsd_file_is_cached,
+       TP_PROTO(
+               const struct inode *inode,
+               int found
+       ),
+       TP_ARGS(inode, found),
+       TP_STRUCT__entry(
+               __field(const struct inode *, inode)
+               __field(int, found)
+       ),
+       TP_fast_assign(
+               __entry->inode = inode;
+               __entry->found = found;
+       ),
+       TP_printk("inode=%p is %scached",
+               __entry->inode,
+               __entry->found ? "" : "not "
+       )
+);
 
 TRACE_EVENT(nfsd_file_fsnotify_handle_event,
        TP_PROTO(struct inode *inode, u32 mask),
@@ -851,6 +1036,76 @@ TRACE_EVENT(nfsd_file_fsnotify_handle_event,
                        __entry->nlink, __entry->mode, __entry->mask)
 );
 
+DECLARE_EVENT_CLASS(nfsd_file_gc_class,
+       TP_PROTO(
+               const struct nfsd_file *nf
+       ),
+       TP_ARGS(nf),
+       TP_STRUCT__entry(
+               __field(void *, nf_inode)
+               __field(void *, nf_file)
+               __field(int, nf_ref)
+               __field(unsigned long, nf_flags)
+       ),
+       TP_fast_assign(
+               __entry->nf_inode = nf->nf_inode;
+               __entry->nf_file = nf->nf_file;
+               __entry->nf_ref = refcount_read(&nf->nf_ref);
+               __entry->nf_flags = nf->nf_flags;
+       ),
+       TP_printk("inode=%p ref=%d nf_flags=%s nf_file=%p",
+               __entry->nf_inode, __entry->nf_ref,
+               show_nf_flags(__entry->nf_flags),
+               __entry->nf_file
+       )
+);
+
+#define DEFINE_NFSD_FILE_GC_EVENT(name)                                        \
+DEFINE_EVENT(nfsd_file_gc_class, name,                                 \
+       TP_PROTO(                                                       \
+               const struct nfsd_file *nf                              \
+       ),                                                              \
+       TP_ARGS(nf))
+
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add_disposed);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del_disposed);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_hashed);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed);
+
+DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class,
+       TP_PROTO(
+               unsigned long removed,
+               unsigned long remaining
+       ),
+       TP_ARGS(removed, remaining),
+       TP_STRUCT__entry(
+               __field(unsigned long, removed)
+               __field(unsigned long, remaining)
+       ),
+       TP_fast_assign(
+               __entry->removed = removed;
+               __entry->remaining = remaining;
+       ),
+       TP_printk("%lu entries removed, %lu remaining",
+               __entry->removed, __entry->remaining)
+);
+
+#define DEFINE_NFSD_FILE_LRUWALK_EVENT(name)                           \
+DEFINE_EVENT(nfsd_file_lruwalk_class, name,                            \
+       TP_PROTO(                                                       \
+               unsigned long removed,                                  \
+               unsigned long remaining                                 \
+       ),                                                              \
+       TP_ARGS(removed, remaining))
+
+DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed);
+DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed);
+
 #include "cache.h"
 
 TRACE_DEFINE_ENUM(RC_DROPIT);
index d79db56..9f486b7 100644 (file)
@@ -199,27 +199,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
                                goto out_nfserr;
                }
        } else {
-               /*
-                * In the nfsd4_open() case, this may be held across
-                * subsequent open and delegation acquisition which may
-                * need to take the child's i_mutex:
-                */
-               fh_lock_nested(fhp, I_MUTEX_PARENT);
-               dentry = lookup_one_len(name, dparent, len);
+               dentry = lookup_one_len_unlocked(name, dparent, len);
                host_err = PTR_ERR(dentry);
                if (IS_ERR(dentry))
                        goto out_nfserr;
                if (nfsd_mountpoint(dentry, exp)) {
-                       /*
-                        * We don't need the i_mutex after all.  It's
-                        * still possible we could open this (regular
-                        * files can be mountpoints too), but the
-                        * i_mutex is just there to prevent renames of
-                        * something that we might be about to delegate,
-                        * and a mountpoint won't be renamed:
-                        */
-                       fh_unlock(fhp);
-                       if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
+                       host_err = nfsd_cross_mnt(rqstp, &dentry, &exp);
+                       if (host_err) {
                                dput(dentry);
                                goto out_nfserr;
                        }
@@ -234,7 +220,15 @@ out_nfserr:
        return nfserrno(host_err);
 }
 
-/*
+/**
+ * nfsd_lookup - look up a single path component for nfsd
+ *
+ * @rqstp:   the request context
+ * @fhp:     the file handle of the directory
+ * @name:    the component name, or %NULL to look up parent
+ * @len:     length of name to examine
+ * @resfh:   pointer to pre-initialised filehandle to hold result.
+ *
  * Look up one component of a pathname.
  * N.B. After this call _both_ fhp and resfh need an fh_put
  *
@@ -244,11 +238,11 @@ out_nfserr:
  * returned. Otherwise the covered directory is returned.
  * NOTE: this mountpoint crossing is not supported properly by all
  *   clients and is explicitly disallowed for NFSv3
- *      NeilBrown <neilb@cse.unsw.edu.au>
+ *
  */
 __be32
 nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
-                               unsigned int len, struct svc_fh *resfh)
+           unsigned int len, struct svc_fh *resfh)
 {
        struct svc_export       *exp;
        struct dentry           *dentry;
@@ -349,11 +343,13 @@ nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
  * Set various file attributes.  After this call fhp needs an fh_put.
  */
 __be32
-nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+            struct nfsd_attrs *attr,
             int check_guard, time64_t guardtime)
 {
        struct dentry   *dentry;
        struct inode    *inode;
+       struct iattr    *iap = attr->na_iattr;
        int             accmode = NFSD_MAY_SATTR;
        umode_t         ftype = 0;
        __be32          err;
@@ -420,7 +416,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                        return err;
        }
 
-       fh_lock(fhp);
+       inode_lock(inode);
        if (size_change) {
                /*
                 * RFC5661, Section 18.30.4:
@@ -456,7 +452,19 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        host_err = notify_change(&init_user_ns, dentry, iap, NULL);
 
 out_unlock:
-       fh_unlock(fhp);
+       if (attr->na_seclabel && attr->na_seclabel->len)
+               attr->na_labelerr = security_inode_setsecctx(dentry,
+                       attr->na_seclabel->data, attr->na_seclabel->len);
+       if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && attr->na_pacl)
+               attr->na_aclerr = set_posix_acl(&init_user_ns,
+                                               inode, ACL_TYPE_ACCESS,
+                                               attr->na_pacl);
+       if (IS_ENABLED(CONFIG_FS_POSIX_ACL) &&
+           !attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode))
+               attr->na_aclerr = set_posix_acl(&init_user_ns,
+                                               inode, ACL_TYPE_DEFAULT,
+                                               attr->na_dpacl);
+       inode_unlock(inode);
        if (size_change)
                put_write_access(inode);
 out:
@@ -494,32 +502,6 @@ int nfsd4_is_junction(struct dentry *dentry)
                return 0;
        return 1;
 }
-#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               struct xdr_netobj *label)
-{
-       __be32 error;
-       int host_error;
-       struct dentry *dentry;
-
-       error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
-       if (error)
-               return error;
-
-       dentry = fhp->fh_dentry;
-
-       inode_lock(d_inode(dentry));
-       host_error = security_inode_setsecctx(dentry, label->data, label->len);
-       inode_unlock(d_inode(dentry));
-       return nfserrno(host_error);
-}
-#else
-__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               struct xdr_netobj *label)
-{
-       return nfserr_notsupp;
-}
-#endif
 
 static struct nfsd4_compound_state *nfsd4_get_cstate(struct svc_rqst *rqstp)
 {
@@ -1202,14 +1184,15 @@ out:
  * @rqstp: RPC transaction being executed
  * @fhp: NFS filehandle of parent directory
  * @resfhp: NFS filehandle of new object
- * @iap: requested attributes of new object
+ * @attrs: requested attributes of new object
  *
  * Returns nfs_ok on success, or an nfsstat in network byte order.
  */
 __be32
 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
-                   struct svc_fh *resfhp, struct iattr *iap)
+                   struct svc_fh *resfhp, struct nfsd_attrs *attrs)
 {
+       struct iattr *iap = attrs->na_iattr;
        __be32 status;
 
        /*
@@ -1230,7 +1213,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
         * if the attributes have not changed.
         */
        if (iap->ia_valid)
-               status = nfsd_setattr(rqstp, resfhp, iap, 0, (time64_t)0);
+               status = nfsd_setattr(rqstp, resfhp, attrs, 0, (time64_t)0);
        else
                status = nfserrno(commit_metadata(resfhp));
 
@@ -1269,11 +1252,12 @@ nfsd_check_ignore_resizing(struct iattr *iap)
 /* The parent directory should already be locked: */
 __be32
 nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               char *fname, int flen, struct iattr *iap,
-               int type, dev_t rdev, struct svc_fh *resfhp)
+                  char *fname, int flen, struct nfsd_attrs *attrs,
+                  int type, dev_t rdev, struct svc_fh *resfhp)
 {
        struct dentry   *dentry, *dchild;
        struct inode    *dirp;
+       struct iattr    *iap = attrs->na_iattr;
        __be32          err;
        int             host_err;
 
@@ -1281,13 +1265,6 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
        dirp = d_inode(dentry);
 
        dchild = dget(resfhp->fh_dentry);
-       if (!fhp->fh_locked) {
-               WARN_ONCE(1, "nfsd_create: parent %pd2 not locked!\n",
-                               dentry);
-               err = nfserr_io;
-               goto out;
-       }
-
        err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE);
        if (err)
                goto out;
@@ -1347,7 +1324,7 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (host_err < 0)
                goto out_nfserr;
 
-       err = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
+       err = nfsd_create_setattr(rqstp, fhp, resfhp, attrs);
 
 out:
        dput(dchild);
@@ -1366,8 +1343,8 @@ out_nfserr:
  */
 __be32
 nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               char *fname, int flen, struct iattr *iap,
-               int type, dev_t rdev, struct svc_fh *resfhp)
+           char *fname, int flen, struct nfsd_attrs *attrs,
+           int type, dev_t rdev, struct svc_fh *resfhp)
 {
        struct dentry   *dentry, *dchild = NULL;
        __be32          err;
@@ -1386,11 +1363,13 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (host_err)
                return nfserrno(host_err);
 
-       fh_lock_nested(fhp, I_MUTEX_PARENT);
+       inode_lock_nested(dentry->d_inode, I_MUTEX_PARENT);
        dchild = lookup_one_len(fname, dentry, flen);
        host_err = PTR_ERR(dchild);
-       if (IS_ERR(dchild))
-               return nfserrno(host_err);
+       if (IS_ERR(dchild)) {
+               err = nfserrno(host_err);
+               goto out_unlock;
+       }
        err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
        /*
         * We unconditionally drop our ref to dchild as fh_compose will have
@@ -1398,9 +1377,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
         */
        dput(dchild);
        if (err)
-               return err;
-       return nfsd_create_locked(rqstp, fhp, fname, flen, iap, type,
-                                       rdev, resfhp);
+               goto out_unlock;
+       fh_fill_pre_attrs(fhp);
+       err = nfsd_create_locked(rqstp, fhp, fname, flen, attrs, type,
+                                rdev, resfhp);
+       fh_fill_post_attrs(fhp);
+out_unlock:
+       inode_unlock(dentry->d_inode);
+       return err;
 }
 
 /*
@@ -1441,15 +1425,25 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
        return 0;
 }
 
-/*
- * Create a symlink and look up its inode
+/**
+ * nfsd_symlink - Create a symlink and look up its inode
+ * @rqstp: RPC transaction being executed
+ * @fhp: NFS filehandle of parent directory
+ * @fname: filename of the new symlink
+ * @flen: length of @fname
+ * @path: content of the new symlink (NUL-terminated)
+ * @attrs: requested attributes of new object
+ * @resfhp: NFS filehandle of new object
+ *
  * N.B. After this call _both_ fhp and resfhp need an fh_put
+ *
+ * Returns nfs_ok on success, or an nfsstat in network byte order.
  */
 __be32
 nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
-                               char *fname, int flen,
-                               char *path,
-                               struct svc_fh *resfhp)
+            char *fname, int flen,
+            char *path, struct nfsd_attrs *attrs,
+            struct svc_fh *resfhp)
 {
        struct dentry   *dentry, *dnew;
        __be32          err, cerr;
@@ -1467,33 +1461,35 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
                goto out;
 
        host_err = fh_want_write(fhp);
-       if (host_err)
-               goto out_nfserr;
+       if (host_err) {
+               err = nfserrno(host_err);
+               goto out;
+       }
 
-       fh_lock(fhp);
        dentry = fhp->fh_dentry;
+       inode_lock_nested(dentry->d_inode, I_MUTEX_PARENT);
        dnew = lookup_one_len(fname, dentry, flen);
-       host_err = PTR_ERR(dnew);
-       if (IS_ERR(dnew))
-               goto out_nfserr;
-
+       if (IS_ERR(dnew)) {
+               err = nfserrno(PTR_ERR(dnew));
+               inode_unlock(dentry->d_inode);
+               goto out_drop_write;
+       }
+       fh_fill_pre_attrs(fhp);
        host_err = vfs_symlink(&init_user_ns, d_inode(dentry), dnew, path);
        err = nfserrno(host_err);
-       fh_unlock(fhp);
+       cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
+       if (!err)
+               nfsd_create_setattr(rqstp, fhp, resfhp, attrs);
+       fh_fill_post_attrs(fhp);
+       inode_unlock(dentry->d_inode);
        if (!err)
                err = nfserrno(commit_metadata(fhp));
-
-       fh_drop_write(fhp);
-
-       cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
        dput(dnew);
        if (err==0) err = cerr;
+out_drop_write:
+       fh_drop_write(fhp);
 out:
        return err;
-
-out_nfserr:
-       err = nfserrno(host_err);
-       goto out;
 }
 
 /*
@@ -1531,22 +1527,25 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                goto out;
        }
 
-       fh_lock_nested(ffhp, I_MUTEX_PARENT);
        ddir = ffhp->fh_dentry;
        dirp = d_inode(ddir);
+       inode_lock_nested(dirp, I_MUTEX_PARENT);
 
        dnew = lookup_one_len(name, ddir, len);
-       host_err = PTR_ERR(dnew);
-       if (IS_ERR(dnew))
-               goto out_nfserr;
+       if (IS_ERR(dnew)) {
+               err = nfserrno(PTR_ERR(dnew));
+               goto out_unlock;
+       }
 
        dold = tfhp->fh_dentry;
 
        err = nfserr_noent;
        if (d_really_is_negative(dold))
                goto out_dput;
+       fh_fill_pre_attrs(ffhp);
        host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL);
-       fh_unlock(ffhp);
+       fh_fill_post_attrs(ffhp);
+       inode_unlock(dirp);
        if (!host_err) {
                err = nfserrno(commit_metadata(ffhp));
                if (!err)
@@ -1557,17 +1556,17 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                else
                        err = nfserrno(host_err);
        }
-out_dput:
        dput(dnew);
-out_unlock:
-       fh_unlock(ffhp);
+out_drop_write:
        fh_drop_write(tfhp);
 out:
        return err;
 
-out_nfserr:
-       err = nfserrno(host_err);
-       goto out_unlock;
+out_dput:
+       dput(dnew);
+out_unlock:
+       inode_unlock(dirp);
+       goto out_drop_write;
 }
 
 static void
@@ -1628,10 +1627,7 @@ retry:
                goto out;
        }
 
-       /* cannot use fh_lock as we need deadlock protective ordering
-        * so do it by hand */
        trap = lock_rename(tdentry, fdentry);
-       ffhp->fh_locked = tfhp->fh_locked = true;
        fh_fill_pre_attrs(ffhp);
        fh_fill_pre_attrs(tfhp);
 
@@ -1687,17 +1683,12 @@ retry:
        dput(odentry);
  out_nfserr:
        err = nfserrno(host_err);
-       /*
-        * We cannot rely on fh_unlock on the two filehandles,
-        * as that would do the wrong thing if the two directories
-        * were the same, so again we do it by hand.
-        */
+
        if (!close_cached) {
                fh_fill_post_attrs(ffhp);
                fh_fill_post_attrs(tfhp);
        }
        unlock_rename(tdentry, fdentry);
-       ffhp->fh_locked = tfhp->fh_locked = false;
        fh_drop_write(ffhp);
 
        /*
@@ -1741,19 +1732,19 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (host_err)
                goto out_nfserr;
 
-       fh_lock_nested(fhp, I_MUTEX_PARENT);
        dentry = fhp->fh_dentry;
        dirp = d_inode(dentry);
+       inode_lock_nested(dirp, I_MUTEX_PARENT);
 
        rdentry = lookup_one_len(fname, dentry, flen);
        host_err = PTR_ERR(rdentry);
        if (IS_ERR(rdentry))
-               goto out_drop_write;
+               goto out_unlock;
 
        if (d_really_is_negative(rdentry)) {
                dput(rdentry);
                host_err = -ENOENT;
-               goto out_drop_write;
+               goto out_unlock;
        }
        rinode = d_inode(rdentry);
        ihold(rinode);
@@ -1761,6 +1752,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (!type)
                type = d_inode(rdentry)->i_mode & S_IFMT;
 
+       fh_fill_pre_attrs(fhp);
        if (type != S_IFDIR) {
                if (rdentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK)
                        nfsd_close_cached_files(rdentry);
@@ -1768,8 +1760,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        } else {
                host_err = vfs_rmdir(&init_user_ns, dirp, rdentry);
        }
+       fh_fill_post_attrs(fhp);
 
-       fh_unlock(fhp);
+       inode_unlock(dirp);
        if (!host_err)
                host_err = commit_metadata(fhp);
        dput(rdentry);
@@ -1791,6 +1784,9 @@ out_nfserr:
        }
 out:
        return err;
+out_unlock:
+       inode_unlock(dirp);
+       goto out_drop_write;
 }
 
 /*
@@ -2144,13 +2140,16 @@ out:
        return err;
 }
 
-/*
- * Removexattr and setxattr need to call fh_lock to both lock the inode
- * and set the change attribute. Since the top-level vfs_removexattr
- * and vfs_setxattr calls already do their own inode_lock calls, call
- * the _locked variant. Pass in a NULL pointer for delegated_inode,
- * and let the client deal with NFS4ERR_DELAY (same as with e.g.
- * setattr and remove).
+/**
+ * nfsd_removexattr - Remove an extended attribute
+ * @rqstp: RPC transaction being executed
+ * @fhp: NFS filehandle of object with xattr to remove
+ * @name: name of xattr to remove (NUL-terminate)
+ *
+ * Pass in a NULL pointer for delegated_inode, and let the client deal
+ * with NFS4ERR_DELAY (same as with e.g. setattr and remove).
+ *
+ * Returns nfs_ok on success, or an nfsstat in network byte order.
  */
 __be32
 nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
@@ -2166,12 +2165,14 @@ nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
        if (ret)
                return nfserrno(ret);
 
-       fh_lock(fhp);
+       inode_lock(fhp->fh_dentry->d_inode);
+       fh_fill_pre_attrs(fhp);
 
        ret = __vfs_removexattr_locked(&init_user_ns, fhp->fh_dentry,
                                       name, NULL);
 
-       fh_unlock(fhp);
+       fh_fill_post_attrs(fhp);
+       inode_unlock(fhp->fh_dentry->d_inode);
        fh_drop_write(fhp);
 
        return nfsd_xattr_errno(ret);
@@ -2191,12 +2192,13 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
        ret = fh_want_write(fhp);
        if (ret)
                return nfserrno(ret);
-       fh_lock(fhp);
+       inode_lock(fhp->fh_dentry->d_inode);
+       fh_fill_pre_attrs(fhp);
 
        ret = __vfs_setxattr_locked(&init_user_ns, fhp->fh_dentry, name, buf,
                                    len, flags, NULL);
-
-       fh_unlock(fhp);
+       fh_fill_post_attrs(fhp);
+       inode_unlock(fhp->fh_dentry->d_inode);
        fh_drop_write(fhp);
 
        return nfsd_xattr_errno(ret);
index 26347d7..c95cd41 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef LINUX_NFSD_VFS_H
 #define LINUX_NFSD_VFS_H
 
+#include <linux/fs.h>
+#include <linux/posix_acl.h>
 #include "nfsfh.h"
 #include "nfsd.h"
 
@@ -42,6 +44,22 @@ struct nfsd_file;
 typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
 
 /* nfsd/vfs.c */
+struct nfsd_attrs {
+       struct iattr            *na_iattr;      /* input */
+       struct xdr_netobj       *na_seclabel;   /* input */
+       struct posix_acl        *na_pacl;       /* input */
+       struct posix_acl        *na_dpacl;      /* input */
+
+       int                     na_labelerr;    /* output */
+       int                     na_aclerr;      /* output */
+};
+
+static inline void nfsd_attrs_free(struct nfsd_attrs *attrs)
+{
+       posix_acl_release(attrs->na_pacl);
+       posix_acl_release(attrs->na_dpacl);
+}
+
 int            nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
                                struct svc_export **expp);
 __be32         nfsd_lookup(struct svc_rqst *, struct svc_fh *,
@@ -50,11 +68,9 @@ __be32                nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
                                const char *, unsigned int,
                                struct svc_export **, struct dentry **);
 __be32         nfsd_setattr(struct svc_rqst *, struct svc_fh *,
-                               struct iattr *, int, time64_t);
+                               struct nfsd_attrs *, int, time64_t);
 int nfsd_mountpoint(struct dentry *, struct svc_export *);
 #ifdef CONFIG_NFSD_V4
-__be32          nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
-                   struct xdr_netobj *);
 __be32         nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
                                    struct file *, loff_t, loff_t, int);
 __be32         nfsd4_clone_file_range(struct svc_rqst *rqstp,
@@ -63,14 +79,14 @@ __be32              nfsd4_clone_file_range(struct svc_rqst *rqstp,
                                       u64 count, bool sync);
 #endif /* CONFIG_NFSD_V4 */
 __be32         nfsd_create_locked(struct svc_rqst *, struct svc_fh *,
-                               char *name, int len, struct iattr *attrs,
+                               char *name, int len, struct nfsd_attrs *attrs,
                                int type, dev_t rdev, struct svc_fh *res);
 __be32         nfsd_create(struct svc_rqst *, struct svc_fh *,
-                               char *name, int len, struct iattr *attrs,
+                               char *name, int len, struct nfsd_attrs *attrs,
                                int type, dev_t rdev, struct svc_fh *res);
 __be32         nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
 __be32         nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
-                               struct svc_fh *resfhp, struct iattr *iap);
+                               struct svc_fh *resfhp, struct nfsd_attrs *iap);
 __be32         nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
                                u64 offset, u32 count, __be32 *verf);
 #ifdef CONFIG_NFSD_V4
@@ -110,8 +126,9 @@ __be32              nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
 __be32         nfsd_readlink(struct svc_rqst *, struct svc_fh *,
                                char *, int *);
 __be32         nfsd_symlink(struct svc_rqst *, struct svc_fh *,
-                               char *name, int len, char *path,
-                               struct svc_fh *res);
+                            char *name, int len, char *path,
+                            struct nfsd_attrs *attrs,
+                            struct svc_fh *res);
 __be32         nfsd_link(struct svc_rqst *, struct svc_fh *,
                                char *, int, struct svc_fh *);
 ssize_t                nfsd_copy_file_range(struct file *, u64,
index 7b74401..9626725 100644 (file)
@@ -279,6 +279,7 @@ struct nfsd4_open {
        struct nfs4_clnt_odstate *op_odstate; /* used during processing */
        struct nfs4_acl *op_acl;
        struct xdr_netobj op_label;
+       struct svc_rqst *op_rqstp;
 };
 
 struct nfsd4_open_confirm {
@@ -302,9 +303,10 @@ struct nfsd4_read {
        u32                     rd_length;          /* request */
        int                     rd_vlen;
        struct nfsd_file        *rd_nf;
-       
+
        struct svc_rqst         *rd_rqstp;          /* response */
-       struct svc_fh           *rd_fhp;             /* response */
+       struct svc_fh           *rd_fhp;            /* response */
+       u32                     rd_eof;             /* response */
 };
 
 struct nfsd4_readdir {
@@ -532,6 +534,13 @@ struct nfsd42_write_res {
        stateid_t               cb_stateid;
 };
 
+struct nfsd4_cb_offload {
+       struct nfsd4_callback   co_cb;
+       struct nfsd42_write_res co_res;
+       __be32                  co_nfserr;
+       struct knfsd_fh         co_fh;
+};
+
 struct nfsd4_copy {
        /* request */
        stateid_t               cp_src_stateid;
@@ -539,18 +548,16 @@ struct nfsd4_copy {
        u64                     cp_src_pos;
        u64                     cp_dst_pos;
        u64                     cp_count;
-       struct nl4_server       cp_src;
-       bool                    cp_intra;
+       struct nl4_server       *cp_src;
 
-       /* both */
-       u32                     cp_synchronous;
+       unsigned long           cp_flags;
+#define NFSD4_COPY_F_STOPPED           (0)
+#define NFSD4_COPY_F_INTRA             (1)
+#define NFSD4_COPY_F_SYNCHRONOUS       (2)
+#define NFSD4_COPY_F_COMMITTED         (3)
 
        /* response */
        struct nfsd42_write_res cp_res;
-
-       /* for cb_offload */
-       struct nfsd4_callback   cp_cb;
-       __be32                  nfserr;
        struct knfsd_fh         fh;
 
        struct nfs4_client      *cp_clp;
@@ -563,14 +570,35 @@ struct nfsd4_copy {
        struct list_head        copies;
        struct task_struct      *copy_task;
        refcount_t              refcount;
-       bool                    stopped;
 
        struct vfsmount         *ss_mnt;
        struct nfs_fh           c_fh;
        nfs4_stateid            stateid;
-       bool                    committed;
 };
 
+static inline void nfsd4_copy_set_sync(struct nfsd4_copy *copy, bool sync)
+{
+       if (sync)
+               set_bit(NFSD4_COPY_F_SYNCHRONOUS, &copy->cp_flags);
+       else
+               clear_bit(NFSD4_COPY_F_SYNCHRONOUS, &copy->cp_flags);
+}
+
+static inline bool nfsd4_copy_is_sync(const struct nfsd4_copy *copy)
+{
+       return test_bit(NFSD4_COPY_F_SYNCHRONOUS, &copy->cp_flags);
+}
+
+static inline bool nfsd4_copy_is_async(const struct nfsd4_copy *copy)
+{
+       return !test_bit(NFSD4_COPY_F_SYNCHRONOUS, &copy->cp_flags);
+}
+
+static inline bool nfsd4_ssc_is_inter(const struct nfsd4_copy *copy)
+{
+       return !test_bit(NFSD4_COPY_F_INTRA, &copy->cp_flags);
+}
+
 struct nfsd4_seek {
        /* request */
        stateid_t       seek_stateid;
@@ -594,19 +622,20 @@ struct nfsd4_offload_status {
 struct nfsd4_copy_notify {
        /* request */
        stateid_t               cpn_src_stateid;
-       struct nl4_server       cpn_dst;
+       struct nl4_server       *cpn_dst;
 
        /* response */
        stateid_t               cpn_cnr_stateid;
        u64                     cpn_sec;
        u32                     cpn_nsec;
-       struct nl4_server       cpn_src;
+       struct nl4_server       *cpn_src;
 };
 
 struct nfsd4_op {
        u32                                     opnum;
-       const struct nfsd4_operation *          opdesc;
        __be32                                  status;
+       const struct nfsd4_operation            *opdesc;
+       struct nfs4_replay                      *replay;
        union nfsd4_op_u {
                struct nfsd4_access             access;
                struct nfsd4_close              close;
@@ -670,7 +699,6 @@ struct nfsd4_op {
                struct nfsd4_listxattrs         listxattrs;
                struct nfsd4_removexattr        removexattr;
        } u;
-       struct nfs4_replay *                    replay;
 };
 
 bool nfsd4_cache_this_op(struct nfsd4_op *);
index c75fd54..961d1cf 100644 (file)
@@ -197,6 +197,7 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode)
         * callers. */
        if (S_ISDIR(mode))
                set_nlink(inode, 2);
+       mode = mode_strip_sgid(&init_user_ns, dir, mode);
        inode_init_owner(&init_user_ns, inode, dir, mode);
        status = dquot_initialize(inode);
        if (status)
index ea59dd0..1a261dc 100644 (file)
@@ -378,14 +378,13 @@ EXPORT_SYMBOL(rw_verify_area);
 
 static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
 {
-       struct iovec iov = { .iov_base = buf, .iov_len = len };
        struct kiocb kiocb;
        struct iov_iter iter;
        ssize_t ret;
 
        init_sync_kiocb(&kiocb, filp);
        kiocb.ki_pos = (ppos ? *ppos : 0);
-       iov_iter_init(&iter, READ, &iov, 1, len);
+       iov_iter_ubuf(&iter, READ, buf, len);
 
        ret = call_read_iter(filp, &kiocb, &iter);
        BUG_ON(ret == -EIOCBQUEUED);
@@ -481,14 +480,13 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
 
 static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
 {
-       struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
        struct kiocb kiocb;
        struct iov_iter iter;
        ssize_t ret;
 
        init_sync_kiocb(&kiocb, filp);
        kiocb.ki_pos = (ppos ? *ppos : 0);
-       iov_iter_init(&iter, WRITE, &iov, 1, len);
+       iov_iter_ubuf(&iter, WRITE, (void __user *)buf, len);
 
        ret = call_write_iter(filp, &kiocb, &iter);
        BUG_ON(ret == -EIOCBQUEUED);
index 93a2c9b..0878b85 100644 (file)
@@ -301,11 +301,9 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
 {
        struct iov_iter to;
        struct kiocb kiocb;
-       unsigned int i_head;
        int ret;
 
        iov_iter_pipe(&to, READ, pipe, len);
-       i_head = to.head;
        init_sync_kiocb(&kiocb, in);
        kiocb.ki_pos = *ppos;
        ret = call_read_iter(in, &kiocb, &to);
@@ -313,9 +311,8 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
                *ppos = kiocb.ki_pos;
                file_accessed(in);
        } else if (ret < 0) {
-               to.head = i_head;
-               to.iov_offset = 0;
-               iov_iter_advance(&to, 0); /* to free what was emitted */
+               /* free what was emitted */
+               pipe_discard_from(pipe, to.start_head);
                /*
                 * callers of ->splice_read() expect -EAGAIN on
                 * "can't put anything in there", rather than -EFAULT.
@@ -1161,39 +1158,40 @@ static int iter_to_pipe(struct iov_iter *from,
        };
        size_t total = 0;
        int ret = 0;
-       bool failed = false;
 
-       while (iov_iter_count(from) && !failed) {
+       while (iov_iter_count(from)) {
                struct page *pages[16];
-               ssize_t copied;
+               ssize_t left;
                size_t start;
-               int n;
+               int i, n;
 
-               copied = iov_iter_get_pages(from, pages, ~0UL, 16, &start);
-               if (copied <= 0) {
-                       ret = copied;
+               left = iov_iter_get_pages2(from, pages, ~0UL, 16, &start);
+               if (left <= 0) {
+                       ret = left;
                        break;
                }
 
-               for (n = 0; copied; n++, start = 0) {
-                       int size = min_t(int, copied, PAGE_SIZE - start);
-                       if (!failed) {
-                               buf.page = pages[n];
-                               buf.offset = start;
-                               buf.len = size;
-                               ret = add_to_pipe(pipe, &buf);
-                               if (unlikely(ret < 0)) {
-                                       failed = true;
-                               } else {
-                                       iov_iter_advance(from, ret);
-                                       total += ret;
-                               }
-                       } else {
-                               put_page(pages[n]);
+               n = DIV_ROUND_UP(left + start, PAGE_SIZE);
+               for (i = 0; i < n; i++) {
+                       int size = min_t(int, left, PAGE_SIZE - start);
+
+                       buf.page = pages[i];
+                       buf.offset = start;
+                       buf.len = size;
+                       ret = add_to_pipe(pipe, &buf);
+                       if (unlikely(ret < 0)) {
+                               iov_iter_revert(from, left);
+                               // this one got dropped by add_to_pipe()
+                               while (++i < n)
+                                       put_page(pages[i]);
+                               goto out;
                        }
-                       copied -= size;
+                       total += ret;
+                       left -= size;
+                       start = 0;
                }
        }
+out:
        return total ? total : ret;
 }
 
index 2d0c23e..8736ce0 100644 (file)
@@ -42,6 +42,6 @@
 /*
  * Convert a port and pin label to its global pin index
  */
- #define RZA2_PIN(port, pin)   ((port) * RZA2_PINS_PER_PORT + (pin))
+#define RZA2_PIN(port, pin)    ((port) * RZA2_PINS_PER_PORT + (pin))
 
 #endif /* __DT_BINDINGS_PINCTRL_RENESAS_RZA2_H */
index b48f8c7..c78ed5e 100644 (file)
@@ -18,6 +18,6 @@
 #define RZG2L_PORT_PINMUX(b, p, f)     ((b) * RZG2L_PINS_PER_PORT + (p) | ((f) << 16))
 
 /* Convert a port and pin label to its global pin index */
- #define RZG2L_GPIO(port, pin) ((port) * RZG2L_PINS_PER_PORT + (pin))
+#define RZG2L_GPIO(port, pin)  ((port) * RZG2L_PINS_PER_PORT + (pin))
 
 #endif /* __DT_BINDINGS_RZG2L_PINCTRL_H */
diff --git a/include/dt-bindings/pinctrl/rzv2m-pinctrl.h b/include/dt-bindings/pinctrl/rzv2m-pinctrl.h
new file mode 100644 (file)
index 0000000..525532c
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * This header provides constants for Renesas RZ/V2M pinctrl bindings.
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ *
+ */
+
+#ifndef __DT_BINDINGS_RZV2M_PINCTRL_H
+#define __DT_BINDINGS_RZV2M_PINCTRL_H
+
+#define RZV2M_PINS_PER_PORT    16
+
+/*
+ * Create the pin index from its bank and position numbers and store in
+ * the upper 16 bits the alternate function identifier
+ */
+#define RZV2M_PORT_PINMUX(b, p, f)     ((b) * RZV2M_PINS_PER_PORT + (p) | ((f) << 16))
+
+/* Convert a port and pin label to its global pin index */
+#define RZV2M_GPIO(port, pin)  ((port) * RZV2M_PINS_PER_PORT + (pin))
+
+#endif /* __DT_BINDINGS_RZV2M_PINCTRL_H */
index 307445d..def8b8d 100644 (file)
@@ -118,7 +118,6 @@ static __always_inline int test_clear_buffer_##name(struct buffer_head *bh) \
  * of the form "mark_buffer_foo()".  These are higher-level functions which
  * do something in addition to setting a b_state bit.
  */
-BUFFER_FNS(Uptodate, uptodate)
 BUFFER_FNS(Dirty, dirty)
 TAS_BUFFER_FNS(Dirty, dirty)
 BUFFER_FNS(Lock, locked)
@@ -136,6 +135,30 @@ BUFFER_FNS(Meta, meta)
 BUFFER_FNS(Prio, prio)
 BUFFER_FNS(Defer_Completion, defer_completion)
 
+static __always_inline void set_buffer_uptodate(struct buffer_head *bh)
+{
+       /*
+        * make it consistent with folio_mark_uptodate
+        * pairs with smp_load_acquire in buffer_uptodate
+        */
+       smp_mb__before_atomic();
+       set_bit(BH_Uptodate, &bh->b_state);
+}
+
+static __always_inline void clear_buffer_uptodate(struct buffer_head *bh)
+{
+       clear_bit(BH_Uptodate, &bh->b_state);
+}
+
+static __always_inline int buffer_uptodate(const struct buffer_head *bh)
+{
+       /*
+        * make it consistent with folio_test_uptodate
+        * pairs with smp_mb__before_atomic in set_buffer_uptodate
+        */
+       return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0;
+}
+
 #define bh_offset(bh)          ((unsigned long)(bh)->b_data & ~PAGE_MASK)
 
 /* If we *know* page->private refers to buffer_heads */
index 010df04..d678afe 100644 (file)
@@ -177,6 +177,7 @@ static inline void dma_pernuma_cma_reserve(void) { }
 #ifdef CONFIG_DMA_DECLARE_COHERENT
 int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
                dma_addr_t device_addr, size_t size);
+void dma_release_coherent_memory(struct device *dev);
 int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
                dma_addr_t *dma_handle, void **ret);
 int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr);
@@ -188,9 +189,11 @@ static inline int dma_declare_coherent_memory(struct device *dev,
 {
        return -ENOSYS;
 }
+
 #define dma_alloc_from_dev_coherent(dev, size, handle, ret) (0)
 #define dma_release_from_dev_coherent(dev, order, vaddr) (0)
 #define dma_mmap_from_dev_coherent(dev, vma, vaddr, order, ret) (0)
+static inline void dma_release_coherent_memory(struct device *dev) { }
 #endif /* CONFIG_DMA_DECLARE_COHERENT */
 
 #ifdef CONFIG_DMA_GLOBAL_POOL
index cbde3b1..9f50dac 100644 (file)
@@ -369,6 +369,11 @@ enum pm_pinctrl_drive_strength {
        PM_PINCTRL_DRIVE_STRENGTH_12MA = 3,
 };
 
+enum pm_pinctrl_tri_state {
+       PM_PINCTRL_TRI_STATE_DISABLE = 0,
+       PM_PINCTRL_TRI_STATE_ENABLE = 1,
+};
+
 enum zynqmp_pm_shutdown_type {
        ZYNQMP_PM_SHUTDOWN_TYPE_SHUTDOWN = 0,
        ZYNQMP_PM_SHUTDOWN_TYPE_RESET = 1,
index 8c127ff..5113f65 100644 (file)
@@ -2035,6 +2035,8 @@ extern long compat_ptr_ioctl(struct file *file, unsigned int cmd,
 void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode,
                      const struct inode *dir, umode_t mode);
 extern bool may_open_dev(const struct path *path);
+umode_t mode_strip_sgid(struct user_namespace *mnt_userns,
+                       const struct inode *dir, umode_t mode);
 
 /*
  * This is the "filldir" function type, used by readdir() to let
index ec5f71f..616b683 100644 (file)
@@ -141,6 +141,7 @@ enum {
        IORES_DESC_DEVICE_PRIVATE_MEMORY        = 6,
        IORES_DESC_RESERVED                     = 7,
        IORES_DESC_SOFT_RESERVED                = 8,
+       IORES_DESC_CXL                          = 9,
 };
 
 /*
@@ -329,6 +330,8 @@ struct resource *devm_request_free_mem_region(struct device *dev,
                struct resource *base, unsigned long size);
 struct resource *request_free_mem_region(struct resource *base,
                unsigned long size, const char *name);
+struct resource *alloc_free_mem_region(struct resource *base,
+               unsigned long size, unsigned long align, const char *name);
 
 static inline void irqresource_disabled(struct resource *res, u32 irq)
 {
index 0d61e07..c74acfa 100644 (file)
@@ -59,6 +59,9 @@ enum {
        /* Platform provides asynchronous flush mechanism */
        ND_REGION_ASYNC = 3,
 
+       /* Region was created by CXL subsystem */
+       ND_REGION_CXL = 4,
+
        /* mark newly adjusted resources as requiring a label update */
        DPA_RESOURCE_ADJUSTED = 1 << 0,
 };
@@ -122,6 +125,7 @@ struct nd_region_desc {
        int numa_node;
        int target_node;
        unsigned long flags;
+       int memregion;
        struct device_node *of_node;
        int (*flush)(struct nd_region *nd_region, struct bio *bio);
 };
@@ -259,6 +263,7 @@ static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus,
                        cmd_mask, num_flush, flush_wpq, NULL, NULL, NULL);
 }
 void nvdimm_delete(struct nvdimm *nvdimm);
+void nvdimm_region_delete(struct nd_region *nd_region);
 
 const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);
 const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
index fcef192..70ce419 100644 (file)
@@ -292,6 +292,7 @@ void                  nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t);
 __be32           nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
                                        struct nlm_lock *);
 void             nlm_release_file(struct nlm_file *);
+void             nlmsvc_put_lockowner(struct nlm_lockowner *);
 void             nlmsvc_release_lockowner(struct nlm_lock *);
 void             nlmsvc_mark_resources(struct net *);
 void             nlmsvc_free_host_resources(struct nlm_host *);
index 398f700..67e4a2c 100644 (file)
@@ -41,6 +41,8 @@ struct nlm_lock {
        struct nfs_fh           fh;
        struct xdr_netobj       oh;
        u32                     svid;
+       u64                     lock_start;
+       u64                     lock_len;
        struct file_lock        fl;
 };
 
index 222ae88..75843c0 100644 (file)
@@ -64,7 +64,7 @@ struct nfsd4_ssc_umount_item {
        refcount_t nsui_refcnt;
        unsigned long nsui_expire;
        struct vfsmount *nsui_vfsmount;
-       char nsui_ipaddr[RPC_MAX_ADDRBUFLEN];
+       char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1];
 };
 #endif
 
diff --git a/include/linux/pci-doe.h b/include/linux/pci-doe.h
new file mode 100644 (file)
index 0000000..ed9b4df
--- /dev/null
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Data Object Exchange
+ *     PCIe r6.0, sec 6.30 DOE
+ *
+ * Copyright (C) 2021 Huawei
+ *     Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ *
+ * Copyright (C) 2022 Intel Corporation
+ *     Ira Weiny <ira.weiny@intel.com>
+ */
+
+#ifndef LINUX_PCI_DOE_H
+#define LINUX_PCI_DOE_H
+
+struct pci_doe_protocol {
+       u16 vid;
+       u8 type;
+};
+
+struct pci_doe_mb;
+
+/**
+ * struct pci_doe_task - represents a single query/response
+ *
+ * @prot: DOE Protocol
+ * @request_pl: The request payload
+ * @request_pl_sz: Size of the request payload (bytes)
+ * @response_pl: The response payload
+ * @response_pl_sz: Size of the response payload (bytes)
+ * @rv: Return value.  Length of received response or error (bytes)
+ * @complete: Called when task is complete
+ * @private: Private data for the consumer
+ * @work: Used internally by the mailbox
+ * @doe_mb: Used internally by the mailbox
+ *
+ * The payload sizes and rv are specified in bytes with the following
+ * restrictions concerning the protocol.
+ *
+ *     1) The request_pl_sz must be a multiple of double words (4 bytes)
+ *     2) The response_pl_sz must be >= a single double word (4 bytes)
+ *     3) rv is returned as bytes but it will be a multiple of double words
+ *
+ * NOTE there is no need for the caller to initialize work or doe_mb.
+ */
+struct pci_doe_task {
+       struct pci_doe_protocol prot;
+       u32 *request_pl;
+       size_t request_pl_sz;
+       u32 *response_pl;
+       size_t response_pl_sz;
+       int rv;
+       void (*complete)(struct pci_doe_task *task);
+       void *private;
+
+       /* No need for the user to initialize these fields */
+       struct work_struct work;
+       struct pci_doe_mb *doe_mb;
+};
+
+/**
+ * pci_doe_for_each_off - Iterate each DOE capability
+ * @pdev: struct pci_dev to iterate
+ * @off: u16 of config space offset of each mailbox capability found
+ */
+#define pci_doe_for_each_off(pdev, off) \
+       for (off = pci_find_next_ext_capability(pdev, off, \
+                                       PCI_EXT_CAP_ID_DOE); \
+               off > 0; \
+               off = pci_find_next_ext_capability(pdev, off, \
+                                       PCI_EXT_CAP_ID_DOE))
+
+struct pci_doe_mb *pcim_doe_create_mb(struct pci_dev *pdev, u16 cap_offset);
+bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type);
+int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task);
+
+#endif
index 7fa460c..6feade6 100644 (file)
 #define PCI_CLASS_OTHERS               0xff
 
 /* Vendors and devices.  Sort key: vendor first, device next. */
+#define PCI_VENDOR_ID_PCI_SIG          0x0001
 
 #define PCI_VENDOR_ID_LOONGSON         0x0014
 
index 70b45d2..487117c 100644 (file)
@@ -26,6 +26,26 @@ struct pin_config_item;
 struct gpio_chip;
 struct device_node;
 
+/**
+ * struct pingroup - provides information on pingroup
+ * @name: a name for pingroup
+ * @pins: an array of pins in the pingroup
+ * @npins: number of pins in the pingroup
+ */
+struct pingroup {
+       const char *name;
+       const unsigned int *pins;
+       size_t npins;
+};
+
+/* Convenience macro to define a single named or anonymous pingroup */
+#define PINCTRL_PINGROUP(_name, _pins, _npins) \
+(struct pingroup){                             \
+       .name = _name,                          \
+       .pins = _pins,                          \
+       .npins = _npins,                        \
+}
+
 /**
  * struct pinctrl_pin_desc - boards/machines provide information on their
  * pins, pads or other muxable units in this struct
index 4ea4969..6cb65df 100644 (file)
@@ -156,26 +156,6 @@ static inline bool pipe_full(unsigned int head, unsigned int tail,
        return pipe_occupancy(head, tail) >= limit;
 }
 
-/**
- * pipe_space_for_user - Return number of slots available to userspace
- * @head: The pipe ring head pointer
- * @tail: The pipe ring tail pointer
- * @pipe: The pipe info structure
- */
-static inline unsigned int pipe_space_for_user(unsigned int head, unsigned int tail,
-                                              struct pipe_inode_info *pipe)
-{
-       unsigned int p_occupancy, p_space;
-
-       p_occupancy = pipe_occupancy(head, tail);
-       if (p_occupancy >= pipe->max_usage)
-               return 0;
-       p_space = pipe->ring_size - p_occupancy;
-       if (p_space > pipe->max_usage)
-               p_space = pipe->max_usage;
-       return p_space;
-}
-
 /**
  * pipe_buf_get - get a reference to a pipe_buffer
  * @pipe:      the pipe that the buffer belongs to
index 6708b4e..dc1fb58 100644 (file)
@@ -57,37 +57,39 @@ struct dev_pm_opp_icc_bw {
        u32 peak;
 };
 
-/**
- * struct dev_pm_opp_info - OPP freq/voltage/current values
- * @rate:      Target clk rate in hz
- * @supplies:  Array of voltage/current values for all power supplies
- *
- * This structure stores the freq/voltage/current values for a single OPP.
- */
-struct dev_pm_opp_info {
-       unsigned long rate;
-       struct dev_pm_opp_supply *supplies;
-};
+typedef int (*config_regulators_t)(struct device *dev,
+                       struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
+                       struct regulator **regulators, unsigned int count);
+
+typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table,
+                       struct dev_pm_opp *opp, void *data, bool scaling_down);
 
 /**
- * struct dev_pm_set_opp_data - Set OPP data
- * @old_opp:   Old OPP info
- * @new_opp:   New OPP info
- * @regulators:        Array of regulator pointers
- * @regulator_count: Number of regulators
- * @clk:       Pointer to clk
- * @dev:       Pointer to the struct device
+ * struct dev_pm_opp_config - Device OPP configuration values
+ * @clk_names: Clk names, NULL terminated array.
+ * @config_clks: Custom set clk helper.
+ * @prop_name: Name to postfix to properties.
+ * @config_regulators: Custom set regulator helper.
+ * @supported_hw: Array of hierarchy of versions to match.
+ * @supported_hw_count: Number of elements in the array.
+ * @regulator_names: Array of pointers to the names of the regulator, NULL terminated.
+ * @genpd_names: Null terminated array of pointers containing names of genpd to
+ *              attach.
+ * @virt_devs: Pointer to return the array of virtual devices.
  *
- * This structure contains all information required for setting an OPP.
+ * This structure contains platform specific OPP configurations for the device.
  */
-struct dev_pm_set_opp_data {
-       struct dev_pm_opp_info old_opp;
-       struct dev_pm_opp_info new_opp;
-
-       struct regulator **regulators;
-       unsigned int regulator_count;
-       struct clk *clk;
-       struct device *dev;
+struct dev_pm_opp_config {
+       /* NULL terminated */
+       const char * const *clk_names;
+       config_clks_t config_clks;
+       const char *prop_name;
+       config_regulators_t config_regulators;
+       const unsigned int *supported_hw;
+       unsigned int supported_hw_count;
+       const char * const *regulator_names;
+       const char * const *genpd_names;
+       struct device ***virt_devs;
 };
 
 #if defined(CONFIG_PM_OPP)
@@ -97,6 +99,8 @@ void dev_pm_opp_put_opp_table(struct opp_table *opp_table);
 
 unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
 
+int dev_pm_opp_get_supplies(struct dev_pm_opp *opp, struct dev_pm_opp_supply *supplies);
+
 unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp);
 
 unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
@@ -119,8 +123,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
                                              bool available);
 struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
                                              unsigned long *freq);
-struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
-                                                    unsigned long u_volt);
 
 struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
                                               unsigned int level);
@@ -154,23 +156,13 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq);
 int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb);
 int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb);
 
-struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
-void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);
-int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
-struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name);
-void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
-struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
-void dev_pm_opp_put_regulators(struct opp_table *opp_table);
-int devm_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
-struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name);
-void dev_pm_opp_put_clkname(struct opp_table *opp_table);
-int devm_pm_opp_set_clkname(struct device *dev, const char *name);
-struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
-void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table);
-int devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
-struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs);
-void dev_pm_opp_detach_genpd(struct opp_table *opp_table);
-int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs);
+int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config);
+int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config);
+void dev_pm_opp_clear_config(int token);
+int dev_pm_opp_config_clks_simple(struct device *dev,
+               struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
+               bool scaling_down);
+
 struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp);
 int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate);
 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
@@ -198,6 +190,11 @@ static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
        return 0;
 }
 
+static inline int dev_pm_opp_get_supplies(struct dev_pm_opp *opp, struct dev_pm_opp_supply *supplies)
+{
+       return -EOPNOTSUPP;
+}
+
 static inline unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp)
 {
        return 0;
@@ -274,12 +271,6 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
        return ERR_PTR(-EOPNOTSUPP);
 }
 
-static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
-                                       unsigned long u_volt)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
 static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
                                        unsigned long *freq)
 {
@@ -342,79 +333,21 @@ static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct noti
        return -EOPNOTSUPP;
 }
 
-static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
-                                                           const u32 *versions,
-                                                           unsigned int count)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
-
-static inline int devm_pm_opp_set_supported_hw(struct device *dev,
-                                              const u32 *versions,
-                                              unsigned int count)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
-                       int (*set_opp)(struct dev_pm_set_opp_data *data))
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {}
-
-static inline int devm_pm_opp_register_set_opp_helper(struct device *dev,
-                                   int (*set_opp)(struct dev_pm_set_opp_data *data))
-{
-       return -EOPNOTSUPP;
-}
-
-static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {}
-
-static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {}
-
-static inline int devm_pm_opp_set_regulators(struct device *dev,
-                                            const char * const names[],
-                                            unsigned int count)
+static inline int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
 {
        return -EOPNOTSUPP;
 }
 
-static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {}
-
-static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name)
+static inline int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
 {
        return -EOPNOTSUPP;
 }
 
-static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {}
+static inline void dev_pm_opp_clear_config(int token) {}
 
-static inline int devm_pm_opp_attach_genpd(struct device *dev,
-                                          const char * const *names,
-                                          struct device ***virt_devs)
+static inline int dev_pm_opp_config_clks_simple(struct device *dev,
+               struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
+               bool scaling_down)
 {
        return -EOPNOTSUPP;
 }
@@ -469,8 +402,6 @@ static inline int dev_pm_opp_sync_regulators(struct device *dev)
 int dev_pm_opp_of_add_table(struct device *dev);
 int dev_pm_opp_of_add_table_indexed(struct device *dev, int index);
 int devm_pm_opp_of_add_table_indexed(struct device *dev, int index);
-int dev_pm_opp_of_add_table_noclk(struct device *dev, int index);
-int devm_pm_opp_of_add_table_noclk(struct device *dev, int index);
 void dev_pm_opp_of_remove_table(struct device *dev);
 int devm_pm_opp_of_add_table(struct device *dev);
 int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
@@ -501,16 +432,6 @@ static inline int devm_pm_opp_of_add_table_indexed(struct device *dev, int index
        return -EOPNOTSUPP;
 }
 
-static inline int dev_pm_opp_of_add_table_noclk(struct device *dev, int index)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline int devm_pm_opp_of_add_table_noclk(struct device *dev, int index)
-{
-       return -EOPNOTSUPP;
-}
-
 static inline void dev_pm_opp_of_remove_table(struct device *dev)
 {
 }
@@ -565,4 +486,149 @@ static inline int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_ta
 }
 #endif
 
+/* OPP Configuration helpers */
+
+/* Regulators helpers */
+static inline int dev_pm_opp_set_regulators(struct device *dev,
+                                           const char * const names[])
+{
+       struct dev_pm_opp_config config = {
+               .regulator_names = names,
+       };
+
+       return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_regulators(int token)
+{
+       dev_pm_opp_clear_config(token);
+}
+
+static inline int devm_pm_opp_set_regulators(struct device *dev,
+                                            const char * const names[])
+{
+       struct dev_pm_opp_config config = {
+               .regulator_names = names,
+       };
+
+       return devm_pm_opp_set_config(dev, &config);
+}
+
+/* Supported-hw helpers */
+static inline int dev_pm_opp_set_supported_hw(struct device *dev,
+                                             const u32 *versions,
+                                             unsigned int count)
+{
+       struct dev_pm_opp_config config = {
+               .supported_hw = versions,
+               .supported_hw_count = count,
+       };
+
+       return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_supported_hw(int token)
+{
+       dev_pm_opp_clear_config(token);
+}
+
+static inline int devm_pm_opp_set_supported_hw(struct device *dev,
+                                              const u32 *versions,
+                                              unsigned int count)
+{
+       struct dev_pm_opp_config config = {
+               .supported_hw = versions,
+               .supported_hw_count = count,
+       };
+
+       return devm_pm_opp_set_config(dev, &config);
+}
+
+/* clkname helpers */
+static inline int dev_pm_opp_set_clkname(struct device *dev, const char *name)
+{
+       const char *names[] = { name, NULL };
+       struct dev_pm_opp_config config = {
+               .clk_names = names,
+       };
+
+       return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_clkname(int token)
+{
+       dev_pm_opp_clear_config(token);
+}
+
+static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name)
+{
+       const char *names[] = { name, NULL };
+       struct dev_pm_opp_config config = {
+               .clk_names = names,
+       };
+
+       return devm_pm_opp_set_config(dev, &config);
+}
+
+/* config-regulators helpers */
+static inline int dev_pm_opp_set_config_regulators(struct device *dev,
+                                                  config_regulators_t helper)
+{
+       struct dev_pm_opp_config config = {
+               .config_regulators = helper,
+       };
+
+       return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_config_regulators(int token)
+{
+       dev_pm_opp_clear_config(token);
+}
+
+/* genpd helpers */
+static inline int dev_pm_opp_attach_genpd(struct device *dev,
+                                         const char * const *names,
+                                         struct device ***virt_devs)
+{
+       struct dev_pm_opp_config config = {
+               .genpd_names = names,
+               .virt_devs = virt_devs,
+       };
+
+       return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_detach_genpd(int token)
+{
+       dev_pm_opp_clear_config(token);
+}
+
+static inline int devm_pm_opp_attach_genpd(struct device *dev,
+                                          const char * const *names,
+                                          struct device ***virt_devs)
+{
+       struct dev_pm_opp_config config = {
+               .genpd_names = names,
+               .virt_devs = virt_devs,
+       };
+
+       return devm_pm_opp_set_config(dev, &config);
+}
+
+/* prop-name helpers */
+static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+{
+       struct dev_pm_opp_config config = {
+               .prop_name = name,
+       };
+
+       return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_prop_name(int token)
+{
+       dev_pm_opp_clear_config(token);
+}
+
 #endif         /* __LINUX_OPP_H__ */
index 5860f32..986c8a1 100644 (file)
@@ -419,8 +419,8 @@ static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr)
  */
 static inline __be32 *xdr_encode_bool(__be32 *p, u32 n)
 {
-       *p = n ? xdr_one : xdr_zero;
-       return p++;
+       *p++ = n ? xdr_one : xdr_zero;
+       return p;
 }
 
 /**
index e3f1e8a..fd3fe5c 100644 (file)
@@ -235,6 +235,22 @@ struct bin_attribute bin_attr_##_name = __BIN_ATTR_WO(_name, _size)
 #define BIN_ATTR_RW(_name, _size)                                      \
 struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size)
 
+
+#define __BIN_ATTR_ADMIN_RO(_name, _size) {                                    \
+       .attr   = { .name = __stringify(_name), .mode = 0400 },         \
+       .read   = _name##_read,                                         \
+       .size   = _size,                                                \
+}
+
+#define __BIN_ATTR_ADMIN_RW(_name, _size)                                      \
+       __BIN_ATTR(_name, 0600, _name##_read, _name##_write, _size)
+
+#define BIN_ATTR_ADMIN_RO(_name, _size)                                        \
+struct bin_attribute bin_attr_##_name = __BIN_ATTR_ADMIN_RO(_name, _size)
+
+#define BIN_ATTR_ADMIN_RW(_name, _size)                                        \
+struct bin_attribute bin_attr_##_name = __BIN_ATTR_ADMIN_RW(_name, _size)
+
 struct sysfs_ops {
        ssize_t (*show)(struct kobject *, struct attribute *, char *);
        ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
index 9a2dc49..5896af3 100644 (file)
@@ -26,6 +26,7 @@ enum iter_type {
        ITER_PIPE,
        ITER_XARRAY,
        ITER_DISCARD,
+       ITER_UBUF,
 };
 
 struct iov_iter_state {
@@ -38,7 +39,11 @@ struct iov_iter {
        u8 iter_type;
        bool nofault;
        bool data_source;
-       size_t iov_offset;
+       bool user_backed;
+       union {
+               size_t iov_offset;
+               int last_offset;
+       };
        size_t count;
        union {
                const struct iovec *iov;
@@ -46,6 +51,7 @@ struct iov_iter {
                const struct bio_vec *bvec;
                struct xarray *xarray;
                struct pipe_inode_info *pipe;
+               void __user *ubuf;
        };
        union {
                unsigned long nr_segs;
@@ -70,6 +76,11 @@ static inline void iov_iter_save_state(struct iov_iter *iter,
        state->nr_segs = iter->nr_segs;
 }
 
+static inline bool iter_is_ubuf(const struct iov_iter *i)
+{
+       return iov_iter_type(i) == ITER_UBUF;
+}
+
 static inline bool iter_is_iovec(const struct iov_iter *i)
 {
        return iov_iter_type(i) == ITER_IOVEC;
@@ -105,6 +116,11 @@ static inline unsigned char iov_iter_rw(const struct iov_iter *i)
        return i->data_source ? WRITE : READ;
 }
 
+static inline bool user_backed_iter(const struct iov_iter *i)
+{
+       return i->user_backed;
+}
+
 /*
  * Total number of bytes covered by an iovec.
  *
@@ -231,9 +247,9 @@ void iov_iter_pipe(struct iov_iter *i, unsigned int direction, struct pipe_inode
 void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count);
 void iov_iter_xarray(struct iov_iter *i, unsigned int direction, struct xarray *xarray,
                     loff_t start, size_t count);
-ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
+ssize_t iov_iter_get_pages2(struct iov_iter *i, struct page **pages,
                        size_t maxsize, unsigned maxpages, size_t *start);
-ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
+ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i, struct page ***pages,
                        size_t maxsize, size_t *start);
 int iov_iter_npages(const struct iov_iter *i, int maxpages);
 void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state);
@@ -322,4 +338,17 @@ ssize_t __import_iovec(int type, const struct iovec __user *uvec,
 int import_single_range(int type, void __user *buf, size_t len,
                 struct iovec *iov, struct iov_iter *i);
 
+static inline void iov_iter_ubuf(struct iov_iter *i, unsigned int direction,
+                       void __user *buf, size_t count)
+{
+       WARN_ON(direction & ~(READ | WRITE));
+       *i = (struct iov_iter) {
+               .iter_type = ITER_UBUF,
+               .user_backed = true,
+               .data_source = direction,
+               .ubuf = buf,
+               .count = count
+       };
+}
+
 #endif
index 499f5fa..e9d412d 100644 (file)
@@ -727,31 +727,31 @@ TRACE_EVENT(afs_cb_call,
            );
 
 TRACE_EVENT(afs_call,
-           TP_PROTO(struct afs_call *call, enum afs_call_trace op,
-                    int usage, int outstanding, const void *where),
+           TP_PROTO(unsigned int call_debug_id, enum afs_call_trace op,
+                    int ref, int outstanding, const void *where),
 
-           TP_ARGS(call, op, usage, outstanding, where),
+           TP_ARGS(call_debug_id, op, ref, outstanding, where),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               call            )
                    __field(int,                        op              )
-                   __field(int,                        usage           )
+                   __field(int,                        ref             )
                    __field(int,                        outstanding     )
                    __field(const void *,               where           )
                             ),
 
            TP_fast_assign(
-                   __entry->call = call->debug_id;
+                   __entry->call = call_debug_id;
                    __entry->op = op;
-                   __entry->usage = usage;
+                   __entry->ref = ref;
                    __entry->outstanding = outstanding;
                    __entry->where = where;
                           ),
 
-           TP_printk("c=%08x %s u=%d o=%d sp=%pSR",
+           TP_printk("c=%08x %s r=%d o=%d sp=%pSR",
                      __entry->call,
                      __print_symbolic(__entry->op, afs_call_traces),
-                     __entry->usage,
+                     __entry->ref,
                      __entry->outstanding,
                      __entry->where)
            );
@@ -1433,10 +1433,10 @@ TRACE_EVENT(afs_cb_miss,
            );
 
 TRACE_EVENT(afs_server,
-           TP_PROTO(struct afs_server *server, int ref, int active,
+           TP_PROTO(unsigned int server_debug_id, int ref, int active,
                     enum afs_server_trace reason),
 
-           TP_ARGS(server, ref, active, reason),
+           TP_ARGS(server_debug_id, ref, active, reason),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               server          )
@@ -1446,7 +1446,7 @@ TRACE_EVENT(afs_server,
                             ),
 
            TP_fast_assign(
-                   __entry->server = server->debug_id;
+                   __entry->server = server_debug_id;
                    __entry->ref = ref;
                    __entry->active = active;
                    __entry->reason = reason;
@@ -1476,36 +1476,36 @@ TRACE_EVENT(afs_volume,
                    __entry->reason = reason;
                           ),
 
-           TP_printk("V=%llx %s u=%d",
+           TP_printk("V=%llx %s ur=%d",
                      __entry->vid,
                      __print_symbolic(__entry->reason, afs_volume_traces),
                      __entry->ref)
            );
 
 TRACE_EVENT(afs_cell,
-           TP_PROTO(unsigned int cell_debug_id, int usage, int active,
+           TP_PROTO(unsigned int cell_debug_id, int ref, int active,
                     enum afs_cell_trace reason),
 
-           TP_ARGS(cell_debug_id, usage, active, reason),
+           TP_ARGS(cell_debug_id, ref, active, reason),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               cell            )
-                   __field(int,                        usage           )
+                   __field(int,                        ref             )
                    __field(int,                        active          )
                    __field(int,                        reason          )
                             ),
 
            TP_fast_assign(
                    __entry->cell = cell_debug_id;
-                   __entry->usage = usage;
+                   __entry->ref = ref;
                    __entry->active = active;
                    __entry->reason = reason;
                           ),
 
-           TP_printk("L=%08x %s u=%d a=%d",
+           TP_printk("L=%08x %s r=%d a=%d",
                      __entry->cell,
                      __print_symbolic(__entry->reason, afs_cell_traces),
-                     __entry->usage,
+                     __entry->ref,
                      __entry->active)
            );
 
index cb3fb33..c078c48 100644 (file)
@@ -49,6 +49,7 @@ enum fscache_volume_trace {
 enum fscache_cookie_trace {
        fscache_cookie_collision,
        fscache_cookie_discard,
+       fscache_cookie_failed,
        fscache_cookie_get_attach_object,
        fscache_cookie_get_end_access,
        fscache_cookie_get_hash_collision,
@@ -131,6 +132,7 @@ enum fscache_access_trace {
 #define fscache_cookie_traces                                          \
        EM(fscache_cookie_collision,            "*COLLIDE*")            \
        EM(fscache_cookie_discard,              "DISCARD  ")            \
+       EM(fscache_cookie_failed,               "FAILED   ")            \
        EM(fscache_cookie_get_attach_object,    "GET attch")            \
        EM(fscache_cookie_get_hash_collision,   "GET hcoll")            \
        EM(fscache_cookie_get_end_access,       "GQ  endac")            \
index c708521..77f14f7 100644 (file)
@@ -40,6 +40,28 @@ DEFINE_EVENT(cpu, cpu_idle,
        TP_ARGS(state, cpu_id)
 );
 
+TRACE_EVENT(cpu_idle_miss,
+
+       TP_PROTO(unsigned int cpu_id, unsigned int state, bool below),
+
+       TP_ARGS(cpu_id, state, below),
+
+       TP_STRUCT__entry(
+               __field(u32,            cpu_id)
+               __field(u32,            state)
+               __field(bool,           below)
+       ),
+
+       TP_fast_assign(
+               __entry->cpu_id = cpu_id;
+               __entry->state = state;
+               __entry->below = below;
+       ),
+
+       TP_printk("cpu_id=%lu state=%lu type=%s", (unsigned long)__entry->cpu_id,
+               (unsigned long)__entry->state, (__entry->below)?"below":"above")
+);
+
 TRACE_EVENT(powernv_throttle,
 
        TP_PROTO(int chip_id, const char *reason, int pmax),
index b61d9c9..5c48be0 100644 (file)
@@ -1989,20 +1989,24 @@ TRACE_EVENT(svc_wake_up,
 
 TRACE_EVENT(svc_alloc_arg_err,
        TP_PROTO(
-               unsigned int pages
+               unsigned int requested,
+               unsigned int allocated
        ),
 
-       TP_ARGS(pages),
+       TP_ARGS(requested, allocated),
 
        TP_STRUCT__entry(
-               __field(unsigned int, pages)
+               __field(unsigned int, requested)
+               __field(unsigned int, allocated)
        ),
 
        TP_fast_assign(
-               __entry->pages = pages;
+               __entry->requested = requested;
+               __entry->allocated = allocated;
        ),
 
-       TP_printk("pages=%u", __entry->pages)
+       TP_printk("requested=%u allocated=%u",
+               __entry->requested, __entry->allocated)
 );
 
 DECLARE_EVENT_CLASS(svc_deferred_event,
index 108f852..57b8e2f 100644 (file)
 #define PCI_EXT_CAP_ID_DVSEC   0x23    /* Designated Vendor-Specific */
 #define PCI_EXT_CAP_ID_DLF     0x25    /* Data Link Feature */
 #define PCI_EXT_CAP_ID_PL_16GT 0x26    /* Physical Layer 16.0 GT/s */
-#define PCI_EXT_CAP_ID_MAX     PCI_EXT_CAP_ID_PL_16GT
+#define PCI_EXT_CAP_ID_DOE     0x2E    /* Data Object Exchange */
+#define PCI_EXT_CAP_ID_MAX     PCI_EXT_CAP_ID_DOE
 
 #define PCI_EXT_CAP_DSN_SIZEOF 12
 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
 #define  PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK                0x000000F0
 #define  PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT       4
 
+/* Data Object Exchange */
+#define PCI_DOE_CAP            0x04    /* DOE Capabilities Register */
+#define  PCI_DOE_CAP_INT_SUP                   0x00000001  /* Interrupt Support */
+#define  PCI_DOE_CAP_INT_MSG_NUM               0x00000ffe  /* Interrupt Message Number */
+#define PCI_DOE_CTRL           0x08    /* DOE Control Register */
+#define  PCI_DOE_CTRL_ABORT                    0x00000001  /* DOE Abort */
+#define  PCI_DOE_CTRL_INT_EN                   0x00000002  /* DOE Interrupt Enable */
+#define  PCI_DOE_CTRL_GO                       0x80000000  /* DOE Go */
+#define PCI_DOE_STATUS         0x0c    /* DOE Status Register */
+#define  PCI_DOE_STATUS_BUSY                   0x00000001  /* DOE Busy */
+#define  PCI_DOE_STATUS_INT_STATUS             0x00000002  /* DOE Interrupt Status */
+#define  PCI_DOE_STATUS_ERROR                  0x00000004  /* DOE Error */
+#define  PCI_DOE_STATUS_DATA_OBJECT_READY      0x80000000  /* Data Object Ready */
+#define PCI_DOE_WRITE          0x10    /* DOE Write Data Mailbox Register */
+#define PCI_DOE_READ           0x14    /* DOE Read Data Mailbox Register */
+
+/* DOE Data Object - note not actually registers */
+#define PCI_DOE_DATA_OBJECT_HEADER_1_VID               0x0000ffff
+#define PCI_DOE_DATA_OBJECT_HEADER_1_TYPE              0x00ff0000
+#define PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH            0x0003ffff
+
+#define PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX           0x000000ff
+#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID             0x0000ffff
+#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL                0x00ff0000
+#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX      0xff000000
+
 #endif /* LINUX_PCI_REGS_H */
index 8c9ad53..80fe60f 100644 (file)
@@ -1411,13 +1411,6 @@ config CC_OPTIMIZE_FOR_PERFORMANCE
          with the "-O2" compiler flag for best performance and most
          helpful compile-time warnings.
 
-config CC_OPTIMIZE_FOR_PERFORMANCE_O3
-       bool "Optimize more for performance (-O3)"
-       depends on ARC
-       help
-         Choosing this option will pass "-O3" to your compiler to optimize
-         the kernel yet more for performance.
-
 config CC_OPTIMIZE_FOR_SIZE
        bool "Optimize for size (-Os)"
        help
@@ -1733,16 +1726,17 @@ config KALLSYMS_ALL
        help
          Normally kallsyms only contains the symbols of functions for nicer
          OOPS messages and backtraces (i.e., symbols from the text and inittext
-         sections). This is sufficient for most cases. And only in very rare
-         cases (e.g., when a debugger is used) all symbols are required (e.g.,
-         names of variables from the data sections, etc).
+         sections). This is sufficient for most cases. And only if you want to
+         enable kernel live patching, or other less common use cases (e.g.,
+         when a debugger is used) all symbols are required (i.e., names of
+         variables from the data sections, etc).
 
          This option makes sure that all symbols are loaded into the kernel
          image (i.e., symbols from all sections) in cost of increased kernel
          size (depending on the kernel configuration, it may be 300KiB or
          something like this).
 
-         Say N unless you really need all symbols.
+         Say N unless you really need all symbols, or kernel live patching.
 
 config KALLSYMS_ABSOLUTE_PERCPU
        bool
@@ -1933,298 +1927,7 @@ config MODULE_SIG_FORMAT
        def_bool n
        select SYSTEM_DATA_VERIFICATION
 
-menuconfig MODULES
-       bool "Enable loadable module support"
-       modules
-       help
-         Kernel modules are small pieces of compiled code which can
-         be inserted in the running kernel, rather than being
-         permanently built into the kernel.  You use the "modprobe"
-         tool to add (and sometimes remove) them.  If you say Y here,
-         many parts of the kernel can be built as modules (by
-         answering M instead of Y where indicated): this is most
-         useful for infrequently used options which are not required
-         for booting.  For more information, see the man pages for
-         modprobe, lsmod, modinfo, insmod and rmmod.
-
-         If you say Y here, you will need to run "make
-         modules_install" to put the modules under /lib/modules/
-         where modprobe can find them (you may need to be root to do
-         this).
-
-         If unsure, say Y.
-
-if MODULES
-
-config MODULE_FORCE_LOAD
-       bool "Forced module loading"
-       default n
-       help
-         Allow loading of modules without version information (ie. modprobe
-         --force).  Forced module loading sets the 'F' (forced) taint flag and
-         is usually a really bad idea.
-
-config MODULE_UNLOAD
-       bool "Module unloading"
-       help
-         Without this option you will not be able to unload any
-         modules (note that some modules may not be unloadable
-         anyway), which makes your kernel smaller, faster
-         and simpler.  If unsure, say Y.
-
-config MODULE_FORCE_UNLOAD
-       bool "Forced module unloading"
-       depends on MODULE_UNLOAD
-       help
-         This option allows you to force a module to unload, even if the
-         kernel believes it is unsafe: the kernel will remove the module
-         without waiting for anyone to stop using it (using the -f option to
-         rmmod).  This is mainly for kernel developers and desperate users.
-         If unsure, say N.
-
-config MODULE_UNLOAD_TAINT_TRACKING
-       bool "Tainted module unload tracking"
-       depends on MODULE_UNLOAD
-       default n
-       help
-         This option allows you to maintain a record of each unloaded
-         module that tainted the kernel. In addition to displaying a
-         list of linked (or loaded) modules e.g. on detection of a bad
-         page (see bad_page()), the aforementioned details are also
-         shown. If unsure, say N.
-
-config MODVERSIONS
-       bool "Module versioning support"
-       help
-         Usually, you have to use modules compiled with your kernel.
-         Saying Y here makes it sometimes possible to use modules
-         compiled for different kernels, by adding enough information
-         to the modules to (hopefully) spot any changes which would
-         make them incompatible with the kernel you are running.  If
-         unsure, say N.
-
-config ASM_MODVERSIONS
-       bool
-       default HAVE_ASM_MODVERSIONS && MODVERSIONS
-       help
-         This enables module versioning for exported symbols also from
-         assembly. This can be enabled only when the target architecture
-         supports it.
-
-config MODULE_SRCVERSION_ALL
-       bool "Source checksum for all modules"
-       help
-         Modules which contain a MODULE_VERSION get an extra "srcversion"
-         field inserted into their modinfo section, which contains a
-         sum of the source files which made it.  This helps maintainers
-         see exactly which source was used to build a module (since
-         others sometimes change the module source without updating
-         the version).  With this option, such a "srcversion" field
-         will be created for all modules.  If unsure, say N.
-
-config MODULE_SIG
-       bool "Module signature verification"
-       select MODULE_SIG_FORMAT
-       help
-         Check modules for valid signatures upon load: the signature
-         is simply appended to the module. For more information see
-         <file:Documentation/admin-guide/module-signing.rst>.
-
-         Note that this option adds the OpenSSL development packages as a
-         kernel build dependency so that the signing tool can use its crypto
-         library.
-
-         You should enable this option if you wish to use either
-         CONFIG_SECURITY_LOCKDOWN_LSM or lockdown functionality imposed via
-         another LSM - otherwise unsigned modules will be loadable regardless
-         of the lockdown policy.
-
-         !!!WARNING!!!  If you enable this option, you MUST make sure that the
-         module DOES NOT get stripped after being signed.  This includes the
-         debuginfo strip done by some packagers (such as rpmbuild) and
-         inclusion into an initramfs that wants the module size reduced.
-
-config MODULE_SIG_FORCE
-       bool "Require modules to be validly signed"
-       depends on MODULE_SIG
-       help
-         Reject unsigned modules or signed modules for which we don't have a
-         key.  Without this, such modules will simply taint the kernel.
-
-config MODULE_SIG_ALL
-       bool "Automatically sign all modules"
-       default y
-       depends on MODULE_SIG || IMA_APPRAISE_MODSIG
-       help
-         Sign all modules during make modules_install. Without this option,
-         modules must be signed manually, using the scripts/sign-file tool.
-
-comment "Do not forget to sign required modules with scripts/sign-file"
-       depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
-
-choice
-       prompt "Which hash algorithm should modules be signed with?"
-       depends on MODULE_SIG || IMA_APPRAISE_MODSIG
-       help
-         This determines which sort of hashing algorithm will be used during
-         signature generation.  This algorithm _must_ be built into the kernel
-         directly so that signature verification can take place.  It is not
-         possible to load a signed module containing the algorithm to check
-         the signature on that module.
-
-config MODULE_SIG_SHA1
-       bool "Sign modules with SHA-1"
-       select CRYPTO_SHA1
-
-config MODULE_SIG_SHA224
-       bool "Sign modules with SHA-224"
-       select CRYPTO_SHA256
-
-config MODULE_SIG_SHA256
-       bool "Sign modules with SHA-256"
-       select CRYPTO_SHA256
-
-config MODULE_SIG_SHA384
-       bool "Sign modules with SHA-384"
-       select CRYPTO_SHA512
-
-config MODULE_SIG_SHA512
-       bool "Sign modules with SHA-512"
-       select CRYPTO_SHA512
-
-endchoice
-
-config MODULE_SIG_HASH
-       string
-       depends on MODULE_SIG || IMA_APPRAISE_MODSIG
-       default "sha1" if MODULE_SIG_SHA1
-       default "sha224" if MODULE_SIG_SHA224
-       default "sha256" if MODULE_SIG_SHA256
-       default "sha384" if MODULE_SIG_SHA384
-       default "sha512" if MODULE_SIG_SHA512
-
-choice
-       prompt "Module compression mode"
-       help
-         This option allows you to choose the algorithm which will be used to
-         compress modules when 'make modules_install' is run. (or, you can
-         choose to not compress modules at all.)
-
-         External modules will also be compressed in the same way during the
-         installation.
-
-         For modules inside an initrd or initramfs, it's more efficient to
-         compress the whole initrd or initramfs instead.
-
-         This is fully compatible with signed modules.
-
-         Please note that the tool used to load modules needs to support the
-         corresponding algorithm. module-init-tools MAY support gzip, and kmod
-         MAY support gzip, xz and zstd.
-
-         Your build system needs to provide the appropriate compression tool
-         to compress the modules.
-
-         If in doubt, select 'None'.
-
-config MODULE_COMPRESS_NONE
-       bool "None"
-       help
-         Do not compress modules. The installed modules are suffixed
-         with .ko.
-
-config MODULE_COMPRESS_GZIP
-       bool "GZIP"
-       help
-         Compress modules with GZIP. The installed modules are suffixed
-         with .ko.gz.
-
-config MODULE_COMPRESS_XZ
-       bool "XZ"
-       help
-         Compress modules with XZ. The installed modules are suffixed
-         with .ko.xz.
-
-config MODULE_COMPRESS_ZSTD
-       bool "ZSTD"
-       help
-         Compress modules with ZSTD. The installed modules are suffixed
-         with .ko.zst.
-
-endchoice
-
-config MODULE_DECOMPRESS
-       bool "Support in-kernel module decompression"
-       depends on MODULE_COMPRESS_GZIP || MODULE_COMPRESS_XZ
-       select ZLIB_INFLATE if MODULE_COMPRESS_GZIP
-       select XZ_DEC if MODULE_COMPRESS_XZ
-       help
-
-         Support for decompressing kernel modules by the kernel itself
-         instead of relying on userspace to perform this task. Useful when
-         load pinning security policy is enabled.
-
-         If unsure, say N.
-
-config MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
-       bool "Allow loading of modules with missing namespace imports"
-       help
-         Symbols exported with EXPORT_SYMBOL_NS*() are considered exported in
-         a namespace. A module that makes use of a symbol exported with such a
-         namespace is required to import the namespace via MODULE_IMPORT_NS().
-         There is no technical reason to enforce correct namespace imports,
-         but it creates consistency between symbols defining namespaces and
-         users importing namespaces they make use of. This option relaxes this
-         requirement and lifts the enforcement when loading a module.
-
-         If unsure, say N.
-
-config MODPROBE_PATH
-       string "Path to modprobe binary"
-       default "/sbin/modprobe"
-       help
-         When kernel code requests a module, it does so by calling
-         the "modprobe" userspace utility. This option allows you to
-         set the path where that binary is found. This can be changed
-         at runtime via the sysctl file
-         /proc/sys/kernel/modprobe. Setting this to the empty string
-         removes the kernel's ability to request modules (but
-         userspace can still load modules explicitly).
-
-config TRIM_UNUSED_KSYMS
-       bool "Trim unused exported kernel symbols" if EXPERT
-       depends on !COMPILE_TEST
-       help
-         The kernel and some modules make many symbols available for
-         other modules to use via EXPORT_SYMBOL() and variants. Depending
-         on the set of modules being selected in your kernel configuration,
-         many of those exported symbols might never be used.
-
-         This option allows for unused exported symbols to be dropped from
-         the build. In turn, this provides the compiler more opportunities
-         (especially when using LTO) for optimizing the code and reducing
-         binary size.  This might have some security advantages as well.
-
-         If unsure, or if you need to build out-of-tree modules, say N.
-
-config UNUSED_KSYMS_WHITELIST
-       string "Whitelist of symbols to keep in ksymtab"
-       depends on TRIM_UNUSED_KSYMS
-       help
-         By default, all unused exported symbols will be un-exported from the
-         build when TRIM_UNUSED_KSYMS is selected.
-
-         UNUSED_KSYMS_WHITELIST allows to whitelist symbols that must be kept
-         exported at all times, even in absence of in-tree users. The value to
-         set here is the path to a text file containing the list of symbols,
-         one per line. The path can be absolute, or relative to the kernel
-         source tree.
-
-endif # MODULES
-
-config MODULES_TREE_LOOKUP
-       def_bool y
-       depends on PERF_EVENTS || TRACING || CFI_CLANG
+source "kernel/module/Kconfig"
 
 config INIT_ALL_POSSIBLE
        bool
index 375fb3c..c21abc7 100644 (file)
@@ -74,7 +74,7 @@ out_unmap_membase:
        return ERR_PTR(-ENOMEM);
 }
 
-static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
+static void _dma_release_coherent_memory(struct dma_coherent_mem *mem)
 {
        if (!mem)
                return;
@@ -126,10 +126,16 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
 
        ret = dma_assign_coherent_memory(dev, mem);
        if (ret)
-               dma_release_coherent_memory(mem);
+               _dma_release_coherent_memory(mem);
        return ret;
 }
 
+void dma_release_coherent_memory(struct device *dev)
+{
+       if (dev)
+               _dma_release_coherent_memory(dev->dma_mem);
+}
+
 static void *__dma_alloc_from_coherent(struct device *dev,
                                       struct dma_coherent_mem *mem,
                                       ssize_t size, dma_addr_t *dma_handle)
diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig
new file mode 100644 (file)
index 0000000..26ea5d0
--- /dev/null
@@ -0,0 +1,293 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menuconfig MODULES
+       bool "Enable loadable module support"
+       modules
+       help
+         Kernel modules are small pieces of compiled code which can
+         be inserted in the running kernel, rather than being
+         permanently built into the kernel.  You use the "modprobe"
+         tool to add (and sometimes remove) them.  If you say Y here,
+         many parts of the kernel can be built as modules (by
+         answering M instead of Y where indicated): this is most
+         useful for infrequently used options which are not required
+         for booting.  For more information, see the man pages for
+         modprobe, lsmod, modinfo, insmod and rmmod.
+
+         If you say Y here, you will need to run "make
+         modules_install" to put the modules under /lib/modules/
+         where modprobe can find them (you may need to be root to do
+         this).
+
+         If unsure, say Y.
+
+if MODULES
+
+config MODULE_FORCE_LOAD
+       bool "Forced module loading"
+       default n
+       help
+         Allow loading of modules without version information (ie. modprobe
+         --force).  Forced module loading sets the 'F' (forced) taint flag and
+         is usually a really bad idea.
+
+config MODULE_UNLOAD
+       bool "Module unloading"
+       help
+         Without this option you will not be able to unload any
+         modules (note that some modules may not be unloadable
+         anyway), which makes your kernel smaller, faster
+         and simpler.  If unsure, say Y.
+
+config MODULE_FORCE_UNLOAD
+       bool "Forced module unloading"
+       depends on MODULE_UNLOAD
+       help
+         This option allows you to force a module to unload, even if the
+         kernel believes it is unsafe: the kernel will remove the module
+         without waiting for anyone to stop using it (using the -f option to
+         rmmod).  This is mainly for kernel developers and desperate users.
+         If unsure, say N.
+
+config MODULE_UNLOAD_TAINT_TRACKING
+       bool "Tainted module unload tracking"
+       depends on MODULE_UNLOAD
+       default n
+       help
+         This option allows you to maintain a record of each unloaded
+         module that tainted the kernel. In addition to displaying a
+         list of linked (or loaded) modules e.g. on detection of a bad
+         page (see bad_page()), the aforementioned details are also
+         shown. If unsure, say N.
+
+config MODVERSIONS
+       bool "Module versioning support"
+       help
+         Usually, you have to use modules compiled with your kernel.
+         Saying Y here makes it sometimes possible to use modules
+         compiled for different kernels, by adding enough information
+         to the modules to (hopefully) spot any changes which would
+         make them incompatible with the kernel you are running.  If
+         unsure, say N.
+
+config ASM_MODVERSIONS
+       bool
+       default HAVE_ASM_MODVERSIONS && MODVERSIONS
+       help
+         This enables module versioning for exported symbols also from
+         assembly. This can be enabled only when the target architecture
+         supports it.
+
+config MODULE_SRCVERSION_ALL
+       bool "Source checksum for all modules"
+       help
+         Modules which contain a MODULE_VERSION get an extra "srcversion"
+         field inserted into their modinfo section, which contains a
+         sum of the source files which made it.  This helps maintainers
+         see exactly which source was used to build a module (since
+         others sometimes change the module source without updating
+         the version).  With this option, such a "srcversion" field
+         will be created for all modules.  If unsure, say N.
+
+config MODULE_SIG
+       bool "Module signature verification"
+       select MODULE_SIG_FORMAT
+       help
+         Check modules for valid signatures upon load: the signature
+         is simply appended to the module. For more information see
+         <file:Documentation/admin-guide/module-signing.rst>.
+
+         Note that this option adds the OpenSSL development packages as a
+         kernel build dependency so that the signing tool can use its crypto
+         library.
+
+         You should enable this option if you wish to use either
+         CONFIG_SECURITY_LOCKDOWN_LSM or lockdown functionality imposed via
+         another LSM - otherwise unsigned modules will be loadable regardless
+         of the lockdown policy.
+
+         !!!WARNING!!!  If you enable this option, you MUST make sure that the
+         module DOES NOT get stripped after being signed.  This includes the
+         debuginfo strip done by some packagers (such as rpmbuild) and
+         inclusion into an initramfs that wants the module size reduced.
+
+config MODULE_SIG_FORCE
+       bool "Require modules to be validly signed"
+       depends on MODULE_SIG
+       help
+         Reject unsigned modules or signed modules for which we don't have a
+         key.  Without this, such modules will simply taint the kernel.
+
+config MODULE_SIG_ALL
+       bool "Automatically sign all modules"
+       default y
+       depends on MODULE_SIG || IMA_APPRAISE_MODSIG
+       help
+         Sign all modules during make modules_install. Without this option,
+         modules must be signed manually, using the scripts/sign-file tool.
+
+comment "Do not forget to sign required modules with scripts/sign-file"
+       depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
+
+choice
+       prompt "Which hash algorithm should modules be signed with?"
+       depends on MODULE_SIG || IMA_APPRAISE_MODSIG
+       help
+         This determines which sort of hashing algorithm will be used during
+         signature generation.  This algorithm _must_ be built into the kernel
+         directly so that signature verification can take place.  It is not
+         possible to load a signed module containing the algorithm to check
+         the signature on that module.
+
+config MODULE_SIG_SHA1
+       bool "Sign modules with SHA-1"
+       select CRYPTO_SHA1
+
+config MODULE_SIG_SHA224
+       bool "Sign modules with SHA-224"
+       select CRYPTO_SHA256
+
+config MODULE_SIG_SHA256
+       bool "Sign modules with SHA-256"
+       select CRYPTO_SHA256
+
+config MODULE_SIG_SHA384
+       bool "Sign modules with SHA-384"
+       select CRYPTO_SHA512
+
+config MODULE_SIG_SHA512
+       bool "Sign modules with SHA-512"
+       select CRYPTO_SHA512
+
+endchoice
+
+config MODULE_SIG_HASH
+       string
+       depends on MODULE_SIG || IMA_APPRAISE_MODSIG
+       default "sha1" if MODULE_SIG_SHA1
+       default "sha224" if MODULE_SIG_SHA224
+       default "sha256" if MODULE_SIG_SHA256
+       default "sha384" if MODULE_SIG_SHA384
+       default "sha512" if MODULE_SIG_SHA512
+
+choice
+       prompt "Module compression mode"
+       help
+         This option allows you to choose the algorithm which will be used to
+         compress modules when 'make modules_install' is run. (or, you can
+         choose to not compress modules at all.)
+
+         External modules will also be compressed in the same way during the
+         installation.
+
+         For modules inside an initrd or initramfs, it's more efficient to
+         compress the whole initrd or initramfs instead.
+
+         This is fully compatible with signed modules.
+
+         Please note that the tool used to load modules needs to support the
+         corresponding algorithm. module-init-tools MAY support gzip, and kmod
+         MAY support gzip, xz and zstd.
+
+         Your build system needs to provide the appropriate compression tool
+         to compress the modules.
+
+         If in doubt, select 'None'.
+
+config MODULE_COMPRESS_NONE
+       bool "None"
+       help
+         Do not compress modules. The installed modules are suffixed
+         with .ko.
+
+config MODULE_COMPRESS_GZIP
+       bool "GZIP"
+       help
+         Compress modules with GZIP. The installed modules are suffixed
+         with .ko.gz.
+
+config MODULE_COMPRESS_XZ
+       bool "XZ"
+       help
+         Compress modules with XZ. The installed modules are suffixed
+         with .ko.xz.
+
+config MODULE_COMPRESS_ZSTD
+       bool "ZSTD"
+       help
+         Compress modules with ZSTD. The installed modules are suffixed
+         with .ko.zst.
+
+endchoice
+
+config MODULE_DECOMPRESS
+       bool "Support in-kernel module decompression"
+       depends on MODULE_COMPRESS_GZIP || MODULE_COMPRESS_XZ
+       select ZLIB_INFLATE if MODULE_COMPRESS_GZIP
+       select XZ_DEC if MODULE_COMPRESS_XZ
+       help
+
+         Support for decompressing kernel modules by the kernel itself
+         instead of relying on userspace to perform this task. Useful when
+         load pinning security policy is enabled.
+
+         If unsure, say N.
+
+config MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
+       bool "Allow loading of modules with missing namespace imports"
+       help
+         Symbols exported with EXPORT_SYMBOL_NS*() are considered exported in
+         a namespace. A module that makes use of a symbol exported with such a
+         namespace is required to import the namespace via MODULE_IMPORT_NS().
+         There is no technical reason to enforce correct namespace imports,
+         but it creates consistency between symbols defining namespaces and
+         users importing namespaces they make use of. This option relaxes this
+         requirement and lifts the enforcement when loading a module.
+
+         If unsure, say N.
+
+config MODPROBE_PATH
+       string "Path to modprobe binary"
+       default "/sbin/modprobe"
+       help
+         When kernel code requests a module, it does so by calling
+         the "modprobe" userspace utility. This option allows you to
+         set the path where that binary is found. This can be changed
+         at runtime via the sysctl file
+         /proc/sys/kernel/modprobe. Setting this to the empty string
+         removes the kernel's ability to request modules (but
+         userspace can still load modules explicitly).
+
+config TRIM_UNUSED_KSYMS
+       bool "Trim unused exported kernel symbols" if EXPERT
+       depends on !COMPILE_TEST
+       help
+         The kernel and some modules make many symbols available for
+         other modules to use via EXPORT_SYMBOL() and variants. Depending
+         on the set of modules being selected in your kernel configuration,
+         many of those exported symbols might never be used.
+
+         This option allows for unused exported symbols to be dropped from
+         the build. In turn, this provides the compiler more opportunities
+         (especially when using LTO) for optimizing the code and reducing
+         binary size.  This might have some security advantages as well.
+
+         If unsure, or if you need to build out-of-tree modules, say N.
+
+config UNUSED_KSYMS_WHITELIST
+       string "Whitelist of symbols to keep in ksymtab"
+       depends on TRIM_UNUSED_KSYMS
+       help
+         By default, all unused exported symbols will be un-exported from the
+         build when TRIM_UNUSED_KSYMS is selected.
+
+         UNUSED_KSYMS_WHITELIST allows to whitelist symbols that must be kept
+         exported at all times, even in absence of in-tree users. The value to
+         set here is the path to a text file containing the list of symbols,
+         one per line. The path can be absolute, or relative to the kernel
+         source tree.
+
+config MODULES_TREE_LOOKUP
+       def_bool y
+       depends on PERF_EVENTS || TRACING || CFI_CLANG
+
+endif # MODULES
index 2fc7081..4d0bcb3 100644 (file)
@@ -119,10 +119,10 @@ static ssize_t module_gzip_decompress(struct load_info *info,
                        goto out_inflate_end;
                }
 
-               s.next_out = kmap(page);
+               s.next_out = kmap_local_page(page);
                s.avail_out = PAGE_SIZE;
                rc = zlib_inflate(&s, 0);
-               kunmap(page);
+               kunmap_local(s.next_out);
 
                new_size += PAGE_SIZE - s.avail_out;
        } while (rc == Z_OK);
@@ -178,11 +178,11 @@ static ssize_t module_xz_decompress(struct load_info *info,
                        goto out;
                }
 
-               xz_buf.out = kmap(page);
+               xz_buf.out = kmap_local_page(page);
                xz_buf.out_pos = 0;
                xz_buf.out_size = PAGE_SIZE;
                xz_ret = xz_dec_run(xz_dec, &xz_buf);
-               kunmap(page);
+               kunmap_local(xz_buf.out);
 
                new_size += xz_buf.out_pos;
        } while (xz_buf.out_pos == PAGE_SIZE && xz_ret == XZ_OK);
index ec104c2..680d980 100644 (file)
@@ -103,7 +103,7 @@ struct module *find_module_all(const char *name, size_t len, bool even_unformed)
 int cmp_name(const void *name, const void *sym);
 long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
                       unsigned int section);
-char *module_flags(struct module *mod, char *buf);
+char *module_flags(struct module *mod, char *buf, bool show_state);
 size_t module_flags_taint(unsigned long taints, char *buf);
 
 static inline void module_assert_mutex_or_preempt(void)
index 77e75be..f5c5c91 100644 (file)
@@ -457,26 +457,39 @@ unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
        return 0;
 }
 
-/* Look for this name: can be of form module:name. */
-unsigned long module_kallsyms_lookup_name(const char *name)
+static unsigned long __module_kallsyms_lookup_name(const char *name)
 {
        struct module *mod;
        char *colon;
-       unsigned long ret = 0;
+
+       colon = strnchr(name, MODULE_NAME_LEN, ':');
+       if (colon) {
+               mod = find_module_all(name, colon - name, false);
+               if (mod)
+                       return find_kallsyms_symbol_value(mod, colon + 1);
+               return 0;
+       }
+
+       list_for_each_entry_rcu(mod, &modules, list) {
+               unsigned long ret;
+
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
+               ret = find_kallsyms_symbol_value(mod, name);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/* Look for this name: can be of form module:name. */
+unsigned long module_kallsyms_lookup_name(const char *name)
+{
+       unsigned long ret;
 
        /* Don't lock: we're in enough trouble already. */
        preempt_disable();
-       if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
-               if ((mod = find_module_all(name, colon - name, false)) != NULL)
-                       ret = find_kallsyms_symbol_value(mod, colon + 1);
-       } else {
-               list_for_each_entry_rcu(mod, &modules, list) {
-                       if (mod->state == MODULE_STATE_UNFORMED)
-                               continue;
-                       if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
-                               break;
-               }
-       }
+       ret = __module_kallsyms_lookup_name(name);
        preempt_enable();
        return ret;
 }
index 57fc282..6a477c6 100644 (file)
@@ -119,7 +119,7 @@ static void mod_update_bounds(struct module *mod)
 }
 
 /* Block module loading/unloading? */
-int modules_disabled = 0;
+int modules_disabled;
 core_param(nomodule, modules_disabled, bint, 0);
 
 /* Waiting for a module to finish initializing? */
@@ -524,7 +524,10 @@ static struct module_attribute modinfo_##field = {                    \
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
-static char last_unloaded_module[MODULE_NAME_LEN+1];
+static struct {
+       char name[MODULE_NAME_LEN + 1];
+       char taints[MODULE_FLAGS_BUF_SIZE];
+} last_unloaded_module;
 
 #ifdef CONFIG_MODULE_UNLOAD
 
@@ -694,6 +697,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
 {
        struct module *mod;
        char name[MODULE_NAME_LEN];
+       char buf[MODULE_FLAGS_BUF_SIZE];
        int ret, forced = 0;
 
        if (!capable(CAP_SYS_MODULE) || modules_disabled)
@@ -753,8 +757,9 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
 
        async_synchronize_full();
 
-       /* Store the name of the last unloaded module for diagnostic purposes */
-       strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
+       /* Store the name and taints of the last unloaded module for diagnostic purposes */
+       strscpy(last_unloaded_module.name, mod->name, sizeof(last_unloaded_module.name));
+       strscpy(last_unloaded_module.taints, module_flags(mod, buf, false), sizeof(last_unloaded_module.taints));
 
        free_module(mod);
        /* someone could wait for the module in add_unformed_module() */
@@ -2151,7 +2156,7 @@ static int move_module(struct module *mod, struct load_info *info)
 
 #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC
        /* Do the allocs. */
-       ptr = vmalloc(mod->data_layout.size);
+       ptr = vzalloc(mod->data_layout.size);
        /*
         * The pointer to this block is stored in the module structure
         * which is inside the block. Just mark it as not being a
@@ -2164,7 +2169,6 @@ static int move_module(struct module *mod, struct load_info *info)
                return -ENOMEM;
        }
 
-       memset(ptr, 0, mod->data_layout.size);
        mod->data_layout.base = ptr;
 #endif
        /* Transfer each section which specifies SHF_ALLOC */
@@ -2423,6 +2427,12 @@ static void do_free_init(struct work_struct *w)
        }
 }
 
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "module."
+/* Default value for module->async_probe_requested */
+static bool async_probe;
+module_param(async_probe, bool, 0644);
+
 /*
  * This is where the real work happens.
  *
@@ -2643,7 +2653,8 @@ static int unknown_module_param_cb(char *param, char *val, const char *modname,
        int ret;
 
        if (strcmp(param, "async_probe") == 0) {
-               mod->async_probe_requested = true;
+               if (strtobool(val, &mod->async_probe_requested))
+                       mod->async_probe_requested = true;
                return 0;
        }
 
@@ -2810,6 +2821,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
        if (err)
                goto bug_cleanup;
 
+       mod->async_probe_requested = async_probe;
+
        /* Module is ready to execute: parsing args may do that. */
        after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
                                  -32768, 32767, mod,
@@ -2984,24 +2997,27 @@ static void cfi_cleanup(struct module *mod)
 }
 
 /* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
-char *module_flags(struct module *mod, char *buf)
+char *module_flags(struct module *mod, char *buf, bool show_state)
 {
        int bx = 0;
 
        BUG_ON(mod->state == MODULE_STATE_UNFORMED);
+       if (!mod->taints && !show_state)
+               goto out;
        if (mod->taints ||
            mod->state == MODULE_STATE_GOING ||
            mod->state == MODULE_STATE_COMING) {
                buf[bx++] = '(';
                bx += module_flags_taint(mod->taints, buf + bx);
                /* Show a - for module-is-being-unloaded */
-               if (mod->state == MODULE_STATE_GOING)
+               if (mod->state == MODULE_STATE_GOING && show_state)
                        buf[bx++] = '-';
                /* Show a + for module-is-being-loaded */
-               if (mod->state == MODULE_STATE_COMING)
+               if (mod->state == MODULE_STATE_COMING && show_state)
                        buf[bx++] = '+';
                buf[bx++] = ')';
        }
+out:
        buf[bx] = '\0';
 
        return buf;
@@ -3134,12 +3150,13 @@ void print_modules(void)
        list_for_each_entry_rcu(mod, &modules, list) {
                if (mod->state == MODULE_STATE_UNFORMED)
                        continue;
-               pr_cont(" %s%s", mod->name, module_flags(mod, buf));
+               pr_cont(" %s%s", mod->name, module_flags(mod, buf, true));
        }
 
        print_unloaded_tainted_modules();
        preempt_enable();
-       if (last_unloaded_module[0])
-               pr_cont(" [last unloaded: %s]", last_unloaded_module);
+       if (last_unloaded_module.name[0])
+               pr_cont(" [last unloaded: %s%s]", last_unloaded_module.name,
+                       last_unloaded_module.taints);
        pr_cont("\n");
 }
index 9a8f4f0..cf5b9f1 100644 (file)
@@ -91,7 +91,7 @@ static int m_show(struct seq_file *m, void *p)
 
        /* Taints info */
        if (mod->taints)
-               seq_printf(m, " %s", module_flags(mod, buf));
+               seq_printf(m, " %s", module_flags(mod, buf, true));
 
        seq_puts(m, "\n");
        return 0;
index 34eaee1..4c5e80b 100644 (file)
@@ -489,8 +489,9 @@ int __weak page_is_ram(unsigned long pfn)
 }
 EXPORT_SYMBOL_GPL(page_is_ram);
 
-static int __region_intersects(resource_size_t start, size_t size,
-                       unsigned long flags, unsigned long desc)
+static int __region_intersects(struct resource *parent, resource_size_t start,
+                              size_t size, unsigned long flags,
+                              unsigned long desc)
 {
        struct resource res;
        int type = 0; int other = 0;
@@ -499,7 +500,7 @@ static int __region_intersects(resource_size_t start, size_t size,
        res.start = start;
        res.end = start + size - 1;
 
-       for (p = iomem_resource.child; p ; p = p->sibling) {
+       for (p = parent->child; p ; p = p->sibling) {
                bool is_type = (((p->flags & flags) == flags) &&
                                ((desc == IORES_DESC_NONE) ||
                                 (desc == p->desc)));
@@ -543,7 +544,7 @@ int region_intersects(resource_size_t start, size_t size, unsigned long flags,
        int ret;
 
        read_lock(&resource_lock);
-       ret = __region_intersects(start, size, flags, desc);
+       ret = __region_intersects(&iomem_resource, start, size, flags, desc);
        read_unlock(&resource_lock);
 
        return ret;
@@ -891,6 +892,13 @@ void insert_resource_expand_to_fit(struct resource *root, struct resource *new)
        }
        write_unlock(&resource_lock);
 }
+/*
+ * Not for general consumption, only early boot memory map parsing, PCI
+ * resource discovery, and late discovery of CXL resources are expected
+ * to use this interface. The former are built-in and only the latter,
+ * CXL, is a module.
+ */
+EXPORT_SYMBOL_NS_GPL(insert_resource_expand_to_fit, CXL);
 
 /**
  * remove_resource - Remove a resource in the resource tree
@@ -1773,62 +1781,139 @@ void resource_list_free(struct list_head *head)
 }
 EXPORT_SYMBOL(resource_list_free);
 
-#ifdef CONFIG_DEVICE_PRIVATE
-static struct resource *__request_free_mem_region(struct device *dev,
-               struct resource *base, unsigned long size, const char *name)
+#ifdef CONFIG_GET_FREE_REGION
+#define GFR_DESCENDING         (1UL << 0)
+#define GFR_REQUEST_REGION     (1UL << 1)
+#define GFR_DEFAULT_ALIGN (1UL << PA_SECTION_SHIFT)
+
+static resource_size_t gfr_start(struct resource *base, resource_size_t size,
+                                resource_size_t align, unsigned long flags)
+{
+       if (flags & GFR_DESCENDING) {
+               resource_size_t end;
+
+               end = min_t(resource_size_t, base->end,
+                           (1ULL << MAX_PHYSMEM_BITS) - 1);
+               return end - size + 1;
+       }
+
+       return ALIGN(base->start, align);
+}
+
+static bool gfr_continue(struct resource *base, resource_size_t addr,
+                        resource_size_t size, unsigned long flags)
+{
+       if (flags & GFR_DESCENDING)
+               return addr > size && addr >= base->start;
+       /*
+        * In the ascend case be careful that the last increment by
+        * @size did not wrap 0.
+        */
+       return addr > addr - size &&
+              addr <= min_t(resource_size_t, base->end,
+                            (1ULL << MAX_PHYSMEM_BITS) - 1);
+}
+
+static resource_size_t gfr_next(resource_size_t addr, resource_size_t size,
+                               unsigned long flags)
 {
-       resource_size_t end, addr;
+       if (flags & GFR_DESCENDING)
+               return addr - size;
+       return addr + size;
+}
+
+static void remove_free_mem_region(void *_res)
+{
+       struct resource *res = _res;
+
+       if (res->parent)
+               remove_resource(res);
+       free_resource(res);
+}
+
+static struct resource *
+get_free_mem_region(struct device *dev, struct resource *base,
+                   resource_size_t size, const unsigned long align,
+                   const char *name, const unsigned long desc,
+                   const unsigned long flags)
+{
+       resource_size_t addr;
        struct resource *res;
        struct region_devres *dr = NULL;
 
-       size = ALIGN(size, 1UL << PA_SECTION_SHIFT);
-       end = min_t(unsigned long, base->end, (1UL << MAX_PHYSMEM_BITS) - 1);
-       addr = end - size + 1UL;
+       size = ALIGN(size, align);
 
        res = alloc_resource(GFP_KERNEL);
        if (!res)
                return ERR_PTR(-ENOMEM);
 
-       if (dev) {
+       if (dev && (flags & GFR_REQUEST_REGION)) {
                dr = devres_alloc(devm_region_release,
                                sizeof(struct region_devres), GFP_KERNEL);
                if (!dr) {
                        free_resource(res);
                        return ERR_PTR(-ENOMEM);
                }
+       } else if (dev) {
+               if (devm_add_action_or_reset(dev, remove_free_mem_region, res))
+                       return ERR_PTR(-ENOMEM);
        }
 
        write_lock(&resource_lock);
-       for (; addr > size && addr >= base->start; addr -= size) {
-               if (__region_intersects(addr, size, 0, IORES_DESC_NONE) !=
-                               REGION_DISJOINT)
+       for (addr = gfr_start(base, size, align, flags);
+            gfr_continue(base, addr, size, flags);
+            addr = gfr_next(addr, size, flags)) {
+               if (__region_intersects(base, addr, size, 0, IORES_DESC_NONE) !=
+                   REGION_DISJOINT)
                        continue;
 
-               if (__request_region_locked(res, &iomem_resource, addr, size,
-                                               name, 0))
-                       break;
+               if (flags & GFR_REQUEST_REGION) {
+                       if (__request_region_locked(res, &iomem_resource, addr,
+                                                   size, name, 0))
+                               break;
 
-               if (dev) {
-                       dr->parent = &iomem_resource;
-                       dr->start = addr;
-                       dr->n = size;
-                       devres_add(dev, dr);
-               }
+                       if (dev) {
+                               dr->parent = &iomem_resource;
+                               dr->start = addr;
+                               dr->n = size;
+                               devres_add(dev, dr);
+                       }
 
-               res->desc = IORES_DESC_DEVICE_PRIVATE_MEMORY;
-               write_unlock(&resource_lock);
+                       res->desc = desc;
+                       write_unlock(&resource_lock);
+
+
+                       /*
+                        * A driver is claiming this region so revoke any
+                        * mappings.
+                        */
+                       revoke_iomem(res);
+               } else {
+                       res->start = addr;
+                       res->end = addr + size - 1;
+                       res->name = name;
+                       res->desc = desc;
+                       res->flags = IORESOURCE_MEM;
+
+                       /*
+                        * Only succeed if the resource hosts an exclusive
+                        * range after the insert
+                        */
+                       if (__insert_resource(base, res) || res->child)
+                               break;
+
+                       write_unlock(&resource_lock);
+               }
 
-               /*
-                * A driver is claiming this region so revoke any mappings.
-                */
-               revoke_iomem(res);
                return res;
        }
        write_unlock(&resource_lock);
 
-       free_resource(res);
-       if (dr)
+       if (flags & GFR_REQUEST_REGION) {
+               free_resource(res);
                devres_free(dr);
+       } else if (dev)
+               devm_release_action(dev, remove_free_mem_region, res);
 
        return ERR_PTR(-ERANGE);
 }
@@ -1847,18 +1932,48 @@ static struct resource *__request_free_mem_region(struct device *dev,
 struct resource *devm_request_free_mem_region(struct device *dev,
                struct resource *base, unsigned long size)
 {
-       return __request_free_mem_region(dev, base, size, dev_name(dev));
+       unsigned long flags = GFR_DESCENDING | GFR_REQUEST_REGION;
+
+       return get_free_mem_region(dev, base, size, GFR_DEFAULT_ALIGN,
+                                  dev_name(dev),
+                                  IORES_DESC_DEVICE_PRIVATE_MEMORY, flags);
 }
 EXPORT_SYMBOL_GPL(devm_request_free_mem_region);
 
 struct resource *request_free_mem_region(struct resource *base,
                unsigned long size, const char *name)
 {
-       return __request_free_mem_region(NULL, base, size, name);
+       unsigned long flags = GFR_DESCENDING | GFR_REQUEST_REGION;
+
+       return get_free_mem_region(NULL, base, size, GFR_DEFAULT_ALIGN, name,
+                                  IORES_DESC_DEVICE_PRIVATE_MEMORY, flags);
 }
 EXPORT_SYMBOL_GPL(request_free_mem_region);
 
-#endif /* CONFIG_DEVICE_PRIVATE */
+/**
+ * alloc_free_mem_region - find a free region relative to @base
+ * @base: resource that will parent the new resource
+ * @size: size in bytes of memory to allocate from @base
+ * @align: alignment requirements for the allocation
+ * @name: resource name
+ *
+ * Buses like CXL, that can dynamically instantiate new memory regions,
+ * need a method to allocate physical address space for those regions.
+ * Allocate and insert a new resource to cover a free, unclaimed by a
+ * descendant of @base, range in the span of @base.
+ */
+struct resource *alloc_free_mem_region(struct resource *base,
+                                      unsigned long size, unsigned long align,
+                                      const char *name)
+{
+       /* Default of ascending direction and insert resource */
+       unsigned long flags = 0;
+
+       return get_free_mem_region(NULL, base, size, align, name,
+                                  IORES_DESC_NONE, flags);
+}
+EXPORT_SYMBOL_NS_GPL(alloc_free_mem_region, CXL);
+#endif /* CONFIG_GET_FREE_REGION */
 
 static int __init strict_iomem(char *str)
 {
index b233714..205d605 100644 (file)
@@ -492,12 +492,12 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
        int *i, vleft, first = 1, err = 0;
        size_t left;
        char *p;
-       
+
        if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
                *lenp = 0;
                return 0;
        }
-       
+
        i = (int *) tbl_data;
        vleft = table->maxlen / sizeof(*i);
        left = *lenp;
@@ -729,7 +729,7 @@ int proc_dobool(struct ctl_table *table, int write, void *buffer,
  * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
+ * values from/to the user buffer, treated as an ASCII string.
  *
  * Returns 0 on success.
  */
@@ -1273,7 +1273,7 @@ static int do_proc_dointvec_ms_jiffies_minmax_conv(bool *negp, unsigned long *lv
  * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
+ * values from/to the user buffer, treated as an ASCII string.
  * The values read are assumed to be in seconds, and are converted into
  * jiffies.
  *
@@ -1306,8 +1306,8 @@ int proc_dointvec_ms_jiffies_minmax(struct ctl_table *table, int write,
  * @ppos: pointer to the file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
- * The values read are assumed to be in 1/USER_HZ seconds, and 
+ * values from/to the user buffer, treated as an ASCII string.
+ * The values read are assumed to be in 1/USER_HZ seconds, and
  * are converted into jiffies.
  *
  * Returns 0 on success.
@@ -1315,8 +1315,8 @@ int proc_dointvec_ms_jiffies_minmax(struct ctl_table *table, int write,
 int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write,
                                 void *buffer, size_t *lenp, loff_t *ppos)
 {
-    return do_proc_dointvec(table,write,buffer,lenp,ppos,
-                           do_proc_dointvec_userhz_jiffies_conv,NULL);
+       return do_proc_dointvec(table, write, buffer, lenp, ppos,
+                               do_proc_dointvec_userhz_jiffies_conv, NULL);
 }
 
 /**
@@ -2061,7 +2061,7 @@ static struct ctl_table kern_table[] = {
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_ONE,
        },
-#if defined(CONFIG_TREE_RCU)
+#ifdef CONFIG_TREE_RCU
        {
                .procname       = "panic_on_rcu_stall",
                .data           = &sysctl_panic_on_rcu_stall,
@@ -2071,8 +2071,6 @@ static struct ctl_table kern_table[] = {
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_ONE,
        },
-#endif
-#if defined(CONFIG_TREE_RCU)
        {
                .procname       = "max_rcu_stall_to_panic",
                .data           = &sysctl_max_rcu_stall_to_panic,
index 0e0be33..4b7fce7 100644 (file)
 
 #define PIPE_PARANOIA /* for now */
 
+/* covers ubuf and kbuf alike */
+#define iterate_buf(i, n, base, len, off, __p, STEP) {         \
+       size_t __maybe_unused off = 0;                          \
+       len = n;                                                \
+       base = __p + i->iov_offset;                             \
+       len -= (STEP);                                          \
+       i->iov_offset += len;                                   \
+       n = len;                                                \
+}
+
 /* covers iovec and kvec alike */
 #define iterate_iovec(i, n, base, len, off, __p, STEP) {       \
        size_t off = 0;                                         \
@@ -110,7 +120,12 @@ __out:                                                             \
        if (unlikely(i->count < n))                             \
                n = i->count;                                   \
        if (likely(n)) {                                        \
-               if (likely(iter_is_iovec(i))) {                 \
+               if (likely(iter_is_ubuf(i))) {                  \
+                       void __user *base;                      \
+                       size_t len;                             \
+                       iterate_buf(i, n, base, len, off,       \
+                                               i->ubuf, (I))   \
+               } else if (likely(iter_is_iovec(i))) {          \
                        const struct iovec *iov = i->iov;       \
                        void __user *base;                      \
                        size_t len;                             \
@@ -168,26 +183,31 @@ static int copyin(void *to, const void __user *from, size_t n)
        return n;
 }
 
+static inline struct pipe_buffer *pipe_buf(const struct pipe_inode_info *pipe,
+                                          unsigned int slot)
+{
+       return &pipe->bufs[slot & (pipe->ring_size - 1)];
+}
+
 #ifdef PIPE_PARANOIA
 static bool sanity(const struct iov_iter *i)
 {
        struct pipe_inode_info *pipe = i->pipe;
        unsigned int p_head = pipe->head;
        unsigned int p_tail = pipe->tail;
-       unsigned int p_mask = pipe->ring_size - 1;
        unsigned int p_occupancy = pipe_occupancy(p_head, p_tail);
        unsigned int i_head = i->head;
        unsigned int idx;
 
-       if (i->iov_offset) {
+       if (i->last_offset) {
                struct pipe_buffer *p;
                if (unlikely(p_occupancy == 0))
                        goto Bad;       // pipe must be non-empty
                if (unlikely(i_head != p_head - 1))
                        goto Bad;       // must be at the last buffer...
 
-               p = &pipe->bufs[i_head & p_mask];
-               if (unlikely(p->offset + p->len != i->iov_offset))
+               p = pipe_buf(pipe, i_head);
+               if (unlikely(p->offset + p->len != abs(i->last_offset)))
                        goto Bad;       // ... at the end of segment
        } else {
                if (i_head != p_head)
@@ -195,7 +215,7 @@ static bool sanity(const struct iov_iter *i)
        }
        return true;
 Bad:
-       printk(KERN_ERR "idx = %d, offset = %zd\n", i_head, i->iov_offset);
+       printk(KERN_ERR "idx = %d, offset = %d\n", i_head, i->last_offset);
        printk(KERN_ERR "head = %d, tail = %d, buffers = %d\n",
                        p_head, p_tail, pipe->ring_size);
        for (idx = 0; idx < pipe->ring_size; idx++)
@@ -211,15 +231,79 @@ Bad:
 #define sanity(i) true
 #endif
 
+static struct page *push_anon(struct pipe_inode_info *pipe, unsigned size)
+{
+       struct page *page = alloc_page(GFP_USER);
+       if (page) {
+               struct pipe_buffer *buf = pipe_buf(pipe, pipe->head++);
+               *buf = (struct pipe_buffer) {
+                       .ops = &default_pipe_buf_ops,
+                       .page = page,
+                       .offset = 0,
+                       .len = size
+               };
+       }
+       return page;
+}
+
+static void push_page(struct pipe_inode_info *pipe, struct page *page,
+                       unsigned int offset, unsigned int size)
+{
+       struct pipe_buffer *buf = pipe_buf(pipe, pipe->head++);
+       *buf = (struct pipe_buffer) {
+               .ops = &page_cache_pipe_buf_ops,
+               .page = page,
+               .offset = offset,
+               .len = size
+       };
+       get_page(page);
+}
+
+static inline int last_offset(const struct pipe_buffer *buf)
+{
+       if (buf->ops == &default_pipe_buf_ops)
+               return buf->len;        // buf->offset is 0 for those
+       else
+               return -(buf->offset + buf->len);
+}
+
+static struct page *append_pipe(struct iov_iter *i, size_t size,
+                               unsigned int *off)
+{
+       struct pipe_inode_info *pipe = i->pipe;
+       int offset = i->last_offset;
+       struct pipe_buffer *buf;
+       struct page *page;
+
+       if (offset > 0 && offset < PAGE_SIZE) {
+               // some space in the last buffer; add to it
+               buf = pipe_buf(pipe, pipe->head - 1);
+               size = min_t(size_t, size, PAGE_SIZE - offset);
+               buf->len += size;
+               i->last_offset += size;
+               i->count -= size;
+               *off = offset;
+               return buf->page;
+       }
+       // OK, we need a new buffer
+       *off = 0;
+       size = min_t(size_t, size, PAGE_SIZE);
+       if (pipe_full(pipe->head, pipe->tail, pipe->max_usage))
+               return NULL;
+       page = push_anon(pipe, size);
+       if (!page)
+               return NULL;
+       i->head = pipe->head - 1;
+       i->last_offset = size;
+       i->count -= size;
+       return page;
+}
+
 static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i)
 {
        struct pipe_inode_info *pipe = i->pipe;
-       struct pipe_buffer *buf;
-       unsigned int p_tail = pipe->tail;
-       unsigned int p_mask = pipe->ring_size - 1;
-       unsigned int i_head = i->head;
-       size_t off;
+       unsigned int head = pipe->head;
 
        if (unlikely(bytes > i->count))
                bytes = i->count;
@@ -230,32 +314,21 @@ static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t by
        if (!sanity(i))
                return 0;
 
-       off = i->iov_offset;
-       buf = &pipe->bufs[i_head & p_mask];
-       if (off) {
-               if (offset == off && buf->page == page) {
-                       /* merge with the last one */
+       if (offset && i->last_offset == -offset) { // could we merge it?
+               struct pipe_buffer *buf = pipe_buf(pipe, head - 1);
+               if (buf->page == page) {
                        buf->len += bytes;
-                       i->iov_offset += bytes;
-                       goto out;
+                       i->last_offset -= bytes;
+                       i->count -= bytes;
+                       return bytes;
                }
-               i_head++;
-               buf = &pipe->bufs[i_head & p_mask];
        }
-       if (pipe_full(i_head, p_tail, pipe->max_usage))
+       if (pipe_full(pipe->head, pipe->tail, pipe->max_usage))
                return 0;
 
-       buf->ops = &page_cache_pipe_buf_ops;
-       buf->flags = 0;
-       get_page(page);
-       buf->page = page;
-       buf->offset = offset;
-       buf->len = bytes;
-
-       pipe->head = i_head + 1;
-       i->iov_offset = offset + bytes;
-       i->head = i_head;
-out:
+       push_page(pipe, page, offset, bytes);
+       i->last_offset = -(offset + bytes);
+       i->head = head;
        i->count -= bytes;
        return bytes;
 }
@@ -275,7 +348,11 @@ out:
  */
 size_t fault_in_iov_iter_readable(const struct iov_iter *i, size_t size)
 {
-       if (iter_is_iovec(i)) {
+       if (iter_is_ubuf(i)) {
+               size_t n = min(size, iov_iter_count(i));
+               n -= fault_in_readable(i->ubuf + i->iov_offset, n);
+               return size - n;
+       } else if (iter_is_iovec(i)) {
                size_t count = min(size, iov_iter_count(i));
                const struct iovec *p;
                size_t skip;
@@ -314,7 +391,11 @@ EXPORT_SYMBOL(fault_in_iov_iter_readable);
  */
 size_t fault_in_iov_iter_writeable(const struct iov_iter *i, size_t size)
 {
-       if (iter_is_iovec(i)) {
+       if (iter_is_ubuf(i)) {
+               size_t n = min(size, iov_iter_count(i));
+               n -= fault_in_safe_writeable(i->ubuf + i->iov_offset, n);
+               return size - n;
+       } else if (iter_is_iovec(i)) {
                size_t count = min(size, iov_iter_count(i));
                const struct iovec *p;
                size_t skip;
@@ -345,6 +426,7 @@ void iov_iter_init(struct iov_iter *i, unsigned int direction,
        *i = (struct iov_iter) {
                .iter_type = ITER_IOVEC,
                .nofault = false,
+               .user_backed = true,
                .data_source = direction,
                .iov = iov,
                .nr_segs = nr_segs,
@@ -354,101 +436,43 @@ void iov_iter_init(struct iov_iter *i, unsigned int direction,
 }
 EXPORT_SYMBOL(iov_iter_init);
 
-static inline bool allocated(struct pipe_buffer *buf)
-{
-       return buf->ops == &default_pipe_buf_ops;
-}
-
-static inline void data_start(const struct iov_iter *i,
-                             unsigned int *iter_headp, size_t *offp)
-{
-       unsigned int p_mask = i->pipe->ring_size - 1;
-       unsigned int iter_head = i->head;
-       size_t off = i->iov_offset;
-
-       if (off && (!allocated(&i->pipe->bufs[iter_head & p_mask]) ||
-                   off == PAGE_SIZE)) {
-               iter_head++;
-               off = 0;
-       }
-       *iter_headp = iter_head;
-       *offp = off;
-}
-
-static size_t push_pipe(struct iov_iter *i, size_t size,
-                       int *iter_headp, size_t *offp)
+// returns the offset in partial buffer (if any)
+static inline unsigned int pipe_npages(const struct iov_iter *i, int *npages)
 {
        struct pipe_inode_info *pipe = i->pipe;
-       unsigned int p_tail = pipe->tail;
-       unsigned int p_mask = pipe->ring_size - 1;
-       unsigned int iter_head;
-       size_t off;
-       ssize_t left;
+       int used = pipe->head - pipe->tail;
+       int off = i->last_offset;
 
-       if (unlikely(size > i->count))
-               size = i->count;
-       if (unlikely(!size))
-               return 0;
+       *npages = max((int)pipe->max_usage - used, 0);
 
-       left = size;
-       data_start(i, &iter_head, &off);
-       *iter_headp = iter_head;
-       *offp = off;
-       if (off) {
-               left -= PAGE_SIZE - off;
-               if (left <= 0) {
-                       pipe->bufs[iter_head & p_mask].len += size;
-                       return size;
-               }
-               pipe->bufs[iter_head & p_mask].len = PAGE_SIZE;
-               iter_head++;
+       if (off > 0 && off < PAGE_SIZE) { // anon and not full
+               (*npages)++;
+               return off;
        }
-       while (!pipe_full(iter_head, p_tail, pipe->max_usage)) {
-               struct pipe_buffer *buf = &pipe->bufs[iter_head & p_mask];
-               struct page *page = alloc_page(GFP_USER);
-               if (!page)
-                       break;
-
-               buf->ops = &default_pipe_buf_ops;
-               buf->flags = 0;
-               buf->page = page;
-               buf->offset = 0;
-               buf->len = min_t(ssize_t, left, PAGE_SIZE);
-               left -= buf->len;
-               iter_head++;
-               pipe->head = iter_head;
-
-               if (left == 0)
-                       return size;
-       }
-       return size - left;
+       return 0;
 }
 
 static size_t copy_pipe_to_iter(const void *addr, size_t bytes,
                                struct iov_iter *i)
 {
-       struct pipe_inode_info *pipe = i->pipe;
-       unsigned int p_mask = pipe->ring_size - 1;
-       unsigned int i_head;
-       size_t n, off;
+       unsigned int off, chunk;
 
-       if (!sanity(i))
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+       if (unlikely(!bytes))
                return 0;
 
-       bytes = n = push_pipe(i, bytes, &i_head, &off);
-       if (unlikely(!n))
+       if (!sanity(i))
                return 0;
-       do {
-               size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
-               memcpy_to_page(pipe->bufs[i_head & p_mask].page, off, addr, chunk);
-               i->head = i_head;
-               i->iov_offset = off + chunk;
-               n -= chunk;
+
+       for (size_t n = bytes; n; n -= chunk) {
+               struct page *page = append_pipe(i, n, &off);
+               chunk = min_t(size_t, n, PAGE_SIZE - off);
+               if (!page)
+                       return bytes - n;
+               memcpy_to_page(page, off, addr, chunk);
                addr += chunk;
-               off = 0;
-               i_head++;
-       } while (n);
-       i->count -= bytes;
+       }
        return bytes;
 }
 
@@ -462,31 +486,32 @@ static __wsum csum_and_memcpy(void *to, const void *from, size_t len,
 static size_t csum_and_copy_to_pipe_iter(const void *addr, size_t bytes,
                                         struct iov_iter *i, __wsum *sump)
 {
-       struct pipe_inode_info *pipe = i->pipe;
-       unsigned int p_mask = pipe->ring_size - 1;
        __wsum sum = *sump;
        size_t off = 0;
-       unsigned int i_head;
-       size_t r;
+       unsigned int chunk, r;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+       if (unlikely(!bytes))
+               return 0;
 
        if (!sanity(i))
                return 0;
 
-       bytes = push_pipe(i, bytes, &i_head, &r);
        while (bytes) {
-               size_t chunk = min_t(size_t, bytes, PAGE_SIZE - r);
-               char *p = kmap_local_page(pipe->bufs[i_head & p_mask].page);
+               struct page *page = append_pipe(i, bytes, &r);
+               char *p;
+
+               if (!page)
+                       break;
+               chunk = min_t(size_t, bytes, PAGE_SIZE - r);
+               p = kmap_local_page(page);
                sum = csum_and_memcpy(p + r, addr + off, chunk, sum, off);
                kunmap_local(p);
-               i->head = i_head;
-               i->iov_offset = r + chunk;
-               bytes -= chunk;
                off += chunk;
-               r = 0;
-               i_head++;
+               bytes -= chunk;
        }
        *sump = sum;
-       i->count -= off;
        return off;
 }
 
@@ -494,7 +519,7 @@ size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
 {
        if (unlikely(iov_iter_is_pipe(i)))
                return copy_pipe_to_iter(addr, bytes, i);
-       if (iter_is_iovec(i))
+       if (user_backed_iter(i))
                might_fault();
        iterate_and_advance(i, bytes, base, len, off,
                copyout(base, addr + off, len),
@@ -518,39 +543,36 @@ static int copyout_mc(void __user *to, const void *from, size_t n)
 static size_t copy_mc_pipe_to_iter(const void *addr, size_t bytes,
                                struct iov_iter *i)
 {
-       struct pipe_inode_info *pipe = i->pipe;
-       unsigned int p_mask = pipe->ring_size - 1;
-       unsigned int i_head;
-       unsigned int valid = pipe->head;
-       size_t n, off, xfer = 0;
+       size_t xfer = 0;
+       unsigned int off, chunk;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+       if (unlikely(!bytes))
+               return 0;
 
        if (!sanity(i))
                return 0;
 
-       n = push_pipe(i, bytes, &i_head, &off);
-       while (n) {
-               size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
-               char *p = kmap_local_page(pipe->bufs[i_head & p_mask].page);
+       while (bytes) {
+               struct page *page = append_pipe(i, bytes, &off);
                unsigned long rem;
+               char *p;
+
+               if (!page)
+                       break;
+               chunk = min_t(size_t, bytes, PAGE_SIZE - off);
+               p = kmap_local_page(page);
                rem = copy_mc_to_kernel(p + off, addr + xfer, chunk);
                chunk -= rem;
                kunmap_local(p);
-               if (chunk) {
-                       i->head = i_head;
-                       i->iov_offset = off + chunk;
-                       xfer += chunk;
-                       valid = i_head + 1;
-               }
+               xfer += chunk;
+               bytes -= chunk;
                if (rem) {
-                       pipe->bufs[i_head & p_mask].len -= rem;
-                       pipe_discard_from(pipe, valid);
+                       iov_iter_revert(i, rem);
                        break;
                }
-               n -= chunk;
-               off = 0;
-               i_head++;
        }
-       i->count -= xfer;
        return xfer;
 }
 
@@ -583,7 +605,7 @@ size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
 {
        if (unlikely(iov_iter_is_pipe(i)))
                return copy_mc_pipe_to_iter(addr, bytes, i);
-       if (iter_is_iovec(i))
+       if (user_backed_iter(i))
                might_fault();
        __iterate_and_advance(i, bytes, base, len, off,
                copyout_mc(base, addr + off, len),
@@ -601,7 +623,7 @@ size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
                WARN_ON(1);
                return 0;
        }
-       if (iter_is_iovec(i))
+       if (user_backed_iter(i))
                might_fault();
        iterate_and_advance(i, bytes, base, len, off,
                copyin(addr + off, base, len),
@@ -684,30 +706,21 @@ static inline bool page_copy_sane(struct page *page, size_t offset, size_t n)
        return false;
 }
 
-static size_t __copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       if (unlikely(iov_iter_is_pipe(i))) {
-               return copy_page_to_iter_pipe(page, offset, bytes, i);
-       } else {
-               void *kaddr = kmap_local_page(page);
-               size_t wanted = _copy_to_iter(kaddr + offset, bytes, i);
-               kunmap_local(kaddr);
-               return wanted;
-       }
-}
-
 size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i)
 {
        size_t res = 0;
        if (unlikely(!page_copy_sane(page, offset, bytes)))
                return 0;
+       if (unlikely(iov_iter_is_pipe(i)))
+               return copy_page_to_iter_pipe(page, offset, bytes, i);
        page += offset / PAGE_SIZE; // first subpage
        offset %= PAGE_SIZE;
        while (1) {
-               size_t n = __copy_page_to_iter(page, offset,
-                               min(bytes, (size_t)PAGE_SIZE - offset), i);
+               void *kaddr = kmap_local_page(page);
+               size_t n = min(bytes, (size_t)PAGE_SIZE - offset);
+               n = _copy_to_iter(kaddr + offset, n, i);
+               kunmap_local(kaddr);
                res += n;
                bytes -= n;
                if (!bytes || !n)
@@ -725,42 +738,53 @@ EXPORT_SYMBOL(copy_page_to_iter);
 size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i)
 {
-       if (page_copy_sane(page, offset, bytes)) {
+       size_t res = 0;
+       if (!page_copy_sane(page, offset, bytes))
+               return 0;
+       page += offset / PAGE_SIZE; // first subpage
+       offset %= PAGE_SIZE;
+       while (1) {
                void *kaddr = kmap_local_page(page);
-               size_t wanted = _copy_from_iter(kaddr + offset, bytes, i);
+               size_t n = min(bytes, (size_t)PAGE_SIZE - offset);
+               n = _copy_from_iter(kaddr + offset, n, i);
                kunmap_local(kaddr);
-               return wanted;
+               res += n;
+               bytes -= n;
+               if (!bytes || !n)
+                       break;
+               offset += n;
+               if (offset == PAGE_SIZE) {
+                       page++;
+                       offset = 0;
+               }
        }
-       return 0;
+       return res;
 }
 EXPORT_SYMBOL(copy_page_from_iter);
 
 static size_t pipe_zero(size_t bytes, struct iov_iter *i)
 {
-       struct pipe_inode_info *pipe = i->pipe;
-       unsigned int p_mask = pipe->ring_size - 1;
-       unsigned int i_head;
-       size_t n, off;
+       unsigned int chunk, off;
 
-       if (!sanity(i))
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+       if (unlikely(!bytes))
                return 0;
 
-       bytes = n = push_pipe(i, bytes, &i_head, &off);
-       if (unlikely(!n))
+       if (!sanity(i))
                return 0;
 
-       do {
-               size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
-               char *p = kmap_local_page(pipe->bufs[i_head & p_mask].page);
+       for (size_t n = bytes; n; n -= chunk) {
+               struct page *page = append_pipe(i, n, &off);
+               char *p;
+
+               if (!page)
+                       return bytes - n;
+               chunk = min_t(size_t, n, PAGE_SIZE - off);
+               p = kmap_local_page(page);
                memset(p + off, 0, chunk);
                kunmap_local(p);
-               i->head = i_head;
-               i->iov_offset = off + chunk;
-               n -= chunk;
-               off = 0;
-               i_head++;
-       } while (n);
-       i->count -= bytes;
+       }
        return bytes;
 }
 
@@ -799,56 +823,30 @@ size_t copy_page_from_iter_atomic(struct page *page, unsigned offset, size_t byt
 }
 EXPORT_SYMBOL(copy_page_from_iter_atomic);
 
-static inline void pipe_truncate(struct iov_iter *i)
-{
-       struct pipe_inode_info *pipe = i->pipe;
-       unsigned int p_tail = pipe->tail;
-       unsigned int p_head = pipe->head;
-       unsigned int p_mask = pipe->ring_size - 1;
-
-       if (!pipe_empty(p_head, p_tail)) {
-               struct pipe_buffer *buf;
-               unsigned int i_head = i->head;
-               size_t off = i->iov_offset;
-
-               if (off) {
-                       buf = &pipe->bufs[i_head & p_mask];
-                       buf->len = off - buf->offset;
-                       i_head++;
-               }
-               while (p_head != i_head) {
-                       p_head--;
-                       pipe_buf_release(pipe, &pipe->bufs[p_head & p_mask]);
-               }
-
-               pipe->head = p_head;
-       }
-}
-
 static void pipe_advance(struct iov_iter *i, size_t size)
 {
        struct pipe_inode_info *pipe = i->pipe;
-       if (size) {
-               struct pipe_buffer *buf;
-               unsigned int p_mask = pipe->ring_size - 1;
-               unsigned int i_head = i->head;
-               size_t off = i->iov_offset, left = size;
+       int off = i->last_offset;
 
+       if (!off && !size) {
+               pipe_discard_from(pipe, i->start_head); // discard everything
+               return;
+       }
+       i->count -= size;
+       while (1) {
+               struct pipe_buffer *buf = pipe_buf(pipe, i->head);
                if (off) /* make it relative to the beginning of buffer */
-                       left += off - pipe->bufs[i_head & p_mask].offset;
-               while (1) {
-                       buf = &pipe->bufs[i_head & p_mask];
-                       if (left <= buf->len)
-                               break;
-                       left -= buf->len;
-                       i_head++;
+                       size += abs(off) - buf->offset;
+               if (size <= buf->len) {
+                       buf->len = size;
+                       i->last_offset = last_offset(buf);
+                       break;
                }
-               i->head = i_head;
-               i->iov_offset = buf->offset + left;
+               size -= buf->len;
+               i->head++;
+               off = 0;
        }
-       i->count -= size;
-       /* ... and discard everything past that point */
-       pipe_truncate(i);
+       pipe_discard_from(pipe, i->head + 1); // discard everything past this one
 }
 
 static void iov_iter_bvec_advance(struct iov_iter *i, size_t size)
@@ -894,16 +892,16 @@ void iov_iter_advance(struct iov_iter *i, size_t size)
 {
        if (unlikely(i->count < size))
                size = i->count;
-       if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i))) {
+       if (likely(iter_is_ubuf(i)) || unlikely(iov_iter_is_xarray(i))) {
+               i->iov_offset += size;
+               i->count -= size;
+       } else if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i))) {
                /* iovec and kvec have identical layouts */
                iov_iter_iovec_advance(i, size);
        } else if (iov_iter_is_bvec(i)) {
                iov_iter_bvec_advance(i, size);
        } else if (iov_iter_is_pipe(i)) {
                pipe_advance(i, size);
-       } else if (unlikely(iov_iter_is_xarray(i))) {
-               i->iov_offset += size;
-               i->count -= size;
        } else if (iov_iter_is_discard(i)) {
                i->count -= size;
        }
@@ -919,28 +917,22 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll)
        i->count += unroll;
        if (unlikely(iov_iter_is_pipe(i))) {
                struct pipe_inode_info *pipe = i->pipe;
-               unsigned int p_mask = pipe->ring_size - 1;
-               unsigned int i_head = i->head;
-               size_t off = i->iov_offset;
-               while (1) {
-                       struct pipe_buffer *b = &pipe->bufs[i_head & p_mask];
-                       size_t n = off - b->offset;
-                       if (unroll < n) {
-                               off -= unroll;
-                               break;
-                       }
-                       unroll -= n;
-                       if (!unroll && i_head == i->start_head) {
-                               off = 0;
-                               break;
+               unsigned int head = pipe->head;
+
+               while (head > i->start_head) {
+                       struct pipe_buffer *b = pipe_buf(pipe, --head);
+                       if (unroll < b->len) {
+                               b->len -= unroll;
+                               i->last_offset = last_offset(b);
+                               i->head = head;
+                               return;
                        }
-                       i_head--;
-                       b = &pipe->bufs[i_head & p_mask];
-                       off = b->offset + b->len;
+                       unroll -= b->len;
+                       pipe_buf_release(pipe, b);
+                       pipe->head--;
                }
-               i->iov_offset = off;
-               i->head = i_head;
-               pipe_truncate(i);
+               i->last_offset = 0;
+               i->head = head;
                return;
        }
        if (unlikely(iov_iter_is_discard(i)))
@@ -950,7 +942,7 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll)
                return;
        }
        unroll -= i->iov_offset;
-       if (iov_iter_is_xarray(i)) {
+       if (iov_iter_is_xarray(i) || iter_is_ubuf(i)) {
                BUG(); /* We should never go beyond the start of the specified
                        * range since we might then be straying into pages that
                        * aren't pinned.
@@ -1042,7 +1034,7 @@ void iov_iter_pipe(struct iov_iter *i, unsigned int direction,
                .pipe = pipe,
                .head = pipe->head,
                .start_head = pipe->head,
-               .iov_offset = 0,
+               .last_offset = 0,
                .count = count
        };
 }
@@ -1158,6 +1150,14 @@ static bool iov_iter_aligned_bvec(const struct iov_iter *i, unsigned addr_mask,
 bool iov_iter_is_aligned(const struct iov_iter *i, unsigned addr_mask,
                         unsigned len_mask)
 {
+       if (likely(iter_is_ubuf(i))) {
+               if (i->count & len_mask)
+                       return false;
+               if ((unsigned long)(i->ubuf + i->iov_offset) & addr_mask)
+                       return false;
+               return true;
+       }
+
        if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
                return iov_iter_aligned_iovec(i, addr_mask, len_mask);
 
@@ -1165,13 +1165,12 @@ bool iov_iter_is_aligned(const struct iov_iter *i, unsigned addr_mask,
                return iov_iter_aligned_bvec(i, addr_mask, len_mask);
 
        if (iov_iter_is_pipe(i)) {
-               unsigned int p_mask = i->pipe->ring_size - 1;
                size_t size = i->count;
 
                if (size & len_mask)
                        return false;
-               if (size && allocated(&i->pipe->bufs[i->head & p_mask])) {
-                       if (i->iov_offset & addr_mask)
+               if (size && i->last_offset > 0) {
+                       if (i->last_offset & addr_mask)
                                return false;
                }
 
@@ -1233,6 +1232,13 @@ static unsigned long iov_iter_alignment_bvec(const struct iov_iter *i)
 
 unsigned long iov_iter_alignment(const struct iov_iter *i)
 {
+       if (likely(iter_is_ubuf(i))) {
+               size_t size = i->count;
+               if (size)
+                       return ((unsigned long)i->ubuf + i->iov_offset) | size;
+               return 0;
+       }
+
        /* iovec and kvec have identical layouts */
        if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
                return iov_iter_alignment_iovec(i);
@@ -1241,11 +1247,10 @@ unsigned long iov_iter_alignment(const struct iov_iter *i)
                return iov_iter_alignment_bvec(i);
 
        if (iov_iter_is_pipe(i)) {
-               unsigned int p_mask = i->pipe->ring_size - 1;
                size_t size = i->count;
 
-               if (size && i->iov_offset && allocated(&i->pipe->bufs[i->head & p_mask]))
-                       return size | i->iov_offset;
+               if (size && i->last_offset > 0)
+                       return size | i->last_offset;
                return size;
        }
 
@@ -1263,6 +1268,9 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
        size_t size = i->count;
        unsigned k;
 
+       if (iter_is_ubuf(i))
+               return 0;
+
        if (WARN_ON(!iter_is_iovec(i)))
                return ~0U;
 
@@ -1281,45 +1289,50 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
 }
 EXPORT_SYMBOL(iov_iter_gap_alignment);
 
-static inline ssize_t __pipe_get_pages(struct iov_iter *i,
-                               size_t maxsize,
-                               struct page **pages,
-                               int iter_head,
-                               size_t *start)
+static int want_pages_array(struct page ***res, size_t size,
+                           size_t start, unsigned int maxpages)
 {
-       struct pipe_inode_info *pipe = i->pipe;
-       unsigned int p_mask = pipe->ring_size - 1;
-       ssize_t n = push_pipe(i, maxsize, &iter_head, start);
-       if (!n)
-               return -EFAULT;
+       unsigned int count = DIV_ROUND_UP(size + start, PAGE_SIZE);
 
-       maxsize = n;
-       n += *start;
-       while (n > 0) {
-               get_page(*pages++ = pipe->bufs[iter_head & p_mask].page);
-               iter_head++;
-               n -= PAGE_SIZE;
+       if (count > maxpages)
+               count = maxpages;
+       WARN_ON(!count);        // caller should've prevented that
+       if (!*res) {
+               *res = kvmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
+               if (!*res)
+                       return 0;
        }
-
-       return maxsize;
+       return count;
 }
 
 static ssize_t pipe_get_pages(struct iov_iter *i,
-                  struct page **pages, size_t maxsize, unsigned maxpages,
+                  struct page ***pages, size_t maxsize, unsigned maxpages,
                   size_t *start)
 {
-       unsigned int iter_head, npages;
-       size_t capacity;
+       unsigned int npages, count, off, chunk;
+       struct page **p;
+       size_t left;
 
        if (!sanity(i))
                return -EFAULT;
 
-       data_start(i, &iter_head, start);
-       /* Amount of free space: some of this one + all after this one */
-       npages = pipe_space_for_user(iter_head, i->pipe->tail, i->pipe);
-       capacity = min(npages, maxpages) * PAGE_SIZE - *start;
-
-       return __pipe_get_pages(i, min(maxsize, capacity), pages, iter_head, start);
+       *start = off = pipe_npages(i, &npages);
+       if (!npages)
+               return -EFAULT;
+       count = want_pages_array(pages, maxsize, off, min(npages, maxpages));
+       if (!count)
+               return -ENOMEM;
+       p = *pages;
+       for (npages = 0, left = maxsize ; npages < count; npages++, left -= chunk) {
+               struct page *page = append_pipe(i, left, &off);
+               if (!page)
+                       break;
+               chunk = min_t(size_t, left, PAGE_SIZE - off);
+               get_page(*p++ = page);
+       }
+       if (!npages)
+               return -EFAULT;
+       return maxsize - left;
 }
 
 static ssize_t iter_xarray_populate_pages(struct page **pages, struct xarray *xa,
@@ -1350,47 +1363,40 @@ static ssize_t iter_xarray_populate_pages(struct page **pages, struct xarray *xa
 }
 
 static ssize_t iter_xarray_get_pages(struct iov_iter *i,
-                                    struct page **pages, size_t maxsize,
+                                    struct page ***pages, size_t maxsize,
                                     unsigned maxpages, size_t *_start_offset)
 {
-       unsigned nr, offset;
-       pgoff_t index, count;
-       size_t size = maxsize;
+       unsigned nr, offset, count;
+       pgoff_t index;
        loff_t pos;
 
-       if (!size || !maxpages)
-               return 0;
-
        pos = i->xarray_start + i->iov_offset;
        index = pos >> PAGE_SHIFT;
        offset = pos & ~PAGE_MASK;
        *_start_offset = offset;
 
-       count = 1;
-       if (size > PAGE_SIZE - offset) {
-               size -= PAGE_SIZE - offset;
-               count += size >> PAGE_SHIFT;
-               size &= ~PAGE_MASK;
-               if (size)
-                       count++;
-       }
-
-       if (count > maxpages)
-               count = maxpages;
-
-       nr = iter_xarray_populate_pages(pages, i->xarray, index, count);
+       count = want_pages_array(pages, maxsize, offset, maxpages);
+       if (!count)
+               return -ENOMEM;
+       nr = iter_xarray_populate_pages(*pages, i->xarray, index, count);
        if (nr == 0)
                return 0;
 
-       return min_t(size_t, nr * PAGE_SIZE - offset, maxsize);
+       maxsize = min_t(size_t, nr * PAGE_SIZE - offset, maxsize);
+       i->iov_offset += maxsize;
+       i->count -= maxsize;
+       return maxsize;
 }
 
-/* must be done on non-empty ITER_IOVEC one */
+/* must be done on non-empty ITER_UBUF or ITER_IOVEC one */
 static unsigned long first_iovec_segment(const struct iov_iter *i, size_t *size)
 {
        size_t skip;
        long k;
 
+       if (iter_is_ubuf(i))
+               return (unsigned long)i->ubuf + i->iov_offset;
+
        for (k = 0, skip = i->iov_offset; k < i->nr_segs; k++, skip = 0) {
                size_t len = i->iov[k].iov_len - skip;
 
@@ -1419,11 +1425,11 @@ static struct page *first_bvec_segment(const struct iov_iter *i,
        return page;
 }
 
-ssize_t iov_iter_get_pages(struct iov_iter *i,
-                  struct page **pages, size_t maxsize, unsigned maxpages,
-                  size_t *start)
+static ssize_t __iov_iter_get_pages_alloc(struct iov_iter *i,
+                  struct page ***pages, size_t maxsize,
+                  unsigned int maxpages, size_t *start)
 {
-       int n, res;
+       unsigned int n;
 
        if (maxsize > i->count)
                maxsize = i->count;
@@ -1432,9 +1438,10 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
        if (maxsize > MAX_RW_COUNT)
                maxsize = MAX_RW_COUNT;
 
-       if (likely(iter_is_iovec(i))) {
+       if (likely(user_backed_iter(i))) {
                unsigned int gup_flags = 0;
                unsigned long addr;
+               int res;
 
                if (iov_iter_rw(i) != WRITE)
                        gup_flags |= FOLL_WRITE;
@@ -1444,24 +1451,36 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
                addr = first_iovec_segment(i, &maxsize);
                *start = addr % PAGE_SIZE;
                addr &= PAGE_MASK;
-               n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
-               if (n > maxpages)
-                       n = maxpages;
-               res = get_user_pages_fast(addr, n, gup_flags, pages);
+               n = want_pages_array(pages, maxsize, *start, maxpages);
+               if (!n)
+                       return -ENOMEM;
+               res = get_user_pages_fast(addr, n, gup_flags, *pages);
                if (unlikely(res <= 0))
                        return res;
-               return min_t(size_t, maxsize, res * PAGE_SIZE - *start);
+               maxsize = min_t(size_t, maxsize, res * PAGE_SIZE - *start);
+               iov_iter_advance(i, maxsize);
+               return maxsize;
        }
        if (iov_iter_is_bvec(i)) {
+               struct page **p;
                struct page *page;
 
                page = first_bvec_segment(i, &maxsize, start);
-               n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
-               if (n > maxpages)
-                       n = maxpages;
+               n = want_pages_array(pages, maxsize, *start, maxpages);
+               if (!n)
+                       return -ENOMEM;
+               p = *pages;
                for (int k = 0; k < n; k++)
-                       get_page(*pages++ = page++);
-               return min_t(size_t, maxsize, n * PAGE_SIZE - *start);
+                       get_page(p[k] = page + k);
+               maxsize = min_t(size_t, maxsize, n * PAGE_SIZE - *start);
+               i->count -= maxsize;
+               i->iov_offset += maxsize;
+               if (i->iov_offset == i->bvec->bv_len) {
+                       i->iov_offset = 0;
+                       i->bvec++;
+                       i->nr_segs--;
+               }
+               return maxsize;
        }
        if (iov_iter_is_pipe(i))
                return pipe_get_pages(i, pages, maxsize, maxpages, start);
@@ -1469,140 +1488,35 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
                return iter_xarray_get_pages(i, pages, maxsize, maxpages, start);
        return -EFAULT;
 }
-EXPORT_SYMBOL(iov_iter_get_pages);
 
-static struct page **get_pages_array(size_t n)
-{
-       return kvmalloc_array(n, sizeof(struct page *), GFP_KERNEL);
-}
-
-static ssize_t pipe_get_pages_alloc(struct iov_iter *i,
-                  struct page ***pages, size_t maxsize,
+ssize_t iov_iter_get_pages2(struct iov_iter *i,
+                  struct page **pages, size_t maxsize, unsigned maxpages,
                   size_t *start)
 {
-       struct page **p;
-       unsigned int iter_head, npages;
-       ssize_t n;
-
-       if (!sanity(i))
-               return -EFAULT;
-
-       data_start(i, &iter_head, start);
-       /* Amount of free space: some of this one + all after this one */
-       npages = pipe_space_for_user(iter_head, i->pipe->tail, i->pipe);
-       n = npages * PAGE_SIZE - *start;
-       if (maxsize > n)
-               maxsize = n;
-       else
-               npages = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
-       p = get_pages_array(npages);
-       if (!p)
-               return -ENOMEM;
-       n = __pipe_get_pages(i, maxsize, p, iter_head, start);
-       if (n > 0)
-               *pages = p;
-       else
-               kvfree(p);
-       return n;
-}
-
-static ssize_t iter_xarray_get_pages_alloc(struct iov_iter *i,
-                                          struct page ***pages, size_t maxsize,
-                                          size_t *_start_offset)
-{
-       struct page **p;
-       unsigned nr, offset;
-       pgoff_t index, count;
-       size_t size = maxsize;
-       loff_t pos;
-
-       if (!size)
+       if (!maxpages)
                return 0;
+       BUG_ON(!pages);
 
-       pos = i->xarray_start + i->iov_offset;
-       index = pos >> PAGE_SHIFT;
-       offset = pos & ~PAGE_MASK;
-       *_start_offset = offset;
-
-       count = 1;
-       if (size > PAGE_SIZE - offset) {
-               size -= PAGE_SIZE - offset;
-               count += size >> PAGE_SHIFT;
-               size &= ~PAGE_MASK;
-               if (size)
-                       count++;
-       }
-
-       p = get_pages_array(count);
-       if (!p)
-               return -ENOMEM;
-       *pages = p;
-
-       nr = iter_xarray_populate_pages(p, i->xarray, index, count);
-       if (nr == 0)
-               return 0;
-
-       return min_t(size_t, nr * PAGE_SIZE - offset, maxsize);
+       return __iov_iter_get_pages_alloc(i, &pages, maxsize, maxpages, start);
 }
+EXPORT_SYMBOL(iov_iter_get_pages2);
 
-ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
+ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i,
                   struct page ***pages, size_t maxsize,
                   size_t *start)
 {
-       struct page **p;
-       int n, res;
+       ssize_t len;
 
-       if (maxsize > i->count)
-               maxsize = i->count;
-       if (!maxsize)
-               return 0;
-       if (maxsize > MAX_RW_COUNT)
-               maxsize = MAX_RW_COUNT;
-
-       if (likely(iter_is_iovec(i))) {
-               unsigned int gup_flags = 0;
-               unsigned long addr;
-
-               if (iov_iter_rw(i) != WRITE)
-                       gup_flags |= FOLL_WRITE;
-               if (i->nofault)
-                       gup_flags |= FOLL_NOFAULT;
-
-               addr = first_iovec_segment(i, &maxsize);
-               *start = addr % PAGE_SIZE;
-               addr &= PAGE_MASK;
-               n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
-               p = get_pages_array(n);
-               if (!p)
-                       return -ENOMEM;
-               res = get_user_pages_fast(addr, n, gup_flags, p);
-               if (unlikely(res <= 0)) {
-                       kvfree(p);
-                       *pages = NULL;
-                       return res;
-               }
-               *pages = p;
-               return min_t(size_t, maxsize, res * PAGE_SIZE - *start);
-       }
-       if (iov_iter_is_bvec(i)) {
-               struct page *page;
+       *pages = NULL;
 
-               page = first_bvec_segment(i, &maxsize, start);
-               n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
-               *pages = p = get_pages_array(n);
-               if (!p)
-                       return -ENOMEM;
-               for (int k = 0; k < n; k++)
-                       get_page(*p++ = page++);
-               return min_t(size_t, maxsize, n * PAGE_SIZE - *start);
+       len = __iov_iter_get_pages_alloc(i, pages, maxsize, ~0U, start);
+       if (len <= 0) {
+               kvfree(*pages);
+               *pages = NULL;
        }
-       if (iov_iter_is_pipe(i))
-               return pipe_get_pages_alloc(i, pages, maxsize, start);
-       if (iov_iter_is_xarray(i))
-               return iter_xarray_get_pages_alloc(i, pages, maxsize, start);
-       return -EFAULT;
+       return len;
 }
-EXPORT_SYMBOL(iov_iter_get_pages_alloc);
+EXPORT_SYMBOL(iov_iter_get_pages_alloc2);
 
 size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
                               struct iov_iter *i)
@@ -1715,22 +1629,23 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages)
 {
        if (unlikely(!i->count))
                return 0;
+       if (likely(iter_is_ubuf(i))) {
+               unsigned offs = offset_in_page(i->ubuf + i->iov_offset);
+               int npages = DIV_ROUND_UP(offs + i->count, PAGE_SIZE);
+               return min(npages, maxpages);
+       }
        /* iovec and kvec have identical layouts */
        if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
                return iov_npages(i, maxpages);
        if (iov_iter_is_bvec(i))
                return bvec_npages(i, maxpages);
        if (iov_iter_is_pipe(i)) {
-               unsigned int iter_head;
                int npages;
-               size_t off;
 
                if (!sanity(i))
                        return 0;
 
-               data_start(i, &iter_head, &off);
-               /* some of this one + all after this one */
-               npages = pipe_space_for_user(iter_head, i->pipe->tail, i->pipe);
+               pipe_npages(i, &npages);
                return min(npages, maxpages);
        }
        if (iov_iter_is_xarray(i)) {
@@ -1749,17 +1664,16 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
                WARN_ON(1);
                return NULL;
        }
-       if (unlikely(iov_iter_is_discard(new) || iov_iter_is_xarray(new)))
-               return NULL;
        if (iov_iter_is_bvec(new))
                return new->bvec = kmemdup(new->bvec,
                                    new->nr_segs * sizeof(struct bio_vec),
                                    flags);
-       else
+       else if (iov_iter_is_kvec(new) || iter_is_iovec(new))
                /* iovec and kvec have identical layout */
                return new->iov = kmemdup(new->iov,
                                   new->nr_segs * sizeof(struct iovec),
                                   flags);
+       return NULL;
 }
 EXPORT_SYMBOL(dup_iter);
 
@@ -1953,10 +1867,12 @@ EXPORT_SYMBOL(import_single_range);
 void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state)
 {
        if (WARN_ON_ONCE(!iov_iter_is_bvec(i) && !iter_is_iovec(i)) &&
-                        !iov_iter_is_kvec(i))
+                        !iov_iter_is_kvec(i) && !iter_is_ubuf(i))
                return;
        i->iov_offset = state->iov_offset;
        i->count = state->count;
+       if (iter_is_ubuf(i))
+               return;
        /*
         * For the *vec iters, nr_segs + iov is constant - if we increment
         * the vec, then we also decrement the nr_segs count. Hence we don't
index e59cf5f..0331f14 100644 (file)
@@ -983,9 +983,14 @@ config HMM_MIRROR
        bool
        depends on MMU
 
+config GET_FREE_REGION
+       depends on SPARSEMEM
+       bool
+
 config DEVICE_PRIVATE
        bool "Unaddressable device memory (GPU memory, ...)"
        depends on ZONE_DEVICE
+       select GET_FREE_REGION
 
        help
          Allows creation of struct pages to represent unaddressable device
index c0894c1..b5d3026 100644 (file)
@@ -597,6 +597,17 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
                type->total_size = size;
                return 0;
        }
+
+       /*
+        * The worst case is when new range overlaps all existing regions,
+        * then we'll need type->cnt + 1 empty regions in @type. So if
+        * type->cnt * 2 + 1 is less than type->max, we know
+        * that there is enough empty regions in @type, and we can insert
+        * regions directly.
+        */
+       if (type->cnt * 2 + 1 < type->max)
+               insert = true;
+
 repeat:
        /*
         * The following is executed twice.  Once with %false @insert and
index e975fcd..5783f11 100644 (file)
@@ -2626,7 +2626,7 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
                        ret = copy_page_to_iter(page, offset, nr, to);
                        put_page(page);
 
-               } else if (iter_is_iovec(to)) {
+               } else if (user_backed_iter(to)) {
                        /*
                         * Copy to user tends to be so well optimized, but
                         * clear_user() not so much, that it is noticeably
index 5bf4dfe..0a6110e 100644 (file)
@@ -1495,7 +1495,7 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to,
        struct p9_client *clnt = fid->clnt;
        struct p9_req_t *req;
        int count = iov_iter_count(to);
-       int rsize, non_zc = 0;
+       int rsize, received, non_zc = 0;
        char *dataptr;
 
        *err = 0;
@@ -1524,36 +1524,40 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to,
        }
        if (IS_ERR(req)) {
                *err = PTR_ERR(req);
+               if (!non_zc)
+                       iov_iter_revert(to, count - iov_iter_count(to));
                return 0;
        }
 
        *err = p9pdu_readf(&req->rc, clnt->proto_version,
-                          "D", &count, &dataptr);
+                          "D", &received, &dataptr);
        if (*err) {
+               if (!non_zc)
+                       iov_iter_revert(to, count - iov_iter_count(to));
                trace_9p_protocol_dump(clnt, &req->rc);
                p9_req_put(clnt, req);
                return 0;
        }
-       if (rsize < count) {
-               pr_err("bogus RREAD count (%d > %d)\n", count, rsize);
-               count = rsize;
+       if (rsize < received) {
+               pr_err("bogus RREAD count (%d > %d)\n", received, rsize);
+               received = rsize;
        }
 
        p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
 
        if (non_zc) {
-               int n = copy_to_iter(dataptr, count, to);
+               int n = copy_to_iter(dataptr, received, to);
 
-               if (n != count) {
+               if (n != received) {
                        *err = -EFAULT;
                        p9_req_put(clnt, req);
                        return n;
                }
        } else {
-               iov_iter_advance(to, count);
+               iov_iter_revert(to, count - received - iov_iter_count(to));
        }
        p9_req_put(clnt, req);
-       return count;
+       return received;
 }
 EXPORT_SYMBOL(p9_client_read_once);
 
@@ -1571,6 +1575,7 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
        while (iov_iter_count(from)) {
                int count = iov_iter_count(from);
                int rsize = fid->iounit;
+               int written;
 
                if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
                        rsize = clnt->msize - P9_IOHDRSZ;
@@ -1588,27 +1593,29 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
                                            offset, rsize, from);
                }
                if (IS_ERR(req)) {
+                       iov_iter_revert(from, count - iov_iter_count(from));
                        *err = PTR_ERR(req);
                        break;
                }
 
-               *err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &count);
+               *err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &written);
                if (*err) {
+                       iov_iter_revert(from, count - iov_iter_count(from));
                        trace_9p_protocol_dump(clnt, &req->rc);
                        p9_req_put(clnt, req);
                        break;
                }
-               if (rsize < count) {
-                       pr_err("bogus RWRITE count (%d > %d)\n", count, rsize);
-                       count = rsize;
+               if (rsize < written) {
+                       pr_err("bogus RWRITE count (%d > %d)\n", written, rsize);
+                       written = rsize;
                }
 
                p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
 
                p9_req_put(clnt, req);
-               iov_iter_advance(from, count);
-               total += count;
-               offset += count;
+               iov_iter_revert(from, count - written - iov_iter_count(from));
+               total += written;
+               offset += written;
        }
        return total;
 }
index 3754c33..83694c6 100644 (file)
@@ -63,9 +63,8 @@ static size_t
 pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size)
 {
        size_t len = min(pdu->capacity - pdu->size, size);
-       struct iov_iter i = *from;
 
-       if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, &i))
+       if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, from))
                len = 0;
 
        pdu->size += len;
index 03770ad..b84d35c 100644 (file)
@@ -331,7 +331,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
                        if (err == -ERESTARTSYS)
                                return err;
                }
-               n = iov_iter_get_pages_alloc(data, pages, count, offs);
+               n = iov_iter_get_pages_alloc2(data, pages, count, offs);
                if (n < 0)
                        return n;
                *need_drop = 1;
@@ -373,6 +373,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
                                (*pages)[index] = kmap_to_page(p);
                        p += PAGE_SIZE;
                }
+               iov_iter_advance(data, len);
                return len;
        }
 }
index f3988ef..7255531 100644 (file)
@@ -632,12 +632,11 @@ int __zerocopy_sg_from_iter(struct msghdr *msg, struct sock *sk,
                if (frag == MAX_SKB_FRAGS)
                        return -EMSGSIZE;
 
-               copied = iov_iter_get_pages(from, pages, length,
+               copied = iov_iter_get_pages2(from, pages, length,
                                            MAX_SKB_FRAGS - frag, &start);
                if (copied < 0)
                        return -EFAULT;
 
-               iov_iter_advance(from, copied);
                length -= copied;
 
                truesize = PAGE_ALIGN(copied + start);
index 8162789..cf3c24c 100644 (file)
@@ -324,14 +324,13 @@ int sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from,
                        goto out;
                }
 
-               copied = iov_iter_get_pages(from, pages, bytes, maxpages,
+               copied = iov_iter_get_pages2(from, pages, bytes, maxpages,
                                            &offset);
                if (copied <= 0) {
                        ret = -EFAULT;
                        goto out;
                }
 
-               iov_iter_advance(from, copied);
                bytes -= copied;
                msg->sg.size += copied;
 
index 799034e..d74be4e 100644 (file)
@@ -391,7 +391,7 @@ static int rds_message_zcopy_from_user(struct rds_message *rm, struct iov_iter *
                size_t start;
                ssize_t copied;
 
-               copied = iov_iter_get_pages(from, &pages, PAGE_SIZE,
+               copied = iov_iter_get_pages2(from, &pages, PAGE_SIZE,
                                            1, &start);
                if (copied < 0) {
                        struct mmpin *mmp;
@@ -405,7 +405,6 @@ static int rds_message_zcopy_from_user(struct rds_message *rm, struct iov_iter *
                        goto err;
                }
                total_copied += copied;
-               iov_iter_advance(from, copied);
                length -= copied;
                sg_set_page(sg, pages, copied, start);
                rm->data.op_nents++;
index 2c4dd7c..2106003 100644 (file)
@@ -691,7 +691,7 @@ static int svc_alloc_arg(struct svc_rqst *rqstp)
                        set_current_state(TASK_RUNNING);
                        return -EINTR;
                }
-               trace_svc_alloc_arg_err(pages);
+               trace_svc_alloc_arg_err(pages, ret);
                memalloc_retry_wait(GFP_KERNEL);
        }
        rqstp->rq_page_end = &rqstp->rq_pages[pages];
index 17db8c8..f76119f 100644 (file)
@@ -1352,7 +1352,7 @@ static int tls_setup_from_iter(struct iov_iter *from,
                        rc = -EFAULT;
                        goto out;
                }
-               copied = iov_iter_get_pages(from, pages,
+               copied = iov_iter_get_pages2(from, pages,
                                            length,
                                            maxpages, &offset);
                if (copied <= 0) {
@@ -1360,8 +1360,6 @@ static int tls_setup_from_iter(struct iov_iter *from,
                        goto out;
                }
 
-               iov_iter_advance(from, copied);
-
                length -= copied;
                size += copied;
                while (copied) {
index 0496efd..a0ccceb 100644 (file)
@@ -25,7 +25,7 @@ failure = $(if-success,$(1),n,y)
 
 # $(cc-option,<flag>)
 # Return y if the compiler supports <flag>, n otherwise
-cc-option = $(success,mkdir .tmp_$$$$; trap "rm -rf .tmp_$$$$" EXIT; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$$$/tmp.o)
+cc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$/tmp.o)
 
 # $(ld-option,<flag>)
 # Return y if the linker supports <flag>, n otherwise
index cac070a..784f46d 100644 (file)
@@ -358,9 +358,8 @@ $(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ;
 
 quiet_cmd_ar_builtin = AR      $@
       cmd_ar_builtin = rm -f $@; \
-               echo $(patsubst $(obj)/%,%,$(real-prereqs)) | \
-               sed -E 's:([^ ]+):$(obj)/\1:g' | \
-               xargs $(AR) cDPrST $@
+       $(if $(real-prereqs), printf "$(obj)/%s " $(patsubst $(obj)/%,%,$(real-prereqs)) | xargs) \
+       $(AR) cDPrST $@
 
 $(obj)/built-in.a: $(real-obj-y) FORCE
        $(call if_changed,ar_builtin)
index 86ecd2a..94d0d40 100644 (file)
@@ -21,8 +21,8 @@ TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$
 # automatically cleaned up.
 try-run = $(shell set -e;              \
        TMP=$(TMPOUT)/tmp;              \
-       mkdir -p $(TMPOUT);             \
        trap "rm -rf $(TMPOUT)" EXIT;   \
+       mkdir -p $(TMPOUT);             \
        if ($(1)) >/dev/null 2>&1;      \
        then echo "$(2)";               \
        else echo "$(3)";               \
index f5f0d6f..9bbaf71 100644 (file)
@@ -47,7 +47,6 @@ else
 
 ifdef CONFIG_CC_IS_CLANG
 KBUILD_CFLAGS += -Wno-initializer-overrides
-KBUILD_CFLAGS += -Wno-format
 KBUILD_CFLAGS += -Wno-sign-compare
 KBUILD_CFLAGS += -Wno-format-zero-length
 KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
index 16a02e9..a4c987c 100644 (file)
@@ -18,6 +18,9 @@ INSTALL_MOD_DIR ?= extra
 dst := $(MODLIB)/$(INSTALL_MOD_DIR)
 endif
 
+$(foreach x, % :, $(if $(findstring $x, $(dst)), \
+       $(error module installation path cannot contain '$x')))
+
 suffix-y                               :=
 suffix-$(CONFIG_MODULE_COMPRESS_GZIP)  := .gz
 suffix-$(CONFIG_MODULE_COMPRESS_XZ)    := .xz
index 77b6121..5017f6b 100644 (file)
@@ -56,7 +56,7 @@ rpm-pkg:
        $(MAKE) clean
        $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec
        $(call cmd,src_tar,$(KERNELPATH),kernel.spec)
-       +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz \
+       +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -ta $(KERNELPATH).tar.gz \
        --define='_smp_mflags %{nil}'
 
 # binrpm-pkg
@@ -66,7 +66,7 @@ binrpm-pkg:
        $(MAKE) -f $(srctree)/Makefile
        $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec
        +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \
-               $(UTS_MACHINE) -bb $(objtree)/binkernel.spec
+               $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec
 
 PHONY += deb-pkg
 deb-pkg:
diff --git a/scripts/check-blacklist-hashes.awk b/scripts/check-blacklist-hashes.awk
deleted file mode 100755 (executable)
index 107c1d3..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/awk -f
-# SPDX-License-Identifier: GPL-2.0
-#
-# Copyright © 2020, Microsoft Corporation. All rights reserved.
-#
-# Author: Mickaël Salaün <mic@linux.microsoft.com>
-#
-# Check that a CONFIG_SYSTEM_BLACKLIST_HASH_LIST file contains a valid array of
-# hash strings.  Such string must start with a prefix ("tbs" or "bin"), then a
-# colon (":"), and finally an even number of hexadecimal lowercase characters
-# (up to 128).
-
-BEGIN {
-       RS = ","
-}
-{
-       if (!match($0, "^[ \t\n\r]*\"([^\"]*)\"[ \t\n\r]*$", part1)) {
-               print "Not a string (item " NR "):", $0;
-               exit 1;
-       }
-       if (!match(part1[1], "^(tbs|bin):(.*)$", part2)) {
-               print "Unknown prefix (item " NR "):", part1[1];
-               exit 1;
-       }
-       if (!match(part2[2], "^([0-9a-f]+)$", part3)) {
-               print "Not a lowercase hexadecimal string (item " NR "):", part2[2];
-               exit 1;
-       }
-       if (length(part3[1]) > 128) {
-               print "Hash string too long (item " NR "):", part3[1];
-               exit 1;
-       }
-       if (length(part3[1]) % 2 == 1) {
-               print "Not an even number of hexadecimal characters (item " NR "):", part3[1];
-               exit 1;
-       }
-}
index d2c3858..d48dfed 100755 (executable)
@@ -16,6 +16,7 @@
 #      AArch64, PARISC ports by Kyle McMartin
 #      sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
 #      ppc64le port by Breno Leitao <leitao@debian.org>
+#      riscv port by Wadim Mueller <wafgo01@gmail.com>
 #
 #      Usage:
 #      objdump -d vmlinux | scripts/checkstack.pl [arch]
@@ -108,6 +109,9 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack);
        } elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
                # f0019d10:       9d e3 bf 90     save  %sp, -112, %sp
                $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
+       } elsif ($arch =~ /^riscv(64)?$/) {
+               #ffffffff8036e868:      c2010113                addi    sp,sp,-992
+               $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
        } else {
                print("wrong or unknown architecture \"$arch\"\n");
                exit
diff --git a/scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h b/scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h
new file mode 100644 (file)
index 0000000..e69de29
index b248314..7db8258 100755 (executable)
@@ -96,12 +96,8 @@ fi
 
 # To set GCC_PLUGINS
 if arg_contain -print-file-name=plugin "$@"; then
-       plugin_dir=$(mktemp -d)
-
-       mkdir -p $plugin_dir/include
-       touch $plugin_dir/include/plugin-version.h
-
-       echo $plugin_dir
+       # Use $0 to find the in-tree dummy directory
+       echo "$(dirname "$(readlink -f "$0")")/dummy-plugin-dir"
        exit 0
 fi
 
index dd554bd..4041881 100755 (executable)
@@ -70,7 +70,6 @@ configs=$(sed -e '
 #
 # The format is <file-name>:<CONFIG-option> in each line.
 config_leak_ignores="
-arch/alpha/include/uapi/asm/setup.h:CONFIG_ALPHA_LEGACY_START_ADDRESS
 arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_16K
 arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_4K
 arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE
@@ -84,7 +83,6 @@ arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT
 arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION
 arch/x86/include/uapi/asm/auxvec.h:CONFIG_X86_64
 arch/x86/include/uapi/asm/mman.h:CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
-include/uapi/asm-generic/fcntl.h:CONFIG_64BIT
 include/uapi/linux/atmdev.h:CONFIG_COMPAT
 include/uapi/linux/eventpoll.h:CONFIG_PM_SLEEP
 include/uapi/linux/hw_breakpoint.h:CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
index 9b695e5..ad652cb 100755 (executable)
@@ -20,5 +20,6 @@ fi
 echo >&2 "*"
 echo >&2 "* Could not find Qt5 via ${HOSTPKG_CONFIG}."
 echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH"
+echo >&2 "* You need $PKG"
 echo >&2 "*"
 exit 1
index cbd6b0f..80d9731 100644 (file)
@@ -1571,9 +1571,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                zeros = calloc(1, sym->st_size);
                symval = zeros;
        } else {
-               symval = (void *)info->hdr
-                       + info->sechdrs[get_secindex(info, sym)].sh_offset
-                       + sym->st_value;
+               symval = sym_get_data(info, sym);
        }
 
        /* First handle the "special" cases */
index 29474ce..55e32af 100644 (file)
@@ -321,13 +321,10 @@ static void *sym_get_data_by_offset(const struct elf_info *info,
 {
        Elf_Shdr *sechdr = &info->sechdrs[secindex];
 
-       if (info->hdr->e_type != ET_REL)
-               offset -= sechdr->sh_addr;
-
        return (void *)info->hdr + sechdr->sh_offset + offset;
 }
 
-static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
 {
        return sym_get_data_by_offset(info, get_secindex(info, sym),
                                      sym->st_value);
@@ -339,8 +336,16 @@ static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
                                      sechdr->sh_name);
 }
 
-static const char *sec_name(const struct elf_info *info, int secindex)
+static const char *sec_name(const struct elf_info *info, unsigned int secindex)
 {
+       /*
+        * If sym->st_shndx is a special section index, there is no
+        * corresponding section header.
+        * Return "" if the index is out of range of info->sechdrs[] array.
+        */
+       if (secindex >= info->num_sections)
+               return "";
+
        return sech_name(info, &info->sechdrs[secindex]);
 }
 
@@ -466,6 +471,10 @@ static int parse_elf(struct elf_info *info, const char *filename)
        sechdrs = (void *)hdr + hdr->e_shoff;
        info->sechdrs = sechdrs;
 
+       /* modpost only works for relocatable objects */
+       if (hdr->e_type != ET_REL)
+               fatal("%s: not relocatable object.", filename);
+
        /* Check if file offset is correct */
        if (hdr->e_shoff > info->size) {
                fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
@@ -737,12 +746,18 @@ static bool match(const char *string, const char *const patterns[])
        return false;
 }
 
+/* useful to pass patterns to match() directly */
+#define PATTERNS(...) \
+       ({ \
+               static const char *const patterns[] = {__VA_ARGS__, NULL}; \
+               patterns; \
+       })
+
 /* sections that we do not want to do full section mismatch check on */
 static const char *const section_white_list[] =
 {
        ".comment*",
        ".debug*",
-       ".cranges",             /* sh64 */
        ".zdebug*",             /* Compressed debug sections. */
        ".GCC.command.line",    /* record-gcc-switches */
        ".mdebug*",        /* alpha, score, mips etc. */
@@ -830,28 +845,12 @@ static const char *const init_data_sections[] =
 /* all init sections */
 static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
 
-/* All init and exit sections (code + data) */
-static const char *const init_exit_sections[] =
-       {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
-
 /* all text sections */
 static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
 
 /* data section */
 static const char *const data_sections[] = { DATA_SECTIONS, NULL };
 
-
-/* symbols in .data that may refer to init/exit sections */
-#define DEFAULT_SYMBOL_WHITE_LIST                                      \
-       "*driver",                                                      \
-       "*_template", /* scsi uses *_template a lot */                  \
-       "*_timer",    /* arm uses ops structures named _timer a lot */  \
-       "*_sht",      /* scsi also used *_sht to some extent */         \
-       "*_ops",                                                        \
-       "*_probe",                                                      \
-       "*_probe_one",                                                  \
-       "*_console"
-
 static const char *const head_sections[] = { ".head.text*", NULL };
 static const char *const linker_symbols[] =
        { "__init_begin", "_sinittext", "_einittext", NULL };
@@ -883,9 +882,6 @@ enum mismatch {
  *
  * @mismatch: Type of mismatch.
  *
- * @symbol_white_list: Do not match a relocation to a symbol in this list
- * even if it is targeting a section in @bad_to_sec.
- *
  * @handler: Specific handler to call when a match is found.  If NULL,
  * default_mismatch_handler() will be called.
  *
@@ -895,7 +891,6 @@ struct sectioncheck {
        const char *bad_tosec[20];
        const char *good_tosec[20];
        enum mismatch mismatch;
-       const char *symbol_white_list[20];
        void (*handler)(const char *modname, struct elf_info *elf,
                        const struct sectioncheck* const mismatch,
                        Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
@@ -915,75 +910,61 @@ static const struct sectioncheck sectioncheck[] = {
        .fromsec = { TEXT_SECTIONS, NULL },
        .bad_tosec = { ALL_INIT_SECTIONS, NULL },
        .mismatch = TEXT_TO_ANY_INIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
        .fromsec = { DATA_SECTIONS, NULL },
        .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
        .mismatch = DATA_TO_ANY_INIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
        .fromsec = { DATA_SECTIONS, NULL },
        .bad_tosec = { INIT_SECTIONS, NULL },
        .mismatch = DATA_TO_ANY_INIT,
-       .symbol_white_list = {
-               "*_template", "*_timer", "*_sht", "*_ops",
-               "*_probe", "*_probe_one", "*_console", NULL
-       },
 },
 {
        .fromsec = { TEXT_SECTIONS, NULL },
        .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
        .mismatch = TEXT_TO_ANY_EXIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
        .fromsec = { DATA_SECTIONS, NULL },
        .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
        .mismatch = DATA_TO_ANY_EXIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 /* Do not reference init code/data from meminit code/data */
 {
        .fromsec = { ALL_XXXINIT_SECTIONS, NULL },
        .bad_tosec = { INIT_SECTIONS, NULL },
        .mismatch = XXXINIT_TO_SOME_INIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 /* Do not reference exit code/data from memexit code/data */
 {
        .fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
        .bad_tosec = { EXIT_SECTIONS, NULL },
        .mismatch = XXXEXIT_TO_SOME_EXIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 /* Do not use exit code/data from init code */
 {
        .fromsec = { ALL_INIT_SECTIONS, NULL },
        .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
        .mismatch = ANY_INIT_TO_ANY_EXIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 /* Do not use init code/data from exit code */
 {
        .fromsec = { ALL_EXIT_SECTIONS, NULL },
        .bad_tosec = { ALL_INIT_SECTIONS, NULL },
        .mismatch = ANY_EXIT_TO_ANY_INIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
        .fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
        .bad_tosec = { INIT_SECTIONS, NULL },
        .mismatch = ANY_INIT_TO_ANY_EXIT,
-       .symbol_white_list = { NULL },
 },
 /* Do not export init/exit functions or data */
 {
        .fromsec = { "___ksymtab*", NULL },
        .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
        .mismatch = EXPORT_TO_INIT_EXIT,
-       .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
        .fromsec = { "__ex_table", NULL },
@@ -1044,15 +1025,6 @@ static const struct sectioncheck *section_mismatch(
  *   fromsec = .data*
  *   atsym   = __param_ops_*
  *
- * Pattern 2:
- *   Many drivers utilise a *driver container with references to
- *   add, remove, probe functions etc.
- *   the pattern is identified by:
- *   tosec   = init or exit section
- *   fromsec = data section
- *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
- *           *probe_one, *_console, *_timer
- *
  * Pattern 3:
  *   Whitelist all references from .head.text to any init section
  *
@@ -1101,10 +1073,22 @@ static int secref_whitelist(const struct sectioncheck *mismatch,
            strstarts(fromsym, "__param_ops_"))
                return 0;
 
-       /* Check for pattern 2 */
-       if (match(tosec, init_exit_sections) &&
-           match(fromsec, data_sections) &&
-           match(fromsym, mismatch->symbol_white_list))
+       /* symbols in data sections that may refer to any init/exit sections */
+       if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+           match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+           match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot
+                                   "*_timer", // arm uses ops structures named _timer a lot
+                                   "*_sht", // scsi also used *_sht to some extent
+                                   "*_ops",
+                                   "*_probe",
+                                   "*_probe_one",
+                                   "*_console")))
+               return 0;
+
+       /* symbols in data sections that may refer to meminit/exit sections */
+       if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+           match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+           match(fromsym, PATTERNS("*driver")))
                return 0;
 
        /* Check for pattern 3 */
@@ -1230,42 +1214,6 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
        return near;
 }
 
-/*
- * Convert a section name to the function/data attribute
- * .init.text => __init
- * .memexitconst => __memconst
- * etc.
- *
- * The memory of returned value has been allocated on a heap. The user of this
- * method should free it after usage.
-*/
-static char *sec2annotation(const char *s)
-{
-       if (match(s, init_exit_sections)) {
-               char *p = NOFAIL(malloc(20));
-               char *r = p;
-
-               *p++ = '_';
-               *p++ = '_';
-               if (*s == '.')
-                       s++;
-               while (*s && *s != '.')
-                       *p++ = *s++;
-               *p = '\0';
-               if (*s == '.')
-                       s++;
-               if (strstr(s, "rodata") != NULL)
-                       strcat(p, "const ");
-               else if (strstr(s, "data") != NULL)
-                       strcat(p, "data ");
-               else
-                       strcat(p, " ");
-               return r;
-       } else {
-               return NOFAIL(strdup(""));
-       }
-}
-
 static int is_function(Elf_Sym *sym)
 {
        if (sym)
@@ -1274,19 +1222,6 @@ static int is_function(Elf_Sym *sym)
                return -1;
 }
 
-static void print_section_list(const char * const list[20])
-{
-       const char *const *s = list;
-
-       while (*s) {
-               fprintf(stderr, "%s", *s);
-               s++;
-               if (*s)
-                       fprintf(stderr, ", ");
-       }
-       fprintf(stderr, "\n");
-}
-
 static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
 {
        switch (is_func) {
@@ -1304,141 +1239,31 @@ static inline void get_pretty_name(int is_func, const char** name, const char**
 static void report_sec_mismatch(const char *modname,
                                const struct sectioncheck *mismatch,
                                const char *fromsec,
-                               unsigned long long fromaddr,
                                const char *fromsym,
-                               int from_is_func,
-                               const char *tosec, const char *tosym,
-                               int to_is_func)
+                               const char *tosec, const char *tosym)
 {
-       const char *from, *from_p;
-       const char *to, *to_p;
-       char *prl_from;
-       char *prl_to;
-
        sec_mismatch_count++;
 
-       get_pretty_name(from_is_func, &from, &from_p);
-       get_pretty_name(to_is_func, &to, &to_p);
-
-       warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
-            "to the %s %s:%s%s\n",
-            modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
-            tosym, to_p);
-
        switch (mismatch->mismatch) {
        case TEXT_TO_ANY_INIT:
-               prl_from = sec2annotation(fromsec);
-               prl_to = sec2annotation(tosec);
-               fprintf(stderr,
-               "The function %s%s() references\n"
-               "the %s %s%s%s.\n"
-               "This is often because %s lacks a %s\n"
-               "annotation or the annotation of %s is wrong.\n",
-               prl_from, fromsym,
-               to, prl_to, tosym, to_p,
-               fromsym, prl_to, tosym);
-               free(prl_from);
-               free(prl_to);
-               break;
-       case DATA_TO_ANY_INIT: {
-               prl_to = sec2annotation(tosec);
-               fprintf(stderr,
-               "The variable %s references\n"
-               "the %s %s%s%s\n"
-               "If the reference is valid then annotate the\n"
-               "variable with __init* or __refdata (see linux/init.h) "
-               "or name the variable:\n",
-               fromsym, to, prl_to, tosym, to_p);
-               print_section_list(mismatch->symbol_white_list);
-               free(prl_to);
-               break;
-       }
+       case DATA_TO_ANY_INIT:
        case TEXT_TO_ANY_EXIT:
-               prl_to = sec2annotation(tosec);
-               fprintf(stderr,
-               "The function %s() references a %s in an exit section.\n"
-               "Often the %s %s%s has valid usage outside the exit section\n"
-               "and the fix is to remove the %sannotation of %s.\n",
-               fromsym, to, to, tosym, to_p, prl_to, tosym);
-               free(prl_to);
-               break;
-       case DATA_TO_ANY_EXIT: {
-               prl_to = sec2annotation(tosec);
-               fprintf(stderr,
-               "The variable %s references\n"
-               "the %s %s%s%s\n"
-               "If the reference is valid then annotate the\n"
-               "variable with __exit* (see linux/init.h) or "
-               "name the variable:\n",
-               fromsym, to, prl_to, tosym, to_p);
-               print_section_list(mismatch->symbol_white_list);
-               free(prl_to);
-               break;
-       }
+       case DATA_TO_ANY_EXIT:
        case XXXINIT_TO_SOME_INIT:
        case XXXEXIT_TO_SOME_EXIT:
-               prl_from = sec2annotation(fromsec);
-               prl_to = sec2annotation(tosec);
-               fprintf(stderr,
-               "The %s %s%s%s references\n"
-               "a %s %s%s%s.\n"
-               "If %s is only used by %s then\n"
-               "annotate %s with a matching annotation.\n",
-               from, prl_from, fromsym, from_p,
-               to, prl_to, tosym, to_p,
-               tosym, fromsym, tosym);
-               free(prl_from);
-               free(prl_to);
-               break;
        case ANY_INIT_TO_ANY_EXIT:
-               prl_from = sec2annotation(fromsec);
-               prl_to = sec2annotation(tosec);
-               fprintf(stderr,
-               "The %s %s%s%s references\n"
-               "a %s %s%s%s.\n"
-               "This is often seen when error handling "
-               "in the init function\n"
-               "uses functionality in the exit path.\n"
-               "The fix is often to remove the %sannotation of\n"
-               "%s%s so it may be used outside an exit section.\n",
-               from, prl_from, fromsym, from_p,
-               to, prl_to, tosym, to_p,
-               prl_to, tosym, to_p);
-               free(prl_from);
-               free(prl_to);
-               break;
        case ANY_EXIT_TO_ANY_INIT:
-               prl_from = sec2annotation(fromsec);
-               prl_to = sec2annotation(tosec);
-               fprintf(stderr,
-               "The %s %s%s%s references\n"
-               "a %s %s%s%s.\n"
-               "This is often seen when error handling "
-               "in the exit function\n"
-               "uses functionality in the init path.\n"
-               "The fix is often to remove the %sannotation of\n"
-               "%s%s so it may be used outside an init section.\n",
-               from, prl_from, fromsym, from_p,
-               to, prl_to, tosym, to_p,
-               prl_to, tosym, to_p);
-               free(prl_from);
-               free(prl_to);
+               warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n",
+                    modname, fromsym, fromsec, tosym, tosec);
                break;
        case EXPORT_TO_INIT_EXIT:
-               prl_to = sec2annotation(tosec);
-               fprintf(stderr,
-               "The symbol %s is exported and annotated %s\n"
-               "Fix this by removing the %sannotation of %s "
-               "or drop the export.\n",
-               tosym, prl_to, prl_to, tosym);
-               free(prl_to);
+               warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n",
+                    modname, tosym, tosec);
                break;
        case EXTABLE_TO_NON_TEXT:
-               fatal("There's a special handler for this mismatch type, "
-                     "we should never get here.");
+               fatal("There's a special handler for this mismatch type, we should never get here.\n");
                break;
        }
-       fprintf(stderr, "\n");
 }
 
 static void default_mismatch_handler(const char *modname, struct elf_info *elf,
@@ -1454,9 +1279,6 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,
        from = find_elf_symbol2(elf, r->r_offset, fromsec);
        fromsym = sym_name(elf, from);
 
-       if (strstarts(fromsym, "reference___initcall"))
-               return;
-
        tosec = sec_name(elf, get_secindex(elf, sym));
        to = find_elf_symbol(elf, r->r_addend, sym);
        tosym = sym_name(elf, to);
@@ -1465,9 +1287,7 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,
        if (secref_whitelist(mismatch,
                             fromsec, fromsym, tosec, tosym)) {
                report_sec_mismatch(modname, mismatch,
-                                   fromsec, r->r_offset, fromsym,
-                                   is_function(from), tosec, tosym,
-                                   is_function(to));
+                                   fromsec, fromsym, tosec, tosym);
        }
 }
 
@@ -1623,9 +1443,6 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
                break;
        case R_386_PC32:
                r->r_addend = TO_NATIVE(*location) + 4;
-               /* For CONFIG_RELOCATABLE=y */
-               if (elf->hdr->e_type == ET_EXEC)
-                       r->r_addend += r->r_offset;
                break;
        }
        return 0;
@@ -1718,8 +1535,7 @@ static void section_rela(const char *modname, struct elf_info *elf,
        Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
        Elf_Rela *stop  = (void *)start + sechdr->sh_size;
 
-       fromsec = sech_name(elf, sechdr);
-       fromsec += strlen(".rela");
+       fromsec = sec_name(elf, sechdr->sh_info);
        /* if from section (name) is know good then skip it */
        if (match(fromsec, section_white_list))
                return;
@@ -1771,8 +1587,7 @@ static void section_rel(const char *modname, struct elf_info *elf,
        Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
        Elf_Rel *stop  = (void *)start + sechdr->sh_size;
 
-       fromsec = sech_name(elf, sechdr);
-       fromsec += strlen(".rel");
+       fromsec = sec_name(elf, sechdr->sh_info);
        /* if from section (name) is know good then skip it */
        if (match(fromsec, section_white_list))
                return;
index 044bdfb..1178f40 100644 (file)
@@ -26,7 +26,6 @@
 #define Elf_Shdr    Elf32_Shdr
 #define Elf_Sym     Elf32_Sym
 #define Elf_Addr    Elf32_Addr
-#define Elf_Sword   Elf64_Sword
 #define Elf_Section Elf32_Half
 #define ELF_ST_BIND ELF32_ST_BIND
 #define ELF_ST_TYPE ELF32_ST_TYPE
@@ -41,7 +40,6 @@
 #define Elf_Shdr    Elf64_Shdr
 #define Elf_Sym     Elf64_Sym
 #define Elf_Addr    Elf64_Addr
-#define Elf_Sword   Elf64_Sxword
 #define Elf_Section Elf64_Half
 #define ELF_ST_BIND ELF64_ST_BIND
 #define ELF_ST_TYPE ELF64_ST_TYPE
@@ -158,22 +156,28 @@ static inline int is_shndx_special(unsigned int i)
        return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
 }
 
-/*
- * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
- * the way to -256..-1, to avoid conflicting with real section
- * indices.
- */
-#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
-
 /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
 static inline unsigned int get_secindex(const struct elf_info *info,
                                        const Elf_Sym *sym)
 {
-       if (is_shndx_special(sym->st_shndx))
-               return SPECIAL(sym->st_shndx);
-       if (sym->st_shndx != SHN_XINDEX)
-               return sym->st_shndx;
-       return info->symtab_shndx_start[sym - info->symtab_start];
+       unsigned int index = sym->st_shndx;
+
+       /*
+        * Elf{32,64}_Sym::st_shndx is 2 byte. Big section numbers are available
+        * in the .symtab_shndx section.
+        */
+       if (index == SHN_XINDEX)
+               return info->symtab_shndx_start[sym - info->symtab_start];
+
+       /*
+        * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
+        * the way to UINT_MAX-255..UINT_MAX, to avoid conflicting with real
+        * section indices.
+        */
+       if (index >= SHN_LORESERVE && index <= SHN_HIRESERVE)
+               return index - SHN_HIRESERVE - 1;
+
+       return index;
 }
 
 /* file2alias.c */
@@ -187,6 +191,7 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen);
 /* from modpost.c */
 char *read_text_file(const char *filename);
 char *get_line(char **stringp);
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym);
 
 enum loglevel {
        LOG_WARN,
index 1d0e1e4..3a3aa23 100644 (file)
@@ -27,6 +27,8 @@ SECTIONS {
        .ctors                  0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
        .init_array             0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }
 
+       .altinstructions        0 : ALIGN(8) { KEEP(*(.altinstructions)) }
+       __bug_table             0 : ALIGN(8) { KEEP(*(__bug_table)) }
        __jump_table            0 : ALIGN(8) { KEEP(*(__jump_table)) }
 
        __patchable_function_entries : { *(__patchable_function_entries) }
index 7c477ca..8fa7c5b 100755 (executable)
@@ -49,6 +49,9 @@ sed -e '/^DEL/d' -e 's/^\t*//' <<EOF
        URL: https://www.kernel.org
 $S     Source: kernel-$__KERNELRELEASE.tar.gz
        Provides: $PROVIDES
+       # $UTS_MACHINE as a fallback of _arch in case
+       # /usr/lib/rpm/platform/*/macros was not included.
+       %define _arch %{?_arch:$UTS_MACHINE}
        %define __spec_install_post /usr/lib/rpm/brp-compress || :
        %define debug_package %{nil}
 
index 348ed6c..cb3496e 100644 (file)
@@ -6,8 +6,6 @@ config SECURITY_APPARMOR
        select SECURITY_PATH
        select SECURITYFS
        select SECURITY_NETWORK
-       select ZLIB_INFLATE
-       select ZLIB_DEFLATE
        default n
        help
          This enables the AppArmor security module.
@@ -17,29 +15,6 @@ config SECURITY_APPARMOR
 
          If you are unsure how to answer this question, answer N.
 
-config SECURITY_APPARMOR_HASH
-       bool "Enable introspection of sha1 hashes for loaded profiles"
-       depends on SECURITY_APPARMOR
-       select CRYPTO
-       select CRYPTO_SHA1
-       default y
-       help
-         This option selects whether introspection of loaded policy
-         is available to userspace via the apparmor filesystem.
-
-config SECURITY_APPARMOR_HASH_DEFAULT
-       bool "Enable policy hash introspection by default"
-       depends on SECURITY_APPARMOR_HASH
-       default y
-       help
-         This option selects whether sha1 hashing of loaded policy
-        is enabled by default. The generation of sha1 hashes for
-        loaded policy provide system administrators a quick way
-        to verify that policy in the kernel matches what is expected,
-        however it can slow down policy load on some devices. In
-        these cases policy hashing can be disabled by default and
-        enabled only if needed.
-
 config SECURITY_APPARMOR_DEBUG
        bool "Build AppArmor with debug code"
        depends on SECURITY_APPARMOR
@@ -69,6 +44,67 @@ config SECURITY_APPARMOR_DEBUG_MESSAGES
          When enabled, various debug messages will be logged to
          the kernel message buffer.
 
+config SECURITY_APPARMOR_INTROSPECT_POLICY
+       bool "Allow loaded policy to be introspected"
+       depends on SECURITY_APPARMOR
+       default y
+       help
+         This option selects whether introspection of loaded policy
+         is available to userspace via the apparmor filesystem. This
+         adds to kernel memory usage. It is required for introspection
+         of loaded policy, and check point and restore support. It
+         can be disabled for embedded systems where reducing memory and
+         cpu is paramount.
+
+config SECURITY_APPARMOR_HASH
+       bool "Enable introspection of sha1 hashes for loaded profiles"
+       depends on SECURITY_APPARMOR_INTROSPECT_POLICY
+       select CRYPTO
+       select CRYPTO_SHA1
+       default y
+       help
+         This option selects whether introspection of loaded policy
+         hashes is available to userspace via the apparmor
+         filesystem. This option provides a light weight means of
+         checking loaded policy.  This option adds to policy load
+         time and can be disabled for small embedded systems.
+
+config SECURITY_APPARMOR_HASH_DEFAULT
+       bool "Enable policy hash introspection by default"
+       depends on SECURITY_APPARMOR_HASH
+       default y
+       help
+         This option selects whether sha1 hashing of loaded policy
+        is enabled by default. The generation of sha1 hashes for
+        loaded policy provide system administrators a quick way
+        to verify that policy in the kernel matches what is expected,
+        however it can slow down policy load on some devices. In
+        these cases policy hashing can be disabled by default and
+        enabled only if needed.
+
+config SECURITY_APPARMOR_EXPORT_BINARY
+       bool "Allow exporting the raw binary policy"
+       depends on SECURITY_APPARMOR_INTROSPECT_POLICY
+       select ZLIB_INFLATE
+       select ZLIB_DEFLATE
+       default y
+       help
+         This option allows reading back binary policy as it was loaded.
+         It increases the amount of kernel memory needed by policy and
+         also increases policy load time. This option is required for
+         checkpoint and restore support, and debugging of loaded policy.
+
+config SECURITY_APPARMOR_PARANOID_LOAD
+       bool "Perform full verification of loaded policy"
+       depends on SECURITY_APPARMOR
+       default y
+       help
+         This options allows controlling whether apparmor does a full
+         verification of loaded policy. This should not be disabled
+         except for embedded systems where the image is read only,
+         includes policy, and has some form of integrity check.
+         Disabling the check will speed up policy loads.
+
 config SECURITY_APPARMOR_KUNIT_TEST
        bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS
        depends on KUNIT=y && SECURITY_APPARMOR
index 0797edb..d066ccc 100644 (file)
@@ -36,6 +36,7 @@
 #include "include/policy_ns.h"
 #include "include/resource.h"
 #include "include/policy_unpack.h"
+#include "include/task.h"
 
 /*
  * The apparmor filesystem interface used for policy load and introspection
@@ -70,6 +71,7 @@ struct rawdata_f_data {
        struct aa_loaddata *loaddata;
 };
 
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
 #define RAWDATA_F_DATA_BUF(p) (char *)(p + 1)
 
 static void rawdata_f_data_free(struct rawdata_f_data *private)
@@ -94,9 +96,10 @@ static struct rawdata_f_data *rawdata_f_data_alloc(size_t size)
 
        return ret;
 }
+#endif
 
 /**
- * aa_mangle_name - mangle a profile name to std profile layout form
+ * mangle_name - mangle a profile name to std profile layout form
  * @name: profile name to mangle  (NOT NULL)
  * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
  *
@@ -401,7 +404,7 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
 
        data->size = copy_size;
        if (copy_from_user(data->data, userbuf, copy_size)) {
-               kvfree(data);
+               aa_put_loaddata(data);
                return ERR_PTR(-EFAULT);
        }
 
@@ -1201,7 +1204,7 @@ SEQ_NS_FOPS(name);
 
 
 /* policy/raw_data/ * file ops */
-
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
 #define SEQ_RAWDATA_FOPS(NAME)                                               \
 static int seq_rawdata_ ##NAME ##_open(struct inode *inode, struct file *file)\
 {                                                                            \
@@ -1294,44 +1297,47 @@ SEQ_RAWDATA_FOPS(compressed_size);
 
 static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen)
 {
-       int error;
-       struct z_stream_s strm;
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
+       if (aa_g_rawdata_compression_level != 0) {
+               int error = 0;
+               struct z_stream_s strm;
 
-       if (aa_g_rawdata_compression_level == 0) {
-               if (dlen < slen)
-                       return -EINVAL;
-               memcpy(dst, src, slen);
-               return 0;
-       }
+               memset(&strm, 0, sizeof(strm));
 
-       memset(&strm, 0, sizeof(strm));
+               strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+               if (!strm.workspace)
+                       return -ENOMEM;
 
-       strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
-       if (!strm.workspace)
-               return -ENOMEM;
-
-       strm.next_in = src;
-       strm.avail_in = slen;
+               strm.next_in = src;
+               strm.avail_in = slen;
 
-       error = zlib_inflateInit(&strm);
-       if (error != Z_OK) {
-               error = -ENOMEM;
-               goto fail_inflate_init;
-       }
+               error = zlib_inflateInit(&strm);
+               if (error != Z_OK) {
+                       error = -ENOMEM;
+                       goto fail_inflate_init;
+               }
 
-       strm.next_out = dst;
-       strm.avail_out = dlen;
+               strm.next_out = dst;
+               strm.avail_out = dlen;
 
-       error = zlib_inflate(&strm, Z_FINISH);
-       if (error != Z_STREAM_END)
-               error = -EINVAL;
-       else
-               error = 0;
+               error = zlib_inflate(&strm, Z_FINISH);
+               if (error != Z_STREAM_END)
+                       error = -EINVAL;
+               else
+                       error = 0;
 
-       zlib_inflateEnd(&strm);
+               zlib_inflateEnd(&strm);
 fail_inflate_init:
-       kvfree(strm.workspace);
-       return error;
+               kvfree(strm.workspace);
+
+               return error;
+       }
+#endif
+
+       if (dlen < slen)
+               return -EINVAL;
+       memcpy(dst, src, slen);
+       return 0;
 }
 
 static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
@@ -1492,10 +1498,12 @@ fail:
 
        return PTR_ERR(dent);
 }
+#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
+
 
 /** fns to setup dynamic per profile/namespace files **/
 
-/**
+/*
  *
  * Requires: @profile->ns->lock held
  */
@@ -1522,7 +1530,7 @@ void __aafs_profile_rmdir(struct aa_profile *profile)
        }
 }
 
-/**
+/*
  *
  * Requires: @old->ns->lock held
  */
@@ -1557,6 +1565,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name,
        return dent;
 }
 
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
 static int profile_depth(struct aa_profile *profile)
 {
        int depth = 0;
@@ -1658,7 +1667,7 @@ static const struct inode_operations rawdata_link_abi_iops = {
 static const struct inode_operations rawdata_link_data_iops = {
        .get_link       = rawdata_get_link_data,
 };
-
+#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
 
 /*
  * Requires: @profile->ns->lock held
@@ -1729,15 +1738,17 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
                profile->dents[AAFS_PROF_HASH] = dent;
        }
 
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
        if (profile->rawdata) {
-               dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir,
-                                  profile->label.proxy, NULL, NULL,
-                                  &rawdata_link_sha1_iops);
-               if (IS_ERR(dent))
-                       goto fail;
-               aa_get_proxy(profile->label.proxy);
-               profile->dents[AAFS_PROF_RAW_HASH] = dent;
-
+               if (aa_g_hash_policy) {
+                       dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir,
+                                          profile->label.proxy, NULL, NULL,
+                                          &rawdata_link_sha1_iops);
+                       if (IS_ERR(dent))
+                               goto fail;
+                       aa_get_proxy(profile->label.proxy);
+                       profile->dents[AAFS_PROF_RAW_HASH] = dent;
+               }
                dent = aafs_create("raw_abi", S_IFLNK | 0444, dir,
                                   profile->label.proxy, NULL, NULL,
                                   &rawdata_link_abi_iops);
@@ -1754,6 +1765,7 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
                aa_get_proxy(profile->label.proxy);
                profile->dents[AAFS_PROF_RAW_DATA] = dent;
        }
+#endif /*CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
 
        list_for_each_entry(child, &profile->base.profiles, base.list) {
                error = __aafs_profile_mkdir(child, prof_child_dir(profile));
@@ -1880,7 +1892,7 @@ static void __aa_fs_list_remove_rawdata(struct aa_ns *ns)
                __aa_fs_remove_rawdata(ent);
 }
 
-/**
+/*
  *
  * Requires: @ns->lock held
  */
@@ -2323,6 +2335,7 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = {
        AA_SFS_FILE_BOOLEAN("v6",       1),
        AA_SFS_FILE_BOOLEAN("v7",       1),
        AA_SFS_FILE_BOOLEAN("v8",       1),
+       AA_SFS_FILE_BOOLEAN("v9",       1),
        { }
 };
 
index f7e97c7..704b0c8 100644 (file)
@@ -137,7 +137,7 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
        }
        if (AUDIT_MODE(profile) == AUDIT_QUIET ||
            (type == AUDIT_APPARMOR_DENIED &&
-            AUDIT_MODE(profile) == AUDIT_QUIET))
+            AUDIT_MODE(profile) == AUDIT_QUIET_DENIED))
                return aad(sa)->error;
 
        if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
index a29e69d..91689d3 100644 (file)
@@ -119,7 +119,7 @@ static inline unsigned int match_component(struct aa_profile *profile,
  * @profile: profile to find perms for
  * @label: label to check access permissions for
  * @stack: whether this is a stacking request
- * @start: state to start match in
+ * @state: state to start match in
  * @subns: whether to do permission checks on components in a subns
  * @request: permissions to request
  * @perms: perms struct to set
@@ -466,7 +466,7 @@ restart:
                                 * xattrs, or a longer match
                                 */
                                candidate = profile;
-                               candidate_len = profile->xmatch_len;
+                               candidate_len = max(count, profile->xmatch_len);
                                candidate_xattrs = ret;
                                conflict = false;
                        }
@@ -1279,7 +1279,6 @@ static int change_profile_perms_wrapper(const char *op, const char *name,
 /**
  * aa_change_profile - perform a one-way profile transition
  * @fqname: name of profile may include namespace (NOT NULL)
- * @onexec: whether this transition is to take place immediately or at exec
  * @flags: flags affecting change behavior
  *
  * Change to new profile @name.  Unlike with hats, there is no way
index 1fbabdb..9c3fc36 100644 (file)
@@ -36,6 +36,7 @@ extern enum audit_mode aa_g_audit;
 extern bool aa_g_audit_header;
 extern bool aa_g_debug;
 extern bool aa_g_hash_policy;
+extern bool aa_g_export_binary;
 extern int aa_g_rawdata_compression_level;
 extern bool aa_g_lock_policy;
 extern bool aa_g_logsyscall;
index 6e14f6c..1e94904 100644 (file)
@@ -114,7 +114,21 @@ int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name,
                     struct dentry *dent);
 
 struct aa_loaddata;
+
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
 void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata);
 int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata);
+#else
+static inline void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata)
+{
+       /* empty stub */
+}
+
+static inline int __aa_fs_create_rawdata(struct aa_ns *ns,
+                                        struct aa_loaddata *rawdata)
+{
+       return 0;
+}
+#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
 
 #endif /* __AA_APPARMORFS_H */
index 7517605..029cb20 100644 (file)
@@ -142,6 +142,7 @@ static inline u16 dfa_map_xindex(u16 mask)
  */
 #define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
                                    ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_user_xbits(dfa, state) (((ACCEPT_TABLE(dfa)[state]) >> 7) & 0x7f)
 #define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f)
 #define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
 #define dfa_user_xindex(dfa, state) \
@@ -150,6 +151,8 @@ static inline u16 dfa_map_xindex(u16 mask)
 #define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
                                      0x7f) |                           \
                                     ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_other_xbits(dfa, state) \
+       ((((ACCEPT_TABLE(dfa)[state]) >> 7) >> 14) & 0x7f)
 #define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
 #define dfa_other_quiet(dfa, state) \
        ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
index 9cafd80..a1ac6ff 100644 (file)
 
 #include <linux/sched.h>
 
-struct aa_profile;
-
-#define AA_PTRACE_TRACE                MAY_WRITE
-#define AA_PTRACE_READ         MAY_READ
-#define AA_MAY_BE_TRACED       AA_MAY_APPEND
-#define AA_MAY_BE_READ         AA_MAY_CREATE
-#define PTRACE_PERM_SHIFT      2
-
-#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
-                            AA_MAY_BE_READ | AA_MAY_BE_TRACED)
-#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
-
-#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
-       "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
-       "xcpu xfsz vtalrm prof winch io pwr sys emt lost"
-
-int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
-                 u32 request);
 int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
 
 #endif /* __AA_IPC_H */
index 9101c2c..860484c 100644 (file)
@@ -92,6 +92,8 @@ enum label_flags {
        FLAG_STALE = 0x800,             /* replaced/removed */
        FLAG_RENAMED = 0x1000,          /* label has renaming in it */
        FLAG_REVOKED = 0x2000,          /* label has revocation in it */
+       FLAG_DEBUG1 = 0x4000,
+       FLAG_DEBUG2 = 0x8000,
 
        /* These flags must correspond with PATH_flags */
        /* TODO: add new path flags */
index e2e8df0..f42359f 100644 (file)
  */
 
 #define DEBUG_ON (aa_g_debug)
+/*
+ * split individual debug cases out in preparation for finer grained
+ * debug controls in the future.
+ */
+#define AA_DEBUG_LABEL DEBUG_ON
 #define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args)
 #define AA_DEBUG(fmt, args...)                                         \
        do {                                                            \
index 44a7945..3431899 100644 (file)
@@ -17,8 +17,8 @@ enum path_flags {
        PATH_CHROOT_REL = 0x8,          /* do path lookup relative to chroot */
        PATH_CHROOT_NSCONNECT = 0x10,   /* connect paths that are at ns root */
 
-       PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
-       PATH_MEDIATE_DELETED = 0x10000,  /* mediate deleted paths */
+       PATH_DELEGATE_DELETED = 0x10000, /* delegate deleted files */
+       PATH_MEDIATE_DELETED = 0x20000,  /* mediate deleted paths */
 };
 
 int aa_path_name(const struct path *path, int flags, char *buffer,
index cb5ef21..639b5b2 100644 (file)
@@ -48,6 +48,10 @@ extern const char *const aa_profile_mode_names[];
 
 #define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT)
 
+#define CHECK_DEBUG1(_profile) ((_profile)->label.flags & FLAG_DEBUG1)
+
+#define CHECK_DEBUG2(_profile) ((_profile)->label.flags & FLAG_DEBUG2)
+
 #define profile_is_stale(_profile) (label_is_stale(&(_profile)->label))
 
 #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
@@ -135,7 +139,7 @@ struct aa_profile {
 
        const char *attach;
        struct aa_dfa *xmatch;
-       int xmatch_len;
+       unsigned int xmatch_len;
        enum audit_mode audit;
        long mode;
        u32 path_flags;
index 3df6f80..33d6655 100644 (file)
@@ -74,6 +74,7 @@ struct aa_ns {
        struct dentry *dents[AAFS_NS_SIZEOF];
 };
 
+extern struct aa_label *kernel_t;
 extern struct aa_ns *root_ns;
 
 extern const char *aa_hidden_ns_name;
index e0e1ca7..eb5f7d7 100644 (file)
@@ -28,6 +28,8 @@ void aa_load_ent_free(struct aa_load_ent *ent);
 struct aa_load_ent *aa_load_ent_alloc(void);
 
 #define PACKED_FLAG_HAT                1
+#define PACKED_FLAG_DEBUG1     2
+#define PACKED_FLAG_DEBUG2     4
 
 #define PACKED_MODE_ENFORCE    0
 #define PACKED_MODE_COMPLAIN   1
index 48ff1dd..a912a5d 100644 (file)
@@ -21,6 +21,9 @@ struct aa_label;
 /* secid value that matches any other secid */
 #define AA_SECID_WILDCARD 1
 
+/* sysctl to enable displaying mode when converting secid to secctx */
+extern int apparmor_display_secid_mode;
+
 struct aa_label *aa_secid_to_label(u32 secid);
 int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
 int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
@@ -31,6 +34,4 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp);
 void aa_free_secid(u32 secid);
 void aa_secid_update(u32 secid, struct aa_label *label);
 
-void aa_secids_init(void);
-
 #endif /* __AA_SECID_H */
index f13d123..13437d6 100644 (file)
@@ -77,4 +77,22 @@ static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
        ctx->token = 0;
 }
 
+#define AA_PTRACE_TRACE                MAY_WRITE
+#define AA_PTRACE_READ         MAY_READ
+#define AA_MAY_BE_TRACED       AA_MAY_APPEND
+#define AA_MAY_BE_READ         AA_MAY_CREATE
+#define PTRACE_PERM_SHIFT      2
+
+#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
+                            AA_MAY_BE_READ | AA_MAY_BE_TRACED)
+#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
+
+#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
+       "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
+       "xcpu xfsz vtalrm prof winch io pwr sys emt lost"
+
+int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
+                 u32 request);
+
+
 #endif /* __AA_TASK_H */
index fe36d11..3dbbc59 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/gfp.h>
-#include <linux/ptrace.h>
 
 #include "include/audit.h"
 #include "include/capability.h"
 #include "include/ipc.h"
 #include "include/sig_names.h"
 
-/**
- * audit_ptrace_mask - convert mask to permission string
- * @mask: permission mask to convert
- *
- * Returns: pointer to static string
- */
-static const char *audit_ptrace_mask(u32 mask)
-{
-       switch (mask) {
-       case MAY_READ:
-               return "read";
-       case MAY_WRITE:
-               return "trace";
-       case AA_MAY_BE_READ:
-               return "readby";
-       case AA_MAY_BE_TRACED:
-               return "tracedby";
-       }
-       return "";
-}
-
-/* call back to audit ptrace fields */
-static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
-{
-       struct common_audit_data *sa = va;
-
-       if (aad(sa)->request & AA_PTRACE_PERM_MASK) {
-               audit_log_format(ab, " requested_mask=\"%s\"",
-                                audit_ptrace_mask(aad(sa)->request));
-
-               if (aad(sa)->denied & AA_PTRACE_PERM_MASK) {
-                       audit_log_format(ab, " denied_mask=\"%s\"",
-                                        audit_ptrace_mask(aad(sa)->denied));
-               }
-       }
-       audit_log_format(ab, " peer=");
-       aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
-                       FLAGS_NONE, GFP_ATOMIC);
-}
-
-/* assumes check for PROFILE_MEDIATES is already done */
-/* TODO: conditionals */
-static int profile_ptrace_perm(struct aa_profile *profile,
-                            struct aa_label *peer, u32 request,
-                            struct common_audit_data *sa)
-{
-       struct aa_perms perms = { };
-
-       aad(sa)->peer = peer;
-       aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request,
-                              &perms);
-       aa_apply_modes_to_perms(profile, &perms);
-       return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
-}
-
-static int profile_tracee_perm(struct aa_profile *tracee,
-                              struct aa_label *tracer, u32 request,
-                              struct common_audit_data *sa)
-{
-       if (profile_unconfined(tracee) || unconfined(tracer) ||
-           !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE))
-               return 0;
-
-       return profile_ptrace_perm(tracee, tracer, request, sa);
-}
-
-static int profile_tracer_perm(struct aa_profile *tracer,
-                              struct aa_label *tracee, u32 request,
-                              struct common_audit_data *sa)
-{
-       if (profile_unconfined(tracer))
-               return 0;
-
-       if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE))
-               return profile_ptrace_perm(tracer, tracee, request, sa);
-
-       /* profile uses the old style capability check for ptrace */
-       if (&tracer->label == tracee)
-               return 0;
-
-       aad(sa)->label = &tracer->label;
-       aad(sa)->peer = tracee;
-       aad(sa)->request = 0;
-       aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
-                                   CAP_OPT_NONE);
-
-       return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
-}
-
-/**
- * aa_may_ptrace - test if tracer task can trace the tracee
- * @tracer: label of the task doing the tracing  (NOT NULL)
- * @tracee: task label to be traced
- * @request: permission request
- *
- * Returns: %0 else error code if permission denied or error
- */
-int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
-                 u32 request)
-{
-       struct aa_profile *profile;
-       u32 xrequest = request << PTRACE_PERM_SHIFT;
-       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE);
-
-       return xcheck_labels(tracer, tracee, profile,
-                       profile_tracer_perm(profile, tracee, request, &sa),
-                       profile_tracee_perm(profile, tracer, xrequest, &sa));
-}
-
 
 static inline int map_signal_num(int sig)
 {
index 0b0265d..0f36ee9 100644 (file)
@@ -197,18 +197,18 @@ static bool vec_is_stale(struct aa_profile **vec, int n)
        return false;
 }
 
-static bool vec_unconfined(struct aa_profile **vec, int n)
+static long union_vec_flags(struct aa_profile **vec, int n, long mask)
 {
+       long u = 0;
        int i;
 
        AA_BUG(!vec);
 
        for (i = 0; i < n; i++) {
-               if (!profile_unconfined(vec[i]))
-                       return false;
+               u |= vec[i]->label.flags & mask;
        }
 
-       return true;
+       return u;
 }
 
 static int sort_cmp(const void *a, const void *b)
@@ -485,7 +485,7 @@ int aa_label_next_confined(struct aa_label *label, int i)
 }
 
 /**
- * aa_label_next_not_in_set - return the next profile of @sub not in @set
+ * __aa_label_next_not_in_set - return the next profile of @sub not in @set
  * @I: label iterator
  * @set: label to test against
  * @sub: label to if is subset of @set
@@ -1097,8 +1097,8 @@ static struct aa_label *label_merge_insert(struct aa_label *new,
                else if (k == b->size)
                        return aa_get_label(b);
        }
-       if (vec_unconfined(new->vec, new->size))
-               new->flags |= FLAG_UNCONFINED;
+       new->flags |= union_vec_flags(new->vec, new->size, FLAG_UNCONFINED |
+                                             FLAG_DEBUG1 | FLAG_DEBUG2);
        ls = labels_set(new);
        write_lock_irqsave(&ls->lock, flags);
        label = __label_insert(labels_set(new), new, false);
@@ -1631,9 +1631,9 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
        AA_BUG(!str && size != 0);
        AA_BUG(!label);
 
-       if (flags & FLAG_ABS_ROOT) {
+       if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) {
                ns = root_ns;
-               len = snprintf(str, size, "=");
+               len = snprintf(str, size, "_");
                update_for_len(total, len, size, str);
        } else if (!ns) {
                ns = labels_ns(label);
@@ -1744,7 +1744,7 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns,
        if (!use_label_hname(ns, label, flags) ||
            display_mode(ns, label, flags)) {
                len  = aa_label_asxprint(&name, ns, label, flags, gfp);
-               if (len == -1) {
+               if (len < 0) {
                        AA_DEBUG("label print error");
                        return;
                }
@@ -1772,7 +1772,7 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
                int len;
 
                len = aa_label_asxprint(&str, ns, label, flags, gfp);
-               if (len == -1) {
+               if (len < 0) {
                        AA_DEBUG("label print error");
                        return;
                }
@@ -1795,7 +1795,7 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
                int len;
 
                len = aa_label_asxprint(&str, ns, label, flags, gfp);
-               if (len == -1) {
+               if (len < 0) {
                        AA_DEBUG("label print error");
                        return;
                }
@@ -1895,7 +1895,8 @@ struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str,
        AA_BUG(!str);
 
        str = skipn_spaces(str, n);
-       if (str == NULL || (*str == '=' && base != &root_ns->unconfined->label))
+       if (str == NULL || (AA_DEBUG_LABEL && *str == '_' &&
+                           base != &root_ns->unconfined->label))
                return ERR_PTR(-EINVAL);
 
        len = label_count_strn_entries(str, end - str);
@@ -2136,7 +2137,7 @@ static void __labelset_update(struct aa_ns *ns)
 }
 
 /**
- * __aa_labelset_udate_subtree - update all labels with a stale component
+ * __aa_labelset_update_subtree - update all labels with a stale component
  * @ns: ns to start update at (NOT NULL)
  *
  * Requires: @ns lock be held
index fa49b81..1c72a61 100644 (file)
@@ -136,7 +136,7 @@ __counted char *aa_str_alloc(int size, gfp_t gfp)
 {
        struct counted_str *str;
 
-       str = kmalloc(sizeof(struct counted_str) + size, gfp);
+       str = kmalloc(struct_size(str, name, size), gfp);
        if (!str)
                return NULL;
 
@@ -322,22 +322,39 @@ static u32 map_other(u32 x)
                ((x & 0x60) << 19);     /* SETOPT/GETOPT */
 }
 
+static u32 map_xbits(u32 x)
+{
+       return ((x & 0x1) << 7) |
+               ((x & 0x7e) << 9);
+}
+
 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
                      struct aa_perms *perms)
 {
+       /* This mapping is convulated due to history.
+        * v1-v4: only file perms
+        * v5: added policydb which dropped in perm user conditional to
+        *     gain new perm bits, but had to map around the xbits because
+        *     the userspace compiler was still munging them.
+        * v9: adds using the xbits in policydb because the compiler now
+        *     supports treating policydb permission bits different.
+        *     Unfortunately there is not way to force auditing on the
+        *     perms represented by the xbits
+        */
        *perms = (struct aa_perms) {
-               .allow = dfa_user_allow(dfa, state),
+               .allow = dfa_user_allow(dfa, state) |
+                        map_xbits(dfa_user_xbits(dfa, state)),
                .audit = dfa_user_audit(dfa, state),
-               .quiet = dfa_user_quiet(dfa, state),
+               .quiet = dfa_user_quiet(dfa, state) |
+                        map_xbits(dfa_other_xbits(dfa, state)),
        };
 
-       /* for v5 perm mapping in the policydb, the other set is used
+       /* for v5-v9 perm mapping in the policydb, the other set is used
         * to extend the general perm set
         */
        perms->allow |= map_other(dfa_other_allow(dfa, state));
        perms->audit |= map_other(dfa_other_audit(dfa, state));
        perms->quiet |= map_other(dfa_other_quiet(dfa, state));
-//     perms->xindex = dfa_user_xindex(dfa, state);
 }
 
 /**
index 900bc54..e29cade 100644 (file)
@@ -832,7 +832,7 @@ static void apparmor_sk_free_security(struct sock *sk)
 }
 
 /**
- * apparmor_clone_security - clone the sk_security field
+ * apparmor_sk_clone_security - clone the sk_security field
  */
 static void apparmor_sk_clone_security(const struct sock *sk,
                                       struct sock *newsk)
@@ -886,10 +886,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family,
        struct aa_label *label;
 
        if (kern) {
-               struct aa_ns *ns = aa_get_current_ns();
-
-               label = aa_get_label(ns_unconfined(ns));
-               aa_put_ns(ns);
+               label = aa_get_label(kernel_t);
        } else
                label = aa_get_current_label();
 
@@ -937,7 +934,7 @@ static int apparmor_socket_connect(struct socket *sock,
 }
 
 /**
- * apparmor_socket_list - check perms before allowing listen
+ * apparmor_socket_listen - check perms before allowing listen
  */
 static int apparmor_socket_listen(struct socket *sock, int backlog)
 {
@@ -1041,7 +1038,7 @@ static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock,
 }
 
 /**
- * apparmor_getsockopt - check perms before getting socket options
+ * apparmor_socket_getsockopt - check perms before getting socket options
  */
 static int apparmor_socket_getsockopt(struct socket *sock, int level,
                                      int optname)
@@ -1051,7 +1048,7 @@ static int apparmor_socket_getsockopt(struct socket *sock, int level,
 }
 
 /**
- * apparmor_setsockopt - check perms before setting socket options
+ * apparmor_socket_setsockopt - check perms before setting socket options
  */
 static int apparmor_socket_setsockopt(struct socket *sock, int level,
                                      int optname)
@@ -1070,7 +1067,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
 
 #ifdef CONFIG_NETWORK_SECMARK
 /**
- * apparmor_socket_sock_recv_skb - check perms before associating skb to sk
+ * apparmor_socket_sock_rcv_skb - check perms before associating skb to sk
  *
  * Note: can not sleep may be called with locks held
  *
@@ -1357,6 +1354,12 @@ bool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT);
 module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR);
 #endif
 
+/* whether policy exactly as loaded is retained for debug and checkpointing */
+bool aa_g_export_binary = IS_ENABLED(CONFIG_SECURITY_APPARMOR_EXPORT_BINARY);
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
+module_param_named(export_binary, aa_g_export_binary, aabool, 0600);
+#endif
+
 /* policy loaddata compression level */
 int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION;
 module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level,
@@ -1399,7 +1402,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR);
  * DEPRECATED: read only as strict checking of load is always done now
  * that none root users (user namespaces) can load policy.
  */
-bool aa_g_paranoid_load = true;
+bool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_APPARMOR_PARANOID_LOAD);
 module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
 
 static int param_get_aaintbool(char *buffer, const struct kernel_param *kp);
@@ -1761,6 +1764,14 @@ static struct ctl_table apparmor_sysctl_table[] = {
                .mode           = 0600,
                .proc_handler   = apparmor_dointvec,
        },
+       {
+               .procname       = "apparmor_display_secid_mode",
+               .data           = &apparmor_display_secid_mode,
+               .maxlen         = sizeof(int),
+               .mode           = 0600,
+               .proc_handler   = apparmor_dointvec,
+       },
+
        { }
 };
 
@@ -1819,11 +1830,8 @@ static const struct nf_hook_ops apparmor_nf_ops[] = {
 
 static int __net_init apparmor_nf_register(struct net *net)
 {
-       int ret;
-
-       ret = nf_register_net_hooks(net, apparmor_nf_ops,
+       return nf_register_net_hooks(net, apparmor_nf_ops,
                                    ARRAY_SIZE(apparmor_nf_ops));
-       return ret;
 }
 
 static void __net_exit apparmor_nf_unregister(struct net *net)
@@ -1857,8 +1865,6 @@ static int __init apparmor_init(void)
 {
        int error;
 
-       aa_secids_init();
-
        error = aa_setup_dfa_engine();
        if (error) {
                AA_ERROR("Unable to setup dfa engine\n");
index aa6fcfd..f612472 100644 (file)
@@ -217,7 +217,6 @@ static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa,
                .allow = dfa_user_allow(dfa, state),
                .audit = dfa_user_audit(dfa, state),
                .quiet = dfa_user_quiet(dfa, state),
-               .xindex = dfa_user_xindex(dfa, state),
        };
 
        return perms;
@@ -229,7 +228,8 @@ static const char * const mnt_info_table[] = {
        "failed srcname match",
        "failed type match",
        "failed flags match",
-       "failed data match"
+       "failed data match",
+       "failed perms check"
 };
 
 /*
@@ -284,8 +284,8 @@ static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
                        return 0;
        }
 
-       /* failed at end of flags match */
-       return 4;
+       /* failed at perms check, don't confuse with flags match */
+       return 6;
 }
 
 
@@ -303,7 +303,7 @@ static int path_flags(struct aa_profile *profile, const struct path *path)
  * @profile: the confining profile
  * @mntpath: for the mntpnt (NOT NULL)
  * @buffer: buffer to be used to lookup mntpath
- * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR)
+ * @devname: string for the devname/src_name (MAY BE NULL OR ERRPTR)
  * @type: string for the dev type (MAYBE NULL)
  * @flags: mount flags to match
  * @data: fs mount data (MAYBE NULL)
@@ -358,7 +358,7 @@ audit:
 /**
  * match_mnt - handle path matching for mount
  * @profile: the confining profile
- * @mntpath: for the mntpnt (NOT NULL)
+ * @path: for the mntpnt (NOT NULL)
  * @buffer: buffer to be used to lookup mntpath
  * @devpath: path devname/src_name (MAYBE NULL)
  * @devbuffer: buffer to be used to lookup devname/src_name
@@ -718,6 +718,7 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path,
                        aa_put_label(target);
                        goto out;
                }
+               aa_put_label(target);
        } else
                /* already audited error */
                error = PTR_ERR(target);
index e0c1b50..7efe4d1 100644 (file)
@@ -145,12 +145,13 @@ int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
 static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
                            struct sock *sk)
 {
+       struct aa_sk_ctx *ctx = SK_CTX(sk);
        int error = 0;
 
        AA_BUG(!label);
        AA_BUG(!sk);
 
-       if (!unconfined(label)) {
+       if (ctx->label != kernel_t && !unconfined(label)) {
                struct aa_profile *profile;
                DEFINE_AUDIT_SK(sa, op, sk);
 
index b0cbc49..499c020 100644 (file)
@@ -422,7 +422,7 @@ static struct aa_profile *__lookup_profile(struct aa_policy *base,
 }
 
 /**
- * aa_lookup_profile - find a profile by its full or partial name
+ * aa_lookupn_profile - find a profile by its full or partial name
  * @ns: the namespace to start from (NOT NULL)
  * @hname: name to do lookup on.  Does not contain namespace prefix (NOT NULL)
  * @n: size of @hname
@@ -952,16 +952,18 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
 
        mutex_lock_nested(&ns->lock, ns->level);
        /* check for duplicate rawdata blobs: space and file dedup */
-       list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) {
-               if (aa_rawdata_eq(rawdata_ent, udata)) {
-                       struct aa_loaddata *tmp;
-
-                       tmp = __aa_get_loaddata(rawdata_ent);
-                       /* check we didn't fail the race */
-                       if (tmp) {
-                               aa_put_loaddata(udata);
-                               udata = tmp;
-                               break;
+       if (!list_empty(&ns->rawdata_list)) {
+               list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) {
+                       if (aa_rawdata_eq(rawdata_ent, udata)) {
+                               struct aa_loaddata *tmp;
+
+                               tmp = __aa_get_loaddata(rawdata_ent);
+                               /* check we didn't fail the race */
+                               if (tmp) {
+                                       aa_put_loaddata(udata);
+                                       udata = tmp;
+                                       break;
+                               }
                        }
                }
        }
@@ -969,7 +971,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
        list_for_each_entry(ent, &lh, list) {
                struct aa_policy *policy;
 
-               ent->new->rawdata = aa_get_loaddata(udata);
+               if (aa_g_export_binary)
+                       ent->new->rawdata = aa_get_loaddata(udata);
                error = __lookup_replace(ns, ent->new->base.hname,
                                         !(mask & AA_MAY_REPLACE_POLICY),
                                         &ent->old, &info);
@@ -1009,7 +1012,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
        }
 
        /* create new fs entries for introspection if needed */
-       if (!udata->dents[AAFS_LOADDATA_DIR]) {
+       if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) {
                error = __aa_fs_create_rawdata(ns, udata);
                if (error) {
                        info = "failed to create raw_data dir and files";
@@ -1037,12 +1040,14 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
 
        /* Done with checks that may fail - do actual replacement */
        __aa_bump_ns_revision(ns);
-       __aa_loaddata_update(udata, ns->revision);
+       if (aa_g_export_binary)
+               __aa_loaddata_update(udata, ns->revision);
        list_for_each_entry_safe(ent, tmp, &lh, list) {
                list_del_init(&ent->list);
                op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
 
-               if (ent->old && ent->old->rawdata == ent->new->rawdata) {
+               if (ent->old && ent->old->rawdata == ent->new->rawdata &&
+                   ent->new->rawdata) {
                        /* dedup actual profile replacement */
                        audit_policy(label, op, ns_name, ent->new->base.hname,
                                     "same as current profile, skipping",
index 70921d9..43beaad 100644 (file)
@@ -22,6 +22,9 @@
 #include "include/label.h"
 #include "include/policy.h"
 
+/* kernel label */
+struct aa_label *kernel_t;
+
 /* root profile namespace */
 struct aa_ns *root_ns;
 const char *aa_hidden_ns_name = "---";
@@ -51,10 +54,10 @@ bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns)
 }
 
 /**
- * aa_na_name - Find the ns name to display for @view from @curr
- * @curr - current namespace (NOT NULL)
- * @view - namespace attempting to view (NOT NULL)
- * @subns - are subns visible
+ * aa_ns_name - Find the ns name to display for @view from @curr
+ * @curr: current namespace (NOT NULL)
+ * @view: namespace attempting to view (NOT NULL)
+ * @subns: are subns visible
  *
  * Returns: name of @view visible from @curr
  */
@@ -77,6 +80,23 @@ const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns)
        return aa_hidden_ns_name;
 }
 
+static struct aa_profile *alloc_unconfined(const char *name)
+{
+       struct aa_profile *profile;
+
+       profile = aa_alloc_profile(name, NULL, GFP_KERNEL);
+       if (!profile)
+               return NULL;
+
+       profile->label.flags |= FLAG_IX_ON_NAME_ERROR |
+               FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
+       profile->mode = APPARMOR_UNCONFINED;
+       profile->file.dfa = aa_get_dfa(nulldfa);
+       profile->policy.dfa = aa_get_dfa(nulldfa);
+
+       return profile;
+}
+
 /**
  * alloc_ns - allocate, initialize and return a new namespace
  * @prefix: parent namespace name (MAYBE NULL)
@@ -101,16 +121,9 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
        init_waitqueue_head(&ns->wait);
 
        /* released by aa_free_ns() */
-       ns->unconfined = aa_alloc_profile("unconfined", NULL, GFP_KERNEL);
+       ns->unconfined = alloc_unconfined("unconfined");
        if (!ns->unconfined)
                goto fail_unconfined;
-
-       ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR |
-               FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
-       ns->unconfined->mode = APPARMOR_UNCONFINED;
-       ns->unconfined->file.dfa = aa_get_dfa(nulldfa);
-       ns->unconfined->policy.dfa = aa_get_dfa(nulldfa);
-
        /* ns and ns->unconfined share ns->unconfined refcount */
        ns->unconfined->ns = ns;
 
@@ -187,7 +200,7 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name)
 
 /**
  * __aa_lookupn_ns - lookup the namespace matching @hname
- * @base: base list to start looking up profile name from  (NOT NULL)
+ * @view: namespace to search in  (NOT NULL)
  * @hname: hierarchical ns name  (NOT NULL)
  * @n: length of @hname
  *
@@ -272,7 +285,7 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
 }
 
 /**
- * aa_create_ns - create an ns, fail if it already exists
+ * __aa_find_or_create_ns - create an ns, fail if it already exists
  * @parent: the parent of the namespace being created
  * @name: the name of the namespace
  * @dir: if not null the dir to put the ns entries in
@@ -388,11 +401,22 @@ static void __ns_list_release(struct list_head *head)
  */
 int __init aa_alloc_root_ns(void)
 {
+       struct aa_profile *kernel_p;
+
        /* released by aa_free_root_ns - used as list ref*/
        root_ns = alloc_ns(NULL, "root");
        if (!root_ns)
                return -ENOMEM;
 
+       kernel_p = alloc_unconfined("kernel_t");
+       if (!kernel_p) {
+               destroy_ns(root_ns);
+               aa_free_ns(root_ns);
+               return -ENOMEM;
+       }
+       kernel_t = &kernel_p->label;
+       root_ns->unconfined->ns = aa_get_ns(root_ns);
+
        return 0;
 }
 
@@ -405,6 +429,7 @@ void __init aa_free_root_ns(void)
 
         root_ns = NULL;
 
+        aa_label_free(kernel_t);
         destroy_ns(ns);
         aa_put_ns(ns);
 }
index 0acca6f..55d31ba 100644 (file)
@@ -125,15 +125,16 @@ void __aa_loaddata_update(struct aa_loaddata *data, long revision)
 {
        AA_BUG(!data);
        AA_BUG(!data->ns);
-       AA_BUG(!data->dents[AAFS_LOADDATA_REVISION]);
        AA_BUG(!mutex_is_locked(&data->ns->lock));
        AA_BUG(data->revision > revision);
 
        data->revision = revision;
-       d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime =
-               current_time(d_inode(data->dents[AAFS_LOADDATA_DIR]));
-       d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime =
-               current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION]));
+       if ((data->dents[AAFS_LOADDATA_REVISION])) {
+               d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime =
+                       current_time(d_inode(data->dents[AAFS_LOADDATA_DIR]));
+               d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime =
+                       current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION]));
+       }
 }
 
 bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r)
@@ -213,7 +214,7 @@ static void *kvmemdup(const void *src, size_t len)
 }
 
 /**
- * aa_u16_chunck - test and do bounds checking for a u16 size based chunk
+ * unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
  * @e: serialized data read head (NOT NULL)
  * @chunk: start address for chunk of data (NOT NULL)
  *
@@ -456,7 +457,9 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
                        ((e->pos - e->start) & 7);
                size_t pad = ALIGN(sz, 8) - sz;
                int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
-                       TO_ACCEPT2_FLAG(YYTD_DATA32) | DFA_FLAG_VERIFY_STATES;
+                       TO_ACCEPT2_FLAG(YYTD_DATA32);
+               if (aa_g_paranoid_load)
+                       flags |= DFA_FLAG_VERIFY_STATES;
                dfa = aa_dfa_unpack(blob + pad, size - pad, flags);
 
                if (IS_ERR(dfa))
@@ -668,6 +671,7 @@ static int datacmp(struct rhashtable_compare_arg *arg, const void *obj)
 /**
  * unpack_profile - unpack a serialized profile
  * @e: serialized data extent information (NOT NULL)
+ * @ns_name: pointer of newly allocated copy of %NULL in case of error
  *
  * NOTE: unpack profile sets audit struct if there is a failure
  */
@@ -744,18 +748,24 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
                goto fail;
        if (tmp & PACKED_FLAG_HAT)
                profile->label.flags |= FLAG_HAT;
+       if (tmp & PACKED_FLAG_DEBUG1)
+               profile->label.flags |= FLAG_DEBUG1;
+       if (tmp & PACKED_FLAG_DEBUG2)
+               profile->label.flags |= FLAG_DEBUG2;
        if (!unpack_u32(e, &tmp, NULL))
                goto fail;
-       if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG))
+       if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) {
                profile->mode = APPARMOR_COMPLAIN;
-       else if (tmp == PACKED_MODE_ENFORCE)
+       } else if (tmp == PACKED_MODE_ENFORCE) {
                profile->mode = APPARMOR_ENFORCE;
-       else if (tmp == PACKED_MODE_KILL)
+       } else if (tmp == PACKED_MODE_KILL) {
                profile->mode = APPARMOR_KILL;
-       else if (tmp == PACKED_MODE_UNCONFINED)
+       } else if (tmp == PACKED_MODE_UNCONFINED) {
                profile->mode = APPARMOR_UNCONFINED;
-       else
+               profile->label.flags |= FLAG_UNCONFINED;
+       } else {
                goto fail;
+       }
        if (!unpack_u32(e, &tmp, NULL))
                goto fail;
        if (tmp)
@@ -936,7 +946,7 @@ fail:
 }
 
 /**
- * verify_head - unpack serialized stream header
+ * verify_header - unpack serialized stream header
  * @e: serialized data read head (NOT NULL)
  * @required: whether the header is required or optional
  * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
@@ -1052,6 +1062,7 @@ struct aa_load_ent *aa_load_ent_alloc(void)
 static int deflate_compress(const char *src, size_t slen, char **dst,
                            size_t *dlen)
 {
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
        int error;
        struct z_stream_s strm;
        void *stgbuf, *dstbuf;
@@ -1123,6 +1134,10 @@ fail_deflate_init:
 fail_deflate:
        kvfree(stgbuf);
        goto fail_stg_alloc;
+#else
+       *dlen = slen;
+       return 0;
+#endif
 }
 
 static int compress_loaddata(struct aa_loaddata *data)
@@ -1141,7 +1156,8 @@ static int compress_loaddata(struct aa_loaddata *data)
                if (error)
                        return error;
 
-               kvfree(udata);
+               if (udata != data->data)
+                       kvfree(udata);
        } else
                data->compressed_size = data->size;
 
@@ -1216,9 +1232,12 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh,
                        goto fail;
                }
        }
-       error = compress_loaddata(udata);
-       if (error)
-               goto fail;
+
+       if (aa_g_export_binary) {
+               error = compress_loaddata(udata);
+               if (error)
+                       goto fail;
+       }
        return 0;
 
 fail_profile:
index 7954cb2..0a969b2 100644 (file)
@@ -48,8 +48,8 @@ struct policy_unpack_fixture {
        size_t e_size;
 };
 
-struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf,
-                                  struct kunit *test, size_t buf_size)
+static struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf,
+                                         struct kunit *test, size_t buf_size)
 {
        char *buf;
        struct aa_ext *e;
@@ -439,7 +439,7 @@ static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test)
 {
        struct policy_unpack_fixture *puf = test->priv;
        bool success;
-       u32 data;
+       u32 data = 0;
 
        puf->e->pos += TEST_U32_BUF_OFFSET;
 
@@ -456,7 +456,7 @@ static void policy_unpack_test_unpack_u32_with_name(struct kunit *test)
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U32_NAME;
        bool success;
-       u32 data;
+       u32 data = 0;
 
        puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
 
@@ -473,7 +473,7 @@ static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test)
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U32_NAME;
        bool success;
-       u32 data;
+       u32 data = 0;
 
        puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
        puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32);
@@ -489,7 +489,7 @@ static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test)
 {
        struct policy_unpack_fixture *puf = test->priv;
        bool success;
-       u64 data;
+       u64 data = 0;
 
        puf->e->pos += TEST_U64_BUF_OFFSET;
 
@@ -506,7 +506,7 @@ static void policy_unpack_test_unpack_u64_with_name(struct kunit *test)
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U64_NAME;
        bool success;
-       u64 data;
+       u64 data = 0;
 
        puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
 
@@ -523,7 +523,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test)
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U64_NAME;
        bool success;
-       u64 data;
+       u64 data = 0;
 
        puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
        puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64);
index fde332e..86ad26e 100644 (file)
@@ -90,7 +90,7 @@ static char *split_token_from_name(const char *op, char *args, u64 *token)
 }
 
 /**
- * aa_setprocattr_chagnehat - handle procattr interface to change_hat
+ * aa_setprocattr_changehat - handle procattr interface to change_hat
  * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
  * @size: size of the args
  * @flags: set of flags governing behavior
index ce545f9..24a0e23 100644 (file)
@@ -13,9 +13,9 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/gfp.h>
-#include <linux/idr.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/xarray.h>
 
 #include "include/cred.h"
 #include "include/lib.h"
@@ -29,8 +29,9 @@
  */
 #define AA_FIRST_SECID 2
 
-static DEFINE_IDR(aa_secids);
-static DEFINE_SPINLOCK(secid_lock);
+static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE);
+
+int apparmor_display_secid_mode;
 
 /*
  * TODO: allow policy to reserve a secid range?
@@ -47,9 +48,9 @@ void aa_secid_update(u32 secid, struct aa_label *label)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&secid_lock, flags);
-       idr_replace(&aa_secids, label, secid);
-       spin_unlock_irqrestore(&secid_lock, flags);
+       xa_lock_irqsave(&aa_secids, flags);
+       __xa_store(&aa_secids, secid, label, 0);
+       xa_unlock_irqrestore(&aa_secids, flags);
 }
 
 /**
@@ -58,19 +59,14 @@ void aa_secid_update(u32 secid, struct aa_label *label)
  */
 struct aa_label *aa_secid_to_label(u32 secid)
 {
-       struct aa_label *label;
-
-       rcu_read_lock();
-       label = idr_find(&aa_secids, secid);
-       rcu_read_unlock();
-
-       return label;
+       return xa_load(&aa_secids, secid);
 }
 
 int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
        /* TODO: cache secctx and ref count so we don't have to recreate */
        struct aa_label *label = aa_secid_to_label(secid);
+       int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT;
        int len;
 
        AA_BUG(!seclen);
@@ -78,15 +74,15 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
        if (!label)
                return -EINVAL;
 
+       if (apparmor_display_secid_mode)
+               flags |= FLAG_SHOW_MODE;
+
        if (secdata)
                len = aa_label_asxprint(secdata, root_ns, label,
-                                       FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
-                                       FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT,
-                                       GFP_ATOMIC);
+                                       flags, GFP_ATOMIC);
        else
-               len = aa_label_snxprint(NULL, 0, root_ns, label,
-                                       FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
-                                       FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT);
+               len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
+
        if (len < 0)
                return -ENOMEM;
 
@@ -126,19 +122,16 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp)
        unsigned long flags;
        int ret;
 
-       idr_preload(gfp);
-       spin_lock_irqsave(&secid_lock, flags);
-       ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC);
-       spin_unlock_irqrestore(&secid_lock, flags);
-       idr_preload_end();
+       xa_lock_irqsave(&aa_secids, flags);
+       ret = __xa_alloc(&aa_secids, &label->secid, label,
+                       XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp);
+       xa_unlock_irqrestore(&aa_secids, flags);
 
        if (ret < 0) {
                label->secid = AA_SECID_INVALID;
                return ret;
        }
 
-       AA_BUG(ret == AA_SECID_INVALID);
-       label->secid = ret;
        return 0;
 }
 
@@ -150,12 +143,7 @@ void aa_free_secid(u32 secid)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&secid_lock, flags);
-       idr_remove(&aa_secids, secid);
-       spin_unlock_irqrestore(&secid_lock, flags);
-}
-
-void aa_secids_init(void)
-{
-       idr_init_base(&aa_secids, AA_FIRST_SECID);
+       xa_lock_irqsave(&aa_secids, flags);
+       __xa_erase(&aa_secids, secid);
+       xa_unlock_irqrestore(&aa_secids, flags);
 }
index d17130e..503dc08 100644 (file)
  * should return to the previous cred if it has not been modified.
  */
 
+#include <linux/gfp.h>
+#include <linux/ptrace.h>
+
+#include "include/audit.h"
 #include "include/cred.h"
+#include "include/policy.h"
 #include "include/task.h"
 
 /**
@@ -177,3 +182,112 @@ int aa_restore_previous_label(u64 token)
 
        return 0;
 }
+
+/**
+ * audit_ptrace_mask - convert mask to permission string
+ * @mask: permission mask to convert
+ *
+ * Returns: pointer to static string
+ */
+static const char *audit_ptrace_mask(u32 mask)
+{
+       switch (mask) {
+       case MAY_READ:
+               return "read";
+       case MAY_WRITE:
+               return "trace";
+       case AA_MAY_BE_READ:
+               return "readby";
+       case AA_MAY_BE_TRACED:
+               return "tracedby";
+       }
+       return "";
+}
+
+/* call back to audit ptrace fields */
+static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+
+       if (aad(sa)->request & AA_PTRACE_PERM_MASK) {
+               audit_log_format(ab, " requested_mask=\"%s\"",
+                                audit_ptrace_mask(aad(sa)->request));
+
+               if (aad(sa)->denied & AA_PTRACE_PERM_MASK) {
+                       audit_log_format(ab, " denied_mask=\"%s\"",
+                                        audit_ptrace_mask(aad(sa)->denied));
+               }
+       }
+       audit_log_format(ab, " peer=");
+       aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+                       FLAGS_NONE, GFP_ATOMIC);
+}
+
+/* assumes check for PROFILE_MEDIATES is already done */
+/* TODO: conditionals */
+static int profile_ptrace_perm(struct aa_profile *profile,
+                            struct aa_label *peer, u32 request,
+                            struct common_audit_data *sa)
+{
+       struct aa_perms perms = { };
+
+       aad(sa)->peer = peer;
+       aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request,
+                              &perms);
+       aa_apply_modes_to_perms(profile, &perms);
+       return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
+}
+
+static int profile_tracee_perm(struct aa_profile *tracee,
+                              struct aa_label *tracer, u32 request,
+                              struct common_audit_data *sa)
+{
+       if (profile_unconfined(tracee) || unconfined(tracer) ||
+           !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE))
+               return 0;
+
+       return profile_ptrace_perm(tracee, tracer, request, sa);
+}
+
+static int profile_tracer_perm(struct aa_profile *tracer,
+                              struct aa_label *tracee, u32 request,
+                              struct common_audit_data *sa)
+{
+       if (profile_unconfined(tracer))
+               return 0;
+
+       if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE))
+               return profile_ptrace_perm(tracer, tracee, request, sa);
+
+       /* profile uses the old style capability check for ptrace */
+       if (&tracer->label == tracee)
+               return 0;
+
+       aad(sa)->label = &tracer->label;
+       aad(sa)->peer = tracee;
+       aad(sa)->request = 0;
+       aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
+                                   CAP_OPT_NONE);
+
+       return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
+}
+
+/**
+ * aa_may_ptrace - test if tracer task can trace the tracee
+ * @tracer: label of the task doing the tracing  (NOT NULL)
+ * @tracee: task label to be traced
+ * @request: permission request
+ *
+ * Returns: %0 else error code if permission denied or error
+ */
+int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
+                 u32 request)
+{
+       struct aa_profile *profile;
+       u32 xrequest = request << PTRACE_PERM_SHIFT;
+       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE);
+
+       return xcheck_labels(tracer, tracee, profile,
+                       profile_tracer_perm(profile, tracee, request, &sa),
+                       profile_tracee_perm(profile, tracer, xrequest, &sa));
+}
index a77b915..8323ac5 100644 (file)
 #define X86_FEATURE_RETHUNK            (11*32+14) /* "" Use REturn THUNK */
 #define X86_FEATURE_UNRET              (11*32+15) /* "" AMD BTB untrain return */
 #define X86_FEATURE_USE_IBPB_FW                (11*32+16) /* "" Use IBPB during runtime firmware calls */
+#define X86_FEATURE_RSB_VMEXIT_LITE    (11*32+17) /* "" Fill RSB on VM-Exit when EIBRS is enabled */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
index cc615be..e057e03 100644 (file)
                                                 * are restricted to targets in
                                                 * kernel.
                                                 */
+#define ARCH_CAP_PBRSB_NO              BIT(24) /*
+                                                * Not susceptible to Post-Barrier
+                                                * Return Stack Buffer Predictions.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
index 3354323..500be85 100644 (file)
@@ -47,6 +47,7 @@ cxl_core-y += $(CXL_CORE_SRC)/memdev.o
 cxl_core-y += $(CXL_CORE_SRC)/mbox.o
 cxl_core-y += $(CXL_CORE_SRC)/pci.o
 cxl_core-y += $(CXL_CORE_SRC)/hdm.o
+cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
 cxl_core-y += config_check.o
 
 obj-m += test/
index 431f2bd..a072b2d 100644 (file)
@@ -14,7 +14,7 @@
 #define NR_CXL_HOST_BRIDGES 2
 #define NR_CXL_ROOT_PORTS 2
 #define NR_CXL_SWITCH_PORTS 2
-#define NR_CXL_PORT_DECODERS 2
+#define NR_CXL_PORT_DECODERS 8
 
 static struct platform_device *cxl_acpi;
 static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES];
@@ -118,7 +118,7 @@ static struct {
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
                        .qtg_id = 0,
-                       .window_size = SZ_256M,
+                       .window_size = SZ_256M * 4UL,
                },
                .target = { 0 },
        },
@@ -133,7 +133,7 @@ static struct {
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
                        .qtg_id = 1,
-                       .window_size = SZ_256M * 2,
+                       .window_size = SZ_256M * 8UL,
                },
                .target = { 0, 1, },
        },
@@ -148,7 +148,7 @@ static struct {
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_PMEM,
                        .qtg_id = 2,
-                       .window_size = SZ_256M,
+                       .window_size = SZ_256M * 4UL,
                },
                .target = { 0 },
        },
@@ -163,7 +163,7 @@ static struct {
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_PMEM,
                        .qtg_id = 3,
-                       .window_size = SZ_256M * 2,
+                       .window_size = SZ_256M * 8UL,
                },
                .target = { 0, 1, },
        },
@@ -429,6 +429,50 @@ static int map_targets(struct device *dev, void *data)
        return 0;
 }
 
+static int mock_decoder_commit(struct cxl_decoder *cxld)
+{
+       struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+       int id = cxld->id;
+
+       if (cxld->flags & CXL_DECODER_F_ENABLE)
+               return 0;
+
+       dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev));
+       if (port->commit_end + 1 != id) {
+               dev_dbg(&port->dev,
+                       "%s: out of order commit, expected decoder%d.%d\n",
+                       dev_name(&cxld->dev), port->id, port->commit_end + 1);
+               return -EBUSY;
+       }
+
+       port->commit_end++;
+       cxld->flags |= CXL_DECODER_F_ENABLE;
+
+       return 0;
+}
+
+static int mock_decoder_reset(struct cxl_decoder *cxld)
+{
+       struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+       int id = cxld->id;
+
+       if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
+               return 0;
+
+       dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev));
+       if (port->commit_end != id) {
+               dev_dbg(&port->dev,
+                       "%s: out of order reset, expected decoder%d.%d\n",
+                       dev_name(&cxld->dev), port->id, port->commit_end);
+               return -EBUSY;
+       }
+
+       port->commit_end--;
+       cxld->flags &= ~CXL_DECODER_F_ENABLE;
+
+       return 0;
+}
+
 static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
 {
        struct cxl_port *port = cxlhdm->port;
@@ -451,25 +495,39 @@ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
                struct cxl_decoder *cxld;
                int rc;
 
-               if (target_count)
-                       cxld = cxl_switch_decoder_alloc(port, target_count);
-               else
-                       cxld = cxl_endpoint_decoder_alloc(port);
-               if (IS_ERR(cxld)) {
-                       dev_warn(&port->dev,
-                                "Failed to allocate the decoder\n");
-                       return PTR_ERR(cxld);
+               if (target_count) {
+                       struct cxl_switch_decoder *cxlsd;
+
+                       cxlsd = cxl_switch_decoder_alloc(port, target_count);
+                       if (IS_ERR(cxlsd)) {
+                               dev_warn(&port->dev,
+                                        "Failed to allocate the decoder\n");
+                               return PTR_ERR(cxlsd);
+                       }
+                       cxld = &cxlsd->cxld;
+               } else {
+                       struct cxl_endpoint_decoder *cxled;
+
+                       cxled = cxl_endpoint_decoder_alloc(port);
+
+                       if (IS_ERR(cxled)) {
+                               dev_warn(&port->dev,
+                                        "Failed to allocate the decoder\n");
+                               return PTR_ERR(cxled);
+                       }
+                       cxld = &cxled->cxld;
                }
 
-               cxld->decoder_range = (struct range) {
+               cxld->hpa_range = (struct range) {
                        .start = 0,
                        .end = -1,
                };
 
-               cxld->flags = CXL_DECODER_F_ENABLE;
                cxld->interleave_ways = min_not_zero(target_count, 1);
                cxld->interleave_granularity = SZ_4K;
                cxld->target_type = CXL_DECODER_EXPANDER;
+               cxld->commit = mock_decoder_commit;
+               cxld->reset = mock_decoder_reset;
 
                if (target_count) {
                        rc = device_for_each_child(port->uport, &ctx,
@@ -569,44 +627,6 @@ static void mock_companion(struct acpi_device *adev, struct device *dev)
 #define SZ_512G (SZ_64G * 8)
 #endif
 
-static struct platform_device *alloc_memdev(int id)
-{
-       struct resource res[] = {
-               [0] = {
-                       .flags = IORESOURCE_MEM,
-               },
-               [1] = {
-                       .flags = IORESOURCE_MEM,
-                       .desc = IORES_DESC_PERSISTENT_MEMORY,
-               },
-       };
-       struct platform_device *pdev;
-       int i, rc;
-
-       for (i = 0; i < ARRAY_SIZE(res); i++) {
-               struct cxl_mock_res *r = alloc_mock_res(SZ_256M);
-
-               if (!r)
-                       return NULL;
-               res[i].start = r->range.start;
-               res[i].end = r->range.end;
-       }
-
-       pdev = platform_device_alloc("cxl_mem", id);
-       if (!pdev)
-               return NULL;
-
-       rc = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
-       if (rc)
-               goto err;
-
-       return pdev;
-
-err:
-       platform_device_put(pdev);
-       return NULL;
-}
-
 static __init int cxl_test_init(void)
 {
        int rc, i;
@@ -619,7 +639,8 @@ static __init int cxl_test_init(void)
                goto err_gen_pool_create;
        }
 
-       rc = gen_pool_add(cxl_mock_pool, SZ_512G, SZ_64G, NUMA_NO_NODE);
+       rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G,
+                         SZ_64G, NUMA_NO_NODE);
        if (rc)
                goto err_gen_pool_add;
 
@@ -708,7 +729,7 @@ static __init int cxl_test_init(void)
                struct platform_device *dport = cxl_switch_dport[i];
                struct platform_device *pdev;
 
-               pdev = alloc_memdev(i);
+               pdev = platform_device_alloc("cxl_mem", i);
                if (!pdev)
                        goto err_mem;
                pdev->dev.parent = &dport->dev;
index 6b9239b..aa2df3a 100644 (file)
@@ -10,6 +10,7 @@
 #include <cxlmem.h>
 
 #define LSA_SIZE SZ_128K
+#define DEV_SIZE SZ_2G
 #define EFFECT(x) (1U << x)
 
 static struct cxl_cel_entry mock_cel[] = {
@@ -25,6 +26,10 @@ static struct cxl_cel_entry mock_cel[] = {
                .opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA),
                .effect = cpu_to_le16(0),
        },
+       {
+               .opcode = cpu_to_le16(CXL_MBOX_OP_GET_PARTITION_INFO),
+               .effect = cpu_to_le16(0),
+       },
        {
                .opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA),
                .effect = cpu_to_le16(EFFECT(1) | EFFECT(2)),
@@ -97,42 +102,37 @@ static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
 
 static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
 {
-       struct platform_device *pdev = to_platform_device(cxlds->dev);
        struct cxl_mbox_identify id = {
                .fw_revision = { "mock fw v1 " },
                .lsa_size = cpu_to_le32(LSA_SIZE),
-               /* FIXME: Add partition support */
-               .partition_align = cpu_to_le64(0),
+               .partition_align =
+                       cpu_to_le64(SZ_256M / CXL_CAPACITY_MULTIPLIER),
+               .total_capacity =
+                       cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
        };
-       u64 capacity = 0;
-       int i;
 
        if (cmd->size_out < sizeof(id))
                return -EINVAL;
 
-       for (i = 0; i < 2; i++) {
-               struct resource *res;
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               if (!res)
-                       break;
-
-               capacity += resource_size(res) / CXL_CAPACITY_MULTIPLIER;
+       memcpy(cmd->payload_out, &id, sizeof(id));
 
-               if (le64_to_cpu(id.partition_align))
-                       continue;
+       return 0;
+}
 
-               if (res->desc == IORES_DESC_PERSISTENT_MEMORY)
-                       id.persistent_capacity = cpu_to_le64(
-                               resource_size(res) / CXL_CAPACITY_MULTIPLIER);
-               else
-                       id.volatile_capacity = cpu_to_le64(
-                               resource_size(res) / CXL_CAPACITY_MULTIPLIER);
-       }
+static int mock_partition_info(struct cxl_dev_state *cxlds,
+                              struct cxl_mbox_cmd *cmd)
+{
+       struct cxl_mbox_get_partition_info pi = {
+               .active_volatile_cap =
+                       cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER),
+               .active_persistent_cap =
+                       cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER),
+       };
 
-       id.total_capacity = cpu_to_le64(capacity);
+       if (cmd->size_out < sizeof(pi))
+               return -EINVAL;
 
-       memcpy(cmd->payload_out, &id, sizeof(id));
+       memcpy(cmd->payload_out, &pi, sizeof(pi));
 
        return 0;
 }
@@ -221,6 +221,9 @@ static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *
        case CXL_MBOX_OP_GET_LSA:
                rc = mock_get_lsa(cxlds, cmd);
                break;
+       case CXL_MBOX_OP_GET_PARTITION_INFO:
+               rc = mock_partition_info(cxlds, cmd);
+               break;
        case CXL_MBOX_OP_SET_LSA:
                rc = mock_set_lsa(cxlds, cmd);
                break;
@@ -282,7 +285,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
        if (IS_ERR(cxlmd))
                return PTR_ERR(cxlmd);
 
-       if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
+       if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM))
                rc = devm_cxl_add_nvdimm(dev, cxlmd);
 
        return 0;
index f1f8c40..bce6a21 100644 (file)
@@ -208,13 +208,15 @@ int __wrap_cxl_await_media_ready(struct cxl_dev_state *cxlds)
 }
 EXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, CXL);
 
-bool __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
-                               struct cxl_hdm *cxlhdm)
+int __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
+                              struct cxl_hdm *cxlhdm)
 {
        int rc = 0, index;
        struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
 
-       if (!ops || !ops->is_mock_dev(cxlds->dev))
+       if (ops && ops->is_mock_dev(cxlds->dev))
+               rc = 0;
+       else
                rc = cxl_hdm_decode_init(cxlds, cxlhdm);
        put_cxl_mock_ops(index);
 
index a698e24..246f7ac 100644 (file)
@@ -45,9 +45,8 @@ help:
        @echo  '  clean           - Remove generated files and symlinks in the directory'
        @echo  ''
        @echo  'Configuration:'
+       @echo  '  make MEMBLOCK_DEBUG=1     - enable memblock_dbg() messages'
        @echo  '  make NUMA=1               - simulate enabled NUMA'
-       @echo  '  make MOVABLE_NODE=1       - override `movable_node_is_enabled`'
-       @echo  '                              definition to simulate movable NUMA nodes'
        @echo  '  make 32BIT_PHYS_ADDR_T=1  - Use 32 bit physical addresses'
 
 vpath %.c ../../lib
index ca6afcf..7ca437d 100644 (file)
@@ -33,12 +33,23 @@ To run the tests, build the main target and run it:
 
 $ make && ./main
 
-A successful run produces no output. It is also possible to override different
-configuration parameters. For example, to simulate enabled NUMA, use:
+A successful run produces no output. It is possible to control the behavior
+by passing options from command line. For example, to include verbose output,
+append the `-v` options when you run the tests:
+
+$ ./main -v
+
+This will print information about which functions are being tested and the
+number of test cases that passed.
+
+For the full list of options from command line, see `./main --help`.
+
+It is also possible to override different configuration parameters to change
+the test functions. For example, to simulate enabled NUMA, use:
 
 $ make NUMA=1
 
-For the full list of options, see `make help`.
+For the full list of build options, see `make help`.
 
 Project structure
 =================
index cd1a30d..33044c6 100644 (file)
@@ -1,25 +1,17 @@
 TODO
 =====
 
-1. Add verbose output (e.g., what is being tested and how many tests cases are
-   passing)
-
-2. Add flags to Makefile:
-   + verbosity level
-   + enable memblock_dbg() messages (i.e. pass "-D CONFIG_DEBUG_MEMORY_INIT"
-     flag)
-
-3. Add tests trying to memblock_add() or memblock_reserve() 129th region.
+1. Add tests trying to memblock_add() or memblock_reserve() 129th region.
    This will trigger memblock_double_array(), make sure it succeeds.
    *Important:* These tests require valid memory ranges, use dummy physical
                 memory block from common.c to implement them. It is also very
                 likely that the current MEM_SIZE won't be enough for these
                 test cases. Use realloc to adjust the size accordingly.
 
-4. Add test cases using this functions (implement them for both directions):
+2. Add test cases using this functions (implement them for both directions):
    + memblock_alloc_raw()
    + memblock_alloc_exact_nid_raw()
    + memblock_alloc_try_nid_raw()
 
-5. Add tests for memblock_alloc_node() to check if the correct NUMA node is set
+3. Add tests for memblock_alloc_node() to check if the correct NUMA node is set
    for the new region
index 94b52a8..fdb7f5d 100644 (file)
@@ -2,6 +2,17 @@
 #ifndef _MM_INTERNAL_H
 #define _MM_INTERNAL_H
 
+/*
+ * Enable memblock_dbg() messages
+ */
+#ifdef MEMBLOCK_DEBUG
+static int memblock_debug = 1;
+#endif
+
+#define pr_warn_ratelimited(fmt, ...)    printf(fmt, ##__VA_ARGS__)
+
+bool mirrored_kernelcore = false;
+
 struct page {};
 
 void memblock_free_pages(struct page *page, unsigned long pfn,
index 4798876..dabe2c5 100644 (file)
@@ -7,13 +7,11 @@
 #include <linux/cache.h>
 #include <linux/types.h>
 
+extern bool movable_node_enabled;
+
 static inline bool movable_node_is_enabled(void)
 {
-#ifdef MOVABLE_NODE
-       return true;
-#else
-       return false;
-#endif
+       return movable_node_enabled;
 }
 
 #endif
index fb183c9..4ca1024 100644 (file)
@@ -3,9 +3,11 @@
 #include "tests/alloc_api.h"
 #include "tests/alloc_helpers_api.h"
 #include "tests/alloc_nid_api.h"
+#include "tests/common.h"
 
 int main(int argc, char **argv)
 {
+       parse_args(argc, argv);
        memblock_basic_checks();
        memblock_alloc_checks();
        memblock_alloc_helpers_checks();
index 641569c..aa6d82d 100644 (file)
@@ -6,14 +6,14 @@ ifeq ($(NUMA), 1)
        CFLAGS += -D CONFIG_NUMA
 endif
 
-# Simulate movable NUMA memory regions
-ifeq ($(MOVABLE_NODE), 1)
-       CFLAGS += -D MOVABLE_NODE
-endif
-
 # Use 32 bit physical addresses.
 # Remember to install 32-bit version of dependencies.
 ifeq ($(32BIT_PHYS_ADDR_T), 1)
        CFLAGS += -m32 -U CONFIG_PHYS_ADDR_T_64BIT
        LDFLAGS += -m32
 endif
+
+# Enable memblock_dbg() messages
+ifeq ($(MEMBLOCK_DEBUG), 1)
+       CFLAGS += -D MEMBLOCK_DEBUG
+endif
index d1aa7e1..a14f38e 100644 (file)
@@ -10,6 +10,8 @@ static int alloc_top_down_simple_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_2;
        phys_addr_t expected_start;
 
@@ -19,12 +21,14 @@ static int alloc_top_down_simple_check(void)
 
        allocated_ptr = memblock_alloc(size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == size);
-       assert(rgn->base == expected_start);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, expected_start);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -55,6 +59,8 @@ static int alloc_top_down_disjoint_check(void)
        struct region r1;
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r2_size = SZ_16;
        /* Use custom alignment */
        phys_addr_t alignment = SMP_CACHE_BYTES * 2;
@@ -73,15 +79,17 @@ static int alloc_top_down_disjoint_check(void)
 
        allocated_ptr = memblock_alloc(r2_size, alignment);
 
-       assert(allocated_ptr);
-       assert(rgn1->size == r1.size);
-       assert(rgn1->base == r1.base);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn1->size, r1.size);
+       ASSERT_EQ(rgn1->base, r1.base);
 
-       assert(rgn2->size == r2_size);
-       assert(rgn2->base == expected_start);
+       ASSERT_EQ(rgn2->size, r2_size);
+       ASSERT_EQ(rgn2->base, expected_start);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -101,6 +109,8 @@ static int alloc_top_down_before_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        /*
         * The first region ends at the aligned address to test region merging
         */
@@ -114,12 +124,14 @@ static int alloc_top_down_before_check(void)
 
        allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == total_size);
-       assert(rgn->base == memblock_end_of_DRAM() - total_size);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, total_size);
+       ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - total_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -141,6 +153,8 @@ static int alloc_top_down_after_check(void)
        struct region r1;
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r2_size = SZ_512;
        phys_addr_t total_size;
 
@@ -158,12 +172,14 @@ static int alloc_top_down_after_check(void)
 
        allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == total_size);
-       assert(rgn->base == r1.base - r2_size);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, total_size);
+       ASSERT_EQ(rgn->base, r1.base - r2_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -186,6 +202,8 @@ static int alloc_top_down_second_fit_check(void)
        struct region r1, r2;
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r3_size = SZ_1K;
        phys_addr_t total_size;
 
@@ -204,12 +222,14 @@ static int alloc_top_down_second_fit_check(void)
 
        allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == r2.size + r3_size);
-       assert(rgn->base == r2.base - r3_size);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, r2.size + r3_size);
+       ASSERT_EQ(rgn->base, r2.base - r3_size);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -231,6 +251,8 @@ static int alloc_in_between_generic_check(void)
        struct region r1, r2;
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t gap_size = SMP_CACHE_BYTES;
        phys_addr_t r3_size = SZ_64;
        /*
@@ -254,12 +276,14 @@ static int alloc_in_between_generic_check(void)
 
        allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == total_size);
-       assert(rgn->base == r1.base - r2.size - r3_size);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, total_size);
+       ASSERT_EQ(rgn->base, r1.base - r2.size - r3_size);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -281,6 +305,8 @@ static int alloc_small_gaps_generic_check(void)
 {
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t region_size = SZ_1K;
        phys_addr_t gap_size = SZ_256;
        phys_addr_t region_end;
@@ -296,7 +322,9 @@ static int alloc_small_gaps_generic_check(void)
 
        allocated_ptr = memblock_alloc(region_size, SMP_CACHE_BYTES);
 
-       assert(!allocated_ptr);
+       ASSERT_EQ(allocated_ptr, NULL);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -309,6 +337,8 @@ static int alloc_all_reserved_generic_check(void)
 {
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        setup_memblock();
 
        /* Simulate full memory */
@@ -316,7 +346,9 @@ static int alloc_all_reserved_generic_check(void)
 
        allocated_ptr = memblock_alloc(SZ_256, SMP_CACHE_BYTES);
 
-       assert(!allocated_ptr);
+       ASSERT_EQ(allocated_ptr, NULL);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -338,6 +370,8 @@ static int alloc_no_space_generic_check(void)
 {
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        setup_memblock();
 
        phys_addr_t available_size = SZ_256;
@@ -348,7 +382,9 @@ static int alloc_no_space_generic_check(void)
 
        allocated_ptr = memblock_alloc(SZ_1K, SMP_CACHE_BYTES);
 
-       assert(!allocated_ptr);
+       ASSERT_EQ(allocated_ptr, NULL);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -369,6 +405,8 @@ static int alloc_limited_space_generic_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t available_size = SZ_256;
        phys_addr_t reserved_size = MEM_SIZE - available_size;
 
@@ -379,12 +417,14 @@ static int alloc_limited_space_generic_check(void)
 
        allocated_ptr = memblock_alloc(available_size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == MEM_SIZE);
-       assert(rgn->base == memblock_start_of_DRAM());
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, MEM_SIZE);
+       ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, MEM_SIZE);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == MEM_SIZE);
+       test_pass_pop();
 
        return 0;
 }
@@ -399,14 +439,18 @@ static int alloc_no_memory_generic_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
 
        allocated_ptr = memblock_alloc(SZ_1K, SMP_CACHE_BYTES);
 
-       assert(!allocated_ptr);
-       assert(rgn->size == 0);
-       assert(rgn->base == 0);
-       assert(memblock.reserved.total_size == 0);
+       ASSERT_EQ(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, 0);
+       ASSERT_EQ(rgn->base, 0);
+       ASSERT_EQ(memblock.reserved.total_size, 0);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -421,16 +465,20 @@ static int alloc_bottom_up_simple_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        setup_memblock();
 
        allocated_ptr = memblock_alloc(SZ_2, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == SZ_2);
-       assert(rgn->base == memblock_start_of_DRAM());
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, SZ_2);
+       ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == SZ_2);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, SZ_2);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -459,6 +507,8 @@ static int alloc_bottom_up_disjoint_check(void)
        struct region r1;
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r2_size = SZ_16;
        /* Use custom alignment */
        phys_addr_t alignment = SMP_CACHE_BYTES * 2;
@@ -477,16 +527,18 @@ static int alloc_bottom_up_disjoint_check(void)
 
        allocated_ptr = memblock_alloc(r2_size, alignment);
 
-       assert(allocated_ptr);
+       ASSERT_NE(allocated_ptr, NULL);
 
-       assert(rgn1->size == r1.size);
-       assert(rgn1->base == r1.base);
+       ASSERT_EQ(rgn1->size, r1.size);
+       ASSERT_EQ(rgn1->base, r1.base);
 
-       assert(rgn2->size == r2_size);
-       assert(rgn2->base == expected_start);
+       ASSERT_EQ(rgn2->size, r2_size);
+       ASSERT_EQ(rgn2->base, expected_start);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -506,6 +558,8 @@ static int alloc_bottom_up_before_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r1_size = SZ_512;
        phys_addr_t r2_size = SZ_128;
        phys_addr_t total_size = r1_size + r2_size;
@@ -516,12 +570,14 @@ static int alloc_bottom_up_before_check(void)
 
        allocated_ptr = memblock_alloc(r1_size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == total_size);
-       assert(rgn->base == memblock_start_of_DRAM());
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, total_size);
+       ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -542,6 +598,8 @@ static int alloc_bottom_up_after_check(void)
        struct region r1;
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r2_size = SZ_512;
        phys_addr_t total_size;
 
@@ -559,12 +617,14 @@ static int alloc_bottom_up_after_check(void)
 
        allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == total_size);
-       assert(rgn->base == r1.base);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, total_size);
+       ASSERT_EQ(rgn->base, r1.base);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -588,6 +648,8 @@ static int alloc_bottom_up_second_fit_check(void)
        struct region r1, r2;
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r3_size = SZ_1K;
        phys_addr_t total_size;
 
@@ -606,12 +668,14 @@ static int alloc_bottom_up_second_fit_check(void)
 
        allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
 
-       assert(allocated_ptr);
-       assert(rgn->size == r2.size + r3_size);
-       assert(rgn->base == r2.base);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, r2.size + r3_size);
+       ASSERT_EQ(rgn->base, r2.base);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -619,6 +683,7 @@ static int alloc_bottom_up_second_fit_check(void)
 /* Test case wrappers */
 static int alloc_simple_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_top_down_simple_check();
        memblock_set_bottom_up(true);
@@ -629,6 +694,7 @@ static int alloc_simple_check(void)
 
 static int alloc_disjoint_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_top_down_disjoint_check();
        memblock_set_bottom_up(true);
@@ -639,6 +705,7 @@ static int alloc_disjoint_check(void)
 
 static int alloc_before_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_top_down_before_check();
        memblock_set_bottom_up(true);
@@ -649,6 +716,7 @@ static int alloc_before_check(void)
 
 static int alloc_after_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_top_down_after_check();
        memblock_set_bottom_up(true);
@@ -659,6 +727,7 @@ static int alloc_after_check(void)
 
 static int alloc_in_between_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_in_between_generic_check();
        memblock_set_bottom_up(true);
@@ -669,6 +738,7 @@ static int alloc_in_between_check(void)
 
 static int alloc_second_fit_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_top_down_second_fit_check();
        memblock_set_bottom_up(true);
@@ -679,6 +749,7 @@ static int alloc_second_fit_check(void)
 
 static int alloc_small_gaps_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_small_gaps_generic_check();
        memblock_set_bottom_up(true);
@@ -689,6 +760,7 @@ static int alloc_small_gaps_check(void)
 
 static int alloc_all_reserved_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_all_reserved_generic_check();
        memblock_set_bottom_up(true);
@@ -699,6 +771,7 @@ static int alloc_all_reserved_check(void)
 
 static int alloc_no_space_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_no_space_generic_check();
        memblock_set_bottom_up(true);
@@ -709,6 +782,7 @@ static int alloc_no_space_check(void)
 
 static int alloc_limited_space_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_limited_space_generic_check();
        memblock_set_bottom_up(true);
@@ -719,6 +793,7 @@ static int alloc_limited_space_check(void)
 
 static int alloc_no_memory_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_no_memory_generic_check();
        memblock_set_bottom_up(true);
@@ -729,6 +804,12 @@ static int alloc_no_memory_check(void)
 
 int memblock_alloc_checks(void)
 {
+       const char *func_testing = "memblock_alloc";
+
+       prefix_reset();
+       prefix_push(func_testing);
+       test_print("Running %s tests...\n", func_testing);
+
        reset_memblock_attributes();
        dummy_physical_memory_init();
 
@@ -746,5 +827,7 @@ int memblock_alloc_checks(void)
 
        dummy_physical_memory_cleanup();
 
+       prefix_pop();
+
        return 0;
 }
index 963a966..1069b4b 100644 (file)
@@ -21,6 +21,8 @@ static int alloc_from_simple_generic_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_16;
        phys_addr_t min_addr;
 
@@ -31,14 +33,16 @@ static int alloc_from_simple_generic_check(void)
        allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, min_addr);
 
-       assert(rgn->size == size);
-       assert(rgn->base == min_addr);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -64,6 +68,8 @@ static int alloc_from_misaligned_generic_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_32;
        phys_addr_t min_addr;
 
@@ -75,14 +81,16 @@ static int alloc_from_misaligned_generic_check(void)
        allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
 
-       assert(rgn->size == size);
-       assert(rgn->base == memblock_end_of_DRAM() - SMP_CACHE_BYTES);
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -110,6 +118,8 @@ static int alloc_from_top_down_high_addr_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_32;
        phys_addr_t min_addr;
 
@@ -120,12 +130,14 @@ static int alloc_from_top_down_high_addr_check(void)
 
        allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
 
-       assert(allocated_ptr);
-       assert(rgn->size == size);
-       assert(rgn->base == memblock_end_of_DRAM() - SMP_CACHE_BYTES);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -151,6 +163,8 @@ static int alloc_from_top_down_no_space_above_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r1_size = SZ_64;
        phys_addr_t r2_size = SZ_2;
        phys_addr_t total_size = r1_size + r2_size;
@@ -165,12 +179,14 @@ static int alloc_from_top_down_no_space_above_check(void)
 
        allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
 
-       assert(allocated_ptr);
-       assert(rgn->base == min_addr - r1_size);
-       assert(rgn->size == total_size);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->base, min_addr - r1_size);
+       ASSERT_EQ(rgn->size, total_size);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -186,6 +202,8 @@ static int alloc_from_top_down_min_addr_cap_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r1_size = SZ_64;
        phys_addr_t min_addr;
        phys_addr_t start_addr;
@@ -199,12 +217,14 @@ static int alloc_from_top_down_min_addr_cap_check(void)
 
        allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
 
-       assert(allocated_ptr);
-       assert(rgn->base == start_addr);
-       assert(rgn->size == MEM_SIZE);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->base, start_addr);
+       ASSERT_EQ(rgn->size, MEM_SIZE);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, MEM_SIZE);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == MEM_SIZE);
+       test_pass_pop();
 
        return 0;
 }
@@ -230,6 +250,8 @@ static int alloc_from_bottom_up_high_addr_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_32;
        phys_addr_t min_addr;
 
@@ -240,12 +262,14 @@ static int alloc_from_bottom_up_high_addr_check(void)
 
        allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
 
-       assert(allocated_ptr);
-       assert(rgn->size == size);
-       assert(rgn->base == memblock_start_of_DRAM());
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -270,6 +294,8 @@ static int alloc_from_bottom_up_no_space_above_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r1_size = SZ_64;
        phys_addr_t min_addr;
        phys_addr_t r2_size;
@@ -284,12 +310,14 @@ static int alloc_from_bottom_up_no_space_above_check(void)
 
        allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
 
-       assert(allocated_ptr);
-       assert(rgn->base == memblock_start_of_DRAM());
-       assert(rgn->size == r1_size);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
+       ASSERT_EQ(rgn->size, r1_size);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == r1_size + r2_size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, r1_size + r2_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -304,6 +332,8 @@ static int alloc_from_bottom_up_min_addr_cap_check(void)
        struct memblock_region *rgn = &memblock.reserved.regions[0];
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t r1_size = SZ_64;
        phys_addr_t min_addr;
        phys_addr_t start_addr;
@@ -315,12 +345,14 @@ static int alloc_from_bottom_up_min_addr_cap_check(void)
 
        allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
 
-       assert(allocated_ptr);
-       assert(rgn->base == start_addr);
-       assert(rgn->size == r1_size);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(rgn->base, start_addr);
+       ASSERT_EQ(rgn->size, r1_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == r1_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, r1_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -328,6 +360,7 @@ static int alloc_from_bottom_up_min_addr_cap_check(void)
 /* Test case wrappers */
 static int alloc_from_simple_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_from_simple_generic_check();
        memblock_set_bottom_up(true);
@@ -338,6 +371,7 @@ static int alloc_from_simple_check(void)
 
 static int alloc_from_misaligned_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_from_misaligned_generic_check();
        memblock_set_bottom_up(true);
@@ -348,6 +382,7 @@ static int alloc_from_misaligned_check(void)
 
 static int alloc_from_high_addr_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_from_top_down_high_addr_check();
        memblock_set_bottom_up(true);
@@ -358,6 +393,7 @@ static int alloc_from_high_addr_check(void)
 
 static int alloc_from_no_space_above_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_from_top_down_no_space_above_check();
        memblock_set_bottom_up(true);
@@ -368,6 +404,7 @@ static int alloc_from_no_space_above_check(void)
 
 static int alloc_from_min_addr_cap_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_from_top_down_min_addr_cap_check();
        memblock_set_bottom_up(true);
@@ -378,6 +415,12 @@ static int alloc_from_min_addr_cap_check(void)
 
 int memblock_alloc_helpers_checks(void)
 {
+       const char *func_testing = "memblock_alloc_from";
+
+       prefix_reset();
+       prefix_push(func_testing);
+       test_print("Running %s tests...\n", func_testing);
+
        reset_memblock_attributes();
        dummy_physical_memory_init();
 
@@ -389,5 +432,7 @@ int memblock_alloc_helpers_checks(void)
 
        dummy_physical_memory_cleanup();
 
+       prefix_pop();
+
        return 0;
 }
index 6390206..255fd51 100644 (file)
@@ -21,6 +21,8 @@ static int alloc_try_nid_top_down_simple_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_128;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -36,15 +38,17 @@ static int alloc_try_nid_top_down_simple_check(void)
        b = (char *)allocated_ptr;
        rgn_end = rgn->base + rgn->size;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, max_addr - size);
+       ASSERT_EQ(rgn_end, max_addr);
 
-       assert(rgn->size == size);
-       assert(rgn->base == max_addr - size);
-       assert(rgn_end == max_addr);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -72,6 +76,8 @@ static int alloc_try_nid_top_down_end_misaligned_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_128;
        phys_addr_t misalign = SZ_2;
        phys_addr_t min_addr;
@@ -88,15 +94,17 @@ static int alloc_try_nid_top_down_end_misaligned_check(void)
        b = (char *)allocated_ptr;
        rgn_end = rgn->base + rgn->size;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
 
-       assert(rgn->size == size);
-       assert(rgn->base == max_addr - size - misalign);
-       assert(rgn_end < max_addr);
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, max_addr - size - misalign);
+       ASSERT_LT(rgn_end, max_addr);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -122,6 +130,8 @@ static int alloc_try_nid_exact_address_generic_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_1K;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -137,15 +147,17 @@ static int alloc_try_nid_exact_address_generic_check(void)
        b = (char *)allocated_ptr;
        rgn_end = rgn->base + rgn->size;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, min_addr);
+       ASSERT_EQ(rgn_end, max_addr);
 
-       assert(rgn->size == size);
-       assert(rgn->base == min_addr);
-       assert(rgn_end == max_addr);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -173,6 +185,8 @@ static int alloc_try_nid_top_down_narrow_range_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_256;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -186,14 +200,16 @@ static int alloc_try_nid_top_down_narrow_range_check(void)
                                               min_addr, max_addr, NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, max_addr - size);
 
-       assert(rgn->size == size);
-       assert(rgn->base == max_addr - size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -222,6 +238,8 @@ static int alloc_try_nid_low_max_generic_check(void)
 {
        void *allocated_ptr = NULL;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_1K;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -234,7 +252,9 @@ static int alloc_try_nid_low_max_generic_check(void)
        allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES,
                                               min_addr, max_addr, NUMA_NO_NODE);
 
-       assert(!allocated_ptr);
+       ASSERT_EQ(allocated_ptr, NULL);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -259,6 +279,8 @@ static int alloc_try_nid_min_reserved_generic_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t r1_size = SZ_128;
        phys_addr_t r2_size = SZ_64;
        phys_addr_t total_size = r1_size + r2_size;
@@ -278,14 +300,16 @@ static int alloc_try_nid_min_reserved_generic_check(void)
                                               min_addr, max_addr, NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
 
-       assert(rgn->size == total_size);
-       assert(rgn->base == reserved_base);
+       ASSERT_EQ(rgn->size, total_size);
+       ASSERT_EQ(rgn->base, reserved_base);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -310,6 +334,8 @@ static int alloc_try_nid_max_reserved_generic_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t r1_size = SZ_64;
        phys_addr_t r2_size = SZ_128;
        phys_addr_t total_size = r1_size + r2_size;
@@ -327,14 +353,16 @@ static int alloc_try_nid_max_reserved_generic_check(void)
                                               min_addr, max_addr, NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, total_size);
+       ASSERT_EQ(rgn->base, min_addr);
 
-       assert(rgn->size == total_size);
-       assert(rgn->base == min_addr);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -364,6 +392,8 @@ static int alloc_try_nid_top_down_reserved_with_space_check(void)
        char *b;
        struct region r1, r2;
 
+       PREFIX_PUSH();
+
        phys_addr_t r3_size = SZ_64;
        phys_addr_t gap_size = SMP_CACHE_BYTES;
        phys_addr_t total_size;
@@ -389,17 +419,19 @@ static int alloc_try_nid_top_down_reserved_with_space_check(void)
                                               min_addr, max_addr, NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn1->size, r1.size + r3_size);
+       ASSERT_EQ(rgn1->base, max_addr - r3_size);
 
-       assert(rgn1->size == r1.size + r3_size);
-       assert(rgn1->base == max_addr - r3_size);
+       ASSERT_EQ(rgn2->size, r2.size);
+       ASSERT_EQ(rgn2->base, r2.base);
 
-       assert(rgn2->size == r2.size);
-       assert(rgn2->base == r2.base);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -427,6 +459,8 @@ static int alloc_try_nid_reserved_full_merge_generic_check(void)
        char *b;
        struct region r1, r2;
 
+       PREFIX_PUSH();
+
        phys_addr_t r3_size = SZ_64;
        phys_addr_t total_size;
        phys_addr_t max_addr;
@@ -451,14 +485,16 @@ static int alloc_try_nid_reserved_full_merge_generic_check(void)
                                               min_addr, max_addr, NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
 
-       assert(rgn->size == total_size);
-       assert(rgn->base == r2.base);
+       ASSERT_EQ(rgn->size, total_size);
+       ASSERT_EQ(rgn->base, r2.base);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -489,6 +525,8 @@ static int alloc_try_nid_top_down_reserved_no_space_check(void)
        char *b;
        struct region r1, r2;
 
+       PREFIX_PUSH();
+
        phys_addr_t r3_size = SZ_256;
        phys_addr_t gap_size = SMP_CACHE_BYTES;
        phys_addr_t total_size;
@@ -514,17 +552,19 @@ static int alloc_try_nid_top_down_reserved_no_space_check(void)
                                               min_addr, max_addr, NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn1->size, r1.size);
+       ASSERT_EQ(rgn1->base, r1.base);
 
-       assert(rgn1->size == r1.size);
-       assert(rgn1->base == r1.base);
+       ASSERT_EQ(rgn2->size, r2.size + r3_size);
+       ASSERT_EQ(rgn2->base, r2.base - r3_size);
 
-       assert(rgn2->size == r2.size + r3_size);
-       assert(rgn2->base == r2.base - r3_size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -554,6 +594,8 @@ static int alloc_try_nid_reserved_all_generic_check(void)
        void *allocated_ptr = NULL;
        struct region r1, r2;
 
+       PREFIX_PUSH();
+
        phys_addr_t r3_size = SZ_256;
        phys_addr_t gap_size = SMP_CACHE_BYTES;
        phys_addr_t max_addr;
@@ -576,7 +618,9 @@ static int alloc_try_nid_reserved_all_generic_check(void)
        allocated_ptr = memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES,
                                               min_addr, max_addr, NUMA_NO_NODE);
 
-       assert(!allocated_ptr);
+       ASSERT_EQ(allocated_ptr, NULL);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -592,6 +636,8 @@ static int alloc_try_nid_top_down_cap_max_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_256;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -605,14 +651,16 @@ static int alloc_try_nid_top_down_cap_max_check(void)
                                               min_addr, max_addr, NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - size);
 
-       assert(rgn->size == size);
-       assert(rgn->base == memblock_end_of_DRAM() - size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -628,6 +676,8 @@ static int alloc_try_nid_top_down_cap_min_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_1K;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -641,14 +691,16 @@ static int alloc_try_nid_top_down_cap_min_check(void)
                                               min_addr, max_addr, NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
 
-       assert(rgn->size == size);
-       assert(rgn->base == memblock_end_of_DRAM() - size);
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -673,6 +725,8 @@ static int alloc_try_nid_bottom_up_simple_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_128;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -689,15 +743,17 @@ static int alloc_try_nid_bottom_up_simple_check(void)
        b = (char *)allocated_ptr;
        rgn_end = rgn->base + rgn->size;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, min_addr);
+       ASSERT_LT(rgn_end, max_addr);
 
-       assert(rgn->size == size);
-       assert(rgn->base == min_addr);
-       assert(rgn_end < max_addr);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -725,6 +781,8 @@ static int alloc_try_nid_bottom_up_start_misaligned_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_128;
        phys_addr_t misalign = SZ_2;
        phys_addr_t min_addr;
@@ -742,15 +800,17 @@ static int alloc_try_nid_bottom_up_start_misaligned_check(void)
        b = (char *)allocated_ptr;
        rgn_end = rgn->base + rgn->size;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, min_addr + (SMP_CACHE_BYTES - misalign));
+       ASSERT_LT(rgn_end, max_addr);
 
-       assert(rgn->size == size);
-       assert(rgn->base == min_addr + (SMP_CACHE_BYTES - misalign));
-       assert(rgn_end < max_addr);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -778,6 +838,8 @@ static int alloc_try_nid_bottom_up_narrow_range_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_256;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -792,14 +854,16 @@ static int alloc_try_nid_bottom_up_narrow_range_check(void)
                                               NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
 
-       assert(rgn->size == size);
-       assert(rgn->base == memblock_start_of_DRAM());
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -829,6 +893,8 @@ static int alloc_try_nid_bottom_up_reserved_with_space_check(void)
        char *b;
        struct region r1, r2;
 
+       PREFIX_PUSH();
+
        phys_addr_t r3_size = SZ_64;
        phys_addr_t gap_size = SMP_CACHE_BYTES;
        phys_addr_t total_size;
@@ -855,17 +921,19 @@ static int alloc_try_nid_bottom_up_reserved_with_space_check(void)
                                               NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
 
-       assert(rgn1->size == r1.size);
-       assert(rgn1->base == max_addr);
+       ASSERT_EQ(rgn1->size, r1.size);
+       ASSERT_EQ(rgn1->base, max_addr);
 
-       assert(rgn2->size == r2.size + r3_size);
-       assert(rgn2->base == r2.base);
+       ASSERT_EQ(rgn2->size, r2.size + r3_size);
+       ASSERT_EQ(rgn2->base, r2.base);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -899,6 +967,8 @@ static int alloc_try_nid_bottom_up_reserved_no_space_check(void)
        char *b;
        struct region r1, r2;
 
+       PREFIX_PUSH();
+
        phys_addr_t r3_size = SZ_256;
        phys_addr_t gap_size = SMP_CACHE_BYTES;
        phys_addr_t total_size;
@@ -925,20 +995,22 @@ static int alloc_try_nid_bottom_up_reserved_no_space_check(void)
                                               NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn3->size, r3_size);
+       ASSERT_EQ(rgn3->base, memblock_start_of_DRAM());
 
-       assert(rgn3->size == r3_size);
-       assert(rgn3->base == memblock_start_of_DRAM());
+       ASSERT_EQ(rgn2->size, r2.size);
+       ASSERT_EQ(rgn2->base, r2.base);
 
-       assert(rgn2->size == r2.size);
-       assert(rgn2->base == r2.base);
+       ASSERT_EQ(rgn1->size, r1.size);
+       ASSERT_EQ(rgn1->base, r1.base);
 
-       assert(rgn1->size == r1.size);
-       assert(rgn1->base == r1.base);
+       ASSERT_EQ(memblock.reserved.cnt, 3);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
 
-       assert(memblock.reserved.cnt == 3);
-       assert(memblock.reserved.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -954,6 +1026,8 @@ static int alloc_try_nid_bottom_up_cap_max_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_256;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -968,14 +1042,16 @@ static int alloc_try_nid_bottom_up_cap_max_check(void)
                                               NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, min_addr);
 
-       assert(rgn->size == size);
-       assert(rgn->base == min_addr);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -991,6 +1067,8 @@ static int alloc_try_nid_bottom_up_cap_min_check(void)
        void *allocated_ptr = NULL;
        char *b;
 
+       PREFIX_PUSH();
+
        phys_addr_t size = SZ_1K;
        phys_addr_t min_addr;
        phys_addr_t max_addr;
@@ -1005,14 +1083,16 @@ static int alloc_try_nid_bottom_up_cap_min_check(void)
                                               NUMA_NO_NODE);
        b = (char *)allocated_ptr;
 
-       assert(allocated_ptr);
-       assert(*b == 0);
+       ASSERT_NE(allocated_ptr, NULL);
+       ASSERT_EQ(*b, 0);
+
+       ASSERT_EQ(rgn->size, size);
+       ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
 
-       assert(rgn->size == size);
-       assert(rgn->base == memblock_start_of_DRAM());
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == size);
+       test_pass_pop();
 
        return 0;
 }
@@ -1020,6 +1100,7 @@ static int alloc_try_nid_bottom_up_cap_min_check(void)
 /* Test case wrappers */
 static int alloc_try_nid_simple_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_top_down_simple_check();
        memblock_set_bottom_up(true);
@@ -1030,6 +1111,7 @@ static int alloc_try_nid_simple_check(void)
 
 static int alloc_try_nid_misaligned_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_top_down_end_misaligned_check();
        memblock_set_bottom_up(true);
@@ -1040,6 +1122,7 @@ static int alloc_try_nid_misaligned_check(void)
 
 static int alloc_try_nid_narrow_range_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_top_down_narrow_range_check();
        memblock_set_bottom_up(true);
@@ -1050,6 +1133,7 @@ static int alloc_try_nid_narrow_range_check(void)
 
 static int alloc_try_nid_reserved_with_space_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_top_down_reserved_with_space_check();
        memblock_set_bottom_up(true);
@@ -1060,6 +1144,7 @@ static int alloc_try_nid_reserved_with_space_check(void)
 
 static int alloc_try_nid_reserved_no_space_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_top_down_reserved_no_space_check();
        memblock_set_bottom_up(true);
@@ -1070,6 +1155,7 @@ static int alloc_try_nid_reserved_no_space_check(void)
 
 static int alloc_try_nid_cap_max_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_top_down_cap_max_check();
        memblock_set_bottom_up(true);
@@ -1080,6 +1166,7 @@ static int alloc_try_nid_cap_max_check(void)
 
 static int alloc_try_nid_cap_min_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_top_down_cap_min_check();
        memblock_set_bottom_up(true);
@@ -1090,6 +1177,7 @@ static int alloc_try_nid_cap_min_check(void)
 
 static int alloc_try_nid_min_reserved_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_min_reserved_generic_check();
        memblock_set_bottom_up(true);
@@ -1100,6 +1188,7 @@ static int alloc_try_nid_min_reserved_check(void)
 
 static int alloc_try_nid_max_reserved_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_max_reserved_generic_check();
        memblock_set_bottom_up(true);
@@ -1110,6 +1199,7 @@ static int alloc_try_nid_max_reserved_check(void)
 
 static int alloc_try_nid_exact_address_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_exact_address_generic_check();
        memblock_set_bottom_up(true);
@@ -1120,6 +1210,7 @@ static int alloc_try_nid_exact_address_check(void)
 
 static int alloc_try_nid_reserved_full_merge_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_reserved_full_merge_generic_check();
        memblock_set_bottom_up(true);
@@ -1130,6 +1221,7 @@ static int alloc_try_nid_reserved_full_merge_check(void)
 
 static int alloc_try_nid_reserved_all_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_reserved_all_generic_check();
        memblock_set_bottom_up(true);
@@ -1140,6 +1232,7 @@ static int alloc_try_nid_reserved_all_check(void)
 
 static int alloc_try_nid_low_max_check(void)
 {
+       test_print("\tRunning %s...\n", __func__);
        memblock_set_bottom_up(false);
        alloc_try_nid_low_max_generic_check();
        memblock_set_bottom_up(true);
@@ -1150,6 +1243,12 @@ static int alloc_try_nid_low_max_check(void)
 
 int memblock_alloc_nid_checks(void)
 {
+       const char *func_testing = "memblock_alloc_try_nid";
+
+       prefix_reset();
+       prefix_push(func_testing);
+       test_print("Running %s tests...\n", func_testing);
+
        reset_memblock_attributes();
        dummy_physical_memory_init();
 
@@ -1170,5 +1269,7 @@ int memblock_alloc_nid_checks(void)
 
        dummy_physical_memory_cleanup();
 
+       prefix_pop();
+
        return 0;
 }
index a7bc180..66f46f2 100644 (file)
@@ -4,21 +4,29 @@
 #include "basic_api.h"
 
 #define EXPECTED_MEMBLOCK_REGIONS                      128
+#define FUNC_ADD                                       "memblock_add"
+#define FUNC_RESERVE                                   "memblock_reserve"
+#define FUNC_REMOVE                                    "memblock_remove"
+#define FUNC_FREE                                      "memblock_free"
 
 static int memblock_initialization_check(void)
 {
-       assert(memblock.memory.regions);
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.max == EXPECTED_MEMBLOCK_REGIONS);
-       assert(strcmp(memblock.memory.name, "memory") == 0);
+       PREFIX_PUSH();
 
-       assert(memblock.reserved.regions);
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.memory.max == EXPECTED_MEMBLOCK_REGIONS);
-       assert(strcmp(memblock.reserved.name, "reserved") == 0);
+       ASSERT_NE(memblock.memory.regions, NULL);
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.max, EXPECTED_MEMBLOCK_REGIONS);
+       ASSERT_EQ(strcmp(memblock.memory.name, "memory"), 0);
 
-       assert(!memblock.bottom_up);
-       assert(memblock.current_limit == MEMBLOCK_ALLOC_ANYWHERE);
+       ASSERT_NE(memblock.reserved.regions, NULL);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.memory.max, EXPECTED_MEMBLOCK_REGIONS);
+       ASSERT_EQ(strcmp(memblock.reserved.name, "reserved"), 0);
+
+       ASSERT_EQ(memblock.bottom_up, false);
+       ASSERT_EQ(memblock.current_limit, MEMBLOCK_ALLOC_ANYWHERE);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -40,14 +48,18 @@ static int memblock_add_simple_check(void)
                .size = SZ_4M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_add(r.base, r.size);
 
-       assert(rgn->base == r.base);
-       assert(rgn->size == r.size);
+       ASSERT_EQ(rgn->base, r.base);
+       ASSERT_EQ(rgn->size, r.size);
+
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, r.size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == r.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -69,18 +81,22 @@ static int memblock_add_node_simple_check(void)
                .size = SZ_16M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_add_node(r.base, r.size, 1, MEMBLOCK_HOTPLUG);
 
-       assert(rgn->base == r.base);
-       assert(rgn->size == r.size);
+       ASSERT_EQ(rgn->base, r.base);
+       ASSERT_EQ(rgn->size, r.size);
 #ifdef CONFIG_NUMA
-       assert(rgn->nid == 1);
+       ASSERT_EQ(rgn->nid, 1);
 #endif
-       assert(rgn->flags == MEMBLOCK_HOTPLUG);
+       ASSERT_EQ(rgn->flags, MEMBLOCK_HOTPLUG);
+
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, r.size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == r.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -113,18 +129,22 @@ static int memblock_add_disjoint_check(void)
                .size = SZ_8K
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_add(r1.base, r1.size);
        memblock_add(r2.base, r2.size);
 
-       assert(rgn1->base == r1.base);
-       assert(rgn1->size == r1.size);
+       ASSERT_EQ(rgn1->base, r1.base);
+       ASSERT_EQ(rgn1->size, r1.size);
+
+       ASSERT_EQ(rgn2->base, r2.base);
+       ASSERT_EQ(rgn2->size, r2.size);
 
-       assert(rgn2->base == r2.base);
-       assert(rgn2->size == r2.size);
+       ASSERT_EQ(memblock.memory.cnt, 2);
+       ASSERT_EQ(memblock.memory.total_size, r1.size + r2.size);
 
-       assert(memblock.memory.cnt == 2);
-       assert(memblock.memory.total_size == r1.size + r2.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -162,17 +182,21 @@ static int memblock_add_overlap_top_check(void)
                .size = SZ_512M
        };
 
+       PREFIX_PUSH();
+
        total_size = (r1.base - r2.base) + r1.size;
 
        reset_memblock_regions();
        memblock_add(r1.base, r1.size);
        memblock_add(r2.base, r2.size);
 
-       assert(rgn->base == r2.base);
-       assert(rgn->size == total_size);
+       ASSERT_EQ(rgn->base, r2.base);
+       ASSERT_EQ(rgn->size, total_size);
+
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, total_size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -210,17 +234,21 @@ static int memblock_add_overlap_bottom_check(void)
                .size = SZ_1G
        };
 
+       PREFIX_PUSH();
+
        total_size = (r2.base - r1.base) + r2.size;
 
        reset_memblock_regions();
        memblock_add(r1.base, r1.size);
        memblock_add(r2.base, r2.size);
 
-       assert(rgn->base == r1.base);
-       assert(rgn->size == total_size);
+       ASSERT_EQ(rgn->base, r1.base);
+       ASSERT_EQ(rgn->size, total_size);
+
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, total_size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -255,15 +283,19 @@ static int memblock_add_within_check(void)
                .size = SZ_1M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_add(r1.base, r1.size);
        memblock_add(r2.base, r2.size);
 
-       assert(rgn->base == r1.base);
-       assert(rgn->size == r1.size);
+       ASSERT_EQ(rgn->base, r1.base);
+       ASSERT_EQ(rgn->size, r1.size);
+
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, r1.size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == r1.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -279,19 +311,27 @@ static int memblock_add_twice_check(void)
                .size = SZ_2M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
 
        memblock_add(r.base, r.size);
        memblock_add(r.base, r.size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == r.size);
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, r.size);
+
+       test_pass_pop();
 
        return 0;
 }
 
 static int memblock_add_checks(void)
 {
+       prefix_reset();
+       prefix_push(FUNC_ADD);
+       test_print("Running %s tests...\n", FUNC_ADD);
+
        memblock_add_simple_check();
        memblock_add_node_simple_check();
        memblock_add_disjoint_check();
@@ -300,6 +340,8 @@ static int memblock_add_checks(void)
        memblock_add_within_check();
        memblock_add_twice_check();
 
+       prefix_pop();
+
        return 0;
 }
 
@@ -320,11 +362,15 @@ static int memblock_reserve_simple_check(void)
                .size = SZ_128M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_reserve(r.base, r.size);
 
-       assert(rgn->base == r.base);
-       assert(rgn->size == r.size);
+       ASSERT_EQ(rgn->base, r.base);
+       ASSERT_EQ(rgn->size, r.size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -356,18 +402,22 @@ static int memblock_reserve_disjoint_check(void)
                .size = SZ_512M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_reserve(r1.base, r1.size);
        memblock_reserve(r2.base, r2.size);
 
-       assert(rgn1->base == r1.base);
-       assert(rgn1->size == r1.size);
+       ASSERT_EQ(rgn1->base, r1.base);
+       ASSERT_EQ(rgn1->size, r1.size);
+
+       ASSERT_EQ(rgn2->base, r2.base);
+       ASSERT_EQ(rgn2->size, r2.size);
 
-       assert(rgn2->base == r2.base);
-       assert(rgn2->size == r2.size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, r1.size + r2.size);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == r1.size + r2.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -406,17 +456,21 @@ static int memblock_reserve_overlap_top_check(void)
                .size = SZ_1G
        };
 
+       PREFIX_PUSH();
+
        total_size = (r1.base - r2.base) + r1.size;
 
        reset_memblock_regions();
        memblock_reserve(r1.base, r1.size);
        memblock_reserve(r2.base, r2.size);
 
-       assert(rgn->base == r2.base);
-       assert(rgn->size == total_size);
+       ASSERT_EQ(rgn->base, r2.base);
+       ASSERT_EQ(rgn->size, total_size);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -455,17 +509,21 @@ static int memblock_reserve_overlap_bottom_check(void)
                .size = SZ_128K
        };
 
+       PREFIX_PUSH();
+
        total_size = (r2.base - r1.base) + r2.size;
 
        reset_memblock_regions();
        memblock_reserve(r1.base, r1.size);
        memblock_reserve(r2.base, r2.size);
 
-       assert(rgn->base == r1.base);
-       assert(rgn->size == total_size);
+       ASSERT_EQ(rgn->base, r1.base);
+       ASSERT_EQ(rgn->size, total_size);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -502,15 +560,19 @@ static int memblock_reserve_within_check(void)
                .size = SZ_64K
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_reserve(r1.base, r1.size);
        memblock_reserve(r2.base, r2.size);
 
-       assert(rgn->base == r1.base);
-       assert(rgn->size == r1.size);
+       ASSERT_EQ(rgn->base, r1.base);
+       ASSERT_EQ(rgn->size, r1.size);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, r1.size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == r1.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -527,19 +589,27 @@ static int memblock_reserve_twice_check(void)
                .size = SZ_2M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
 
        memblock_reserve(r.base, r.size);
        memblock_reserve(r.base, r.size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == r.size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, r.size);
+
+       test_pass_pop();
 
        return 0;
 }
 
 static int memblock_reserve_checks(void)
 {
+       prefix_reset();
+       prefix_push(FUNC_RESERVE);
+       test_print("Running %s tests...\n", FUNC_RESERVE);
+
        memblock_reserve_simple_check();
        memblock_reserve_disjoint_check();
        memblock_reserve_overlap_top_check();
@@ -547,6 +617,8 @@ static int memblock_reserve_checks(void)
        memblock_reserve_within_check();
        memblock_reserve_twice_check();
 
+       prefix_pop();
+
        return 0;
 }
 
@@ -581,16 +653,20 @@ static int memblock_remove_simple_check(void)
                .size = SZ_4M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_add(r1.base, r1.size);
        memblock_add(r2.base, r2.size);
        memblock_remove(r1.base, r1.size);
 
-       assert(rgn->base == r2.base);
-       assert(rgn->size == r2.size);
+       ASSERT_EQ(rgn->base, r2.base);
+       ASSERT_EQ(rgn->size, r2.size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == r2.size);
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, r2.size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -626,15 +702,19 @@ static int memblock_remove_absent_check(void)
                .size = SZ_1G
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_add(r1.base, r1.size);
        memblock_remove(r2.base, r2.size);
 
-       assert(rgn->base == r1.base);
-       assert(rgn->size == r1.size);
+       ASSERT_EQ(rgn->base, r1.base);
+       ASSERT_EQ(rgn->size, r1.size);
+
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, r1.size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == r1.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -674,6 +754,8 @@ static int memblock_remove_overlap_top_check(void)
                .size = SZ_32M
        };
 
+       PREFIX_PUSH();
+
        r1_end = r1.base + r1.size;
        r2_end = r2.base + r2.size;
        total_size = r1_end - r2_end;
@@ -682,11 +764,13 @@ static int memblock_remove_overlap_top_check(void)
        memblock_add(r1.base, r1.size);
        memblock_remove(r2.base, r2.size);
 
-       assert(rgn->base == r1.base + r2.base);
-       assert(rgn->size == total_size);
+       ASSERT_EQ(rgn->base, r1.base + r2.base);
+       ASSERT_EQ(rgn->size, total_size);
+
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, total_size);
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
@@ -724,17 +808,22 @@ static int memblock_remove_overlap_bottom_check(void)
                .size = SZ_256M
        };
 
+       PREFIX_PUSH();
+
        total_size = r2.base - r1.base;
 
        reset_memblock_regions();
        memblock_add(r1.base, r1.size);
        memblock_remove(r2.base, r2.size);
 
-       assert(rgn->base == r1.base);
-       assert(rgn->size == total_size);
+       ASSERT_EQ(rgn->base, r1.base);
+       ASSERT_EQ(rgn->size, total_size);
+
+       ASSERT_EQ(memblock.memory.cnt, 1);
+       ASSERT_EQ(memblock.memory.total_size, total_size);
+
+       test_pass_pop();
 
-       assert(memblock.memory.cnt == 1);
-       assert(memblock.memory.total_size == total_size);
        return 0;
 }
 
@@ -774,6 +863,8 @@ static int memblock_remove_within_check(void)
                .size = SZ_1M
        };
 
+       PREFIX_PUSH();
+
        r1_size = r2.base - r1.base;
        r2_size = (r1.base + r1.size) - (r2.base + r2.size);
        total_size = r1_size + r2_size;
@@ -782,26 +873,34 @@ static int memblock_remove_within_check(void)
        memblock_add(r1.base, r1.size);
        memblock_remove(r2.base, r2.size);
 
-       assert(rgn1->base == r1.base);
-       assert(rgn1->size == r1_size);
+       ASSERT_EQ(rgn1->base, r1.base);
+       ASSERT_EQ(rgn1->size, r1_size);
+
+       ASSERT_EQ(rgn2->base, r2.base + r2.size);
+       ASSERT_EQ(rgn2->size, r2_size);
 
-       assert(rgn2->base == r2.base + r2.size);
-       assert(rgn2->size == r2_size);
+       ASSERT_EQ(memblock.memory.cnt, 2);
+       ASSERT_EQ(memblock.memory.total_size, total_size);
 
-       assert(memblock.memory.cnt == 2);
-       assert(memblock.memory.total_size == total_size);
+       test_pass_pop();
 
        return 0;
 }
 
 static int memblock_remove_checks(void)
 {
+       prefix_reset();
+       prefix_push(FUNC_REMOVE);
+       test_print("Running %s tests...\n", FUNC_REMOVE);
+
        memblock_remove_simple_check();
        memblock_remove_absent_check();
        memblock_remove_overlap_top_check();
        memblock_remove_overlap_bottom_check();
        memblock_remove_within_check();
 
+       prefix_pop();
+
        return 0;
 }
 
@@ -835,16 +934,20 @@ static int memblock_free_simple_check(void)
                .size = SZ_1M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_reserve(r1.base, r1.size);
        memblock_reserve(r2.base, r2.size);
        memblock_free((void *)r1.base, r1.size);
 
-       assert(rgn->base == r2.base);
-       assert(rgn->size == r2.size);
+       ASSERT_EQ(rgn->base, r2.base);
+       ASSERT_EQ(rgn->size, r2.size);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, r2.size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == r2.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -880,15 +983,19 @@ static int memblock_free_absent_check(void)
                .size = SZ_128M
        };
 
+       PREFIX_PUSH();
+
        reset_memblock_regions();
        memblock_reserve(r1.base, r1.size);
        memblock_free((void *)r2.base, r2.size);
 
-       assert(rgn->base == r1.base);
-       assert(rgn->size == r1.size);
+       ASSERT_EQ(rgn->base, r1.base);
+       ASSERT_EQ(rgn->size, r1.size);
+
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, r1.size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == r1.size);
+       test_pass_pop();
 
        return 0;
 }
@@ -928,17 +1035,21 @@ static int memblock_free_overlap_top_check(void)
                .size = SZ_8M
        };
 
+       PREFIX_PUSH();
+
        total_size = (r1.size + r1.base) - (r2.base + r2.size);
 
        reset_memblock_regions();
        memblock_reserve(r1.base, r1.size);
        memblock_free((void *)r2.base, r2.size);
 
-       assert(rgn->base == r2.base + r2.size);
-       assert(rgn->size == total_size);
+       ASSERT_EQ(rgn->base, r2.base + r2.size);
+       ASSERT_EQ(rgn->size, total_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -973,17 +1084,21 @@ static int memblock_free_overlap_bottom_check(void)
                .size = SZ_32M
        };
 
+       PREFIX_PUSH();
+
        total_size = r2.base - r1.base;
 
        reset_memblock_regions();
        memblock_reserve(r1.base, r1.size);
        memblock_free((void *)r2.base, r2.size);
 
-       assert(rgn->base == r1.base);
-       assert(rgn->size == total_size);
+       ASSERT_EQ(rgn->base, r1.base);
+       ASSERT_EQ(rgn->size, total_size);
 
-       assert(memblock.reserved.cnt == 1);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 1);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
@@ -1024,6 +1139,8 @@ static int memblock_free_within_check(void)
                .size = SZ_1M
        };
 
+       PREFIX_PUSH();
+
        r1_size = r2.base - r1.base;
        r2_size = (r1.base + r1.size) - (r2.base + r2.size);
        total_size = r1_size + r2_size;
@@ -1032,26 +1149,34 @@ static int memblock_free_within_check(void)
        memblock_reserve(r1.base, r1.size);
        memblock_free((void *)r2.base, r2.size);
 
-       assert(rgn1->base == r1.base);
-       assert(rgn1->size == r1_size);
+       ASSERT_EQ(rgn1->base, r1.base);
+       ASSERT_EQ(rgn1->size, r1_size);
 
-       assert(rgn2->base == r2.base + r2.size);
-       assert(rgn2->size == r2_size);
+       ASSERT_EQ(rgn2->base, r2.base + r2.size);
+       ASSERT_EQ(rgn2->size, r2_size);
 
-       assert(memblock.reserved.cnt == 2);
-       assert(memblock.reserved.total_size == total_size);
+       ASSERT_EQ(memblock.reserved.cnt, 2);
+       ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+       test_pass_pop();
 
        return 0;
 }
 
 static int memblock_free_checks(void)
 {
+       prefix_reset();
+       prefix_push(FUNC_FREE);
+       test_print("Running %s tests...\n", FUNC_FREE);
+
        memblock_free_simple_check();
        memblock_free_absent_check();
        memblock_free_overlap_top_check();
        memblock_free_overlap_bottom_check();
        memblock_free_within_check();
 
+       prefix_pop();
+
        return 0;
 }
 
index 62d3191..e43b267 100644 (file)
@@ -1,11 +1,39 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 #include "tests/common.h"
 #include <string.h>
+#include <getopt.h>
+#include <linux/memory_hotplug.h>
+#include <linux/build_bug.h>
 
 #define INIT_MEMBLOCK_REGIONS                  128
 #define INIT_MEMBLOCK_RESERVED_REGIONS         INIT_MEMBLOCK_REGIONS
+#define PREFIXES_MAX                           15
+#define DELIM                                  ": "
 
 static struct test_memory memory_block;
+static const char __maybe_unused *prefixes[PREFIXES_MAX];
+static int __maybe_unused nr_prefixes;
+
+static const char *short_opts = "mv";
+static const struct option long_opts[] = {
+       {"movable-node", 0, NULL, 'm'},
+       {"verbose", 0, NULL, 'v'},
+       {NULL, 0, NULL, 0}
+};
+
+static const char * const help_opts[] = {
+       "disallow allocations from regions marked as hotplugged\n\t\t\t"
+               "by simulating enabling the \"movable_node\" kernel\n\t\t\t"
+               "parameter",
+       "enable verbose output, which includes the name of the\n\t\t\t"
+               "memblock function being tested, the name of the test,\n\t\t\t"
+               "and whether the test passed or failed."
+};
+
+static int verbose;
+
+/* sets global variable returned by movable_node_is_enabled() stub */
+bool movable_node_enabled;
 
 void reset_memblock_regions(void)
 {
@@ -46,3 +74,93 @@ void dummy_physical_memory_cleanup(void)
 {
        free(memory_block.base);
 }
+
+static void usage(const char *prog)
+{
+       BUILD_BUG_ON(ARRAY_SIZE(help_opts) != ARRAY_SIZE(long_opts) - 1);
+
+       printf("Usage: %s [-%s]\n", prog, short_opts);
+
+       for (int i = 0; long_opts[i].name; i++) {
+               printf("  -%c, --%-12s\t%s\n", long_opts[i].val,
+                      long_opts[i].name, help_opts[i]);
+       }
+
+       exit(1);
+}
+
+void parse_args(int argc, char **argv)
+{
+       int c;
+
+       while ((c = getopt_long_only(argc, argv, short_opts, long_opts,
+                                    NULL)) != -1) {
+               switch (c) {
+               case 'm':
+                       movable_node_enabled = true;
+                       break;
+               case 'v':
+                       verbose = 1;
+                       break;
+               default:
+                       usage(argv[0]);
+               }
+       }
+}
+
+void print_prefixes(const char *postfix)
+{
+       for (int i = 0; i < nr_prefixes; i++)
+               test_print("%s%s", prefixes[i], DELIM);
+       test_print(postfix);
+}
+
+void test_fail(void)
+{
+       if (verbose) {
+               ksft_test_result_fail(": ");
+               print_prefixes("failed\n");
+       }
+}
+
+void test_pass(void)
+{
+       if (verbose) {
+               ksft_test_result_pass(": ");
+               print_prefixes("passed\n");
+       }
+}
+
+void test_print(const char *fmt, ...)
+{
+       if (verbose) {
+               int saved_errno = errno;
+               va_list args;
+
+               va_start(args, fmt);
+               errno = saved_errno;
+               vprintf(fmt, args);
+               va_end(args);
+       }
+}
+
+void prefix_reset(void)
+{
+       memset(prefixes, 0, PREFIXES_MAX * sizeof(char *));
+       nr_prefixes = 0;
+}
+
+void prefix_push(const char *prefix)
+{
+       assert(nr_prefixes < PREFIXES_MAX);
+       prefixes[nr_prefixes] = prefix;
+       nr_prefixes++;
+}
+
+void prefix_pop(void)
+{
+       if (nr_prefixes > 0) {
+               prefixes[nr_prefixes - 1] = 0;
+               nr_prefixes--;
+       }
+}
index 619054d..3e7f23d 100644 (file)
@@ -7,9 +7,49 @@
 #include <linux/types.h>
 #include <linux/memblock.h>
 #include <linux/sizes.h>
+#include <linux/printk.h>
+#include <../selftests/kselftest.h>
 
 #define MEM_SIZE SZ_16K
 
+/**
+ * ASSERT_EQ():
+ * Check the condition
+ * @_expected == @_seen
+ * If false, print failed test message (if in VERBOSE mode) and then assert
+ */
+#define ASSERT_EQ(_expected, _seen) do { \
+       if ((_expected) != (_seen)) \
+               test_fail(); \
+       assert((_expected) == (_seen)); \
+} while (0)
+
+/**
+ * ASSERT_NE():
+ * Check the condition
+ * @_expected != @_seen
+ * If false, print failed test message (if in VERBOSE mode) and then assert
+ */
+#define ASSERT_NE(_expected, _seen) do { \
+       if ((_expected) == (_seen)) \
+               test_fail(); \
+       assert((_expected) != (_seen)); \
+} while (0)
+
+/**
+ * ASSERT_LT():
+ * Check the condition
+ * @_expected < @_seen
+ * If false, print failed test message (if in VERBOSE mode) and then assert
+ */
+#define ASSERT_LT(_expected, _seen) do { \
+       if ((_expected) >= (_seen)) \
+               test_fail(); \
+       assert((_expected) < (_seen)); \
+} while (0)
+
+#define PREFIX_PUSH() prefix_push(__func__)
+
 /*
  * Available memory registered with memblock needs to be valid for allocs
  * test to run. This is a convenience wrapper for memory allocated in
@@ -30,5 +70,19 @@ void reset_memblock_attributes(void);
 void setup_memblock(void);
 void dummy_physical_memory_init(void);
 void dummy_physical_memory_cleanup(void);
+void parse_args(int argc, char **argv);
+
+void test_fail(void);
+void test_pass(void);
+void test_print(const char *fmt, ...);
+void prefix_reset(void);
+void prefix_push(const char *prefix);
+void prefix_pop(void);
+
+static inline void test_pass_pop(void)
+{
+       test_pass();
+       prefix_pop();
+}
 
 #endif
index b00b1bf..cb1108b 100644 (file)
@@ -13,6 +13,7 @@
 #include <stdint.h>
 #include <dirent.h>
 #include <libintl.h>
+#include <limits.h>
 #include <ctype.h>
 #include <time.h>
 #include <syslog.h>
@@ -33,9 +34,9 @@ int sysfs_set_ulong(char *path, char *filename, unsigned long val)
 {
        FILE *fd;
        int ret = -1;
-       char filepath[256];
+       char filepath[PATH_MAX + 2]; /* NUL and '/' */
 
-       snprintf(filepath, 256, "%s/%s", path, filename);
+       snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
 
        fd = fopen(filepath, "w");
        if (!fd) {
@@ -57,9 +58,9 @@ static int sysfs_get_ulong(char *path, char *filename, unsigned long *p_ulong)
 {
        FILE *fd;
        int ret = -1;
-       char filepath[256];
+       char filepath[PATH_MAX + 2]; /* NUL and '/' */
 
-       snprintf(filepath, 256, "%s/%s", path, filename);
+       snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
 
        fd = fopen(filepath, "r");
        if (!fd) {
@@ -76,9 +77,9 @@ static int sysfs_get_string(char *path, char *filename, char *str)
 {
        FILE *fd;
        int ret = -1;
-       char filepath[256];
+       char filepath[PATH_MAX + 2]; /* NUL and '/' */
 
-       snprintf(filepath, 256, "%s/%s", path, filename);
+       snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
 
        fd = fopen(filepath, "r");
        if (!fd) {
@@ -199,8 +200,8 @@ static int find_tzone_cdev(struct dirent *nl, char *tz_name,
 {
        unsigned long trip_instance = 0;
        char cdev_name_linked[256];
-       char cdev_name[256];
-       char cdev_trip_name[256];
+       char cdev_name[PATH_MAX];
+       char cdev_trip_name[PATH_MAX];
        int cdev_id;
 
        if (nl->d_type == DT_LNK) {
@@ -213,7 +214,8 @@ static int find_tzone_cdev(struct dirent *nl, char *tz_name,
                        return -EINVAL;
                }
                /* find the link to real cooling device record binding */
-               snprintf(cdev_name, 256, "%s/%s", tz_name, nl->d_name);
+               snprintf(cdev_name, sizeof(cdev_name) - 2, "%s/%s",
+                        tz_name, nl->d_name);
                memset(cdev_name_linked, 0, sizeof(cdev_name_linked));
                if (readlink(cdev_name, cdev_name_linked,
                                sizeof(cdev_name_linked) - 1) != -1) {
@@ -226,8 +228,8 @@ static int find_tzone_cdev(struct dirent *nl, char *tz_name,
                        /* find the trip point in which the cdev is binded to
                         * in this tzone
                         */
-                       snprintf(cdev_trip_name, 256, "%s%s", nl->d_name,
-                               "_trip_point");
+                       snprintf(cdev_trip_name, sizeof(cdev_trip_name) - 1,
+                               "%s%s", nl->d_name, "_trip_point");
                        sysfs_get_ulong(tz_name, cdev_trip_name,
                                        &trip_instance);
                        /* validate trip point range, e.g. trip could return -1