Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Apr 2016 01:03:33 +0000 (20:03 -0500)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Apr 2016 01:03:33 +0000 (20:03 -0500)
Pull networking fixes from David Miller:

 1) Missing device reference in IPSEC input path results in crashes
    during device unregistration.  From Subash Abhinov Kasiviswanathan.

 2) Per-queue ISR register writes not being done properly in macb
    driver, from Cyrille Pitchen.

 3) Stats accounting bugs in bcmgenet, from Patri Gynther.

 4) Lightweight tunnel's TTL and TOS were swapped in netlink dumps, from
    Quentin Armitage.

 5) SXGBE driver has off-by-one in probe error paths, from Rasmus
    Villemoes.

 6) Fix race in save/swap/delete options in netfilter ipset, from
    Vishwanath Pai.

 7) Ageing time of bridge not set properly when not operating over a
    switchdev device.  Fix from Haishuang Yan.

 8) Fix GRO regression wrt nested FOU/GUE based tunnels, from Alexander
    Duyck.

 9) IPV6 UDP code bumps wrong stats, from Eric Dumazet.

10) FEC driver should only access registers that actually exist on the
    given chipset, fix from Fabio Estevam.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (73 commits)
  net: mvneta: fix changing MTU when using per-cpu processing
  stmmac: fix MDIO settings
  Revert "stmmac: Fix 'eth0: No PHY found' regression"
  stmmac: fix TX normal DESC
  net: mvneta: use cache_line_size() to get cacheline size
  net: mvpp2: use cache_line_size() to get cacheline size
  net: mvpp2: fix maybe-uninitialized warning
  tun, bpf: fix suspicious RCU usage in tun_{attach, detach}_filter
  net: usb: cdc_ncm: adding Telit LE910 V2 mobile broadband card
  rtnl: fix msg size calculation in if_nlmsg_size()
  fec: Do not access unexisting register in Coldfire
  net: mvneta: replace MVNETA_CPU_D_CACHE_LINE_SIZE with L1_CACHE_BYTES
  net: mvpp2: replace MVPP2_CPU_D_CACHE_LINE_SIZE with L1_CACHE_BYTES
  net: dsa: mv88e6xxx: Clear the PDOWN bit on setup
  net: dsa: mv88e6xxx: Introduce _mv88e6xxx_phy_page_{read, write}
  bpf: make padding in bpf_tunnel_key explicit
  ipv6: udp: fix UDP_MIB_IGNOREDMULTI updates
  bnxt_en: Fix ethtool -a reporting.
  bnxt_en: Fix typo in bnxt_hwrm_set_pause_common().
  bnxt_en: Implement proper firmware message padding.
  ...

579 files changed:
.mailmap
Documentation/ABI/stable/sysfs-fs-orangefs [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/devicetree/bindings/mtd/atmel-nand.txt
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/rockchip-io-domain.txt
Documentation/devicetree/bindings/rtc/maxim,mcp795.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/dma-buf-sharing.txt
Documentation/filesystems/nfs/pnfs-scsi-server.txt [new file with mode: 0644]
Documentation/filesystems/orangefs.txt [new file with mode: 0644]
Documentation/kasan.txt
MAINTAINERS
Makefile
arch/arc/include/asm/page.h
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/at91-sama5d3_xplained.dts
arch/arm/boot/dts/at91-sama5d4_xplained.dts
arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts
arch/arm/boot/dts/imx25.dtsi
arch/arm/boot/dts/imx28-apf28dev.dts
arch/arm/boot/dts/imx28-eukrea-mbmx28lc.dtsi
arch/arm/boot/dts/imx28-tx28.dts
arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts
arch/arm/boot/dts/imx35.dtsi
arch/arm/boot/dts/imx51-babbage.dts
arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi
arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts
arch/arm/boot/dts/imx51-pinfunc.h
arch/arm/boot/dts/imx53-ard.dts
arch/arm/boot/dts/imx53-qsb-common.dtsi
arch/arm/boot/dts/imx53-tx53-x03x.dts
arch/arm/boot/dts/imx53-tx53-x13x.dts
arch/arm/boot/dts/imx53-tx53.dtsi
arch/arm/boot/dts/imx6dl-tx6u-811x.dts
arch/arm/boot/dts/imx6dl-wandboard-revb1.dts
arch/arm/boot/dts/imx6q-apalis-ixora.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6q-b450v3.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6q-b650v3.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6q-b850v3.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6q-ba16.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6q-bx50v3.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6q-evi.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6q-gk802.dts
arch/arm/boot/dts/imx6q-icore-rqs.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6q-tbs2910.dts
arch/arm/boot/dts/imx6q-tx6q-1110.dts
arch/arm/boot/dts/imx6q-wandboard-revb1.dts
arch/arm/boot/dts/imx6q.dtsi
arch/arm/boot/dts/imx6qdl-apalis.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
arch/arm/boot/dts/imx6qdl-gw552x.dtsi
arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-microsom.dtsi
arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
arch/arm/boot/dts/imx6qdl-sabresd.dtsi
arch/arm/boot/dts/imx6qdl-tx6.dtsi
arch/arm/boot/dts/imx6qdl-udoo.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/imx6qp-sabreauto.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6qp-sabresd.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6qp.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6sl-warp.dts
arch/arm/boot/dts/imx6sx-sabreauto.dts
arch/arm/boot/dts/imx6sx-sdb.dtsi
arch/arm/boot/dts/imx6ul-14x14-evk.dts
arch/arm/boot/dts/imx6ul-pinfunc.h
arch/arm/boot/dts/imx6ul.dtsi
arch/arm/boot/dts/imx7d-sbc-imx7.dts
arch/arm/boot/dts/imx7d-sdb.dts
arch/arm/boot/dts/imx7d.dtsi
arch/arm/boot/dts/ls1021a.dtsi
arch/arm/boot/dts/uniphier-common32.dtsi
arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts
arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts
arch/arm/boot/dts/uniphier-ph1-pro4-ace.dts [new file with mode: 0644]
arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts
arch/arm/boot/dts/uniphier-ph1-pro4-sanji.dts [new file with mode: 0644]
arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
arch/arm/boot/dts/uniphier-ph1-pro5.dtsi
arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts
arch/arm/boot/dts/uniphier-ph1-sld3.dtsi
arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts
arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
arch/arm/boot/dts/uniphier-pinctrl.dtsi
arch/arm/boot/dts/uniphier-proxstream2-gentil.dts
arch/arm/boot/dts/uniphier-proxstream2.dtsi
arch/arm/boot/dts/uniphier-ref-daughter.dtsi
arch/arm/boot/dts/uniphier-support-card.dtsi
arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
arch/arm/boot/dts/vf-colibri.dtsi
arch/arm/boot/dts/vf500-colibri-eval-v3.dts
arch/arm/boot/dts/vf500-colibri.dtsi
arch/arm/boot/dts/vf500.dtsi
arch/arm/boot/dts/vf610-colibri-eval-v3.dts
arch/arm/boot/dts/vf610-colibri.dtsi
arch/arm/boot/dts/vf610-twr.dts
arch/arm/boot/dts/vf610.dtsi
arch/arm/boot/dts/vfxxx.dtsi
arch/arm/include/asm/exception.h
arch/arm/include/asm/page-nommu.h
arch/arm/kernel/vmlinux.lds.S
arch/arm/plat-samsung/devs.c
arch/arm64/boot/dts/socionext/Makefile
arch/arm64/boot/dts/socionext/uniphier-ph1-ld10-ref.dts [deleted file]
arch/arm64/boot/dts/socionext/uniphier-ph1-ld10.dtsi [deleted file]
arch/arm64/boot/dts/socionext/uniphier-ph1-ld20-ref.dts [new file with mode: 0644]
arch/arm64/boot/dts/socionext/uniphier-ph1-ld20.dtsi [new file with mode: 0644]
arch/arm64/configs/defconfig
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/exception.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_hyp.h
arch/arm64/include/asm/kvm_perf_event.h [deleted file]
arch/arm64/include/asm/opcodes.h
arch/arm64/include/asm/perf_event.h
arch/arm64/kernel/entry.S
arch/arm64/kernel/head.S
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/mm/flush.c
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c
arch/blackfin/kernel/vmlinux.lds.S
arch/c6x/kernel/vmlinux.lds.S
arch/frv/include/asm/page.h
arch/h8300/boot/dts/edosk2674.dts
arch/h8300/boot/dts/h8300h_sim.dts
arch/h8300/boot/dts/h8s_sim.dts
arch/h8300/configs/h8300h-sim_defconfig
arch/h8300/kernel/setup.c
arch/h8300/kernel/sim-console.c
arch/ia64/include/asm/unistd.h
arch/ia64/include/uapi/asm/unistd.h
arch/ia64/kernel/entry.S
arch/m68k/include/asm/page_mm.h
arch/m68k/include/asm/page_no.h
arch/metag/kernel/vmlinux.lds.S
arch/microblaze/kernel/vmlinux.lds.S
arch/mips/include/asm/mach-jz4740/jz4740_nand.h
arch/mips/kernel/vmlinux.lds.S
arch/nios2/kernel/prom.c
arch/nios2/kernel/vmlinux.lds.S
arch/openrisc/include/asm/page.h
arch/openrisc/kernel/vmlinux.lds.S
arch/parisc/Kconfig
arch/parisc/include/asm/assembly.h
arch/parisc/include/asm/compat.h
arch/parisc/include/asm/syscall.h
arch/parisc/include/asm/uaccess.h
arch/parisc/include/uapi/asm/unistd.h
arch/parisc/kernel/ptrace.c
arch/parisc/kernel/signal32.c
arch/parisc/kernel/sys_parisc.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/syscall_table.S
arch/parisc/kernel/traps.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/mm/fault.c
arch/powerpc/include/asm/processor.h
arch/powerpc/kernel/process.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/mm/hugetlbpage.c
arch/s390/Kconfig
arch/s390/crypto/prng.c
arch/s390/include/asm/cache.h
arch/s390/include/uapi/asm/unistd.h
arch/s390/kernel/perf_cpum_cf.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/gup.c
arch/s390/mm/init.c
arch/s390/pci/pci_clp.c
arch/sh/kernel/vmlinux.lds.S
arch/sparc/include/asm/compat_signal.h
arch/sparc/include/asm/obio.h
arch/sparc/include/asm/openprom.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/processor_64.h
arch/sparc/include/asm/sigcontext.h
arch/sparc/include/asm/tsb.h
arch/sparc/include/uapi/asm/stat.h
arch/sparc/kernel/audit.c
arch/sparc/kernel/compat_audit.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/ioport.c
arch/sparc/kernel/kernel.h
arch/sparc/kernel/leon_kernel.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/setup_32.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/signal32.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/sysfs.c
arch/sparc/kernel/unaligned_64.c
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/mm/fault_32.c
arch/sparc/net/bpf_jit_comp.c
arch/tile/include/hv/drv_mpipe_intf.h
arch/tile/kernel/kgdb.c
arch/tile/kernel/pci_gx.c
arch/tile/kernel/vmlinux.lds.S
arch/x86/include/asm/pmem.h
arch/x86/include/asm/tlbflush.h
arch/x86/kernel/Makefile
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/mm/tlb.c
block/blk-mq-sysfs.c
block/blk-mq.c
crypto/asymmetric_keys/pkcs7_trust.c
drivers/acpi/acpi_apd.c
drivers/acpi/acpi_processor.c
drivers/acpi/bus.c
drivers/acpi/internal.h
drivers/acpi/property.c
drivers/acpi/resource.c
drivers/acpi/sleep.c
drivers/acpi/utils.c
drivers/base/power/clock_ops.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/null_blk.c
drivers/block/rbd.c
drivers/char/ppdev.c
drivers/clk/mediatek/reset.c
drivers/clk/mmp/reset.c
drivers/clk/qcom/gcc-ipq4019.c
drivers/clk/qcom/reset.c
drivers/clk/qcom/reset.h
drivers/clk/rockchip/softrst.c
drivers/clk/sirf/clk-atlas7.c
drivers/clk/sunxi/clk-a10-ve.c
drivers/clk/sunxi/clk-sun9i-mmc.c
drivers/clk/sunxi/clk-usb.c
drivers/clk/tegra/clk.c
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpuidle/governors/menu.c
drivers/devfreq/Kconfig
drivers/dma-buf/dma-buf.c
drivers/dma/idma64.h
drivers/firewire/nosy.c
drivers/gpio/gpio-menz127.c
drivers/gpio/gpio-xgene.c
drivers/gpu/drm/amd/acp/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/powerplay/Makefile
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/i915/i915_gem_dmabuf.c
drivers/gpu/drm/msm/hdmi/hdmi.h
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_kms.h
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
drivers/gpu/drm/radeon/radeon_dp_mst.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/udl/udl_gem.c
drivers/hwmon/max1111.c
drivers/ide/icside.c
drivers/ide/palm_bk3710.c
drivers/idle/intel_idle.c
drivers/input/input-compat.c
drivers/input/input-compat.h
drivers/input/input.c
drivers/input/misc/ati_remote2.c
drivers/input/misc/ims-pcu.c
drivers/input/misc/uinput.c
drivers/input/mouse/byd.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/synaptics.c
drivers/input/rmi4/rmi_driver.c
drivers/input/touchscreen/melfas_mip4.c
drivers/input/touchscreen/sur40.c
drivers/lightnvm/core.c
drivers/lightnvm/gennvm.c
drivers/lightnvm/gennvm.h
drivers/lightnvm/rrpc.c
drivers/lightnvm/rrpc.h
drivers/memory/fsl_ifc.c
drivers/memstick/host/r592.c
drivers/mtd/Kconfig
drivers/mtd/bcm47xxpart.c
drivers/mtd/bcm63xxpart.c
drivers/mtd/devices/docg3.c
drivers/mtd/devices/mtdram.c
drivers/mtd/mtdpart.c
drivers/mtd/mtdswap.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/atmel_nand_ecc.h
drivers/mtd/nand/atmel_nand_nfc.h
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/hisi504_nand.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_bch.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/qcom_nandc.c [new file with mode: 0644]
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/vf610_nfc.c
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/onenand_bbt.c
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/mtk-quadspi.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/tests/oobtest.c
drivers/mtd/ubi/misc.c
drivers/mtd/ubi/ubi.h
drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
drivers/net/ethernet/netronome/nfp/nfp_net.h
drivers/ntb/hw/amd/ntb_hw_amd.c
drivers/ntb/ntb_transport.c
drivers/ntb/test/ntb_perf.c
drivers/nvdimm/pmem.c
drivers/nvme/host/lightnvm.c
drivers/nvme/host/pci.c
drivers/power/avs/rockchip-io-domain.c
drivers/rtc/Kconfig
drivers/rtc/rtc-abx80x.c
drivers/rtc/rtc-asm9260.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-mcp795.c
drivers/rtc/rtc-rv8803.c
drivers/rtc/rtc-s3c.c
drivers/s390/block/dasd_alias.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_int.h
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/scsi_common.c
drivers/scsi/scsi_sas_internal.h
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/ufs/Kconfig
drivers/scsi/ufs/ufs-qcom.c
drivers/scsi/ufs/ufs-qcom.h
drivers/scsi/ufs/ufs.h
drivers/scsi/ufs/ufs_quirks.h [new file with mode: 0644]
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/scsi/ufs/ufshci.h
drivers/scsi/ufs/unipro.h
drivers/staging/android/ion/ion.c
drivers/staging/mt29f_spinand/mt29f_spinand.c
drivers/staging/mt29f_spinand/mt29f_spinand.h
fs/Kconfig
fs/Makefile
fs/btrfs/disk-io.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/crypto/crypto.c
fs/dlm/config.c
fs/fs-writeback.c
fs/jffs2/gc.c
fs/jffs2/jffs2_fs_sb.h
fs/jffs2/nodemgmt.c
fs/jffs2/wbuf.c
fs/namei.c
fs/nfs/blocklayout/blocklayout.c
fs/nfs/blocklayout/blocklayout.h
fs/nfs/blocklayout/dev.c
fs/nfs/blocklayout/extent_tree.c
fs/nfs/blocklayout/rpc_pipefs.c
fs/nfsd/Kconfig
fs/nfsd/Makefile
fs/nfsd/blocklayout.c
fs/nfsd/blocklayoutxdr.c
fs/nfsd/blocklayoutxdr.h
fs/nfsd/nfs3proc.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4xdr.c
fs/nfsd/pnfs.h
fs/nfsd/vfs.h
fs/ocfs2/alloc.c
fs/ocfs2/aops.c
fs/ocfs2/aops.h
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/dlm/dlmconvert.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/file.c
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/journal.c
fs/ocfs2/localalloc.c
fs/ocfs2/mmap.c
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_trace.h
fs/ocfs2/quota_global.c
fs/ocfs2/resize.c
fs/ocfs2/super.c
fs/ocfs2/super.h
fs/orangefs/Kconfig [new file with mode: 0644]
fs/orangefs/Makefile [new file with mode: 0644]
fs/orangefs/acl.c [new file with mode: 0644]
fs/orangefs/dcache.c [new file with mode: 0644]
fs/orangefs/devorangefs-req.c [new file with mode: 0644]
fs/orangefs/dir.c [new file with mode: 0644]
fs/orangefs/downcall.h [new file with mode: 0644]
fs/orangefs/file.c [new file with mode: 0644]
fs/orangefs/inode.c [new file with mode: 0644]
fs/orangefs/namei.c [new file with mode: 0644]
fs/orangefs/orangefs-bufmap.c [new file with mode: 0644]
fs/orangefs/orangefs-bufmap.h [new file with mode: 0644]
fs/orangefs/orangefs-cache.c [new file with mode: 0644]
fs/orangefs/orangefs-debug.h [new file with mode: 0644]
fs/orangefs/orangefs-debugfs.c [new file with mode: 0644]
fs/orangefs/orangefs-debugfs.h [new file with mode: 0644]
fs/orangefs/orangefs-dev-proto.h [new file with mode: 0644]
fs/orangefs/orangefs-kernel.h [new file with mode: 0644]
fs/orangefs/orangefs-mod.c [new file with mode: 0644]
fs/orangefs/orangefs-sysfs.c [new file with mode: 0644]
fs/orangefs/orangefs-sysfs.h [new file with mode: 0644]
fs/orangefs/orangefs-utils.c [new file with mode: 0644]
fs/orangefs/protocol.h [new file with mode: 0644]
fs/orangefs/super.c [new file with mode: 0644]
fs/orangefs/symlink.c [new file with mode: 0644]
fs/orangefs/upcall.h [new file with mode: 0644]
fs/orangefs/waitqueue.c [new file with mode: 0644]
fs/orangefs/xattr.c [new file with mode: 0644]
fs/ubifs/Makefile
fs/ubifs/misc.c [new file with mode: 0644]
fs/ubifs/ubifs.h
fs/ubifs/xattr.c
fs/xfs/Makefile
fs/xfs/xfs_export.c
fs/xfs/xfs_pnfs.h
include/asm-generic/bug.h
include/asm-generic/io-64-nonatomic-hi-lo.h [deleted file]
include/asm-generic/io-64-nonatomic-lo-hi.h [deleted file]
include/asm-generic/page.h
include/asm-generic/vmlinux.lds.h
include/linux/blk-mq.h
include/linux/ceph/ceph_features.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/libceph.h
include/linux/ceph/mon_client.h
include/linux/ceph/osd_client.h
include/linux/compiler-clang.h
include/linux/dma-buf.h
include/linux/fence.h
include/linux/ftrace.h
include/linux/huge_mm.h
include/linux/interrupt.h
include/linux/kasan.h
include/linux/lightnvm.h
include/linux/mm.h
include/linux/mtd/bbm.h
include/linux/mtd/inftl.h
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/nand_bch.h
include/linux/mtd/nftl.h
include/linux/mtd/spi-nor.h
include/linux/nfs4.h
include/linux/ntb.h
include/linux/oom.h
include/linux/platform_data/mtd-nand-s3c2410.h
include/linux/pm_clock.h
include/linux/pmem.h
include/linux/sched.h
include/linux/slab.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/stackdepot.h [new file with mode: 0644]
include/scsi/scsi_transport_fc.h
include/trace/events/page_isolation.h
init/Kconfig
kernel/exit.c
kernel/power/hibernate.c
kernel/softirq.c
kernel/time/timer.c
kernel/trace/trace_functions_graph.c
lib/Kconfig
lib/Kconfig.debug
lib/Kconfig.kasan
lib/Makefile
lib/stackdepot.c [new file with mode: 0644]
lib/test_kasan.c
mm/Makefile
mm/filemap.c
mm/huge_memory.c
mm/internal.h
mm/kasan/kasan.c
mm/kasan/kasan.h
mm/kasan/report.c
mm/memory.c
mm/mempool.c
mm/oom_kill.c
mm/page_alloc.c
mm/page_isolation.c
mm/rmap.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slub.c
net/ceph/ceph_common.c
net/ceph/debugfs.c
net/ceph/messenger.c
net/ceph/mon_client.c
net/ceph/osd_client.c
scripts/Kbuild.include
scripts/Makefile.dtbinst
scripts/basic/fixdep.c
scripts/coccinelle/api/pm_runtime.cocci
scripts/coccinelle/api/setup_timer.cocci [new file with mode: 0644]
scripts/coccinelle/iterators/use_after_iter.cocci
scripts/coccinelle/misc/array_size.cocci
scripts/coccinelle/misc/badty.cocci
scripts/coccinelle/misc/bugon.cocci
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/link-vmlinux.sh
scripts/package/mkspec
scripts/sortextable.c
scripts/tags.sh
sound/core/timer.c
sound/core/timer_compat.c
sound/firewire/dice/dice-stream.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/usb/quirks.c
sound/usb/stream.c

index 7e6c533..90c0aef 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -33,6 +33,7 @@ Björn Steinbrink <B.Steinbrink@gmx.de>
 Brian Avery <b.avery@hp.com>
 Brian King <brking@us.ibm.com>
 Christoph Hellwig <hch@lst.de>
+Christophe Ricard <christophe.ricard@gmail.com>
 Corey Minyard <minyard@acm.org>
 Damian Hobson-Garcia <dhobsong@igel.co.jp>
 David Brownell <david-b@pacbell.net>
diff --git a/Documentation/ABI/stable/sysfs-fs-orangefs b/Documentation/ABI/stable/sysfs-fs-orangefs
new file mode 100644 (file)
index 0000000..affdb11
--- /dev/null
@@ -0,0 +1,87 @@
+What:                  /sys/fs/orangefs/perf_counters/*
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       Counters and settings for various caches.
+                       Read only.
+
+
+What:                  /sys/fs/orangefs/perf_counter_reset
+Date:                  June 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       echo a 0 or a 1 into perf_counter_reset to
+                       reset all the counters in
+                       /sys/fs/orangefs/perf_counters
+                       except ones with PINT_PERF_PRESERVE set.
+
+
+What:                  /sys/fs/orangefs/perf_time_interval_secs
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       Length of perf counter intervals in
+                       seconds.
+
+
+What:                  /sys/fs/orangefs/perf_history_size
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       The perf_counters cache statistics have N, or
+                       perf_history_size, samples. The default is
+                       one.
+
+                       Every perf_time_interval_secs the (first)
+                       samples are reset.
+
+                       If N is greater than one, the "current" set
+                       of samples is reset, and the samples from the
+                       other N-1 intervals remain available.
+
+
+What:                  /sys/fs/orangefs/op_timeout_secs
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       Service operation timeout in seconds.
+
+
+What:                  /sys/fs/orangefs/slot_timeout_secs
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       "Slot" timeout in seconds. A "slot"
+                       is an indexed buffer in the shared
+                       memory segment used for communication
+                       between the kernel module and userspace.
+                       Slots are requested and waited for,
+                       the wait times out after slot_timeout_secs.
+
+
+What:                  /sys/fs/orangefs/acache/*
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       Attribute cache configurable settings.
+
+
+What:                  /sys/fs/orangefs/ncache/*
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       Name cache configurable settings.
+
+
+What:                  /sys/fs/orangefs/capcache/*
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       Capability cache configurable settings.
+
+
+What:                  /sys/fs/orangefs/ccache/*
+Date:                  Jun 2015
+Contact:               Mike Marshall <hubcap@omnibond.com>
+Description:
+                       Credential cache configurable settings.
index b683e8e..1650133 100644 (file)
@@ -271,3 +271,72 @@ Description:       Parameters for the CPU cache attributes
                        - WriteBack: data is written only to the cache line and
                                     the modified cache line is written to main
                                     memory only when it is replaced
+
+What:          /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats
+               /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/turbo_stat
+               /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/sub_turbo_stat
+               /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/unthrottle
+               /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/powercap
+               /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/overtemp
+               /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/supply_fault
+               /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/overcurrent
+               /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/occ_reset
+Date:          March 2016
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+               Linux for PowerPC mailing list <linuxppc-dev@ozlabs.org>
+Description:   POWERNV CPUFreq driver's frequency throttle stats directory and
+               attributes
+
+               'cpuX/cpufreq/throttle_stats' directory contains the CPU frequency
+               throttle stat attributes for the chip. The throttle stats of a cpu
+               is common across all the cpus belonging to a chip. Below are the
+               throttle attributes exported in the 'throttle_stats' directory:
+
+               - turbo_stat : This file gives the total number of times the max
+               frequency is throttled to lower frequency in turbo (at and above
+               nominal frequency) range of frequencies.
+
+               - sub_turbo_stat : This file gives the total number of times the
+               max frequency is throttled to lower frequency in sub-turbo(below
+               nominal frequency) range of frequencies.
+
+               - unthrottle : This file gives the total number of times the max
+               frequency is unthrottled after being throttled.
+
+               - powercap : This file gives the total number of times the max
+               frequency is throttled due to 'Power Capping'.
+
+               - overtemp : This file gives the total number of times the max
+               frequency is throttled due to 'CPU Over Temperature'.
+
+               - supply_fault : This file gives the total number of times the
+               max frequency is throttled due to 'Power Supply Failure'.
+
+               - overcurrent : This file gives the total number of times the
+               max frequency is throttled due to 'Overcurrent'.
+
+               - occ_reset : This file gives the total number of times the max
+               frequency is throttled due to 'OCC Reset'.
+
+               The sysfs attributes representing different throttle reasons like
+               powercap, overtemp, supply_fault, overcurrent and occ_reset map to
+               the reasons provided by OCC firmware for throttling the frequency.
+
+What:          /sys/devices/system/cpu/cpufreq/policyX/throttle_stats
+               /sys/devices/system/cpu/cpufreq/policyX/throttle_stats/turbo_stat
+               /sys/devices/system/cpu/cpufreq/policyX/throttle_stats/sub_turbo_stat
+               /sys/devices/system/cpu/cpufreq/policyX/throttle_stats/unthrottle
+               /sys/devices/system/cpu/cpufreq/policyX/throttle_stats/powercap
+               /sys/devices/system/cpu/cpufreq/policyX/throttle_stats/overtemp
+               /sys/devices/system/cpu/cpufreq/policyX/throttle_stats/supply_fault
+               /sys/devices/system/cpu/cpufreq/policyX/throttle_stats/overcurrent
+               /sys/devices/system/cpu/cpufreq/policyX/throttle_stats/occ_reset
+Date:          March 2016
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+               Linux for PowerPC mailing list <linuxppc-dev@ozlabs.org>
+Description:   POWERNV CPUFreq driver's frequency throttle stats directory and
+               attributes
+
+               'policyX/throttle_stats' directory and all the attributes are same as
+               the /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats directory and
+               attributes which give the frequency throttle information of the chip.
index 7d4c8eb..d53aba9 100644 (file)
@@ -1,7 +1,10 @@
 Atmel NAND flash
 
 Required properties:
-- compatible : should be "atmel,at91rm9200-nand" or "atmel,sama5d4-nand".
+- compatible: The possible values are:
+       "atmel,at91rm9200-nand"
+       "atmel,sama5d2-nand"
+       "atmel,sama5d4-nand"
 - reg : should specify localbus address and size used for the chip,
        and hardware ECC controller if available.
        If the hardware ECC is PMECC, it should contain address and size for
@@ -21,10 +24,11 @@ Optional properties:
 - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
   "soft_bch".
-- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware.
-  Only supported by at91sam9x5 or later sam9 product.
+- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware,
+  capable of BCH encoding and decoding, on devices where it is present.
 - atmel,pmecc-cap : error correct capability for Programmable Multibit ECC
-  Controller. Supported values are: 2, 4, 8, 12, 24.
+  Controller. Supported values are: 2, 4, 8, 12, 24. If the compatible string
+  is "atmel,sama5d2-nand", 32 is also valid.
 - atmel,pmecc-sector-size : sector size for ECC computation. Supported values
   are: 512, 1024.
 - atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM
@@ -32,15 +36,16 @@ Optional properties:
   sector size 1024. If not specified, driver will build the table in runtime.
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
-- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
-  - Required properties:
-    - compatible : "atmel,sama5d3-nfc".
-    - reg : should specify the address and size used for NFC command registers,
-            NFC registers and NFC Sram. NFC Sram address and size can be absent
-            if don't want to use it.
-    - clocks: phandle to the peripheral clock
-  - Optional properties:
-    - atmel,write-by-sram: boolean to enable NFC write by sram.
+
+Nand Flash Controller(NFC) is an optional sub-node
+Required properties:
+- compatible : "atmel,sama5d3-nfc" or "atmel,sama5d4-nfc".
+- reg : should specify the address and size used for NFC command registers,
+        NFC registers and NFC SRAM. NFC SRAM address and size can be absent
+        if don't want to use it.
+- clocks: phandle to the peripheral clock
+Optional properties:
+- atmel,write-by-sram: boolean to enable NFC write by SRAM.
 
 Examples:
 nand0: nand@40000000,0 {
index 00c587b..0333ec8 100644 (file)
@@ -3,7 +3,9 @@
 Required properties:
   - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi",
                 "fsl,imx7d-qspi", "fsl,imx6ul-qspi",
-                "fsl,ls1021-qspi"
+                "fsl,ls1021a-qspi"
+                or
+                "fsl,ls2080a-qspi" followed by "fsl,ls1021a-qspi"
   - reg : the first contains the register location and length,
           the second contains the memory mapping address and length
   - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
@@ -19,6 +21,7 @@ Optional properties:
                              But if there are two NOR flashes connected to the
                              bus, you should enable this property.
                              (Please check the board's schematic.)
+  - big-endian : That means the IP register is big endian
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
new file mode 100644 (file)
index 0000000..70dd511
--- /dev/null
@@ -0,0 +1,86 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:          should be "qcom,ipq806x-nand"
+- reg:                 MMIO address range
+- clocks:              must contain core clock and always on clock
+- clock-names:         must contain "core" for the core clock and "aon" for the
+                       always on clock
+- dmas:                        DMA specifier, consisting of a phandle to the ADM DMA
+                       controller node and the channel number to be used for
+                       NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:           must be "rxtx"
+- qcom,cmd-crci:       must contain the ADM command type CRCI block instance
+                       number specified for the NAND controller on the given
+                       platform
+- qcom,data-crci:      must contain the ADM data type CRCI block instance
+                       number specified for the NAND controller on the given
+                       platform
+- #address-cells:      <1> - subnodes give the chip-select number
+- #size-cells:         <0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:          should contain "qcom,nandcs"
+- reg:                 a single integer representing the chip-select
+                       number (e.g., 0, 1, 2, etc.)
+- #address-cells:      see partition.txt
+- #size-cells:         see partition.txt
+- nand-ecc-strength:   see nand.txt
+- nand-ecc-step-size:  must be 512. see nand.txt for more details.
+
+Optional properties:
+- nand-bus-width:      see nand.txt
+
+Each nandcs device node may optionally contain a 'partitions' sub-node, which
+further contains sub-nodes describing the flash partition mapping. See
+partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+       compatible = "qcom,ebi2-nandc";
+       reg = <0x1ac00000 0x800>;
+
+       clocks = <&gcc EBI2_CLK>,
+                <&gcc EBI2_AON_CLK>;
+       clock-names = "core", "aon";
+
+       dmas = <&adm_dma 3>;
+       dma-names = "rxtx";
+       qcom,cmd-crci = <15>;
+       qcom,data-crci = <3>;
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       nandcs@0 {
+               compatible = "qcom,nandcs";
+               reg = <0>;
+
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "boot-nand";
+                               reg = <0 0x58a0000>;
+                       };
+
+                       partition@58a0000 {
+                               label = "fs-nand";
+                               reg = <0x58a0000 0x4000000>;
+                       };
+               };
+       };
+};
index b8627e7..c84fb47 100644 (file)
@@ -35,6 +35,8 @@ Required properties:
   - "rockchip,rk3288-io-voltage-domain" for rk3288
   - "rockchip,rk3368-io-voltage-domain" for rk3368
   - "rockchip,rk3368-pmu-io-voltage-domain" for rk3368 pmu-domains
+  - "rockchip,rk3399-io-voltage-domain" for rk3399
+  - "rockchip,rk3399-pmu-io-voltage-domain" for rk3399 pmu-domains
 - rockchip,grf: phandle to the syscon managing the "general register files"
 
 
@@ -79,6 +81,15 @@ Possible supplies for rk3368 pmu-domains:
 - pmu-supply:    The supply connected to PMUIO_VDD.
 - vop-supply:    The supply connected to LCDC_VDD.
 
+Possible supplies for rk3399:
+- bt656-supply:  The supply connected to APIO2_VDD.
+- audio-supply:  The supply connected to APIO5_VDD.
+- sdmmc-supply:  The supply connected to SDMMC0_VDD.
+- gpio1830       The supply connected to APIO4_VDD.
+
+Possible supplies for rk3399 pmu-domains:
+- pmu1830-supply:The supply connected to PMUIO2_VDD.
+
 Example:
 
        io-domains {
diff --git a/Documentation/devicetree/bindings/rtc/maxim,mcp795.txt b/Documentation/devicetree/bindings/rtc/maxim,mcp795.txt
new file mode 100644 (file)
index 0000000..a59fdd8
--- /dev/null
@@ -0,0 +1,11 @@
+* Maxim MCP795         SPI Serial Real-Time Clock
+
+Required properties:
+- compatible: Should contain "maxim,mcp795".
+- reg: SPI address for chip
+
+Example:
+       mcp795: rtc@0 {
+               compatible = "maxim,mcp795";
+               reg = <0>;
+       };
index 03c0e98..66f6adf 100644 (file)
@@ -38,6 +38,9 @@ Optional properties:
                          defined or a value in the array is "0" then it is assumed
                          that the frequency is set by the parent clock or a
                          fixed rate clock source.
+-lanes-per-direction   : number of lanes available per direction - either 1 or 2.
+                         Note that it is assume same number of lanes is used both
+                         directions at once. If not specified, default is 2 lanes per direction.
 
 Note: If above properties are not defined it can be assumed that the supply
 regulators or clocks are always on.
index 42adb41..86740d4 100644 (file)
@@ -10,6 +10,7 @@ ad    Avionic Design GmbH
 adapteva       Adapteva, Inc.
 adh    AD Holdings Plc.
 adi    Analog Devices, Inc.
+advantech      Advantech Corporation
 aeroflexgaisler        Aeroflex Gaisler AB
 al     Annapurna Labs
 allwinner      Allwinner Technology Co., Ltd.
@@ -89,6 +90,7 @@ fcs   Fairchild Semiconductor
 firefly        Firefly
 focaltech      FocalTech Systems Co.,Ltd
 fsl    Freescale Semiconductor
+ge     General Electric Company
 GEFanuc        GE Fanuc Intelligent Platforms Embedded Systems, Inc.
 gef    GE Fanuc Intelligent Platforms Embedded Systems, Inc.
 geniatech      Geniatech, Inc.
index 32ac32e..ca44c58 100644 (file)
@@ -352,7 +352,8 @@ Being able to mmap an export dma-buf buffer object has 2 main use-cases:
 
    No special interfaces, userspace simply calls mmap on the dma-buf fd, making
    sure that the cache synchronization ioctl (DMA_BUF_IOCTL_SYNC) is *always*
-   used when the access happens. This is discussed next paragraphs.
+   used when the access happens. Note that DMA_BUF_IOCTL_SYNC can fail with
+   -EAGAIN or -EINTR, in which case it must be restarted.
 
    Some systems might need some sort of cache coherency management e.g. when
    CPU and GPU domains are being accessed through dma-buf at the same time. To
@@ -366,10 +367,10 @@ Being able to mmap an export dma-buf buffer object has 2 main use-cases:
        want (with the new data being consumed by the GPU or say scanout device)
      - munmap once you don't need the buffer any more
 
-    Therefore, for correctness and optimal performance, systems with the memory
-    cache shared by the GPU and CPU i.e. the "coherent" and also the
-    "incoherent" are always required to use SYNC_START and SYNC_END before and
-    after, respectively, when accessing the mapped address.
+    For correctness and optimal performance, it is always required to use
+    SYNC_START and SYNC_END before and after, respectively, when accessing the
+    mapped address. Userspace cannot rely on coherent access, even when there
+    are systems where it just works without calling these ioctls.
 
 2. Supporting existing mmap interfaces in importers
 
diff --git a/Documentation/filesystems/nfs/pnfs-scsi-server.txt b/Documentation/filesystems/nfs/pnfs-scsi-server.txt
new file mode 100644 (file)
index 0000000..5bef726
--- /dev/null
@@ -0,0 +1,23 @@
+
+pNFS SCSI layout server user guide
+==================================
+
+This document describes support for pNFS SCSI layouts in the Linux NFS server.
+With pNFS SCSI layouts, the NFS server acts as Metadata Server (MDS) for pNFS,
+which in addition to handling all the metadata access to the NFS export,
+also hands out layouts to the clients so that they can directly access the
+underlying SCSI LUNs that are shared with the client.
+
+To use pNFS SCSI layouts with with the Linux NFS server, the exported file
+system needs to support the pNFS SCSI layouts (currently just XFS), and the
+file system must sit on a SCSI LUN that is accessible to the clients in
+addition to the MDS.  As of now the file system needs to sit directly on the
+exported LUN, striping or concatenation of LUNs on the MDS and clients
+is not supported yet.
+
+On a server built with CONFIG_NFSD_SCSI, the pNFS SCSI volume support is
+automatically enabled if the file system is exported using the "pnfs"
+option and the underlying SCSI device support persistent reservations.
+On the client make sure the kernel has the CONFIG_PNFS_BLOCK option
+enabled, and the file system is mounted using the NFSv4.1 protocol
+version (mount -o vers=4.1).
diff --git a/Documentation/filesystems/orangefs.txt b/Documentation/filesystems/orangefs.txt
new file mode 100644 (file)
index 0000000..e1a0056
--- /dev/null
@@ -0,0 +1,406 @@
+ORANGEFS
+========
+
+OrangeFS is an LGPL userspace scale-out parallel storage system. It is ideal
+for large storage problems faced by HPC, BigData, Streaming Video,
+Genomics, Bioinformatics.
+
+Orangefs, originally called PVFS, was first developed in 1993 by
+Walt Ligon and Eric Blumer as a parallel file system for Parallel
+Virtual Machine (PVM) as part of a NASA grant to study the I/O patterns
+of parallel programs.
+
+Orangefs features include:
+
+  * Distributes file data among multiple file servers
+  * Supports simultaneous access by multiple clients
+  * Stores file data and metadata on servers using local file system
+    and access methods
+  * Userspace implementation is easy to install and maintain
+  * Direct MPI support
+  * Stateless
+
+
+MAILING LIST
+============
+
+http://beowulf-underground.org/mailman/listinfo/pvfs2-users
+
+
+DOCUMENTATION
+=============
+
+http://www.orangefs.org/documentation/
+
+
+USERSPACE FILESYSTEM SOURCE
+===========================
+
+http://www.orangefs.org/download
+
+Orangefs versions prior to 2.9.3 would not be compatible with the
+upstream version of the kernel client.
+
+
+BUILDING THE USERSPACE FILESYSTEM ON A SINGLE SERVER
+====================================================
+
+When Orangefs is upstream, "--with-kernel" shouldn't be needed, but
+until then the path to where the kernel with the Orangefs kernel client
+patch was built is needed to ensure that pvfs2-client-core (the bridge
+between kernel space and user space) will build properly. You can omit
+--prefix if you don't care that things are sprinkled around in
+/usr/local.
+
+./configure --prefix=/opt/ofs --with-kernel=/path/to/orangefs/kernel
+
+make
+
+make install
+
+Create an orangefs config file:
+/opt/ofs/bin/pvfs2-genconfig /etc/pvfs2.conf
+
+  for "Enter hostnames", use the hostname, don't let it default to
+  localhost.
+
+create a pvfs2tab file in /etc:
+cat /etc/pvfs2tab
+tcp://myhostname:3334/orangefs /mymountpoint pvfs2 defaults,noauto 0 0
+
+create the mount point you specified in the tab file if needed:
+mkdir /mymountpoint
+
+bootstrap the server:
+/opt/ofs/sbin/pvfs2-server /etc/pvfs2.conf -f
+
+start the server:
+/opt/osf/sbin/pvfs2-server /etc/pvfs2.conf
+
+Now the server is running. At this point you might like to
+prove things are working with:
+
+/opt/osf/bin/pvfs2-ls /mymountpoint
+
+You might not want to enforce selinux, it doesn't seem to matter by
+linux 3.11...
+
+If stuff seems to be working, turn on the client core:
+/opt/osf/sbin/pvfs2-client -p /opt/osf/sbin/pvfs2-client-core
+
+Mount your filesystem.
+mount -t pvfs2 tcp://myhostname:3334/orangefs /mymountpoint
+
+
+OPTIONS
+=======
+
+The following mount options are accepted:
+
+  acl
+    Allow the use of Access Control Lists on files and directories.
+
+  intr
+    Some operations between the kernel client and the user space
+    filesystem can be interruptible, such as changes in debug levels
+    and the setting of tunable parameters.
+
+  local_lock
+    Enable posix locking from the perspective of "this" kernel. The
+    default file_operations lock action is to return ENOSYS. Posix
+    locking kicks in if the filesystem is mounted with -o local_lock.
+    Distributed locking is being worked on for the future.
+
+
+DEBUGGING
+=========
+
+If you want the debug (GOSSIP) statements in a particular
+source file (inode.c for example) go to syslog:
+
+  echo inode > /sys/kernel/debug/orangefs/kernel-debug
+
+No debugging (the default):
+
+  echo none > /sys/kernel/debug/orangefs/kernel-debug
+
+Debugging from several source files:
+
+  echo inode,dir > /sys/kernel/debug/orangefs/kernel-debug
+
+All debugging:
+
+  echo all > /sys/kernel/debug/orangefs/kernel-debug
+
+Get a list of all debugging keywords:
+
+  cat /sys/kernel/debug/orangefs/debug-help
+
+
+PROTOCOL BETWEEN KERNEL MODULE AND USERSPACE
+============================================
+
+Orangefs is a user space filesystem and an associated kernel module.
+We'll just refer to the user space part of Orangefs as "userspace"
+from here on out. Orangefs descends from PVFS, and userspace code
+still uses PVFS for function and variable names. Userspace typedefs
+many of the important structures. Function and variable names in
+the kernel module have been transitioned to "orangefs", and The Linux
+Coding Style avoids typedefs, so kernel module structures that
+correspond to userspace structures are not typedefed.
+
+The kernel module implements a pseudo device that userspace
+can read from and write to. Userspace can also manipulate the
+kernel module through the pseudo device with ioctl.
+
+THE BUFMAP:
+
+At startup userspace allocates two page-size-aligned (posix_memalign)
+mlocked memory buffers, one is used for IO and one is used for readdir
+operations. The IO buffer is 41943040 bytes and the readdir buffer is
+4194304 bytes. Each buffer contains logical chunks, or partitions, and
+a pointer to each buffer is added to its own PVFS_dev_map_desc structure
+which also describes its total size, as well as the size and number of
+the partitions.
+
+A pointer to the IO buffer's PVFS_dev_map_desc structure is sent to a
+mapping routine in the kernel module with an ioctl. The structure is
+copied from user space to kernel space with copy_from_user and is used
+to initialize the kernel module's "bufmap" (struct orangefs_bufmap), which
+then contains:
+
+  * refcnt - a reference counter
+  * desc_size - PVFS2_BUFMAP_DEFAULT_DESC_SIZE (4194304) - the IO buffer's
+    partition size, which represents the filesystem's block size and
+    is used for s_blocksize in super blocks.
+  * desc_count - PVFS2_BUFMAP_DEFAULT_DESC_COUNT (10) - the number of
+    partitions in the IO buffer.
+  * desc_shift - log2(desc_size), used for s_blocksize_bits in super blocks.
+  * total_size - the total size of the IO buffer.
+  * page_count - the number of 4096 byte pages in the IO buffer.
+  * page_array - a pointer to page_count * (sizeof(struct page*)) bytes
+    of kcalloced memory. This memory is used as an array of pointers
+    to each of the pages in the IO buffer through a call to get_user_pages.
+  * desc_array - a pointer to desc_count * (sizeof(struct orangefs_bufmap_desc))
+    bytes of kcalloced memory. This memory is further intialized:
+
+      user_desc is the kernel's copy of the IO buffer's ORANGEFS_dev_map_desc
+      structure. user_desc->ptr points to the IO buffer.
+
+      pages_per_desc = bufmap->desc_size / PAGE_SIZE
+      offset = 0
+
+        bufmap->desc_array[0].page_array = &bufmap->page_array[offset]
+        bufmap->desc_array[0].array_count = pages_per_desc = 1024
+        bufmap->desc_array[0].uaddr = (user_desc->ptr) + (0 * 1024 * 4096)
+        offset += 1024
+                           .
+                           .
+                           .
+        bufmap->desc_array[9].page_array = &bufmap->page_array[offset]
+        bufmap->desc_array[9].array_count = pages_per_desc = 1024
+        bufmap->desc_array[9].uaddr = (user_desc->ptr) +
+                                               (9 * 1024 * 4096)
+        offset += 1024
+
+  * buffer_index_array - a desc_count sized array of ints, used to
+    indicate which of the IO buffer's partitions are available to use.
+  * buffer_index_lock - a spinlock to protect buffer_index_array during update.
+  * readdir_index_array - a five (ORANGEFS_READDIR_DEFAULT_DESC_COUNT) element
+    int array used to indicate which of the readdir buffer's partitions are
+    available to use.
+  * readdir_index_lock - a spinlock to protect readdir_index_array during
+    update.
+
+OPERATIONS:
+
+The kernel module builds an "op" (struct orangefs_kernel_op_s) when it
+needs to communicate with userspace. Part of the op contains the "upcall"
+which expresses the request to userspace. Part of the op eventually
+contains the "downcall" which expresses the results of the request.
+
+The slab allocator is used to keep a cache of op structures handy.
+
+At init time the kernel module defines and initializes a request list
+and an in_progress hash table to keep track of all the ops that are
+in flight at any given time.
+
+Ops are stateful:
+
+ * unknown  - op was just initialized
+ * waiting  - op is on request_list (upward bound)
+ * inprogr  - op is in progress (waiting for downcall)
+ * serviced - op has matching downcall; ok
+ * purged   - op has to start a timer since client-core
+              exited uncleanly before servicing op
+ * given up - submitter has given up waiting for it
+
+When some arbitrary userspace program needs to perform a
+filesystem operation on Orangefs (readdir, I/O, create, whatever)
+an op structure is initialized and tagged with a distinguishing ID
+number. The upcall part of the op is filled out, and the op is
+passed to the "service_operation" function.
+
+Service_operation changes the op's state to "waiting", puts
+it on the request list, and signals the Orangefs file_operations.poll
+function through a wait queue. Userspace is polling the pseudo-device
+and thus becomes aware of the upcall request that needs to be read.
+
+When the Orangefs file_operations.read function is triggered, the
+request list is searched for an op that seems ready-to-process.
+The op is removed from the request list. The tag from the op and
+the filled-out upcall struct are copy_to_user'ed back to userspace.
+
+If any of these (and some additional protocol) copy_to_users fail,
+the op's state is set to "waiting" and the op is added back to
+the request list. Otherwise, the op's state is changed to "in progress",
+and the op is hashed on its tag and put onto the end of a list in the
+in_progress hash table at the index the tag hashed to.
+
+When userspace has assembled the response to the upcall, it
+writes the response, which includes the distinguishing tag, back to
+the pseudo device in a series of io_vecs. This triggers the Orangefs
+file_operations.write_iter function to find the op with the associated
+tag and remove it from the in_progress hash table. As long as the op's
+state is not "canceled" or "given up", its state is set to "serviced".
+The file_operations.write_iter function returns to the waiting vfs,
+and back to service_operation through wait_for_matching_downcall.
+
+Service operation returns to its caller with the op's downcall
+part (the response to the upcall) filled out.
+
+The "client-core" is the bridge between the kernel module and
+userspace. The client-core is a daemon. The client-core has an
+associated watchdog daemon. If the client-core is ever signaled
+to die, the watchdog daemon restarts the client-core. Even though
+the client-core is restarted "right away", there is a period of
+time during such an event that the client-core is dead. A dead client-core
+can't be triggered by the Orangefs file_operations.poll function.
+Ops that pass through service_operation during a "dead spell" can timeout
+on the wait queue and one attempt is made to recycle them. Obviously,
+if the client-core stays dead too long, the arbitrary userspace processes
+trying to use Orangefs will be negatively affected. Waiting ops
+that can't be serviced will be removed from the request list and
+have their states set to "given up". In-progress ops that can't 
+be serviced will be removed from the in_progress hash table and
+have their states set to "given up".
+
+Readdir and I/O ops are atypical with respect to their payloads.
+
+  - readdir ops use the smaller of the two pre-allocated pre-partitioned
+    memory buffers. The readdir buffer is only available to userspace.
+    The kernel module obtains an index to a free partition before launching
+    a readdir op. Userspace deposits the results into the indexed partition
+    and then writes them to back to the pvfs device.
+
+  - io (read and write) ops use the larger of the two pre-allocated
+    pre-partitioned memory buffers. The IO buffer is accessible from
+    both userspace and the kernel module. The kernel module obtains an
+    index to a free partition before launching an io op. The kernel module
+    deposits write data into the indexed partition, to be consumed
+    directly by userspace. Userspace deposits the results of read
+    requests into the indexed partition, to be consumed directly
+    by the kernel module.
+
+Responses to kernel requests are all packaged in pvfs2_downcall_t
+structs. Besides a few other members, pvfs2_downcall_t contains a
+union of structs, each of which is associated with a particular
+response type.
+
+The several members outside of the union are:
+ - int32_t type - type of operation.
+ - int32_t status - return code for the operation.
+ - int64_t trailer_size - 0 unless readdir operation.
+ - char *trailer_buf - initialized to NULL, used during readdir operations.
+
+The appropriate member inside the union is filled out for any
+particular response.
+
+  PVFS2_VFS_OP_FILE_IO
+    fill a pvfs2_io_response_t
+
+  PVFS2_VFS_OP_LOOKUP
+    fill a PVFS_object_kref
+
+  PVFS2_VFS_OP_CREATE
+    fill a PVFS_object_kref
+
+  PVFS2_VFS_OP_SYMLINK
+    fill a PVFS_object_kref
+
+  PVFS2_VFS_OP_GETATTR
+    fill in a PVFS_sys_attr_s (tons of stuff the kernel doesn't need)
+    fill in a string with the link target when the object is a symlink.
+
+  PVFS2_VFS_OP_MKDIR
+    fill a PVFS_object_kref
+
+  PVFS2_VFS_OP_STATFS
+    fill a pvfs2_statfs_response_t with useless info <g>. It is hard for
+    us to know, in a timely fashion, these statistics about our
+    distributed network filesystem. 
+
+  PVFS2_VFS_OP_FS_MOUNT
+    fill a pvfs2_fs_mount_response_t which is just like a PVFS_object_kref
+    except its members are in a different order and "__pad1" is replaced
+    with "id".
+
+  PVFS2_VFS_OP_GETXATTR
+    fill a pvfs2_getxattr_response_t
+
+  PVFS2_VFS_OP_LISTXATTR
+    fill a pvfs2_listxattr_response_t
+
+  PVFS2_VFS_OP_PARAM
+    fill a pvfs2_param_response_t
+
+  PVFS2_VFS_OP_PERF_COUNT
+    fill a pvfs2_perf_count_response_t
+
+  PVFS2_VFS_OP_FSKEY
+    file a pvfs2_fs_key_response_t
+
+  PVFS2_VFS_OP_READDIR
+    jamb everything needed to represent a pvfs2_readdir_response_t into
+    the readdir buffer descriptor specified in the upcall.
+
+Userspace uses writev() on /dev/pvfs2-req to pass responses to the requests
+made by the kernel side.
+
+A buffer_list containing:
+  - a pointer to the prepared response to the request from the
+    kernel (struct pvfs2_downcall_t).
+  - and also, in the case of a readdir request, a pointer to a
+    buffer containing descriptors for the objects in the target
+    directory.
+... is sent to the function (PINT_dev_write_list) which performs
+the writev.
+
+PINT_dev_write_list has a local iovec array: struct iovec io_array[10];
+
+The first four elements of io_array are initialized like this for all
+responses:
+
+  io_array[0].iov_base = address of local variable "proto_ver" (int32_t)
+  io_array[0].iov_len = sizeof(int32_t)
+
+  io_array[1].iov_base = address of global variable "pdev_magic" (int32_t)
+  io_array[1].iov_len = sizeof(int32_t)
+  
+  io_array[2].iov_base = address of parameter "tag" (PVFS_id_gen_t)
+  io_array[2].iov_len = sizeof(int64_t)
+
+  io_array[3].iov_base = address of out_downcall member (pvfs2_downcall_t)
+                         of global variable vfs_request (vfs_request_t)
+  io_array[3].iov_len = sizeof(pvfs2_downcall_t)
+
+Readdir responses initialize the fifth element io_array like this:
+
+  io_array[4].iov_base = contents of member trailer_buf (char *)
+                         from out_downcall member of global variable
+                         vfs_request
+  io_array[4].iov_len = contents of member trailer_size (PVFS_size)
+                        from out_downcall member of global variable
+                        vfs_request
+  
+
index aa1e0c9..7dd95b3 100644 (file)
@@ -12,8 +12,7 @@ KASAN uses compile-time instrumentation for checking every memory access,
 therefore you will need a GCC version 4.9.2 or later. GCC 5.0 or later is
 required for detection of out-of-bounds accesses to stack or global variables.
 
-Currently KASAN is supported only for x86_64 architecture and requires the
-kernel to be built with the SLUB allocator.
+Currently KASAN is supported only for x86_64 architecture.
 
 1. Usage
 ========
@@ -27,7 +26,7 @@ inline are compiler instrumentation types. The former produces smaller binary
 the latter is 1.1 - 2 times faster. Inline instrumentation requires a GCC
 version 5.0 or later.
 
-Currently KASAN works only with the SLUB memory allocator.
+KASAN works with both SLUB and SLAB memory allocators.
 For better bug detection and nicer reporting, enable CONFIG_STACKTRACE.
 
 To disable instrumentation for specific files or directories, add a line
index 32bafda..7ba7bc4 100644 (file)
@@ -228,13 +228,13 @@ F:        kernel/sys_ni.c
 
 ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/abituguru.c
 
 ABIT UGURU 3 HARDWARE MONITOR DRIVER
 M:     Alistair John Strachan <alistair@devzero.co.uk>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/abituguru3.c
 
@@ -392,14 +392,14 @@ F:        Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
 
 ADM1025 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/adm1025
 F:     drivers/hwmon/adm1025.c
 
 ADM1029 HARDWARE MONITOR DRIVER
 M:     Corentin Labbe <clabbe.montjoie@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/adm1029.c
 
@@ -444,7 +444,7 @@ F:  drivers/video/backlight/adp8860_bl.c
 
 ADS1015 HARDWARE MONITOR DRIVER
 M:     Dirk Eibach <eibach@gdsys.de>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/ads1015
 F:     drivers/hwmon/ads1015.c
@@ -457,7 +457,7 @@ F:  drivers/macintosh/therm_adt746x.c
 
 ADT7475 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/adt7475
 F:     drivers/hwmon/adt7475.c
@@ -634,7 +634,7 @@ F:  include/linux/ccp.h
 
 AMD FAM15H PROCESSOR POWER MONITORING DRIVER
 M:     Huang Rui <ray.huang@amd.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Supported
 F:     Documentation/hwmon/fam15h_power
 F:     drivers/hwmon/fam15h_power.c
@@ -806,7 +806,7 @@ F:  drivers/input/mouse/bcm5974.c
 
 APPLE SMC DRIVER
 M:     Henrik Rydberg <rydberg@bitmath.org>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Odd fixes
 F:     drivers/hwmon/applesmc.c
 
@@ -1865,7 +1865,7 @@ F:        include/media/i2c/as3645a.h
 
 ASC7621 HARDWARE MONITOR DRIVER
 M:     George Joseph <george.joseph@fairview5.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/asc7621
 F:     drivers/hwmon/asc7621.c
@@ -1958,7 +1958,7 @@ F:        drivers/net/wireless/ath/carl9170/
 
 ATK0110 HWMON DRIVER
 M:     Luca Tettamanti <kronos.it@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/asus_atk0110.c
 
@@ -3094,7 +3094,7 @@ F:        mm/swap_cgroup.c
 
 CORETEMP HARDWARE MONITORING DRIVER
 M:     Fenghua Yu <fenghua.yu@intel.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/coretemp
 F:     drivers/hwmon/coretemp.c
@@ -3683,7 +3683,7 @@ T:        git git://git.infradead.org/users/vkoul/slave-dma.git
 
 DME1737 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/dme1737
 F:     drivers/hwmon/dme1737.c
@@ -4381,7 +4381,7 @@ F:        include/video/exynos_mipi*
 
 F71805F HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/f71805f
 F:     drivers/hwmon/f71805f.c
@@ -4460,7 +4460,7 @@ F:        fs/*
 
 FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:     Riku Voipio <riku.voipio@iki.fi>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/f75375s.c
 F:     include/linux/f75375s.h
@@ -5021,8 +5021,8 @@ F:        drivers/media/usb/hackrf/
 HARDWARE MONITORING
 M:     Jean Delvare <jdelvare@suse.com>
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
-W:     http://www.lm-sensors.org/
+L:     linux-hwmon@vger.kernel.org
+W:     http://hwmon.wiki.kernel.org/
 T:     quilt http://jdelvare.nerim.net/devel/linux/jdelvare-hwmon/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:     Maintained
@@ -5554,7 +5554,7 @@ F:        drivers/usb/atm/ueagle-atm.c
 
 INA209 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/ina209
 F:     Documentation/devicetree/bindings/i2c/ina209.txt
@@ -5562,7 +5562,7 @@ F:        drivers/hwmon/ina209.c
 
 INA2XX HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/ina2xx
 F:     drivers/hwmon/ina2xx.c
@@ -6067,7 +6067,7 @@ F:        drivers/isdn/hardware/eicon/
 
 IT87 HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/it87
 F:     drivers/hwmon/it87.c
@@ -6103,7 +6103,7 @@ F:        drivers/media/dvb-frontends/ix2505v*
 
 JC42.4 TEMPERATURE SENSOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/jc42.c
 F:     Documentation/hwmon/jc42
@@ -6153,18 +6153,32 @@ F:      drivers/tty/serial/jsm/
 
 K10TEMP HARDWARE MONITORING DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/k10temp
 F:     drivers/hwmon/k10temp.c
 
 K8TEMP HARDWARE MONITORING DRIVER
 M:     Rudolf Marek <r.marek@assembler.cz>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/k8temp
 F:     drivers/hwmon/k8temp.c
 
+KASAN
+M:     Andrey Ryabinin <aryabinin@virtuozzo.com>
+R:     Alexander Potapenko <glider@google.com>
+R:     Dmitry Vyukov <dvyukov@google.com>
+L:     kasan-dev@googlegroups.com
+S:     Maintained
+F:     arch/*/include/asm/kasan.h
+F:     arch/*/mm/kasan_init*
+F:     Documentation/kasan.txt
+F:     include/linux/kasan.h
+F:     lib/test_kasan.c
+F:     mm/kasan/
+F:     scripts/Makefile.kasan
+
 KCONFIG
 M:     "Yann E. MORIN" <yann.morin.1998@free.fr>
 L:     linux-kbuild@vger.kernel.org
@@ -6693,27 +6707,27 @@ F:      net/llc/
 
 LM73 HARDWARE MONITOR DRIVER
 M:     Guillaume Ligneul <guillaume.ligneul@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/lm73.c
 
 LM78 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/lm78
 F:     drivers/hwmon/lm78.c
 
 LM83 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/lm83
 F:     drivers/hwmon/lm83.c
 
 LM90 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/lm90
 F:     Documentation/devicetree/bindings/hwmon/lm90.txt
@@ -6721,7 +6735,7 @@ F:        drivers/hwmon/lm90.c
 
 LM95234 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/lm95234
 F:     drivers/hwmon/lm95234.c
@@ -6787,7 +6801,7 @@ F:        drivers/scsi/sym53c8xx_2/
 
 LTC4261 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/ltc4261
 F:     drivers/hwmon/ltc4261.c
@@ -6957,28 +6971,28 @@ F:      include/uapi/linux/matroxfb.h
 
 MAX16065 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max16065
 F:     drivers/hwmon/max16065.c
 
 MAX20751 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max20751
 F:     drivers/hwmon/max20751.c
 
 MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:     "Hans J. Koch" <hjk@hansjkoch.de>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max6650
 F:     drivers/hwmon/max6650.c
 
 MAX6697 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max6697
 F:     Documentation/devicetree/bindings/i2c/max6697.txt
@@ -7547,7 +7561,7 @@ F:        drivers/scsi/NCR_D700.*
 
 NCT6775 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/nct6775
 F:     drivers/hwmon/nct6775.c
@@ -8237,6 +8251,14 @@ S:       Supported
 F:     fs/overlayfs/
 F:     Documentation/filesystems/overlayfs.txt
 
+ORANGEFS FILESYSTEM
+M:     Mike Marshall <hubcap@omnibond.com>
+L:     pvfs2-developers@beowulf-underground.org (subscribers-only)
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git
+S:     Supported
+F:     fs/orangefs/
+F:     Documentation/filesystems/orangefs.txt
+
 P54 WIRELESS DRIVER
 M:     Christian Lamparter <chunkeey@googlemail.com>
 L:     linux-wireless@vger.kernel.org
@@ -8337,7 +8359,7 @@ F:        drivers/video/logo/logo_parisc*
 
 PC87360 HARDWARE MONITORING DRIVER
 M:     Jim Cromie <jim.cromie@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/pc87360
 F:     drivers/hwmon/pc87360.c
@@ -8349,7 +8371,7 @@ F:        drivers/char/pc8736x_gpio.c
 
 PC87427 HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/pc87427
 F:     drivers/hwmon/pc87427.c
@@ -8729,8 +8751,8 @@ F:        drivers/rtc/rtc-puv3.c
 
 PMBUS HARDWARE MONITORING DRIVERS
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
-W:     http://www.lm-sensors.org/
+L:     linux-hwmon@vger.kernel.org
+W:     http://hwmon.wiki.kernel.org/
 W:     http://www.roeck-us.net/linux/drivers/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:     Maintained
@@ -8935,7 +8957,7 @@ F:        drivers/media/usb/pwc/*
 
 PWM FAN DRIVER
 M:     Kamil Debski <k.debski@samsung.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Supported
 F:     Documentation/devicetree/bindings/hwmon/pwm-fan.txt
 F:     Documentation/hwmon/pwm-fan
@@ -10256,28 +10278,28 @@ F:    Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
 
 SMM665 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/smm665
 F:     drivers/hwmon/smm665.c
 
 SMSC EMC2103 HARDWARE MONITOR DRIVER
 M:     Steve Glendinning <steve.glendinning@shawell.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/emc2103
 F:     drivers/hwmon/emc2103.c
 
 SMSC SCH5627 HARDWARE MONITOR DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Supported
 F:     Documentation/hwmon/sch5627
 F:     drivers/hwmon/sch5627.c
 
 SMSC47B397 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/smsc47b397
 F:     drivers/hwmon/smsc47b397.c
@@ -11115,8 +11137,8 @@ F:      include/uapi/linux/tipc*.h
 F:     net/tipc/
 
 TILE ARCHITECTURE
-M:     Chris Metcalf <cmetcalf@ezchip.com>
-W:     http://www.ezchip.com/scm/
+M:     Chris Metcalf <cmetcalf@mellanox.com>
+W:     http://www.mellanox.com/repository/solutions/tile-scm/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git
 S:     Supported
 F:     arch/tile/
@@ -11205,7 +11227,7 @@ F:      include/linux/mmc/sh_mobile_sdhi.h
 
 TMP401 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/tmp401
 F:     drivers/hwmon/tmp401.c
@@ -11326,12 +11348,13 @@ S:    Maintained
 F:     drivers/scsi/u14-34f.c
 
 UBI FILE SYSTEM (UBIFS)
+M:     Richard Weinberger <richard@nod.at>
 M:     Artem Bityutskiy <dedekind1@gmail.com>
 M:     Adrian Hunter <adrian.hunter@intel.com>
 L:     linux-mtd@lists.infradead.org
 T:     git git://git.infradead.org/ubifs-2.6.git
 W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
-S:     Maintained
+S:     Supported
 F:     Documentation/filesystems/ubifs.txt
 F:     fs/ubifs/
 
@@ -11957,14 +11980,14 @@ F:    Documentation/networking/vrf.txt
 
 VT1211 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/vt1211
 F:     drivers/hwmon/vt1211.c
 
 VT8231 HARDWARE MONITOR DRIVER
 M:     Roger Lucas <vt8231@hiddenengine.co.uk>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/vt8231.c
 
@@ -11983,21 +12006,21 @@ F:    drivers/w1/
 
 W83791D HARDWARE MONITORING DRIVER
 M:     Marc Hulsman <m.hulsman@tudelft.nl>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/w83791d
 F:     drivers/hwmon/w83791d.c
 
 W83793 HARDWARE MONITORING DRIVER
 M:     Rudolf Marek <r.marek@assembler.cz>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/w83793
 F:     drivers/hwmon/w83793.c
 
 W83795 HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/w83795.c
 
index b98a4f7..916b26e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
-PATCHLEVEL = 5
+PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = Blurry Fish Butt
 
 # *DOCUMENTATION*
@@ -782,6 +782,9 @@ KBUILD_CFLAGS   += $(call cc-option,-Werror=strict-prototypes)
 # Prohibit date/time macros, which would make the build non-deterministic
 KBUILD_CFLAGS   += $(call cc-option,-Werror=date-time)
 
+# enforce correct pointer usage
+KBUILD_CFLAGS   += $(call cc-option,-Werror=incompatible-pointer-types)
+
 # use the deterministic mode of AR if available
 KBUILD_ARFLAGS := $(call ar-option,D)
 
index 9a7cf52..36da89e 100644 (file)
@@ -12,9 +12,6 @@
 
 #ifndef __ASSEMBLY__
 
-#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)     free_page(addr)
-
 #define clear_page(paddr)              memset((paddr), 0, PAGE_SIZE)
 #define copy_page(to, from)            memcpy((to), (from), PAGE_SIZE)
 
index 52b34a0..95c1923 100644 (file)
@@ -325,12 +325,17 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
        imx6dl-udoo.dtb \
        imx6dl-wandboard.dtb \
        imx6dl-wandboard-revb1.dtb \
+       imx6q-apalis-ixora.dtb \
        imx6q-apf6dev.dtb \
        imx6q-arm2.dtb \
+       imx6q-b450v3.dtb \
+       imx6q-b650v3.dtb \
+       imx6q-b850v3.dtb \
        imx6q-cm-fx6.dtb \
        imx6q-cubox-i.dtb \
        imx6q-dfi-fs700-m60.dtb \
        imx6q-dmo-edmqmx6.dtb \
+       imx6q-evi.dtb \
        imx6q-gk802.dtb \
        imx6q-gw51xx.dtb \
        imx6q-gw52xx.dtb \
@@ -340,6 +345,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
        imx6q-gw551x.dtb \
        imx6q-gw552x.dtb \
        imx6q-hummingboard.dtb \
+       imx6q-icore-rqs.dtb \
        imx6q-nitrogen6x.dtb \
        imx6q-nitrogen6_max.dtb \
        imx6q-novena.dtb \
@@ -357,7 +363,9 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
        imx6q-tx6q-1110.dtb \
        imx6q-udoo.dtb \
        imx6q-wandboard.dtb \
-       imx6q-wandboard-revb1.dtb
+       imx6q-wandboard-revb1.dtb \
+       imx6qp-sabreauto.dtb \
+       imx6qp-sabresd.dtb
 dtb-$(CONFIG_SOC_IMX6SL) += \
        imx6sl-evk.dtb \
        imx6sl-warp.dtb
@@ -752,7 +760,9 @@ dtb-$(CONFIG_ARCH_U8500) += \
 dtb-$(CONFIG_ARCH_UNIPHIER) += \
        uniphier-ph1-ld4-ref.dtb \
        uniphier-ph1-ld6b-ref.dtb \
+       uniphier-ph1-pro4-ace.dtb \
        uniphier-ph1-pro4-ref.dtb \
+       uniphier-ph1-pro4-sanji.dtb \
        uniphier-ph1-sld3-ref.dtb \
        uniphier-ph1-sld8-ref.dtb \
        uniphier-proxstream2-gentil.dtb \
index ff888d2..f3e2b96 100644 (file)
                regulator-name = "mmc0-card-supply";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
+               regulator-always-on;
        };
 
        gpio_keys {
index 569026e..da84e65 100644 (file)
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                vin-supply = <&vcc_3v3_reg>;
+               regulator-always-on;
        };
 };
index ed1d0b4..cda6907 100644 (file)
@@ -30,7 +30,7 @@
                        label = "BP1";
                        gpios = <&gpio3 18 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_MISC>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index cde329e..6b1f4bb 100644 (file)
                                status = "disabled";
                        };
 
-                       tsc: tsc@50030000 {
-                               compatible = "fsl,imx25-adc", "fsl,imx21-tsc";
-                               reg = <0x50030000 0x4000>;
+                       tscadc: tscadc@50030000 {
+                               compatible = "fsl,imx25-tsadc";
+                               reg = <0x50030000 0xc>;
                                interrupts = <46>;
                                clocks = <&clks 119>;
                                clock-names = "ipg";
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
                                status = "disabled";
+
+                               adc: adc@50030800 {
+                                       compatible = "fsl,imx25-gcq";
+                                       reg = <0x50030800 0x60>;
+                                       interrupt-parent = <&tscadc>;
+                                       interrupts = <1>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                                       status = "disabled";
+                               };
+
+                               tsc: tcq@50030400 {
+                                       compatible = "fsl,imx25-tcq";
+                                       reg = <0x50030400 0x60>;
+                                       interrupt-parent = <&tscadc>;
+                                       interrupts = <0>;
+                                       fsl,wires = <4>;
+                                       status = "disabled";
+                               };
                        };
 
                        ssi1: ssi@50034000 {
                                compatible = "fsl,imx25-usb", "fsl,imx27-usb";
                                reg = <0x53ff4000 0x0200>;
                                interrupts = <37>;
-                               clocks = <&clks 70>;
+                               clocks = <&clks 9>, <&clks 70>, <&clks 8>;
+                               clock-names = "ipg", "ahb", "per";
                                fsl,usbmisc = <&usbmisc 0>;
                                fsl,usbphy = <&usbphy0>;
                                status = "disabled";
                                compatible = "fsl,imx25-usb", "fsl,imx27-usb";
                                reg = <0x53ff4400 0x0200>;
                                interrupts = <35>;
-                               clocks = <&clks 70>;
+                               clocks = <&clks 9>, <&clks 70>, <&clks 8>;
+                               clock-names = "ipg", "ahb", "per";
                                fsl,usbmisc = <&usbmisc 1>;
                                fsl,usbphy = <&usbphy1>;
                                status = "disabled";
                        usbmisc: usbmisc@53ff4600 {
                                #index-cells = <1>;
                                compatible = "fsl,imx25-usbmisc";
-                               clocks = <&clks 9>, <&clks 70>, <&clks 8>;
-                               clock-names = "ipg", "ahb", "per";
                                reg = <0x53ff4600 0x00f>;
                        };
 
index 7ac4f1a..1eaa131 100644 (file)
                        label = "User button";
                        gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
                        linux,code = <0x100>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 };
index 927b391..8859474 100644 (file)
@@ -36,7 +36,7 @@
                        label = "SW3";
                        gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_MISC>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
@@ -49,7 +49,7 @@
                        label = "SW4";
                        gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_MISC>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 4ea8934..fd20e99 100644 (file)
                        compatible = "fixed-clock";
                        reg = <0>;
                        #clock-cells = <0>;
-                       clock-frequency = <27000000>;
+                       clock-frequency = <26000000>;
                };
        };
 
                        0x02020049 /* row 2, col 2, KEY_KP9 */
                >;
                gpio-activelow;
-               linux,wakeup;
+               wakeup-source;
                debounce-delay-ms = <100>;
                col-scan-delay-us = <5000>;
                linux,no-autorepeat;
index 75b0367..4727bbb 100644 (file)
@@ -30,7 +30,7 @@
                        label = "BP1";
                        gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_MISC>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                        linux,input-type = <1>;
                };
        };
index ed3dc33..14e1320 100644 (file)
                                compatible = "fsl,imx35-usb", "fsl,imx27-usb";
                                reg = <0x53ff4000 0x0200>;
                                interrupts = <37>;
-                               clocks = <&clks 73>;
+                               clocks = <&clks 9>, <&clks 73>, <&clks 28>;
+                               clock-names = "ipg", "ahb", "per";
                                fsl,usbmisc = <&usbmisc 0>;
                                fsl,usbphy = <&usbphy0>;
                                status = "disabled";
                                compatible = "fsl,imx35-usb", "fsl,imx27-usb";
                                reg = <0x53ff4400 0x0200>;
                                interrupts = <35>;
-                               clocks = <&clks 73>;
+                               clocks = <&clks 9>, <&clks 73>, <&clks 28>;
+                               clock-names = "ipg", "ahb", "per";
                                fsl,usbmisc = <&usbmisc 1>;
                                fsl,usbphy = <&usbphy1>;
                                dr_mode = "host";
                        usbmisc: usbmisc@53ff4600 {
                                #index-cells = <1>;
                                compatible = "fsl,imx35-usbmisc";
-                               clocks = <&clks 9>, <&clks 73>, <&clks 28>;
-                               clock-names = "ipg", "ahb", "per";
                                reg = <0x53ff4600 0x00f>;
                        };
                };
index 649befe..018d24e 100644 (file)
                        label = "Power Button";
                        gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_POWER>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 321662f..16fc69c 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc2>;
        cap-sdio-irq;
-       enable-sdio-wakeup;
+       wakeup-source;
        keep-power-in-suspend;
        max-frequency = <50000000>;
        no-1-8-v;
index 34599c5..d270df3 100644 (file)
@@ -41,7 +41,7 @@
                        label = "BP1";
                        gpios = <&gpio3 31 GPIO_ACTIVE_LOW>;
                        linux,code = <256>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                        linux,input-type = <1>;
                };
        };
index 9eb92ab..82eae3c 100644 (file)
 #define MX51_PAD_DISPB2_SER_CLK__DISP1_PIN7            0x2c4 0x6c4 0x000 0x3 0x0
 #define MX51_PAD_DISPB2_SER_CLK__DISPB2_SER_CLK                0x2c4 0x6c4 0x000 0x0 0x0
 #define MX51_PAD_DISPB2_SER_CLK__GPIO3_7               0x2c4 0x6c4 0x990 0x4 0x1
-#define MX51_PAD_DISPB2_SER_RS__DISP1_EXT_CLK          0x2c8 0x6c8 0x000 0x2 0x0
 #define MX51_PAD_DISPB2_SER_RS__DISP1_PIN16            0x2c8 0x6c8 0x000 0x2 0x0
 #define MX51_PAD_DISPB2_SER_RS__DISP1_PIN8             0x2c8 0x6c8 0x000 0x3 0x0
 #define MX51_PAD_DISPB2_SER_RS__DISPB2_SER_RS          0x2c8 0x6c8 0x000 0x0 0x0
index 3bc1883..4486bc4 100644 (file)
                        label = "Home";
                        gpios = <&gpio5 10 0>;
                        linux,code = <102>; /* KEY_HOME */
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                back {
                        label = "Back";
                        gpios = <&gpio5 11 0>;
                        linux,code = <158>; /* KEY_BACK */
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                program {
                        label = "Program";
                        gpios = <&gpio5 12 0>;
                        linux,code = <362>; /* KEY_PROGRAM */
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                volume-up {
index 53fd75c..c05e7cf 100644 (file)
 
                power {
                        label = "Power Button";
-                       gpios = <&gpio1 8 0>;
-                       linux,code = <116>; /* KEY_POWER */
+                       gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
                };
 
                volume-up {
                        label = "Volume Up";
-                       gpios = <&gpio2 14 0>;
-                       linux,code = <115>; /* KEY_VOLUMEUP */
-                       gpio-key,wakeup;
+                       gpios = <&gpio2 14 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+                       wakeup-source;
                };
 
                volume-down {
                        label = "Volume Down";
-                       gpios = <&gpio2 15 0>;
-                       linux,code = <114>; /* KEY_VOLUMEDOWN */
-                       gpio-key,wakeup;
+                       gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEDOWN>;
+                       wakeup-source;
                };
        };
 
index 13e842b..0ecb43d 100644 (file)
                interrupts = <26 0>;
                gpios = <&gpio3 26 GPIO_ACTIVE_LOW>;
                ti,x-plate-ohms = <660>;
-               linux,wakeup;
+               wakeup-source;
        };
 };
 
index 6480471..3cf682a 100644 (file)
                interrupt-parent = <&gpio3>;
                interrupts = <23 0>;
                wakeup-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
-               linux,wakeup;
+               wakeup-source;
        };
 };
 
                interrupt-parent = <&gpio3>;
                interrupts = <22 0>;
                wakeup-gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>;
-               linux,wakeup;
+               wakeup-source;
        };
 };
 
        status = "okay";
 
        lvds0: lvds-channel@0 {
-               fsl,data-mapping = "jeida";
-               fsl,data-width = <24>;
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <18>;
                status = "okay";
 
                display-timings {
-                       native-mode = <&lvds_timing0>;
-                       lvds_timing0: hsd100pxn1 {
+                       native-mode = <&lvds0_timing0>;
+
+                       lvds0_timing0: hsd100pxn1 {
                                clock-frequency = <65000000>;
                                hactive = <1024>;
                                vactive = <768>;
                                hsync-active = <0>;
                                vsync-active = <0>;
                                de-active = <1>;
-                               pixelclk-active = <0>;
+                               pixelclk-active = <1>;
+                       };
+
+                       lvds0_timing1: nl12880bc20 {
+                               clock-frequency = <71000000>;
+                               hactive = <1280>;
+                               vactive = <800>;
+                               hback-porch = <50>;
+                               hsync-len = <60>;
+                               hfront-porch = <50>;
+                               vback-porch = <5>;
+                               vsync-len = <13>;
+                               vfront-porch = <5>;
+                               hsync-active = <0>;
+                               vsync-active = <0>;
+                               de-active = <1>;
+                               pixelclk-active = <1>;
                        };
                };
        };
 
        lvds1: lvds-channel@1 {
-               fsl,data-mapping = "jeida";
-               fsl,data-width = <24>;
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <18>;
                status = "okay";
 
                display-timings {
-                       native-mode = <&lvds_timing1>;
-                       lvds_timing1: hsd100pxn1 {
+                       native-mode = <&lvds1_timing0>;
+
+                       lvds1_timing0: hsd100pxn1 {
                                clock-frequency = <65000000>;
                                hactive = <1024>;
                                vactive = <768>;
                                hsync-active = <0>;
                                vsync-active = <0>;
                                de-active = <1>;
-                               pixelclk-active = <0>;
+                               pixelclk-active = <1>;
                        };
                };
        };
index d3e50b2..bd3dfef 100644 (file)
@@ -37,7 +37,7 @@
                        compatible = "fixed-clock";
                        reg = <0>;
                        #clock-cells = <0>;
-                       clock-frequency = <27000000>;
+                       clock-frequency = <26000000>;
                };
        };
 
@@ -50,7 +50,7 @@
                        label = "Power Button";
                        gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
                        linux,code = <116>; /* KEY_POWER */
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index c275eec..d35a5cd 100644 (file)
@@ -77,7 +77,7 @@
                interrupt-parent = <&gpio3>;
                interrupts = <22 0>;
                wakeup-gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>;
-               linux,wakeup;
+               wakeup-source;
        };
 };
 
index f607d4f..8c314ee 100644 (file)
@@ -13,7 +13,7 @@
 #include "imx6qdl-wandboard-revb1.dtsi"
 
 / {
-       model = "Wandboard i.MX6 Dual Lite Board";
+       model = "Wandboard i.MX6 Dual Lite Board rev B1";
        compatible = "wand,imx6dl-wandboard", "fsl,imx6dl";
 
        memory {
diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora.dts b/arch/arm/boot/dts/imx6q-apalis-ixora.dts
new file mode 100644 (file)
index 0000000..2cba82d
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2014-2016 Toradex AG
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "imx6q.dtsi"
+#include "imx6qdl-apalis.dtsi"
+
+/ {
+       model = "Toradex Apalis iMX6Q/D Module on Ixora Carrier Board";
+       compatible = "toradex,apalis_imx6q-ixora", "toradex,apalis_imx6q",
+                    "fsl,imx6q";
+
+       aliases {
+               i2c0 = &i2cddc;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+       };
+
+       aliases {
+               rtc0 = &rtc_i2c;
+               rtc1 = &snvs_rtc;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_keys>;
+
+               wakeup {
+                       label = "Wake-Up";
+                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WAKEUP>;
+                       debounce-interval = <10>;
+                       wakeup-source;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_leds_ixora>;
+
+               led4-green {
+                       label = "LED_4_GREEN";
+                       gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
+               };
+
+               led4-red {
+                       label = "LED_4_RED";
+                       gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
+               };
+
+               led5-green {
+                       label = "LED_5_GREEN";
+                       gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+               };
+
+               led5-red {
+                       label = "LED_5_RED";
+                       gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       pwmleds {
+               compatible = "pwm-leds";
+
+               ledpwm1 {
+                       label = "PWM1";
+                       pwms = <&pwm1 0 50000>;
+                       max-brightness = <255>;
+               };
+
+               ledpwm2 {
+                       label = "PWM2";
+                       pwms = <&pwm2 0 50000>;
+                       max-brightness = <255>;
+               };
+
+               ledpwm3 {
+                       label = "PWM3";
+                       pwms = <&pwm3 0 50000>;
+                       max-brightness = <255>;
+               };
+       };
+};
+
+&backlight {
+       brightness-levels = <0 127 191 223 239 247 251 255>;
+       default-brightness-level = <1>;
+       status = "okay";
+};
+
+&can1 {
+       status = "okay";
+};
+
+&can2 {
+       status = "okay";
+};
+
+&hdmi {
+       ddc-i2c-bus = <&i2cddc>;
+       status = "okay";
+};
+
+&i2cddc {
+       status = "okay";
+};
+
+/* GEN1_I2C: I2C1_SDA/SCL on MXM3 209/211 (e.g. RTC on carrier board) */
+&i2c1 {
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+       };
+
+       /* M41T0M6 real time clock on carrier board */
+       rtc_i2c: rtc@68 {
+               compatible = "st,m41t00";
+               reg = <0x68>;
+       };
+};
+
+&ldb {
+       status = "okay";
+};
+
+&pcie {
+       /* active-low meaning opposite of regular PERST# active-low polarity */
+       reset-gpio = <&gpio1 28 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&pwm1 {
+       status = "okay";
+};
+
+&pwm2 {
+       status = "okay";
+};
+
+&pwm3 {
+       status = "okay";
+};
+
+&pwm4 {
+       status = "okay";
+};
+
+&reg_usb_otg_vbus {
+       status = "okay";
+};
+
+&reg_usb_host_vbus {
+       status = "okay";
+};
+
+&sata {
+       status = "okay";
+};
+
+&sound_spdif {
+       status = "okay";
+};
+
+&spdif {
+       status = "okay";
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&uart2 {
+       status = "okay";
+};
+
+&uart4 {
+       status = "okay";
+};
+
+&uart5 {
+       status = "okay";
+};
+
+&usbh1 {
+       vbus-supply = <&reg_usb_host_vbus>;
+       status = "okay";
+};
+
+&usbotg {
+       vbus-supply = <&reg_usb_otg_vbus>;
+       status = "okay";
+};
+
+/* SD1 */
+&usdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sd_cd>;
+       cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&iomuxc {
+       /*
+        * Mux the Apalis GPIOs
+        * GPIO5, 6 used by optional fusion_F0710A kernel module
+        */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_apalis_gpio1 &pinctrl_apalis_gpio2
+                    &pinctrl_apalis_gpio3 &pinctrl_apalis_gpio4
+                    &pinctrl_apalis_gpio5 &pinctrl_apalis_gpio6
+                    &pinctrl_apalis_gpio7 &pinctrl_apalis_gpio8
+                   >;
+
+       pinctrl_leds_ixora: ledsixoragrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b0
+                       MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x1b0b0
+                       MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0
+                       MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0
+               >;
+       };
+};
diff --git a/arch/arm/boot/dts/imx6q-b450v3.dts b/arch/arm/boot/dts/imx6q-b450v3.dts
new file mode 100644 (file)
index 0000000..3101be5
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 Timesys Corporation.
+ * Copyright 2015 General Electric Company
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6q-bx50v3.dtsi"
+
+/ {
+       model = "General Electric B450v3";
+       compatible = "ge,imx6q-b450v3", "advantech,imx6q-ba16", "fsl,imx6q";
+
+       chosen {
+               stdout-path = &uart3;
+       };
+
+       panel-lvds0 {
+               compatible = "innolux,g121x1-l03";
+               backlight = <&backlight_lvds>;
+               power-supply = <&reg_lvds>;
+
+               port {
+                       panel_in_lvds0: endpoint {
+                               remote-endpoint = <&lvds0_out>;
+                       };
+               };
+       };
+};
+
+&ldb {
+       assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+                         <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+       assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+                                <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+       status = "okay";
+
+       lvds0: lvds-channel@0 {
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <24>;
+               status = "okay";
+
+               port@4 {
+                       reg = <4>;
+
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&panel_in_lvds0>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx6q-b650v3.dts b/arch/arm/boot/dts/imx6q-b650v3.dts
new file mode 100644 (file)
index 0000000..823f55c
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 Timesys Corporation.
+ * Copyright 2015 General Electric Company
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6q-bx50v3.dtsi"
+
+/ {
+       model = "General Electric B650v3";
+       compatible = "ge,imx6q-b650v3", "advantech,imx6q-ba16", "fsl,imx6q";
+
+       chosen {
+               stdout-path = &uart3;
+       };
+
+       panel-lvds0 {
+               compatible = "innolux,g121x1-l03";
+               backlight = <&backlight_lvds>;
+               power-supply = <&reg_lvds>;
+
+               port {
+                       panel_in_lvds0: endpoint {
+                               remote-endpoint = <&lvds0_out>;
+                       };
+               };
+       };
+};
+
+&ldb {
+       assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+                         <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+       assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+                                <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+       status = "okay";
+
+       lvds0: lvds-channel@0 {
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <24>;
+               status = "okay";
+
+               port@4 {
+                       reg = <4>;
+
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&panel_in_lvds0>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx6q-b850v3.dts b/arch/arm/boot/dts/imx6q-b850v3.dts
new file mode 100644 (file)
index 0000000..984d000
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2015 Timesys Corporation.
+ * Copyright 2015 General Electric Company
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6q-bx50v3.dtsi"
+
+/ {
+       model = "General Electric B850v3";
+       compatible = "ge,imx6q-b850v3", "advantech,imx6q-ba16", "fsl,imx6q";
+
+       chosen {
+               stdout-path = &uart3;
+       };
+
+       panel-lvds0 {
+               compatible = "auo,b133htn01";
+               backlight = <&backlight_lvds>;
+               ddc-i2c-bus = <&mux2_i2c2>;
+
+               port {
+                       panel_in_lvds0: endpoint {
+                               remote-endpoint = <&lvds0_out>;
+                       };
+               };
+       };
+};
+
+&ldb {
+       assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+                         <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+       assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+                                <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+       fsl,dual-channel;
+       status = "okay";
+
+       lvds0: lvds-channel@0 {
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <24>;
+               status = "okay";
+
+               port@4 {
+                       reg = <4>;
+
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&panel_in_lvds0>;
+                       };
+               };
+       };
+};
+
+&i2c2 {
+       pca9547_ddc: mux@70 {
+               compatible = "nxp,pca9547";
+               reg = <0x70>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               mux2_i2c1: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0>;
+               };
+
+               mux2_i2c2: i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x1>;
+               };
+
+               mux2_i2c3: i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x2>;
+               };
+
+               mux2_i2c4: i2c@3 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x3>;
+               };
+
+               mux2_i2c5: i2c@4 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x4>;
+               };
+
+               mux2_i2c6: i2c@5 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x5>;
+               };
+
+               mux2_i2c7: i2c@6 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x6>;
+               };
+
+               mux2_i2c8: i2c@7 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x7>;
+               };
+       };
+};
+
+&hdmi {
+       ddc-i2c-bus = <&mux2_i2c1>;
+};
+
+&mux1_i2c1 {
+       ads7830@4a {
+               compatible = "ti,ads7830";
+               reg = <0x4a>;
+       };
+};
diff --git a/arch/arm/boot/dts/imx6q-ba16.dtsi b/arch/arm/boot/dts/imx6q-ba16.dtsi
new file mode 100644 (file)
index 0000000..8f6e603
--- /dev/null
@@ -0,0 +1,632 @@
+/*
+ * Support for imx6 based Advantech DMS-BA16 Qseven module
+ *
+ * Copyright 2015 Timesys Corporation.
+ * Copyright 2015 General Electric Company
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "imx6q.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       memory {
+               reg = <0x10000000 0x40000000>;
+       };
+
+       backlight_lvds: backlight {
+               compatible = "pwm-backlight";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_display>;
+               pwms = <&pwm1 0 5000000>;
+               brightness-levels = <  0   1   2   3   4   5   6   7   8   9
+                                     10  11  12  13  14  15  16  17  18  19
+                                     20  21  22  23  24  25  26  27  28  29
+                                     30  31  32  33  34  35  36  37  38  39
+                                     40  41  42  43  44  45  46  47  48  49
+                                     50  51  52  53  54  55  56  57  58  59
+                                     60  61  62  63  64  65  66  67  68  69
+                                     70  71  72  73  74  75  76  77  78  79
+                                     80  81  82  83  84  85  86  87  88  89
+                                     90  91  92  93  94  95  96  97  98  99
+                                    100 101 102 103 104 105 106 107 108 109
+                                    110 111 112 113 114 115 116 117 118 119
+                                    120 121 122 123 124 125 126 127 128 129
+                                    130 131 132 133 134 135 136 137 138 139
+                                    140 141 142 143 144 145 146 147 148 149
+                                    150 151 152 153 154 155 156 157 158 159
+                                    160 161 162 163 164 165 166 167 168 169
+                                    170 171 172 173 174 175 176 177 178 179
+                                    180 181 182 183 184 185 186 187 188 189
+                                    190 191 192 193 194 195 196 197 198 199
+                                    200 201 202 203 204 205 206 207 208 209
+                                    210 211 212 213 214 215 216 217 218 219
+                                    220 221 222 223 224 225 226 227 228 229
+                                    230 231 232 233 234 235 236 237 238 239
+                                    240 241 242 243 244 245 246 247 248 249
+                                    250 251 252 253 254 255>;
+               default-brightness-level = <255>;
+               enable-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+       };
+
+       reg_1p8v: regulator-1p8v {
+               compatible = "regulator-fixed";
+               regulator-name = "1P8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+
+       reg_3p3v: regulator-3p3v {
+               compatible = "regulator-fixed";
+               regulator-name = "3P3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       reg_lvds: regulator-lvds {
+               compatible = "regulator-fixed";
+               regulator-name = "lvds_ppen";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_usb_h1_vbus: regulator-usbh1vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb_h1_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       reg_usb_otg_vbus: regulator-usbotgvbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb_otg_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+};
+
+&audmux {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_audmux>;
+       status = "okay";
+};
+
+&ecspi1 {
+       fsl,spi-num-chipselects = <1>;
+       cs-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       status = "okay";
+
+       flash: n25q032@0 {
+               compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <20000000>;
+               reg = <0>;
+
+               partition@0 {
+                       label = "U-Boot";
+                       reg = <0x0 0xc0000>;
+               };
+
+               partition@c0000 {
+                       label = "env";
+                       reg = <0xc0000 0x10000>;
+               };
+
+               partition@d0000 {
+                       label = "spare";
+                       reg = <0xd0000 0x130000>;
+               };
+       };
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet>;
+       phy-mode = "rgmii";
+       status = "okay";
+};
+
+&hdmi {
+       ddc-i2c-bus = <&i2c2>;
+       status = "okay";
+};
+
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+};
+
+&i2c2 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+
+       pmic@58 {
+               compatible = "dlg,da9063";
+               reg = <0x58>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pmic>;
+               interrupt-parent = <&gpio7>;
+               interrupts = <13 IRQ_TYPE_LEVEL_LOW>;
+
+               onkey {
+                       compatible = "dlg,da9063-onkey";
+               };
+
+               regulators {
+                       vdd_bcore1: bcore1 {
+                               regulator-min-microvolt = <1420000>;
+                               regulator-max-microvolt = <1420000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       vdd_bcore2: bcore2 {
+                               regulator-min-microvolt = <1420000>;
+                               regulator-max-microvolt = <1420000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       vdd_bpro: bpro {
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       vdd_bmem: bmem {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       vdd_bio: bio {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       vdd_bperi: bperi {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       vdd_ldo1: ldo1 {
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1860000>;
+                       };
+
+                       vdd_ldo2: ldo2 {
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1860000>;
+                       };
+
+                       vdd_ldo3: ldo3 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3440000>;
+                       };
+
+                       vdd_ldo4: ldo4 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3440000>;
+                       };
+
+                       vdd_ldo5: ldo5 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3600000>;
+                       };
+
+                       vdd_ldo6: ldo6 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3600000>;
+                       };
+
+                       vdd_ldo7: ldo7 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3600000>;
+                       };
+
+                       vdd_ldo8: ldo8 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3600000>;
+                       };
+
+                       vdd_ldo9: ldo9 {
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <3600000>;
+                       };
+
+                       vdd_ldo10: ldo10 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3600000>;
+                       };
+
+                       vdd_ldo11: ldo11 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3600000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+               };
+       };
+
+       rtc@32 {
+               compatible = "epson,rx8010";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_rtc>;
+               reg = <0x32>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+       };
+};
+
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie>;
+       reset-gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&pwm1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm1>;
+       status = "okay";
+};
+
+&pwm2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm2>;
+       status = "okay";
+};
+
+&sata {
+       status = "okay";
+};
+
+&ssi1 {
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       fsl,uart-has-rtscts;
+       status = "okay";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       status = "okay";
+};
+
+&usbh1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbhub>;
+       vbus-supply = <&reg_usb_h1_vbus>;
+       reset-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&usbotg {
+       vbus-supply = <&reg_usb_otg_vbus>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       disable-over-current;
+       status = "okay";
+};
+
+&usdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+       no-1-8-v;
+       keep-power-in-suspend;
+       wakeup-source;
+       status = "okay";
+};
+
+&usdhc3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc3 &pinctrl_usdhc3_reset>;
+       bus-width = <8>;
+       vmmc-supply = <&vdd_bperi>;
+       vqmmc-supply = <&vdd_bio>;
+       non-removable;
+       keep-power-in-suspend;
+       status = "okay";
+};
+
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog>;
+
+       pinctrl_audmux: audmuxgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT20__AUD4_TXC  0x130b0
+                       MX6QDL_PAD_DISP0_DAT21__AUD4_TXD  0x130b0
+                       MX6QDL_PAD_DISP0_DAT22__AUD4_TXFS 0x130b0
+                       MX6QDL_PAD_DISP0_DAT23__AUD4_RXD  0x130b0
+               >;
+       };
+
+       pinctrl_display: dispgrp {
+               fsl,pins = <
+                       /* BLEN_OUT */
+                       MX6QDL_PAD_GPIO_0__GPIO1_IO00    0x1b0b0
+                       /* LVDS_PPEN_OUT */
+                       MX6QDL_PAD_EIM_D22__GPIO3_IO22   0x1b0b0
+               >;
+       };
+
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
+                       MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
+                       MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
+                       /* SPI1 CS */
+                       MX6QDL_PAD_EIM_EB2__GPIO2_IO30  0x1b0b0
+               >;
+       };
+
+       pinctrl_ecspi5: ecspi5grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_DAT0__ECSPI5_MISO        0x1b0b0
+                       MX6QDL_PAD_SD1_CMD__ECSPI5_MOSI         0x1b0b0
+                       MX6QDL_PAD_SD1_CLK__ECSPI5_SCLK         0x1b0b0
+                       MX6QDL_PAD_SD1_DAT1__GPIO1_IO17         0x1b0b0
+               >;
+       };
+
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO       0x100b0
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC         0x100b0
+                       MX6QDL_PAD_RGMII_TXC__RGMII_TXC       0x100b0
+                       MX6QDL_PAD_RGMII_TD0__RGMII_TD0       0x100b0
+                       MX6QDL_PAD_RGMII_TD1__RGMII_TD1       0x100b0
+                       MX6QDL_PAD_RGMII_TD2__RGMII_TD2       0x100b0
+                       MX6QDL_PAD_RGMII_TD3__RGMII_TD3       0x100b0
+                       MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
+                       MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK  0x100b0
+                       MX6QDL_PAD_RGMII_RXC__RGMII_RXC       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD0__RGMII_RD0       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD1__RGMII_RD1       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD2__RGMII_RD2       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD3__RGMII_RD3       0x1b0b0
+                       MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+                       /* FEC Reset */
+                       MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28     0x1b0b0
+                       /* AR8033 Interrupt */
+                       MX6QDL_PAD_GPIO_19__GPIO4_IO05        0x1b0b0
+               >;
+       };
+
+       pinctrl_hog: hoggrp {
+               fsl,pins = <
+                       /* GPIO 0-7 */
+                       MX6QDL_PAD_NANDF_D0__GPIO2_IO00  0x1b0b0
+                       MX6QDL_PAD_NANDF_D1__GPIO2_IO01  0x1b0b0
+                       MX6QDL_PAD_NANDF_D2__GPIO2_IO02  0x1b0b0
+                       MX6QDL_PAD_NANDF_D3__GPIO2_IO03  0x1b0b0
+                       MX6QDL_PAD_NANDF_D4__GPIO2_IO04  0x1b0b0
+                       MX6QDL_PAD_NANDF_D5__GPIO2_IO05  0x1b0b0
+                       MX6QDL_PAD_NANDF_D6__GPIO2_IO06  0x1b0b0
+                       MX6QDL_PAD_NANDF_D7__GPIO2_IO07  0x1b0b0
+                       /* SUS_S3_OUT to CPLD */
+                       MX6QDL_PAD_KEY_ROW2__GPIO4_IO11  0x1b0b0
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT8__I2C1_SDA  0x4001b8b1
+                       MX6QDL_PAD_CSI0_DAT9__I2C1_SCL  0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL3__I2C2_SCL   0x4001b8b1
+                       MX6QDL_PAD_KEY_ROW3__I2C2_SDA   0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_3__I2C3_SCL     0x4001b8b1
+                       MX6QDL_PAD_GPIO_6__I2C3_SDA     0x4001b8b1
+               >;
+       };
+
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       /* PCIe Reset */
+                       MX6QDL_PAD_GPIO_17__GPIO7_IO12  0x1b0b0
+                       /* PCIe Wake */
+                       MX6QDL_PAD_GPIO_5__GPIO1_IO05   0x1b0b0
+               >;
+       };
+
+       pinctrl_pmic: pmicgrp {
+               fsl,pins = <
+                       /* PMIC Interrupt */
+                       MX6QDL_PAD_GPIO_18__GPIO7_IO13  0x1b0b0
+               >;
+       };
+
+       pinctrl_pwm1: pwm1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_DAT3__PWM1_OUT   0x1b0b1
+               >;
+       };
+
+       pinctrl_pwm2: pwm2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_1__PWM2_OUT     0x1b0b1
+               >;
+       };
+
+       pinctrl_rtc: rtcgrp {
+               fsl,pins = <
+                       /* RTC_INT */
+                       MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0
+               >;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_EIM_D23__UART3_CTS_B   0x1b0b1
+                       MX6QDL_PAD_EIM_D31__UART3_RTS_B   0x1b0b1
+               >;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1
+               >;
+       };
+
+       pinctrl_usbhub: usbhubgrp {
+               fsl,pins = <
+                       /* HUB_RESET */
+                       MX6QDL_PAD_GPIO_16__GPIO7_IO11  0x1b0b0
+               >;
+       };
+
+       pinctrl_usbotg: usbotggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD2_CMD__SD2_CMD     0x17059
+                       MX6QDL_PAD_SD2_CLK__SD2_CLK     0x10059
+                       MX6QDL_PAD_SD2_DAT0__SD2_DATA0  0x17059
+                       MX6QDL_PAD_SD2_DAT1__SD2_DATA1  0x17059
+                       MX6QDL_PAD_SD2_DAT2__SD2_DATA2  0x17059
+                       MX6QDL_PAD_SD2_DAT3__SD2_DATA3  0x17059
+                       /* uSDHC2 CD */
+                       MX6QDL_PAD_GPIO_4__GPIO1_IO04   0x1b0b0
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD     0x17059
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK     0x10059
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0  0x17059
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1  0x17059
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2  0x17059
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3  0x17059
+                       MX6QDL_PAD_SD3_DAT4__SD3_DATA4  0x17059
+                       MX6QDL_PAD_SD3_DAT5__SD3_DATA5  0x17059
+                       MX6QDL_PAD_SD3_DAT6__SD3_DATA6  0x17059
+                       MX6QDL_PAD_SD3_DAT7__SD3_DATA7  0x17059
+               >;
+       };
+
+       pinctrl_usdhc3_reset: usdhc3grp-reset {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_RST__SD3_RESET   0x170F9
+               >;
+       };
+
+       pinctrl_usdhc4: usdhc4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_CMD__SD4_CMD     0x17059
+                       MX6QDL_PAD_SD4_CLK__SD4_CLK     0x17059
+                       MX6QDL_PAD_SD4_DAT0__SD4_DATA0  0x17059
+                       MX6QDL_PAD_SD4_DAT1__SD4_DATA1  0x17059
+                       MX6QDL_PAD_SD4_DAT2__SD4_DATA2  0x17059
+                       MX6QDL_PAD_SD4_DAT3__SD4_DATA3  0x17059
+                       MX6QDL_PAD_SD4_DAT4__SD4_DATA4  0x17059
+                       MX6QDL_PAD_SD4_DAT5__SD4_DATA5  0x17059
+                       MX6QDL_PAD_SD4_DAT6__SD4_DATA6  0x17059
+                       MX6QDL_PAD_SD4_DAT7__SD4_DATA7  0x17059
+                       /* uSDHC4 CD */
+                       MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x1b0b0
+                       /* uSDHC4 SDIO PWR */
+                       MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x1b0b0
+                       /* uSDHC4 SDIO WP */
+                       MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x1b0b0
+                       /* uSDHC4 SDIO LED */
+                       MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x1b0b0
+               >;
+       };
+
+       pinctrl_wdog: wdoggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_9__WDOG1_B      0x1b0b0
+               >;
+       };
+};
diff --git a/arch/arm/boot/dts/imx6q-bx50v3.dtsi b/arch/arm/boot/dts/imx6q-bx50v3.dtsi
new file mode 100644 (file)
index 0000000..bb66dfd
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2015 Timesys Corporation.
+ * Copyright 2015 General Electric Company
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "imx6q-ba16.dtsi"
+
+/ {
+       clocks {
+               mclk: clock@0 {
+                       compatible = "fixed-clock";
+                       reg = <0>;
+                       #clock-cells = <0>;
+                       clock-frequency = <22000000>;
+               };
+       };
+
+       reg_wl18xx_vmmc: regulator-wl18xx {
+               compatible = "regulator-fixed";
+               regulator-name = "vwl1807";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&pca9539 3 GPIO_ACTIVE_HIGH>;
+               startup-delay-us = <70000>;
+               enable-active-high;
+       };
+
+       reg_wlan: regulator-wlan {
+               compatible = "regulator-fixed";
+               regulator-name = "3P3V_wlan";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               gpio = <&gpio6 14 GPIO_ACTIVE_HIGH>;
+       };
+
+       sound {
+               compatible = "fsl,imx6q-ba16-sgtl5000",
+                            "fsl,imx-audio-sgtl5000";
+               model = "imx6q-ba16-sgtl5000";
+               ssi-controller = <&ssi1>;
+               audio-codec = <&sgtl5000>;
+               audio-routing =
+                       "MIC_IN", "Mic Jack",
+                       "Mic Jack", "Mic Bias",
+                       "LINE_IN", "Line In Jack",
+                       "Headphone Jack", "HP_OUT";
+               mux-int-port = <1>;
+               mux-ext-port = <4>;
+       };
+};
+
+&ecspi5 {
+       fsl,spi-num-chipselects = <1>;
+       cs-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi5>;
+       status = "okay";
+
+       m25_eeprom: m25p80@0 {
+               compatible = "atmel,at25";
+               spi-max-frequency = <20000000>;
+               size = <0x8000>;
+               pagesize = <64>;
+               reg = <0>;
+               address-width = <16>;
+       };
+};
+
+&i2c1 {
+       pca9547: mux@70 {
+               compatible = "nxp,pca9547";
+               reg = <0x70>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               mux1_i2c1: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0>;
+
+                       ads7830: ads7830@48 {
+                               compatible = "ti,ads7830";
+                               reg = <0x48>;
+                       };
+
+                       mma8453: mma8453@1c {
+                               compatible = "fsl,mma8453";
+                               reg = <0x1c>;
+                       };
+               };
+
+               mux1_i2c2: i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x1>;
+
+                       eeprom: eeprom@50 {
+                               compatible = "atmel,24c08";
+                               reg = <0x50>;
+                       };
+
+                       mpl3115: mpl3115@60 {
+                               compatible = "fsl,mpl3115";
+                               reg = <0x60>;
+                       };
+               };
+
+               mux1_i2c3: i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x2>;
+               };
+
+               mux1_i2c4: i2c@3 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x3>;
+
+                       sgtl5000: codec@0a {
+                               compatible = "fsl,sgtl5000";
+                               reg = <0x0a>;
+                               clocks = <&mclk>;
+                               VDDA-supply = <&reg_1p8v>;
+                               VDDIO-supply = <&reg_3p3v>;
+                       };
+               };
+
+               mux1_i2c5: i2c@4 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x4>;
+
+                       pca9539: pca9539@74 {
+                               compatible = "nxp,pca9539";
+                               reg = <0x74>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               interrupt-parent = <&gpio2>;
+                               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+                       };
+               };
+
+               mux1_i2c6: i2c@5 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x5>;
+               };
+
+               mux1_i2c7: i2c@6 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x6>;
+               };
+
+               mux1_i2c8: i2c@7 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x7>;
+               };
+       };
+};
+
+&usdhc4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc4>;
+       bus-width = <4>;
+       vmmc-supply = <&reg_wl18xx_vmmc>;
+       no-1-8-v;
+       non-removable;
+       wakeup-source;
+       keep-power-in-suspend;
+       cap-power-off-card;
+       max-frequency = <25000000>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+
+       wlcore: wlcore@2 {
+               compatible = "ti,wl1837";
+               reg = <2>;
+               interrupt-parent = <&gpio2>;
+               interrupts = <6 IRQ_TYPE_LEVEL_HIGH>;
+               tcxo-clock-frequency = <26000000>;
+       };
+};
diff --git a/arch/arm/boot/dts/imx6q-evi.dts b/arch/arm/boot/dts/imx6q-evi.dts
new file mode 100644 (file)
index 0000000..4fa5601
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * Copyright 2016 United Western Technologies.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/dts-v1/;
+#include "imx6q.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       model = "Uniwest Evi";
+       compatible = "uniwest,imx6q-evi", "fsl,imx6q";
+
+       memory {
+               reg = <0x10000000 0x40000000>;
+       };
+
+       reg_usbh1_vbus: regulator-usbhubreset {
+               compatible = "regulator-fixed";
+               regulator-name = "usbh1_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               enable-active-high;
+               startup-delay-us = <2>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbh1_hubreset>;
+               gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+       };
+
+       reg_usb_otg_vbus: regulator-usbotgvbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb_otg_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbotgvbus>;
+               gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       panel {
+               compatible = "sharp,lq101k1ly04";
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&lvds0_out>;
+                       };
+               };
+       };
+};
+
+&ecspi1 {
+       fsl,spi-num-chipselects = <1>;
+       cs-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1cs>;
+       status = "okay";
+};
+
+&ecspi3 {
+       fsl,spi-num-chipselects = <3>;
+       cs-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>,
+               <&gpio4 25 GPIO_ACTIVE_LOW>,
+               <&gpio4 26 GPIO_ACTIVE_LOW>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi3 &pinctrl_ecspi3cs>;
+       status = "okay";
+};
+
+&ecspi5 {
+       fsl,spi-num-chipselects = <4>;
+       cs-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>,
+               <&gpio1 13 GPIO_ACTIVE_LOW>,
+               <&gpio1 12 GPIO_ACTIVE_LOW>,
+               <&gpio2 9 GPIO_ACTIVE_HIGH>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi5 &pinctrl_ecspi5cs>;
+       status = "okay";
+
+       eeprom: m95m02@1 {
+               compatible = "st,m95m02", "atmel,at25";
+               size = <262144>;
+               pagesize = <256>;
+               address-width = <24>;
+               spi-max-frequency = <5000000>;
+               reg = <1>;
+       };
+
+       pb_rtc: rtc@3 {
+               compatible = "nxp,rtc-pcf2123";
+               spi-max-frequency = <2450000>;
+               spi-cs-high;
+               reg = <3>;
+       };
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet>;
+       phy-mode = "rgmii";
+       phy-reset-gpios = <&gpio1 25 0>;
+       status = "okay";
+};
+
+&gpmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpminand>;
+       status = "okay";
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       clock-frequency = <100000>;
+       status = "okay";
+};
+
+&i2c3 {
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       pinctrl-1 = <&pinctrl_i2c3_gpio>;
+       clock-frequency = <100000>;
+       scl-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+       sda-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       battery: sbs-battery@b {
+               compatible = "sbs,sbs-battery";
+               reg = <0x0b>;
+               sbs,poll-retry-count = <100>;
+               sbs,i2c-retry-count = <100>;
+       };
+};
+
+&ldb {
+       status = "okay";
+
+       lvds0: lvds-channel@0 {
+               status = "okay";
+
+               port@4 {
+                       reg = <4>;
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
+       };
+};
+
+&ssi1 {
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&usbh1 {
+       vbus-supply = <&reg_usbh1_vbus>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh1>;
+       dr_mode = "host";
+       disable-over-current;
+       status = "okay";
+};
+
+&usbotg {
+       vbus-supply = <&reg_usb_otg_vbus>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       disable-over-current;
+       dr_mode = "otg";
+       status = "okay";
+};
+
+&usdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       non-removable;
+       status = "okay";
+};
+
+&weim {
+       #address-cells = <2>;
+       #size-cells = <1>;
+       ranges = <0 0 0x08000000 0x08000000>;
+       fsl,weim-cs-gpr = <&gpr>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_weimfpga &pinctrl_weimcs>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog>;
+
+       pinctrl_hog: hoggrp {
+               fsl,pins = <
+                       /* pwr mcu alert irq */
+                       MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x1b0b0
+                       /* remainder ???? */
+                       MX6QDL_PAD_CSI0_MCLK__GPIO5_IO19 0x1b0b0
+               >;
+       };
+
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1
+                       MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1
+                       MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1
+               >;
+       };
+
+       pinctrl_ecspi1cs: ecspi1csgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0
+               >;
+       };
+
+       pinctrl_ecspi3: ecspi3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x10068
+                       MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x10068
+                       MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x1f068
+               >;
+       };
+
+       pinctrl_ecspi3cs: ecspi3csgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x1b0b0
+                       MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x1b0b0
+                       MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x1b0b0
+                       MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x1b0b0
+               >;
+       };
+
+       pinctrl_ecspi5: ecspi5grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD2_CLK__ECSPI5_SCLK 0x100b1
+                       MX6QDL_PAD_SD2_CMD__ECSPI5_MOSI 0x100b1
+                       MX6QDL_PAD_SD2_DAT0__ECSPI5_MISO 0x100b1
+               >;
+       };
+
+       pinctrl_ecspi5cs: ecspi5csgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD2_DAT1__GPIO1_IO14 0x1b0b0
+                       MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x1b0b0
+                       MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x1b0b0
+                       MX6QDL_PAD_SD4_DAT1__GPIO2_IO09 0x1b0b0
+               >;
+       };
+
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
+                       MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0
+                       MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0
+                       MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0
+                       MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0
+                       MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0
+                       MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0
+                       MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
+                       MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
+                       MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0
+                       MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0
+                       MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0
+                       MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0
+                       MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+                       MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x4001b0a8
+                       MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0
+               >;
+       };
+
+       pinctrl_gpminand: gpminandgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1
+                       MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1
+                       MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1
+                       MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000
+                       MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1
+                       MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1
+                       MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1
+                       MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1
+                       MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1
+                       MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1
+                       MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1
+                       MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1
+                       MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1
+                       MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1
+                       MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1
+                       MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1
+                       MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+                       MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
+                       MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3_gpio: i2c3gpiogrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x4001b8b1
+                       MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x4001b8b1
+               >;
+       };
+
+       pinctrl_weimcs: weimcsgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0xb0b1
+                       MX6QDL_PAD_EIM_CS1__EIM_CS1_B 0xb0b1
+               >;
+       };
+
+       pinctrl_weimfpga: weimfpgagrp {
+               fsl,pins = <
+                       /* weim misc */
+                       MX6QDL_PAD_EIM_OE__EIM_OE_B 0xb0b1
+                       MX6QDL_PAD_EIM_RW__EIM_RW 0xb0b1
+                       MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0xb060
+                       MX6QDL_PAD_EIM_BCLK__EIM_BCLK 0xb0b1
+                       MX6QDL_PAD_EIM_LBA__EIM_LBA_B 0xb0b1
+                       MX6QDL_PAD_EIM_EB0__EIM_EB0_B 0xb0b1
+                       MX6QDL_PAD_EIM_EB1__EIM_EB1_B 0xb0b1
+                       MX6QDL_PAD_EIM_EB2__EIM_EB2_B 0xb0b1
+                       MX6QDL_PAD_EIM_EB3__EIM_EB3_B 0xb0b1
+                       /* weim data */
+                       MX6QDL_PAD_CSI0_DATA_EN__EIM_DATA00 0x1b0b0
+                       MX6QDL_PAD_CSI0_VSYNC__EIM_DATA01 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT4__EIM_DATA02 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT5__EIM_DATA03 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT6__EIM_DATA04 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT7__EIM_DATA05 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT8__EIM_DATA06 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT9__EIM_DATA07 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT12__EIM_DATA08 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT13__EIM_DATA09 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT14__EIM_DATA10 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT15__EIM_DATA11 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT16__EIM_DATA12 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT17__EIM_DATA13 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT18__EIM_DATA14 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT19__EIM_DATA15 0x1b0b0
+                       MX6QDL_PAD_EIM_D16__EIM_DATA16 0x1b0b0
+                       MX6QDL_PAD_EIM_D17__EIM_DATA17 0x1b0b0
+                       MX6QDL_PAD_EIM_D18__EIM_DATA18 0x1b0b0
+                       MX6QDL_PAD_EIM_D19__EIM_DATA19 0x1b0b0
+                       MX6QDL_PAD_EIM_D20__EIM_DATA20 0x1b0b0
+                       MX6QDL_PAD_EIM_D21__EIM_DATA21 0x1b0b0
+                       MX6QDL_PAD_EIM_D22__EIM_DATA22 0x1b0b0
+                       MX6QDL_PAD_EIM_D23__EIM_DATA23 0x1b0b0
+                       MX6QDL_PAD_EIM_D24__EIM_DATA24 0x1b0b0
+                       MX6QDL_PAD_EIM_D25__EIM_DATA25 0x1b0b0
+                       MX6QDL_PAD_EIM_D26__EIM_DATA26 0x1b0b0
+                       MX6QDL_PAD_EIM_D27__EIM_DATA27 0x1b0b0
+                       MX6QDL_PAD_EIM_D28__EIM_DATA28 0x1b0b0
+                       MX6QDL_PAD_EIM_D29__EIM_DATA29 0x1b0b0
+                       MX6QDL_PAD_EIM_D30__EIM_DATA30 0x1b0b0
+                       MX6QDL_PAD_EIM_D31__EIM_DATA31 0x1b0b0
+                       /* weim address */
+                       MX6QDL_PAD_EIM_A25__EIM_ADDR25 0xb0b1
+                       MX6QDL_PAD_EIM_A24__EIM_ADDR24 0xb0b1
+                       MX6QDL_PAD_EIM_A23__EIM_ADDR23 0xb0b1
+                       MX6QDL_PAD_EIM_A22__EIM_ADDR22 0xb0b1
+                       MX6QDL_PAD_EIM_A21__EIM_ADDR21 0xb0b1
+                       MX6QDL_PAD_EIM_A20__EIM_ADDR20 0xb0b1
+                       MX6QDL_PAD_EIM_A19__EIM_ADDR19 0xb0b1
+                       MX6QDL_PAD_EIM_A18__EIM_ADDR18 0xb0b1
+                       MX6QDL_PAD_EIM_A17__EIM_ADDR17 0xb0b1
+                       MX6QDL_PAD_EIM_A16__EIM_ADDR16 0xb0b1
+                       MX6QDL_PAD_EIM_DA15__EIM_AD15 0xb0b1
+                       MX6QDL_PAD_EIM_DA14__EIM_AD14 0xb0b1
+                       MX6QDL_PAD_EIM_DA13__EIM_AD13 0xb0b1
+                       MX6QDL_PAD_EIM_DA12__EIM_AD12 0xb0b1
+                       MX6QDL_PAD_EIM_DA11__EIM_AD11 0xb0b1
+                       MX6QDL_PAD_EIM_DA10__EIM_AD10 0xb0b1
+                       MX6QDL_PAD_EIM_DA9__EIM_AD09 0xb0b1
+                       MX6QDL_PAD_EIM_DA8__EIM_AD08 0xb0b1
+                       MX6QDL_PAD_EIM_DA7__EIM_AD07 0xb0b1
+                       MX6QDL_PAD_EIM_DA6__EIM_AD06 0xb0b1
+                       MX6QDL_PAD_EIM_DA5__EIM_AD05 0xb0b1
+                       MX6QDL_PAD_EIM_DA4__EIM_AD04 0xb0b1
+                       MX6QDL_PAD_EIM_DA3__EIM_AD03 0xb0b1
+                       MX6QDL_PAD_EIM_DA2__EIM_AD02 0xb0b1
+                       MX6QDL_PAD_EIM_DA1__EIM_AD01 0xb0b1
+                       MX6QDL_PAD_EIM_DA0__EIM_AD00 0xb0b1
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_DAT5__UART2_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_SD3_DAT4__UART2_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_SD3_CLK__UART2_RTS_B 0x1b0b1
+                       MX6QDL_PAD_SD3_CMD__UART2_CTS_B 0x1b0b1
+               >;
+       };
+
+       pinctrl_usbh1: usbh1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0
+                       /* usbh1_b OC */
+                       MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0
+               >;
+       };
+
+       pinctrl_usbh1_hubreset: usbh1hubresetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
+               >;
+       };
+
+       pinctrl_usbotg: usbotggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+                       MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0
+               >;
+       };
+
+       pinctrl_usbotgvbus: usbotgvbusgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x000b0
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059
+                       MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059
+                       MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
+                       MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
+                       MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
+                       MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
+               >;
+       };
+};
index 00bd63e..b715deb 100644 (file)
@@ -44,7 +44,7 @@
                        label = "recovery";
                        gpios = <&gpio3 16 1>;
                        linux,code = <0x198>; /* KEY_RESTART */
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 };
diff --git a/arch/arm/boot/dts/imx6q-icore-rqs.dts b/arch/arm/boot/dts/imx6q-icore-rqs.dts
new file mode 100644 (file)
index 0000000..0053188
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Amarula Solutions B.V.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include "imx6qdl-icore-rqs.dtsi"
+
+/ {
+       model = "Engicam i.CoreM6 Quad SOM";
+       compatible = "engicam,imx6-icore-rqs", "fsl,imx6q";
+
+       sound {
+               compatible = "fsl,imx-audio-sgtl5000";
+               model = "imx-audio-sgtl5000";
+               ssi-controller = <&ssi1>;
+               audio-codec = <&codec>;
+               audio-routing =
+                       "MIC_IN", "Mic Jack",
+                       "Mic Jack", "Mic Bias",
+                       "Headphone Jack", "HP_OUT";
+               mux-int-port = <1>;
+               mux-ext-port = <4>;
+       };
+};
+
+&i2c3 {
+       codec: sgtl5000@0a {
+               compatible = "fsl,sgtl5000";
+               reg = <0x0a>;
+               clocks = <&clks IMX6QDL_CLK_CKO>;
+               VDDA-supply = <&reg_2p5v>;
+               VDDIO-supply = <&reg_3p3v>;
+               VDDD-supply = <&reg_1p8v>;
+       };
+};
+
+&sata {
+       status = "okay";
+};
index 5645d52..0da81bc 100644 (file)
                };
        };
 
-       regulators {
-               compatible = "simple-bus";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               reg_2p5v: regulator@0 {
-                       compatible = "regulator-fixed";
-                       reg = <0>;
-                       regulator-name = "2P5V";
-                       regulator-min-microvolt = <2500000>;
-                       regulator-max-microvolt = <2500000>;
-               };
+       reg_2p5v: regulator-2p5v {
+               compatible = "regulator-fixed";
+               regulator-name = "2P5V";
+               regulator-min-microvolt = <2500000>;
+               regulator-max-microvolt = <2500000>;
+       };
 
-               reg_3p3v: regulator@1 {
-                       compatible = "regulator-fixed";
-                       reg = <1>;
-                       regulator-name = "3P3V";
-                       regulator-min-microvolt = <3300000>;
-                       regulator-max-microvolt = <3300000>;
-               };
+       reg_3p3v: regulator-3p3v {
+               compatible = "regulator-fixed";
+               regulator-name = "3P3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
 
-               reg_5p0v: regulator@2 {
-                       compatible = "regulator-fixed";
-                       reg = <2>;
-                       regulator-name = "5P0V";
-                       regulator-min-microvolt = <5000000>;
-                       regulator-max-microvolt = <5000000>;
-               };
+       reg_5p0v: regulator-5p0v {
+               compatible = "regulator-fixed";
+               regulator-name = "5P0V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
        };
 
        sound-sgtl5000 {
 };
 
 &sata {
+       fsl,transmit-level-mV = <1104>;
+       fsl,transmit-boost-mdB = <3330>;
+       fsl,transmit-atten-16ths = <16>;
+       fsl,receive-eq-mdB = <3000>;
        status = "okay";
 };
 
        bus-width = <4>;
        cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
+       vqmmc-supply = <&reg_3p3v>;
+       voltage-ranges = <3300 3300>;
+       no-1-8-v;
        status = "okay";
 };
 
        cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
+       vqmmc-supply = <&reg_3p3v>;
+       voltage-ranges = <3300 3300>;
+       no-1-8-v;
        status = "okay";
 };
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
        bus-width = <8>;
+       vmmc-supply = <&reg_3p3v>;
+       vqmmc-supply = <&reg_3p3v>;
+       voltage-ranges = <3300 3300>;
        non-removable;
        no-1-8-v;
        status = "okay";
 };
 
 &iomuxc {
-       imx6q-tbs2910 {
-               pinctrl_enet: enetgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_ENET_MDIO__ENET_MDIO       0x1b0b0
-                               MX6QDL_PAD_ENET_MDC__ENET_MDC         0x1b0b0
-                               MX6QDL_PAD_RGMII_TXC__RGMII_TXC       0x1b0b0
-                               MX6QDL_PAD_RGMII_TD0__RGMII_TD0       0x1b0b0
-                               MX6QDL_PAD_RGMII_TD1__RGMII_TD1       0x1b0b0
-                               MX6QDL_PAD_RGMII_TD2__RGMII_TD2       0x1b0b0
-                               MX6QDL_PAD_RGMII_TD3__RGMII_TD3       0x1b0b0
-                               MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0
-                               MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK  0x1b0b0
-                               MX6QDL_PAD_RGMII_RXC__RGMII_RXC       0x1b0b0
-                               MX6QDL_PAD_RGMII_RD0__RGMII_RD0       0x1b0b0
-                               MX6QDL_PAD_RGMII_RD1__RGMII_RD1       0x1b0b0
-                               MX6QDL_PAD_RGMII_RD2__RGMII_RD2       0x1b0b0
-                               MX6QDL_PAD_RGMII_RD3__RGMII_RD3       0x1b0b0
-                               MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
-                               MX6QDL_PAD_GPIO_16__ENET_REF_CLK      0x4001b0a8
-                               MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25    0x1b059
-                       >;
-               };
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO       0x1b0b0
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC         0x1b0b0
+                       MX6QDL_PAD_RGMII_TXC__RGMII_TXC       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD0__RGMII_TD0       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD1__RGMII_TD1       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD2__RGMII_TD2       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD3__RGMII_TD3       0x1b0b0
+                       MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0
+                       MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK  0x1b0b0
+                       MX6QDL_PAD_RGMII_RXC__RGMII_RXC       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD0__RGMII_RD0       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD1__RGMII_RD1       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD2__RGMII_RD2       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD3__RGMII_RD3       0x1b0b0
+                       MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+                       MX6QDL_PAD_GPIO_16__ENET_REF_CLK      0x4001b0a8
+                       MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25    0x1b059
+               >;
+       };
 
-               pinctrl_hdmi: hdmigrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
-                       >;
-               };
+       pinctrl_gpio_fan: gpiofangrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D28__GPIO3_IO28        0x130b1
+               >;
+       };
 
-               pinctrl_i2c1: i2c1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT9__I2C1_SCL        0x4001b8b1
-                               MX6QDL_PAD_CSI0_DAT8__I2C1_SDA        0x4001b8b1
-                       >;
-               };
+       pinctrl_gpio_leds: gpioledsgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_2__GPIO1_IO02         0x130b1
+               >;
+       };
 
-               pinctrl_i2c2: i2c2grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_KEY_COL3__I2C2_SCL         0x4001b8b1
-                               MX6QDL_PAD_KEY_ROW3__I2C2_SDA         0x4001b8b1
-                       >;
-               };
+       pinctrl_hdmi: hdmigrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
+               >;
+       };
 
-               pinctrl_i2c3: i2c3grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_3__I2C3_SCL           0x4001b8b1
-                               MX6QDL_PAD_GPIO_6__I2C3_SDA           0x4001b8b1
-                       >;
-               };
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT9__I2C1_SCL        0x4001b8b1
+                       MX6QDL_PAD_CSI0_DAT8__I2C1_SDA        0x4001b8b1
+               >;
+       };
 
-               pinctrl_ir: irgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_EIM_D18__GPIO3_IO18        0x17059
-                       >;
-               };
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL3__I2C2_SCL         0x4001b8b1
+                       MX6QDL_PAD_KEY_ROW3__I2C2_SDA         0x4001b8b1
+               >;
+       };
 
-               pinctrl_pcie: pciegrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_17__GPIO7_IO12        0x17059
-                       >;
-               };
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_3__I2C3_SCL           0x4001b8b1
+                       MX6QDL_PAD_GPIO_6__I2C3_SDA           0x4001b8b1
+               >;
+       };
 
-               pinctrl_sgtl5000: sgtl5000grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT7__AUD3_RXD        0x130b0
-                               MX6QDL_PAD_CSI0_DAT4__AUD3_TXC        0x130b0
-                               MX6QDL_PAD_CSI0_DAT5__AUD3_TXD        0x110b0
-                               MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS       0x130b0
-                               MX6QDL_PAD_GPIO_0__CCM_CLKO1          0x130b0
-                       >;
-               };
+       pinctrl_ir: irgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D18__GPIO3_IO18        0x17059
+               >;
+       };
 
-               pinctrl_spdif: spdifgrp {
-                       fsl,pins = <MX6QDL_PAD_GPIO_19__SPDIF_OUT     0x13091
-                       >;
-               };
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_17__GPIO7_IO12        0x17059
+               >;
+       };
 
-               pinctrl_uart1: uart1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA  0x1b0b1
-                               MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA  0x1b0b1
-                       >;
-               };
+       pinctrl_sgtl5000: sgtl5000grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT7__AUD3_RXD        0x130b0
+                       MX6QDL_PAD_CSI0_DAT4__AUD3_TXC        0x130b0
+                       MX6QDL_PAD_CSI0_DAT5__AUD3_TXD        0x110b0
+                       MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS       0x130b0
+                       MX6QDL_PAD_GPIO_0__CCM_CLKO1          0x130b0
+               >;
+       };
 
-               pinctrl_uart2: uart2grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_EIM_D26__UART2_TX_DATA     0x1b0b1
-                               MX6QDL_PAD_EIM_D27__UART2_RX_DATA     0x1b0b1
-                       >;
-               };
+       pinctrl_spdif: spdifgrp {
+               fsl,pins = <MX6QDL_PAD_GPIO_19__SPDIF_OUT     0x13091
+               >;
+       };
 
-               pinctrl_usbotg: usbotggrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID     0x17059
-                       >;
-               };
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA  0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA  0x1b0b1
+               >;
+       };
 
-               pinctrl_usdhc2: usdhc2grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD2_CMD__SD2_CMD           0x17059
-                               MX6QDL_PAD_SD2_CLK__SD2_CLK           0x10059
-                               MX6QDL_PAD_SD2_DAT0__SD2_DATA0        0x17059
-                               MX6QDL_PAD_SD2_DAT1__SD2_DATA1        0x17059
-                               MX6QDL_PAD_SD2_DAT2__SD2_DATA2        0x17059
-                               MX6QDL_PAD_SD2_DAT3__SD2_DATA3        0x17059
-                               MX6QDL_PAD_NANDF_D2__GPIO2_IO02       0x17059
-                       >;
-               };
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D26__UART2_TX_DATA     0x1b0b1
+                       MX6QDL_PAD_EIM_D27__UART2_RX_DATA     0x1b0b1
+               >;
+       };
 
-               pinctrl_usdhc3: usdhc3grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD3_CMD__SD3_CMD           0x17059
-                               MX6QDL_PAD_SD3_CLK__SD3_CLK           0x10059
-                               MX6QDL_PAD_SD3_DAT0__SD3_DATA0        0x17059
-                               MX6QDL_PAD_SD3_DAT1__SD3_DATA1        0x17059
-                               MX6QDL_PAD_SD3_DAT2__SD3_DATA2        0x17059
-                               MX6QDL_PAD_SD3_DAT3__SD3_DATA3        0x17059
-                               MX6QDL_PAD_NANDF_D0__GPIO2_IO00       0x17059
-                               MX6QDL_PAD_NANDF_D1__GPIO2_IO01       0x17059
-                       >;
-               };
+       pinctrl_usbotg: usbotggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID     0x17059
+               >;
+       };
 
-               pinctrl_usdhc4: usdhc4grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD4_CMD__SD4_CMD           0x17059
-                               MX6QDL_PAD_SD4_CLK__SD4_CLK           0x10059
-                               MX6QDL_PAD_SD4_DAT0__SD4_DATA0        0x17059
-                               MX6QDL_PAD_SD4_DAT1__SD4_DATA1        0x17059
-                               MX6QDL_PAD_SD4_DAT2__SD4_DATA2        0x17059
-                               MX6QDL_PAD_SD4_DAT3__SD4_DATA3        0x17059
-                               MX6QDL_PAD_SD4_DAT4__SD4_DATA4        0x17059
-                               MX6QDL_PAD_SD4_DAT5__SD4_DATA5        0x17059
-                               MX6QDL_PAD_SD4_DAT6__SD4_DATA6        0x17059
-                               MX6QDL_PAD_SD4_DAT7__SD4_DATA7        0x17059
-                       >;
-               };
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD2_CMD__SD2_CMD           0x17059
+                       MX6QDL_PAD_SD2_CLK__SD2_CLK           0x10059
+                       MX6QDL_PAD_SD2_DAT0__SD2_DATA0        0x17059
+                       MX6QDL_PAD_SD2_DAT1__SD2_DATA1        0x17059
+                       MX6QDL_PAD_SD2_DAT2__SD2_DATA2        0x17059
+                       MX6QDL_PAD_SD2_DAT3__SD2_DATA3        0x17059
+                       MX6QDL_PAD_NANDF_D2__GPIO2_IO02       0x17059
+               >;
        };
 
-       gpio_fan {
-               pinctrl_gpio_fan: gpiofangrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_EIM_D28__GPIO3_IO28        0x130b1
-                       >;
-               };
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD           0x17059
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK           0x10059
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0        0x17059
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1        0x17059
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2        0x17059
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3        0x17059
+                       MX6QDL_PAD_NANDF_D0__GPIO2_IO00       0x17059
+                       MX6QDL_PAD_NANDF_D1__GPIO2_IO01       0x17059
+               >;
        };
 
-       gpio_leds {
-               pinctrl_gpio_leds: gpioledsgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_2__GPIO1_IO02         0x130b1
-                       >;
-               };
+       pinctrl_usdhc4: usdhc4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_CMD__SD4_CMD           0x17059
+                       MX6QDL_PAD_SD4_CLK__SD4_CLK           0x10059
+                       MX6QDL_PAD_SD4_DAT0__SD4_DATA0        0x17059
+                       MX6QDL_PAD_SD4_DAT1__SD4_DATA1        0x17059
+                       MX6QDL_PAD_SD4_DAT2__SD4_DATA2        0x17059
+                       MX6QDL_PAD_SD4_DAT3__SD4_DATA3        0x17059
+                       MX6QDL_PAD_SD4_DAT4__SD4_DATA4        0x17059
+                       MX6QDL_PAD_SD4_DAT5__SD4_DATA5        0x17059
+                       MX6QDL_PAD_SD4_DAT6__SD4_DATA6        0x17059
+                       MX6QDL_PAD_SD4_DAT7__SD4_DATA7        0x17059
+               >;
        };
 };
index 88aa1e4..2792da9 100644 (file)
@@ -77,7 +77,7 @@
                interrupt-parent = <&gpio3>;
                interrupts = <22 0>;
                wakeup-gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>;
-               linux,wakeup;
+               wakeup-source;
        };
 };
 
index 20bf3c2..9207d80 100644 (file)
@@ -13,7 +13,7 @@
 #include "imx6qdl-wandboard-revb1.dtsi"
 
 / {
-       model = "Wandboard i.MX6 Quad Board";
+       model = "Wandboard i.MX6 Quad Board rev B1";
        compatible = "wand,imx6q-wandboard", "fsl,imx6q";
 
        memory {
index 0d93c0e..cd10c8d 100644 (file)
@@ -22,7 +22,7 @@
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@0 {
+               cpu0: cpu@0 {
                        compatible = "arm,cortex-a9";
                        device_type = "cpu";
                        reg = <0>;
                                };
 
                                ipu2_di0_mipi: endpoint@2 {
+                                       remote-endpoint = <&mipi_mux_2>;
                                };
 
                                ipu2_di0_lvds0: endpoint@3 {
                                };
 
                                ipu2_di1_mipi: endpoint@2 {
+                                       remote-endpoint = <&mipi_mux_3>;
                                };
 
                                ipu2_di1_lvds0: endpoint@3 {
diff --git a/arch/arm/boot/dts/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/imx6qdl-apalis.dtsi
new file mode 100644 (file)
index 0000000..b33e5a9
--- /dev/null
@@ -0,0 +1,984 @@
+/*
+ * Copyright 2014-2016 Toradex AG
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "Toradex Apalis iMX6Q/D Module";
+       compatible = "toradex,apalis_imx6q", "fsl,imx6q";
+
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm4 0 5000000>;
+               status = "disabled";
+       };
+
+       /* DDC_I2C: I2C2_SDA/SCL on MXM3 205/207 */
+       i2cddc: i2c@0 {
+               compatible = "i2c-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c_ddc>;
+               gpios = <&gpio3 16 GPIO_ACTIVE_HIGH /* sda */
+                        &gpio2 30 GPIO_ACTIVE_HIGH /* scl */
+                       >;
+               i2c-gpio,delay-us = <2>;        /* ~100 kHz */
+               status = "disabled";
+       };
+
+       reg_1p8v: regulator-1p8v {
+               compatible = "regulator-fixed";
+               regulator-name = "1P8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+
+       reg_2p5v: regulator-2p5v {
+               compatible = "regulator-fixed";
+               regulator-name = "2P5V";
+               regulator-min-microvolt = <2500000>;
+               regulator-max-microvolt = <2500000>;
+               regulator-always-on;
+       };
+
+       reg_3p3v: regulator-3p3v {
+               compatible = "regulator-fixed";
+               regulator-name = "3P3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       reg_usb_otg_vbus: regulator-usb-otg-vbus {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_regulator_usbotg_pwr>;
+               regulator-name = "usb_otg_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               status = "disabled";
+       };
+
+       /* on module USB hub */
+       reg_usb_host_vbus_hub: regulator-usb-host-vbus-hub {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_regulator_usbhub_pwr>;
+               regulator-name = "usb_host_vbus_hub";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio3 28 GPIO_ACTIVE_HIGH>;
+               startup-delay-us = <2000>;
+               enable-active-high;
+               status = "okay";
+       };
+
+       reg_usb_host_vbus: regulator-usb-host-vbus {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_regulator_usbh_pwr>;
+               regulator-name = "usb_host_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio =  <&gpio1 0 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&reg_usb_host_vbus_hub>;
+               status = "disabled";
+       };
+
+       sound {
+               compatible = "fsl,imx-audio-sgtl5000";
+               model = "imx6q-apalis-sgtl5000";
+               ssi-controller = <&ssi1>;
+               audio-codec = <&codec>;
+               audio-routing =
+                       "LINE_IN", "Line In Jack",
+                       "MIC_IN", "Mic Jack",
+                       "Mic Jack", "Mic Bias",
+                       "Headphone Jack", "HP_OUT";
+               mux-int-port = <1>;
+               mux-ext-port = <4>;
+       };
+
+       sound_spdif: sound-spdif {
+               compatible = "fsl,imx-audio-spdif";
+               model = "imx-spdif";
+               spdif-controller = <&spdif>;
+               spdif-in;
+               spdif-out;
+               status = "disabled";
+       };
+};
+
+&audmux {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_audmux>;
+       status = "okay";
+};
+
+&can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       status = "disabled";
+};
+
+&can2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       status = "disabled";
+};
+
+/* Apalis SPI1 */
+&ecspi1 {
+       fsl,spi-num-chipselects = <1>;
+       cs-gpios = <&gpio5 25 GPIO_ACTIVE_HIGH>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       status = "disabled";
+};
+
+/* Apalis SPI2 */
+&ecspi2 {
+       fsl,spi-num-chipselects = <1>;
+       cs-gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       status = "disabled";
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet>;
+       phy-mode = "rgmii";
+       phy-handle = <&ethphy>;
+       phy-reset-duration = <10>;
+       phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy: ethernet-phy@7 {
+                       interrupt-parent = <&gpio1>;
+                       interrupts = <30 IRQ_TYPE_LEVEL_LOW>;
+                       reg = <7>;
+               };
+       };
+};
+
+/*
+ * GEN1_I2C: I2C1_SDA/SCL on MXM3 209/211 (e.g. RTC on carrier
+ * board)
+ */
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "disabled";
+};
+
+/*
+ * PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and
+ * touch screen controller
+ */
+&i2c2 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+
+       pmic: pfuze100@08 {
+               compatible = "fsl,pfuze100";
+               reg = <0x08>;
+
+               regulators {
+                       sw1a_reg: sw1ab {
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       sw1c_reg: sw1c {
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       sw3a_reg: sw3a {
+                               regulator-min-microvolt = <400000>;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       swbst_reg: swbst {
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5150000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       snvs_reg: vsnvs {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vref_reg: vrefddr {
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen1_reg: vgen1 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen2_reg: vgen2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen3_reg: vgen3 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen4_reg: vgen4 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen5_reg: vgen5 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen6_reg: vgen6 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+               };
+       };
+
+       codec: sgtl5000@0a {
+               compatible = "fsl,sgtl5000";
+               reg = <0x0a>;
+               clocks = <&clks 201>;
+               VDDA-supply = <&reg_2p5v>;
+               VDDIO-supply = <&reg_3p3v>;
+       };
+
+       /* STMPE811 touch screen controller */
+       stmpe811@41 {
+               compatible = "st,stmpe811";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_touch_int>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x41>;
+               interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-parent = <&gpio4>;
+               interrupt-controller;
+               id = <0>;
+               blocks = <0x5>;
+               irq-trigger = <0x1>;
+
+               stmpe_touchscreen {
+                       compatible = "st,stmpe-ts";
+                       reg = <0>;
+                       /* 3.25 MHz ADC clock speed */
+                       st,adc-freq = <1>;
+                       /* 8 sample average control */
+                       st,ave-ctrl = <3>;
+                       /* 7 length fractional part in z */
+                       st,fraction-z = <7>;
+                       /*
+                        * 50 mA typical 80 mA max touchscreen drivers
+                        * current limit value
+                        */
+                       st,i-drive = <1>;
+                       /* 12-bit ADC */
+                       st,mod-12b = <1>;
+                       /* internal ADC reference */
+                       st,ref-sel = <0>;
+                       /* ADC converstion time: 80 clocks */
+                       st,sample-time = <4>;
+                       /* 1 ms panel driver settling time */
+                       st,settling = <3>;
+                       /* 5 ms touch detect interrupt delay */
+                       st,touch-det-delay = <5>;
+               };
+       };
+};
+
+/*
+ * GEN2_I2C, CAM: I2C3_SDA/SCL on MXM3 201/203 (unused)
+ */
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default", "recovery";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       pinctrl-1 = <&pinctrl_i2c3_recovery>;
+       scl-gpios = <&gpio3 17 GPIO_ACTIVE_HIGH>;
+       sda-gpios = <&gpio3 18 GPIO_ACTIVE_HIGH>;
+       status = "disabled";
+};
+
+&pwm1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm1>;
+       status = "disabled";
+};
+
+&pwm2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm2>;
+       status = "disabled";
+};
+
+&pwm3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm3>;
+       status = "disabled";
+};
+
+&pwm4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm4>;
+       status = "disabled";
+};
+
+&spdif {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spdif>;
+       status = "disabled";
+};
+
+&ssi1 {
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1_dte &pinctrl_uart1_ctrl>;
+       fsl,dte-mode;
+       fsl,uart-has-rtscts;
+       status = "disabled";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2_dte>;
+       fsl,dte-mode;
+       fsl,uart-has-rtscts;
+       status = "disabled";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4_dte>;
+       fsl,dte-mode;
+       status = "disabled";
+};
+
+&uart5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart5_dte>;
+       fsl,dte-mode;
+       status = "disabled";
+};
+
+&usbotg {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       disable-over-current;
+       status = "disabled";
+};
+
+/* MMC1 */
+&usdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       vqmmc-supply = <&reg_3p3v>;
+       bus-width = <8>;
+       voltage-ranges = <3300 3300>;
+       status = "disabled";
+};
+
+/* SD1 */
+&usdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       vqmmc-supply = <&reg_3p3v>;
+       bus-width = <4>;
+       voltage-ranges = <3300 3300>;
+       status = "disabled";
+};
+
+/* eMMC */
+&usdhc3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       vqmmc-supply = <&reg_3p3v>;
+       bus-width = <8>;
+       voltage-ranges = <3300 3300>;
+       non-removable;
+       status = "okay";
+};
+
+&weim {
+       status = "disabled";
+};
+
+&iomuxc {
+       /* pins used on module */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_reset_moci>;
+
+       pinctrl_apalis_gpio1: gpio2io04grp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x130b0
+               >;
+       };
+
+       pinctrl_apalis_gpio2: gpio2io05grp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x130b0
+               >;
+       };
+
+       pinctrl_apalis_gpio3: gpio2io06grp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x130b0
+               >;
+       };
+
+       pinctrl_apalis_gpio4: gpio2io07grp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x130b0
+               >;
+       };
+
+       pinctrl_apalis_gpio5: gpio6io10grp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x130b0
+               >;
+       };
+
+       pinctrl_apalis_gpio6: gpio6io09grp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x130b0
+               >;
+       };
+
+       pinctrl_apalis_gpio7: gpio1io02grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x130b0
+               >;
+       };
+
+       pinctrl_apalis_gpio8: gpio1io06grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x130b0
+               >;
+       };
+
+       pinctrl_audmux: audmuxgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT20__AUD4_TXC        0x130b0
+                       MX6QDL_PAD_DISP0_DAT21__AUD4_TXD        0x130b0
+                       MX6QDL_PAD_DISP0_DAT22__AUD4_TXFS       0x130b0
+                       MX6QDL_PAD_DISP0_DAT23__AUD4_RXD        0x130b0
+                       /* SGTL5000 sys_mclk */
+                       MX6QDL_PAD_GPIO_5__CCM_CLKO1            0x130b0
+               >;
+       };
+
+       pinctrl_cam_mclk: cammclkgrp {
+               fsl,pins = <
+                       /* CAM sys_mclk */
+                       MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x00b0
+               >;
+       };
+
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT6__ECSPI1_MISO 0x100b1
+                       MX6QDL_PAD_CSI0_DAT5__ECSPI1_MOSI 0x100b1
+                       MX6QDL_PAD_CSI0_DAT4__ECSPI1_SCLK 0x100b1
+                       /* SPI1 cs */
+                       MX6QDL_PAD_CSI0_DAT7__GPIO5_IO25 0x000b1
+               >;
+       };
+
+       pinctrl_ecspi2: ecspi2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1
+                       MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
+                       MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1
+                       /* SPI2 cs */
+                       MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x000b1
+               >;
+       };
+
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x100b0
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC           0x100b0
+                       MX6QDL_PAD_RGMII_TXC__RGMII_TXC         0x100b0
+                       MX6QDL_PAD_RGMII_TD0__RGMII_TD0         0x100b0
+                       MX6QDL_PAD_RGMII_TD1__RGMII_TD1         0x100b0
+                       MX6QDL_PAD_RGMII_TD2__RGMII_TD2         0x100b0
+                       MX6QDL_PAD_RGMII_TD3__RGMII_TD3         0x100b0
+                       MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL   0x100b0
+                       MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK    0x100b0
+                       MX6QDL_PAD_RGMII_RXC__RGMII_RXC         0x1b0b0
+                       MX6QDL_PAD_RGMII_RD0__RGMII_RD0         0x1b0b0
+                       MX6QDL_PAD_RGMII_RD1__RGMII_RD1         0x1b0b0
+                       MX6QDL_PAD_RGMII_RD2__RGMII_RD2         0x1b0b0
+                       MX6QDL_PAD_RGMII_RD3__RGMII_RD3         0x1b0b0
+                       MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL   0x1b0b0
+                       /* Ethernet PHY reset */
+                       MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25      0x000b0
+                       /* Ethernet PHY interrupt */
+                       MX6QDL_PAD_ENET_TXD0__GPIO1_IO30        0x000b1
+               >;
+       };
+
+       pinctrl_flexcan1: flexcan1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x1b0b0
+                       MX6QDL_PAD_GPIO_8__FLEXCAN1_RX 0x1b0b0
+               >;
+       };
+
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b0
+                       MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b0
+               >;
+       };
+
+       pinctrl_gpio_keys: gpio1io04grp {
+               fsl,pins = <
+                       /* Power button */
+                       MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0
+               >;
+       };
+
+       pinctrl_hdmi_cec: hdmicecgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
+               >;
+       };
+
+       pinctrl_i2c_ddc: gpioi2cddcgrp {
+               fsl,pins = <
+                       /* DDC bitbang */
+                       MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0
+                       MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x1b0b0
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
+                       MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+                       MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
+                       MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3_recovery: i2c3recoverygrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D17__GPIO3_IO17 0x4001b8b1
+                       MX6QDL_PAD_EIM_D18__GPIO3_IO18 0x4001b8b1
+               >;
+       };
+
+       pinctrl_ipu1_csi0: ipu1csi0grp { /* parallel camera */
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12  0xb0b1
+                       MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13  0xb0b1
+                       MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14  0xb0b1
+                       MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15  0xb0b1
+                       MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16  0xb0b1
+                       MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17  0xb0b1
+                       MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18  0xb0b1
+                       MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19  0xb0b1
+                       MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0xb0b1
+                       MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC    0xb0b1
+                       MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC   0xb0b1
+               >;
+       };
+
+       pinctrl_ipu1_lcdif: ipu1lcdifgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_A16__IPU1_DI1_DISP_CLK   0x61
+                       /* DE */
+                       MX6QDL_PAD_EIM_DA10__IPU1_DI1_PIN15     0x61
+                       /* HSync */
+                       MX6QDL_PAD_EIM_DA11__IPU1_DI1_PIN02     0x61
+                       /* VSync */
+                       MX6QDL_PAD_EIM_DA12__IPU1_DI1_PIN03     0x61
+                       MX6QDL_PAD_EIM_DA9__IPU1_DISP1_DATA00   0x61
+                       MX6QDL_PAD_EIM_DA8__IPU1_DISP1_DATA01   0x61
+                       MX6QDL_PAD_EIM_DA7__IPU1_DISP1_DATA02   0x61
+                       MX6QDL_PAD_EIM_DA6__IPU1_DISP1_DATA03   0x61
+                       MX6QDL_PAD_EIM_DA5__IPU1_DISP1_DATA04   0x61
+                       MX6QDL_PAD_EIM_DA4__IPU1_DISP1_DATA05   0x61
+                       MX6QDL_PAD_EIM_DA3__IPU1_DISP1_DATA06   0x61
+                       MX6QDL_PAD_EIM_DA2__IPU1_DISP1_DATA07   0x61
+                       MX6QDL_PAD_EIM_DA1__IPU1_DISP1_DATA08   0x61
+                       MX6QDL_PAD_EIM_DA0__IPU1_DISP1_DATA09   0x61
+                       MX6QDL_PAD_EIM_EB1__IPU1_DISP1_DATA10   0x61
+                       MX6QDL_PAD_EIM_EB0__IPU1_DISP1_DATA11   0x61
+                       MX6QDL_PAD_EIM_A17__IPU1_DISP1_DATA12   0x61
+                       MX6QDL_PAD_EIM_A18__IPU1_DISP1_DATA13   0x61
+                       MX6QDL_PAD_EIM_A19__IPU1_DISP1_DATA14   0x61
+                       MX6QDL_PAD_EIM_A20__IPU1_DISP1_DATA15   0x61
+                       MX6QDL_PAD_EIM_A21__IPU1_DISP1_DATA16   0x61
+                       MX6QDL_PAD_EIM_A22__IPU1_DISP1_DATA17   0x61
+                       MX6QDL_PAD_EIM_A23__IPU1_DISP1_DATA18   0x61
+                       MX6QDL_PAD_EIM_A24__IPU1_DISP1_DATA19   0x61
+                       MX6QDL_PAD_EIM_D31__IPU1_DISP1_DATA20   0x61
+                       MX6QDL_PAD_EIM_D30__IPU1_DISP1_DATA21   0x61
+                       MX6QDL_PAD_EIM_D26__IPU1_DISP1_DATA22   0x61
+                       MX6QDL_PAD_EIM_D27__IPU1_DISP1_DATA23   0x61
+               >;
+       };
+
+       pinctrl_ipu2_vdac: ipu2vdacgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_DI0_DISP_CLK__IPU2_DI0_DISP_CLK 0xd1
+                       MX6QDL_PAD_DI0_PIN15__IPU2_DI0_PIN15       0xd1
+                       MX6QDL_PAD_DI0_PIN2__IPU2_DI0_PIN02        0xd1
+                       MX6QDL_PAD_DI0_PIN3__IPU2_DI0_PIN03        0xd1
+                       MX6QDL_PAD_DISP0_DAT0__IPU2_DISP0_DATA00   0xf9
+                       MX6QDL_PAD_DISP0_DAT1__IPU2_DISP0_DATA01   0xf9
+                       MX6QDL_PAD_DISP0_DAT2__IPU2_DISP0_DATA02   0xf9
+                       MX6QDL_PAD_DISP0_DAT3__IPU2_DISP0_DATA03   0xf9
+                       MX6QDL_PAD_DISP0_DAT4__IPU2_DISP0_DATA04   0xf9
+                       MX6QDL_PAD_DISP0_DAT5__IPU2_DISP0_DATA05   0xf9
+                       MX6QDL_PAD_DISP0_DAT6__IPU2_DISP0_DATA06   0xf9
+                       MX6QDL_PAD_DISP0_DAT7__IPU2_DISP0_DATA07   0xf9
+                       MX6QDL_PAD_DISP0_DAT8__IPU2_DISP0_DATA08   0xf9
+                       MX6QDL_PAD_DISP0_DAT9__IPU2_DISP0_DATA09   0xf9
+                       MX6QDL_PAD_DISP0_DAT10__IPU2_DISP0_DATA10  0xf9
+                       MX6QDL_PAD_DISP0_DAT11__IPU2_DISP0_DATA11  0xf9
+                       MX6QDL_PAD_DISP0_DAT12__IPU2_DISP0_DATA12  0xf9
+                       MX6QDL_PAD_DISP0_DAT13__IPU2_DISP0_DATA13  0xf9
+                       MX6QDL_PAD_DISP0_DAT14__IPU2_DISP0_DATA14  0xf9
+                       MX6QDL_PAD_DISP0_DAT15__IPU2_DISP0_DATA15  0xf9
+               >;
+       };
+
+       pinctrl_mmc_cd: gpiommccdgrp {
+               fsl,pins = <
+                        /* MMC1 CD */
+                       MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x000b0
+               >;
+       };
+
+       pinctrl_pwm1: pwm1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_9__PWM1_OUT 0x1b0b1
+               >;
+       };
+
+       pinctrl_pwm2: pwm2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_1__PWM2_OUT 0x1b0b1
+               >;
+       };
+
+       pinctrl_pwm3: pwm3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+               >;
+       };
+
+       pinctrl_pwm4: pwm4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x1b0b1
+               >;
+       };
+
+       pinctrl_regulator_usbh_pwr: gpioregusbhpwrgrp {
+               fsl,pins = <
+                       /* USBH_EN */
+                       MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x0f058
+               >;
+       };
+
+       pinctrl_regulator_usbhub_pwr: gpioregusbhubpwrgrp {
+               fsl,pins = <
+                       /* USBH_HUB_EN */
+                       MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x0f058
+               >;
+       };
+
+       pinctrl_regulator_usbotg_pwr: gpioregusbotgpwrgrp {
+               fsl,pins = <
+                       /* USBO1 power en */
+                       MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x0f058
+               >;
+       };
+
+       pinctrl_reset_moci: gpioresetmocigrp {
+               fsl,pins = <
+                       /* RESET_MOCI control */
+                       MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x0f058
+               >;
+       };
+
+       pinctrl_sd_cd: gpiosdcdgrp {
+               fsl,pins = <
+                       /* SD1 CD */
+                       MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x000b0
+               >;
+       };
+
+       pinctrl_spdif: spdifgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_16__SPDIF_IN  0x1b0b0
+                       MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0
+               >;
+       };
+
+       pinctrl_touch_int: gpiotouchintgrp {
+               fsl,pins = <
+                       /* STMPE811 interrupt */
+                       MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0
+               >;
+       };
+
+       pinctrl_uart1_dce: uart1dcegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
+               >;
+       };
+
+       /* DTE mode */
+       pinctrl_uart1_dte: uart1dtegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT10__UART1_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT11__UART1_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_EIM_D19__UART1_RTS_B 0x1b0b1
+                       MX6QDL_PAD_EIM_D20__UART1_CTS_B 0x1b0b1
+               >;
+       };
+
+       /* Additional DTR, DSR, DCD */
+       pinctrl_uart1_ctrl: uart1ctrlgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D23__UART1_DCD_B 0x1b0b0
+                       MX6QDL_PAD_EIM_D24__UART1_DTR_B 0x1b0b0
+                       MX6QDL_PAD_EIM_D25__UART1_DSR_B 0x1b0b0
+               >;
+       };
+
+       pinctrl_uart2_dce: uart2dcegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA      0x1b0b1
+                       MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA      0x1b0b1
+               >;
+       };
+
+       /* DTE mode */
+       pinctrl_uart2_dte: uart2dtegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_DAT4__UART2_TX_DATA      0x1b0b1
+                       MX6QDL_PAD_SD4_DAT7__UART2_RX_DATA      0x1b0b1
+                       MX6QDL_PAD_SD4_DAT6__UART2_RTS_B        0x1b0b1
+                       MX6QDL_PAD_SD4_DAT5__UART2_CTS_B        0x1b0b1
+               >;
+       };
+
+       pinctrl_uart4_dce: uart4dcegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1
+               >;
+       };
+
+       /* DTE mode */
+       pinctrl_uart4_dte: uart4dtegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL0__UART4_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_KEY_ROW0__UART4_TX_DATA 0x1b0b1
+               >;
+       };
+
+       pinctrl_uart5_dce: uart5dcegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1
+               >;
+       };
+
+       /* DTE mode */
+       pinctrl_uart5_dte: uart5dtegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL1__UART5_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_KEY_ROW1__UART5_TX_DATA 0x1b0b1
+               >;
+       };
+
+       pinctrl_usbotg: usbotggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_CMD__SD1_CMD    0x17071
+                       MX6QDL_PAD_SD1_CLK__SD1_CLK    0x10071
+                       MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17071
+                       MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17071
+                       MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17071
+                       MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17071
+                       MX6QDL_PAD_NANDF_D0__SD1_DATA4 0x17071
+                       MX6QDL_PAD_NANDF_D1__SD1_DATA5 0x17071
+                       MX6QDL_PAD_NANDF_D2__SD1_DATA6 0x17071
+                       MX6QDL_PAD_NANDF_D3__SD1_DATA7 0x17071
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD2_CMD__SD2_CMD    0x17071
+                       MX6QDL_PAD_SD2_CLK__SD2_CLK    0x10071
+                       MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17071
+                       MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17071
+                       MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17071
+                       MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17071
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD    0x17059
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK    0x10059
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+                       MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059
+                       MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059
+                       MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059
+                       MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059
+                       /* eMMC reset */
+                       MX6QDL_PAD_SD3_RST__SD3_RESET  0x17059
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3100mhzgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD    0x170b9
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK    0x100b9
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9
+                       MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170b9
+                       MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170b9
+                       MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170b9
+                       MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170b9
+                       /* eMMC reset */
+                       MX6QDL_PAD_SD3_RST__SD3_RESET  0x170b9
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3200mhzgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD    0x170f9
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK    0x100f9
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9
+                       MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170f9
+                       MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170f9
+                       MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170f9
+                       MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170f9
+                       /* eMMC reset */
+                       MX6QDL_PAD_SD3_RST__SD3_RESET  0x170f9
+               >;
+       };
+};
index e26ebeb..a8f3500 100644 (file)
@@ -94,7 +94,7 @@
                        label = "User button";
                        gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_MISC>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 5cd16f2..9d7ab6c 100644 (file)
 
                pinctrl_pwm3: pwm3grp {
                        fsl,pins = <
-                               MX6QDL_PAD_SD4_DAT1__PWM3_OUT           0x1b0b1
+                               MX6QDL_PAD_SD1_DAT1__PWM3_OUT           0x1b0b1
                        >;
                };
 
                pinctrl_pwm4: pwm4grp {
                        fsl,pins = <
-                               MX6QDL_PAD_SD4_DAT2__PWM4_OUT           0x1b0b1
+                               MX6QDL_PAD_SD1_CMD__PWM4_OUT            0x1b0b1
                        >;
                };
 
index 9fa8a10..8dd74e9 100644 (file)
 
                pinctrl_pwm3: pwm3grp {
                        fsl,pins = <
-                               MX6QDL_PAD_SD4_DAT1__PWM3_OUT           0x1b0b1
+                               MX6QDL_PAD_SD1_DAT1__PWM3_OUT           0x1b0b1
                        >;
                };
 
index e8375e1..ec3fe74 100644 (file)
 
                pinctrl_pwm3: pwm3grp {
                        fsl,pins = <
-                               MX6QDL_PAD_SD4_DAT1__PWM3_OUT           0x1b0b1
+                               MX6QDL_PAD_SD1_DAT1__PWM3_OUT           0x1b0b1
                        >;
                };
 
index 66983dc..367cc49 100644 (file)
 };
 
 &pwm4 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_pwm4>;
+       pinctrl-names = "default", "state_dio";
+       pinctrl-0 = <&pinctrl_pwm4_backlight>;
+       pinctrl-1 = <&pinctrl_pwm4_dio>;
        status = "okay";
 };
 
                        >;
                };
 
-               pinctrl_pwm4: pwm4grp {
+               pinctrl_pwm4_backlight: pwm4grpbacklight {
                        fsl,pins = <
+                               /* LVDS_PWM J6.5 */
                                MX6QDL_PAD_SD1_CMD__PWM4_OUT            0x1b0b1
                        >;
                };
 
+               pinctrl_pwm4_dio: pwm4grpdio {
+                       fsl,pins = <
+                               /* DIO3 J16.4 */
+                               MX6QDL_PAD_SD4_DAT2__PWM4_OUT           0x1b0b1
+                       >;
+               };
+
                pinctrl_uart1: uart1grp {
                        fsl,pins = <
                                MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA      0x1b0b1
index cca39f1..f27f184 100644 (file)
 
                pinctrl_pwm3: pwm3grp {
                        fsl,pins = <
-                               MX6QDL_PAD_SD4_DAT1__PWM3_OUT           0x1b0b1
+                               MX6QDL_PAD_SD1_DAT1__PWM3_OUT           0x1b0b1
                        >;
                };
 
index 6dd0b76..d6c2358 100644 (file)
@@ -48,7 +48,7 @@
 
        ir_recv: ir-receiver {
                compatible = "gpio-ir-receiver";
-               gpios = <&gpio3 5 1>;
+               gpios = <&gpio3 5 GPIO_ACTIVE_LOW>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_hummingboard_gpio3_5>;
        };
@@ -67,7 +67,7 @@
                reg_usbh1_vbus: usb-h1-vbus {
                        compatible = "regulator-fixed";
                        enable-active-high;
-                       gpio = <&gpio1 0 0>;
+                       gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_hummingboard_usbh1_vbus>;
                        regulator-name = "usb_h1_vbus";
@@ -78,7 +78,7 @@
                reg_usbotg_vbus: usb-otg-vbus {
                        compatible = "regulator-fixed";
                        enable-active-high;
-                       gpio = <&gpio3 22 0>;
+                       gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_hummingboard_usbotg_vbus>;
                        regulator-name = "usb_otg_vbus";
 &pcie {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_hummingboard_pcie_reset>;
-       reset-gpio = <&gpio3 4 0>;
+       reset-gpio = <&gpio3 4 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
new file mode 100644 (file)
index 0000000..f8d945a
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2015 Amarula Solutions B.V.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/imx6qdl-clock.h>
+
+/ {
+       memory {
+               reg = <0x10000000 0x80000000>;
+       };
+
+       reg_1p8v: regulator-1p8v {
+               compatible = "regulator-fixed";
+               regulator-name = "1P8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       reg_2p5v: regulator-2p5v {
+               compatible = "regulator-fixed";
+               regulator-name = "2P5V";
+               regulator-min-microvolt = <2500000>;
+               regulator-max-microvolt = <2500000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       reg_3p3v: regulator-3p3v {
+               compatible = "regulator-fixed";
+               regulator-name = "3P3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       reg_sd3_vmmc: regulator-sd3-vmmc {
+               compatible = "regulator-fixed";
+               regulator-name = "P3V3_SD3_SWITCHED";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio1 4 GPIO_ACTIVE_LOW>;
+               enable-active-high;
+       };
+
+       reg_sd4_vmmc: regulator-sd4-vmmc {
+               compatible = "regulator-fixed";
+               regulator-name = "P3V3_SD4_SWITCHED";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       reg_usb_h1_vbus: regulator-usb-h1-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb_h1_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       reg_usb_otg_vbus: regulator-usb-otg-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb_otg_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       usb_hub: usb-hub {
+               compatible = "smsc,usb3503a";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbhub>;
+               reset-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
+               clocks = <&clks IMX6QDL_CLK_LVDS2_GATE>;
+               clock-names = "refclk";
+       };
+};
+
+&clks {
+       assigned-clocks = <&clks IMX6QDL_CLK_LVDS2_SEL>;
+       assigned-clock-parents = <&clks IMX6QDL_CLK_OSC>;
+};
+
+&audmux {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_audmux>;
+       status = "okay";
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet>;
+       phy-handle = <&eth_phy>;
+       phy-mode = "rgmii";
+       status = "okay";
+
+       mdio {
+               eth_phy: ethernet-phy {
+                       rxc-skew-ps = <1140>;
+                       txc-skew-ps = <1140>;
+                       txen-skew-ps = <600>;
+                       rxdv-skew-ps = <240>;
+                       rxd0-skew-ps = <420>;
+                       rxd1-skew-ps = <600>;
+                       rxd2-skew-ps = <420>;
+                       rxd3-skew-ps = <240>;
+                       txd0-skew-ps = <60>;
+                       txd1-skew-ps = <60>;
+                       txd2-skew-ps = <60>;
+                       txd3-skew-ps = <240>;
+               };
+       };
+};
+
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+};
+
+&i2c2 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+};
+
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie>;
+       reset-gpio = <&gpio3 29 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&ssi1 {
+       fsl,mode = "i2s-slave";
+       status = "okay";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       status = "okay";
+};
+
+&usbh1 {
+       vbus-supply = <&reg_usb_h1_vbus>;
+       disable-over-current;
+       clocks = <&clks IMX6QDL_CLK_USBOH3>;
+       status = "okay";
+};
+
+&usbotg {
+       vbus-supply = <&reg_usb_otg_vbus>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       disable-over-current;
+       status = "okay";
+};
+
+&usdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       no-1-8-v;
+       status = "okay";
+};
+
+&usdhc3 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+       vmcc-supply = <&reg_sd3_vmmc>;
+       cd-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
+       bus-witdh=<4>;
+       no-1-8-v;
+       status = "okay";
+};
+
+&usdhc4 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc4>;
+       pinctrl-1 = <&pinctrl_usdhc4_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc4_200mhz>;
+       vmcc-supply = <&reg_sd4_vmmc>;
+       bus-witdh=<8>;
+       no-1-8-v;
+       non-removable;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_audmux: audmux {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT20__AUD4_TXC  0x130b0
+                       MX6QDL_PAD_DISP0_DAT21__AUD4_TXD  0x110b0
+                       MX6QDL_PAD_DISP0_DAT22__AUD4_TXFS 0x130b0
+                       MX6QDL_PAD_DISP0_DAT23__AUD4_RXD  0x130b0
+               >;
+       };
+
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO       0x1b0b0
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC         0x1b0b0
+                       MX6QDL_PAD_RGMII_TXC__RGMII_TXC       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD0__RGMII_TD0       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD1__RGMII_TD1       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD2__RGMII_TD2       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD3__RGMII_TD3       0x1b0b0
+                       MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0
+                       MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK  0x1b0b0
+                       MX6QDL_PAD_RGMII_RXC__RGMII_RXC       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD0__RGMII_RD0       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD1__RGMII_RD1       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD2__RGMII_RD2       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD3__RGMII_RD3       0x1b0b0
+                       MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+                       MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN     0x1b0b0
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
+                       MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+                       MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_5__I2C3_SCL  0x4001b8b1
+                       MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
+                       MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x130b0
+               >;
+       };
+
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1f059  /* PCIe Reset */
+               >;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1
+               >;
+       };
+
+       pinctrl_usbhub: usbhubgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_6__GPIO1_IO06  0x1f059  /* HUB USB Reset */
+               >;
+       };
+
+       pinctrl_usbotg: usbotggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_CMD__SD1_CMD    0x17071
+                       MX6QDL_PAD_SD1_CLK__SD1_CLK    0x10071
+                       MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17071
+                       MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17071
+                       MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17071
+                       MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17071
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD    0x17070
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK    0x10070
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17070
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17070
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17070
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17070
+                       MX6QDL_PAD_GPIO_1__GPIO1_IO01  0x1f059  /* CD */
+                       MX6QDL_PAD_GPIO_4__GPIO1_IO04  0x1f059  /* PWR */
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3grp_100mhz {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD    0x170B1
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK    0x100B1
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170B1
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170B1
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170B1
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170B1
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3grp_200mhz {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD    0x170F9
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK    0x100F9
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170F9
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170F9
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170F9
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170F9
+               >;
+       };
+
+       pinctrl_usdhc4: usdhc4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_CMD__SD4_CMD    0x17070
+                       MX6QDL_PAD_SD4_CLK__SD4_CLK    0x10070
+                       MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17070
+                       MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17070
+                       MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17070
+                       MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17070
+                       MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17070
+                       MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17070
+                       MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17070
+                       MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17070
+               >;
+       };
+
+       pinctrl_usdhc4_100mhz: usdhc4grp_100mhz {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_CMD__SD4_CMD    0x170B1
+                       MX6QDL_PAD_SD4_CLK__SD4_CLK    0x100B1
+                       MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x170B1
+                       MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x170B1
+                       MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x170B1
+                       MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x170B1
+                       MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x170B1
+                       MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x170B1
+                       MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x170B1
+                       MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x170B1
+               >;
+       };
+
+       pinctrl_usdhc4_200mhz: usdhc4grp_200mhz {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_CMD__SD4_CMD    0x170F9
+                       MX6QDL_PAD_SD4_CLK__SD4_CLK    0x100F9
+                       MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x170F9
+                       MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x170F9
+                       MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x170F9
+                       MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x170F9
+                       MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x170F9
+                       MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x170F9
+                       MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x170F9
+                       MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x170F9
+               >;
+       };
+};
index 6d4069c..86460e4 100644 (file)
        bus-width = <4>;
        mmc-pwrseq = <&usdhc1_pwrseq>;
        keep-power-in-suspend;
+       no-1-8-v;
        non-removable;
        vmmc-supply = <&reg_brcm>;
        status = "okay";
index a35d54f..dc74aa3 100644 (file)
                        label = "Power Button";
                        gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                menu {
index caeed56..c6c590d 100644 (file)
                        label = "Power Button";
                        gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                menu {
index 1a69a34..0f1aca4 100644 (file)
                        label = "Power Button";
                        gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                menu {
index a6d445c..0b5c4de 100644 (file)
                power {
                        label = "Power Button";
                        gpios = <&gpio3 29 GPIO_ACTIVE_LOW>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                        linux,code = <KEY_POWER>;
                };
 
                volume-up {
                        label = "Volume Up";
                        gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                        linux,code = <KEY_VOLUMEUP>;
                };
 
                volume-down {
                        label = "Volume Down";
                        gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
        };
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
                                regulator-always-on;
+                               regulator-ramp-delay = <6250>;
                        };
 
                        sw3a_reg: sw3a {
index 13cb7cc..efd06b5 100644 (file)
@@ -41,7 +41,7 @@
                        compatible = "fixed-clock";
                        reg = <0>;
                        #clock-cells = <0>;
-                       clock-frequency = <27000000>;
+                       clock-frequency = <26000000>;
                };
        };
 
@@ -52,7 +52,7 @@
                        label = "Power Button";
                        gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_POWER>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
+       clocks = <&clks IMX6QDL_CLK_ENET>,
+                <&clks IMX6QDL_CLK_ENET>,
+                <&clks IMX6QDL_CLK_ENET_REF>,
+                <&clks IMX6QDL_CLK_ENET_REF>;
+       clock-names = "ipg", "ahb", "ptp", "enet_out";
        phy-mode = "rmii";
        phy-reset-gpios = <&gpio7 6 GPIO_ACTIVE_HIGH>;
        phy-supply = <&reg_3v3_etn>;
                interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
                reset-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>;
                wake-gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
-               linux,wakeup;
+               wakeup-source;
        };
 
        touchscreen: tsc2007@48 {
                interrupts = <26 0>;
                gpios = <&gpio3 26 GPIO_ACTIVE_LOW>;
                ti,x-plate-ohms = <660>;
-               linux,wakeup;
+               wakeup-source;
        };
 };
 
index 1211da8..d3e54e4 100644 (file)
                        gpio = <&gpio7 12 0>;
                };
        };
+
+       sound {
+               compatible = "fsl,imx6q-udoo-ac97",
+                            "fsl,imx-audio-ac97";
+               model = "fsl,imx6q-udoo-ac97";
+               audio-cpu = <&ssi1>;
+               audio-routing =
+                       "RX", "Mic Jack",
+                       "Headphone Jack", "TX";
+               mux-int-port = <1>;
+               mux-ext-port = <6>;
+       };
 };
 
 &fec {
                                MX6QDL_PAD_SD3_DAT3__SD3_DATA3          0x17059
                        >;
                };
+
+               pinctrl_ac97_running: ac97running {
+                       fsl,pins = <
+                               MX6QDL_PAD_DI0_PIN2__AUD6_TXD           0x1b0b0
+                               MX6QDL_PAD_DI0_PIN3__AUD6_TXFS          0x1b0b0
+                               MX6QDL_PAD_DI0_PIN4__AUD6_RXD           0x1b0b0
+                               MX6QDL_PAD_DI0_PIN15__AUD6_TXC          0x1b0b0
+                               MX6QDL_PAD_EIM_EB2__GPIO2_IO30          0x1b0b0
+                       >;
+               };
+
+               pinctrl_ac97_warm_reset: ac97warmreset {
+                       fsl,pins = <
+                               MX6QDL_PAD_DI0_PIN2__AUD6_TXD           0x1b0b0
+                               MX6QDL_PAD_DI0_PIN3__GPIO4_IO19         0x1b0b0
+                               MX6QDL_PAD_DI0_PIN4__AUD6_RXD           0x1b0b0
+                               MX6QDL_PAD_DI0_PIN15__AUD6_TXC          0x1b0b0
+                               MX6QDL_PAD_EIM_EB2__GPIO2_IO30          0x1b0b0
+                       >;
+               };
+
+               pinctrl_ac97_reset: ac97reset {
+                       fsl,pins = <
+                               MX6QDL_PAD_DI0_PIN2__GPIO4_IO18         0x1b0b0
+                               MX6QDL_PAD_DI0_PIN3__GPIO4_IO19         0x1b0b0
+                               MX6QDL_PAD_DI0_PIN4__AUD6_RXD           0x1b0b0
+                               MX6QDL_PAD_DI0_PIN15__AUD6_TXC          0x1b0b0
+                               MX6QDL_PAD_EIM_EB2__GPIO2_IO30          0x1b0b0
+                       >;
+               };
        };
 };
 
        non-removable;
        status = "okay";
 };
+
+&audmux {
+       status = "okay";
+};
+
+&ssi1 {
+       cell-index = <0>;
+       fsl,mode = "ac97-slave";
+       pinctrl-names = "ac97-running", "ac97-reset", "ac97-warm-reset";
+       pinctrl-0 = <&pinctrl_ac97_running>;
+       pinctrl-1 = <&pinctrl_ac97_reset>;
+       pinctrl-2 = <&pinctrl_ac97_warm_reset>;
+       ac97-gpios = <&gpio4 19 0 &gpio4 18 0 &gpio2 30 0>;
+       status = "okay";
+};
index f74d3db..b42822a 100644 (file)
                                        clocks = <&clks IMX6QDL_CLK_ECSPI1>,
                                                 <&clks IMX6QDL_CLK_ECSPI1>;
                                        clock-names = "ipg", "per";
-                                       dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
+                                       dmas = <&sdma 3 8 1>, <&sdma 4 8 2>;
                                        dma-names = "rx", "tx";
                                        status = "disabled";
                                };
                                        clocks = <&clks IMX6QDL_CLK_ECSPI2>,
                                                 <&clks IMX6QDL_CLK_ECSPI2>;
                                        clock-names = "ipg", "per";
-                                       dmas = <&sdma 5 7 1>, <&sdma 6 7 2>;
+                                       dmas = <&sdma 5 8 1>, <&sdma 6 8 2>;
                                        dma-names = "rx", "tx";
                                        status = "disabled";
                                };
                                        clocks = <&clks IMX6QDL_CLK_ECSPI3>,
                                                 <&clks IMX6QDL_CLK_ECSPI3>;
                                        clock-names = "ipg", "per";
-                                       dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;
+                                       dmas = <&sdma 7 8 1>, <&sdma 8 8 2>;
                                        dma-names = "rx", "tx";
                                        status = "disabled";
                                };
                                        clocks = <&clks IMX6QDL_CLK_ECSPI4>,
                                                 <&clks IMX6QDL_CLK_ECSPI4>;
                                        clock-names = "ipg", "per";
-                                       dmas = <&sdma 9 7 1>, <&sdma 10 7 2>;
+                                       dmas = <&sdma 9 8 1>, <&sdma 10 8 2>;
                                        dma-names = "rx", "tx";
                                        status = "disabled";
                                };
diff --git a/arch/arm/boot/dts/imx6qp-sabreauto.dts b/arch/arm/boot/dts/imx6qp-sabreauto.dts
new file mode 100644 (file)
index 0000000..5ce3840
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6qp.dtsi"
+#include "imx6qdl-sabreauto.dtsi"
+
+/ {
+       model = "Freescale i.MX6 Quad Plus SABRE Automotive Board";
+       compatible = "fsl,imx6qp-sabreauto", "fsl,imx6qp";
+};
+
+&i2c2 {
+       max7322: gpio@68 {
+               compatible = "maxim,max7322";
+               reg = <0x68>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+};
+
+&iomuxc {
+       imx6qdl-sabreauto {
+               pinctrl_enet: enetgrp {
+                       fsl,pins = <
+                               MX6QDL_PAD_KEY_COL1__ENET_MDIO          0x1b0b0
+                               MX6QDL_PAD_KEY_COL2__ENET_MDC           0x1b0b0
+                               MX6QDL_PAD_RGMII_TXC__RGMII_TXC         0x1b018
+                               MX6QDL_PAD_RGMII_TD0__RGMII_TD0         0x1b018
+                               MX6QDL_PAD_RGMII_TD1__RGMII_TD1         0x1b018
+                               MX6QDL_PAD_RGMII_TD2__RGMII_TD2         0x1b018
+                               MX6QDL_PAD_RGMII_TD3__RGMII_TD3         0x1b018
+                               MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL   0x1b018
+                               MX6QDL_PAD_RGMII_RXC__RGMII_RXC         0x1b018
+                               MX6QDL_PAD_RGMII_RD0__RGMII_RD0         0x1b018
+                               MX6QDL_PAD_RGMII_RD1__RGMII_RD1         0x1b018
+                               MX6QDL_PAD_RGMII_RD2__RGMII_RD2         0x1b018
+                               MX6QDL_PAD_RGMII_RD3__RGMII_RD3         0x1b018
+                               MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL   0x1b018
+                               MX6QDL_PAD_GPIO_16__ENET_REF_CLK        0x4001b0a8
+                               MX6QDL_PAD_GPIO_6__ENET_IRQ             0x000b1
+                       >;
+               };
+       };
+};
+
+&pcie {
+       status = "disabled";
+};
+
+&vgen3_reg {
+       regulator-always-on;
+};
diff --git a/arch/arm/boot/dts/imx6qp-sabresd.dts b/arch/arm/boot/dts/imx6qp-sabresd.dts
new file mode 100644 (file)
index 0000000..b234580
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6qp.dtsi"
+#include "imx6qdl-sabresd.dtsi"
+
+/ {
+       model = "Freescale i.MX6 Quad Plus SABRE Smart Device Board";
+       compatible = "fsl,imx6qp-sabresd", "fsl,imx6qp";
+};
+
+&cpu0 {
+       arm-supply = <&sw2_reg>;
+};
+
+&iomuxc {
+       imx6qdl-sabresd {
+               pinctrl_usdhc2: usdhc2grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_SD2_CMD__SD2_CMD             0x17059
+                               MX6QDL_PAD_SD2_CLK__SD2_CLK             0x10071
+                               MX6QDL_PAD_SD2_DAT0__SD2_DATA0          0x17059
+                               MX6QDL_PAD_SD2_DAT1__SD2_DATA1          0x17059
+                               MX6QDL_PAD_SD2_DAT2__SD2_DATA2          0x17059
+                               MX6QDL_PAD_SD2_DAT3__SD2_DATA3          0x17059
+                               MX6QDL_PAD_NANDF_D4__SD2_DATA4          0x17059
+                               MX6QDL_PAD_NANDF_D5__SD2_DATA5          0x17059
+                               MX6QDL_PAD_NANDF_D6__SD2_DATA6          0x17059
+                               MX6QDL_PAD_NANDF_D7__SD2_DATA7          0x17059
+                       >;
+               };
+
+               pinctrl_usdhc3: usdhc3grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_SD3_CMD__SD3_CMD             0x17059
+                               MX6QDL_PAD_SD3_CLK__SD3_CLK             0x10071
+                               MX6QDL_PAD_SD3_DAT0__SD3_DATA0          0x17059
+                               MX6QDL_PAD_SD3_DAT1__SD3_DATA1          0x17059
+                               MX6QDL_PAD_SD3_DAT2__SD3_DATA2          0x17059
+                               MX6QDL_PAD_SD3_DAT3__SD3_DATA3          0x17059
+                               MX6QDL_PAD_SD3_DAT4__SD3_DATA4          0x17059
+                               MX6QDL_PAD_SD3_DAT5__SD3_DATA5          0x17059
+                               MX6QDL_PAD_SD3_DAT6__SD3_DATA6          0x17059
+                               MX6QDL_PAD_SD3_DAT7__SD3_DATA7          0x17059
+                       >;
+               };
+       };
+};
+
+&pcie {
+       status = "disabled";
+};
diff --git a/arch/arm/boot/dts/imx6qp.dtsi b/arch/arm/boot/dts/imx6qp.dtsi
new file mode 100644 (file)
index 0000000..1ada714
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "imx6q.dtsi"
+
+/ {
+       soc {
+               ocram2: sram@00940000 {
+                       compatible = "mmio-sram";
+                       reg = <0x00940000 0x20000>;
+                       clocks = <&clks IMX6QDL_CLK_OCRAM>;
+               };
+
+               ocram3: sram@00960000 {
+                       compatible = "mmio-sram";
+                       reg = <0x00960000 0x20000>;
+                       clocks = <&clks IMX6QDL_CLK_OCRAM>;
+               };
+
+               ipu1: ipu@02400000 {
+                       compatible = "fsl,imx6qp-ipu", "fsl,imx6q-ipu";
+                       clocks = <&clks IMX6QDL_CLK_IPU1>,
+                                <&clks IMX6QDL_CLK_IPU1_DI0>, <&clks IMX6QDL_CLK_IPU1_DI1>,
+                                <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>,
+                                <&clks IMX6QDL_CLK_LDB_DI0_PODF>, <&clks IMX6QDL_CLK_LDB_DI1_PODF>,
+                                <&clks IMX6QDL_CLK_PRG0_APB>;
+                       clock-names = "bus",
+                                     "di0", "di1",
+                                     "di0_sel", "di1_sel",
+                                     "ldb_di0", "ldb_di1", "prg";
+               };
+
+               ipu2: ipu@02800000 {
+                       compatible = "fsl,imx6qp-ipu", "fsl,imx6q-ipu";
+                       clocks = <&clks IMX6QDL_CLK_IPU2>,
+                                <&clks IMX6QDL_CLK_IPU2_DI0>, <&clks IMX6QDL_CLK_IPU2_DI1>,
+                                <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, <&clks IMX6QDL_CLK_IPU2_DI1_SEL>,
+                                <&clks IMX6QDL_CLK_LDB_DI0_PODF>, <&clks IMX6QDL_CLK_LDB_DI1_PODF>,
+                                <&clks IMX6QDL_CLK_PRG1_APB>;
+                       clock-names = "bus",
+                                     "di0", "di1",
+                                     "di0_sel", "di1_sel",
+                                     "ldb_di0", "ldb_di1", "prg";
+               };
+
+       };
+};
index 10c6996..058bcdc 100644 (file)
        bus-width = <4>;
        non-removable;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        mmc-pwrseq = <&usdhc3_pwrseq>;
        status = "okay";
 };
index 115f3fd..96ea936 100644 (file)
@@ -52,7 +52,7 @@
        cd-gpios = <&gpio7 10 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        vmmc-supply = <&vcc_sd3>;
        status = "okay";
 };
index 94ac400..f1d3730 100644 (file)
        status = "okay";
 };
 
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+};
+
 &i2c4 {
         clock-frequency = <100000>;
         pinctrl-names = "default";
        non-removable;
        no-1-8-v;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        status = "okay";
 };
 
        cd-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        vmmc-supply = <&vcc_sd3>;
        status = "okay";
 };
                        >;
                };
 
+               pinctrl_i2c3: i2c3grp {
+                       fsl,pins = <
+                               MX6SX_PAD_KEY_ROW4__I2C3_SDA            0x4001b8b1
+                               MX6SX_PAD_KEY_COL4__I2C3_SCL            0x4001b8b1
+                       >;
+               };
+
                pinctrl_i2c4: i2c4grp {
                        fsl,pins = <
                                MX6SX_PAD_CSI_DATA07__I2C4_SDA          0x4001b8b1
index 6aaa5ec..7207280 100644 (file)
@@ -8,7 +8,6 @@
 
 /dts-v1/;
 
-#include <dt-bindings/input/input.h>
 #include "imx6ul.dtsi"
 
 / {
        pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
        cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        vmmc-supply = <&reg_sd1_vmmc>;
        status = "okay";
 };
        pinctrl-0 = <&pinctrl_usdhc2>;
        no-1-8-v;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        status = "okay";
 };
 
index 20c7da1..0034eeb 100644 (file)
  * The pin function ID is a tuple of
  * <mux_reg conf_reg input_reg mux_mode input_val>
  */
-#define MX6UL_PAD_BOOT_MODE0__GPIO5_IO10                               0x0014 0x02a0 0x0000 5 0
-#define MX6UL_PAD_BOOT_MODE1__GPIO5_IO11                               0x0018 0x02a4 0x0000 5 0
+#define MX6UL_PAD_BOOT_MODE0__GPIO5_IO10               0x0014 0x02a0 0x0000 5 0
+#define MX6UL_PAD_BOOT_MODE1__GPIO5_IO11               0x0018 0x02a4 0x0000 5 0
 
-#define MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00                             0x001c 0x02a8 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01                             0x0020 0x02ac 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02                             0x0024 0x02b0 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03                             0x0028 0x02b4 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04                             0x002c 0x02b8 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05                             0x0030 0x02bc 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER6__GPIO5_IO06                             0x0034 0x02c0 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07                             0x0038 0x02c4 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08                             0x003c 0x02c8 0x0000 5 0
-#define MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09                             0x0040 0x02cc 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00             0x001c 0x02a8 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01             0x0020 0x02ac 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02             0x0024 0x02b0 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03             0x0028 0x02b4 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04             0x002c 0x02b8 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05             0x0030 0x02bc 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER6__GPIO5_IO06             0x0034 0x02c0 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07             0x0038 0x02c4 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08             0x003c 0x02c8 0x0000 5 0
+#define MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09             0x0040 0x02cc 0x0000 5 0
 
-#define MX6UL_PAD_JTAG_MOD__SJC_MOD                                    0x0044 0x02d0 0x0000 0 0
-#define MX6UL_PAD_JTAG_MOD__GPT2_CLK                                   0x0044 0x02d0 0x05a0 1 0
-#define MX6UL_PAD_JTAG_MOD__SPDIF_OUT                                  0x0044 0x02d0 0x0000 2 0
-#define MX6UL_PAD_JTAG_MOD__ENET1_REF_CLK_25M                          0x0044 0x02d0 0x0000 3 0
-#define MX6UL_PAD_JTAG_MOD__CCM_PMIC_RDY                               0x0044 0x02d0 0x04c0 4 0
-#define MX6UL_PAD_JTAG_MOD__GPIO1_IO10                                 0x0044 0x02d0 0x0000 5 0
-#define MX6UL_PAD_JTAG_MOD__SDMA_EXT_EVENT00                           0x0044 0x02d0 0x0000 6 0
-#define MX6UL_PAD_JTAG_TMS__SJC_TMS                                    0x0048 0x02d4 0x0000 0 0
-#define MX6UL_PAD_JTAG_TMS__GPT2_CAPTURE1                              0x0048 0x02d4 0x0598 1 0
-#define MX6UL_PAD_JTAG_TMS__SAI2_MCLK                                  0x0048 0x02d4 0x0000 2 0
-#define MX6UL_PAD_JTAG_TMS__CCM_CLKO1                                  0x0048 0x02d4 0x0000 3 0
-#define MX6UL_PAD_JTAG_TMS__CCM_WAIT                                   0x0048 0x02d4 0x0000 4 0
-#define MX6UL_PAD_JTAG_TMS__GPIO1_IO11                                 0x0048 0x02d4 0x0000 5 0
-#define MX6UL_PAD_JTAG_TMS__SDMA_EXT_EVENT01                           0x0048 0x02d4 0x0000 6 0
-#define MX6UL_PAD_JTAG_TMS__EPIT1_OUT                                  0x0048 0x02d4 0x0000 8 0
-#define MX6UL_PAD_JTAG_TDO__SJC_TDO                                    0x004c 0x02d8 0x0000 0 0
-#define MX6UL_PAD_JTAG_TDO__GPT2_CAPTURE2                              0x004c 0x02d8 0x059c 1 0
-#define MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC                               0x004c 0x02d8 0x05fc 2 0
-#define MX6UL_PAD_JTAG_TDO__CCM_CLKO2                                  0x004c 0x02d8 0x0000 3 0
-#define MX6UL_PAD_JTAG_TDO__CCM_STOP                                   0x004c 0x02d8 0x0000 4 0
-#define MX6UL_PAD_JTAG_TDO__GPIO1_IO12                                 0x004c 0x02d8 0x0000 5 0
-#define MX6UL_PAD_JTAG_TDO__MQS_RIGHT                                  0x004c 0x02d8 0x0000 6 0
-#define MX6UL_PAD_JTAG_TDO__EPIT2_OUT                                  0x004c 0x02d8 0x0000 8 0
-#define MX6UL_PAD_JTAG_TDI__SJC_TDI                                    0x0050 0x02dc 0x0000 0 0
-#define MX6UL_PAD_JTAG_TDI__GPT2_COMPARE1                              0x0050 0x02dc 0x0000 1 0
-#define MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK                               0x0050 0x02dc 0x05f8 2 0
-#define MX6UL_PAD_JTAG_TDI__PWM6_OUT                                   0x0050 0x02dc 0x0000 4 0
-#define MX6UL_PAD_JTAG_TDI__GPIO1_IO13                                 0x0050 0x02dc 0x0000 5 0
-#define MX6UL_PAD_JTAG_TDI__MQS_LEFT                                   0x0050 0x02dc 0x0000 6 0
-#define MX6UL_PAD_JTAG_TDI__SIM1_POWER_FAIL                            0x0050 0x02dc 0x0000 8 0
-#define MX6UL_PAD_JTAG_TCK__SJC_TCK                                    0x0054 0x02e0 0x0000 0 0
-#define MX6UL_PAD_JTAG_TCK__GPT2_COMPARE2                              0x0054 0x02e0 0x0000 1 0
-#define MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA                               0x0054 0x02e0 0x0000 2 0
-#define MX6UL_PAD_JTAG_TCK__PWM7_OUT                                   0x0054 0x02e0 0x0000 4 0
-#define MX6UL_PAD_JTAG_TCK__GPIO1_IO14                                 0x0054 0x02e0 0x0000 5 0
-#define MX6UL_PAD_JTAG_TCK__SIM2_POWER_FAIL                            0x0054 0x02e0 0x0000 8 0
-#define MX6UL_PAD_JTAG_TRST_B__SJC_TRSTB                               0x0058 0x02e4 0x0000 0 0
-#define MX6UL_PAD_JTAG_TRST_B__GPT2_COMPARE3                           0x0058 0x02e4 0x0000 1 0
-#define MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA                            0x0058 0x02e4 0x0000 2 0
-#define MX6UL_PAD_JTAG_TRST_B__PWM8_OUT                                0x0058 0x02e4 0x0000 4 0
-#define MX6UL_PAD_JTAG_TRST_B__GPIO1_IO15                              0x0058 0x02e4 0x0000 5 0
-#define MX6UL_PAD_JTAG_TRST_B__CAAM_RNG_OSC_OBS                        0x0058 0x02e4 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO00__I2C2_SCL                                 0x005c 0x02e8 0x05ac 0 1
-#define MX6UL_PAD_GPIO1_IO00__GPT1_CAPTURE1                            0x005c 0x02e8 0x058c 1 0
-#define MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID                           0x005c 0x02e8 0x04b8 2 0
-#define MX6UL_PAD_GPIO1_IO00__ENET1_REF_CLK1                           0x005c 0x02e8 0x0574 3 0
-#define MX6UL_PAD_GPIO1_IO00__MQS_RIGHT                                0x005c 0x02e8 0x0000 4 0
-#define MX6UL_PAD_GPIO1_IO00__GPIO1_IO00                               0x005c 0x02e8 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO00__ENET1_1588_EVENT0_IN                     0x005c 0x02e8 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO00__SRC_SYSTEM_RESET                         0x005c 0x02e8 0x0000 7 0
-#define MX6UL_PAD_GPIO1_IO00__WDOG3_WDOG_B                             0x005c 0x02e8 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO01__I2C2_SDA                                 0x0060 0x02ec 0x05b0 0 1
-#define MX6UL_PAD_GPIO1_IO01__GPT1_COMPARE1                            0x0060 0x02ec 0x0000 1 0
-#define MX6UL_PAD_GPIO1_IO01__USB_OTG1_OC                              0x0060 0x02ec 0x0664 2 0
-#define MX6UL_PAD_GPIO1_IO01__ENET2_REF_CLK2                           0x0060 0x02ec 0x057c 3 0
-#define MX6UL_PAD_GPIO1_IO01__MQS_LEFT                                 0x0060 0x02ec 0x0000 4 0
-#define MX6UL_PAD_GPIO1_IO01__GPIO1_IO01                               0x0060 0x02ec 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO01__ENET1_1588_EVENT0_OUT                    0x0060 0x02ec 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO01__SRC_EARLY_RESET                          0x0060 0x02ec 0x0000 7 0
-#define MX6UL_PAD_GPIO1_IO01__WDOG1_WDOG_B                             0x0060 0x02ec 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO02__I2C1_SCL                                 0x0064 0x02f0 0x05a4 0 0
-#define MX6UL_PAD_GPIO1_IO02__GPT1_COMPARE2                            0x0064 0x02f0 0x0000 1 0
-#define MX6UL_PAD_GPIO1_IO02__USB_OTG2_PWR                             0x0064 0x02f0 0x0000 2 0
-#define MX6UL_PAD_GPIO1_IO02__ENET1_REF_CLK_25M                        0x0064 0x02f0 0x0000 3 0
-#define MX6UL_PAD_GPIO1_IO02__USDHC1_WP                                0x0064 0x02f0 0x066c 4 0
-#define MX6UL_PAD_GPIO1_IO02__GPIO1_IO02                               0x0064 0x02f0 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO02__SDMA_EXT_EVENT00                         0x0064 0x02f0 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO02__SRC_ANY_PU_RESET                         0x0064 0x02f0 0x0000 7 0
-#define MX6UL_PAD_GPIO1_IO02__UART1_DCE_TX                             0x0064 0x02f0 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO02__UART1_DTE_RX                             0x0064 0x02f0 0x0624 8 0
-#define MX6UL_PAD_GPIO1_IO03__I2C1_SDA                                 0x0068 0x02f4 0x05a8 0 1
-#define MX6UL_PAD_GPIO1_IO03__GPT1_COMPARE3                            0x0068 0x02f4 0x0000 1 0
-#define MX6UL_PAD_GPIO1_IO03__USB_OTG2_OC                              0x0068 0x02f4 0x0660 2 0
-#define MX6UL_PAD_GPIO1_IO03__USDHC1_CD_B                              0x0068 0x02f4 0x0668 4 0
-#define MX6UL_PAD_GPIO1_IO03__GPIO1_IO03                               0x0068 0x02f4 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO03__CCM_DI0_eXT_CLK                          0x0068 0x02f4 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO03__SRC_TESTER_ACK                           0x0068 0x02f4 0x0000 7 0
-#define MX6UL_PAD_GPIO1_IO03__UART1_DTE_TX                             0x0068 0x02f4 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO03__UART1_DCE_RX                             0x0068 0x02f4 0x0624 8 1
-#define MX6UL_PAD_GPIO1_IO04__ENET1_REF_CLK1                           0x006c 0x02f8 0x0574 0 1
-#define MX6UL_PAD_GPIO1_IO04__PWM3_OUT                                 0x006c 0x02f8 0x0000 1 0
-#define MX6UL_PAD_GPIO1_IO04__USB_OTG1_PWR                             0x006c 0x02f8 0x0000 2 0
-#define MX6UL_PAD_GPIO1_IO04__USDHC1_RESET_B                           0x006c 0x02f8 0x0000 4 0
-#define MX6UL_PAD_GPIO1_IO04__GPIO1_IO04                               0x006c 0x02f8 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO04__ENET2_1588_EVENT0_IN                     0x006c 0x02f8 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO04__UART5_DCE_TX                             0x006c 0x02f8 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO04__UART5_DTE_RX                             0x006c 0x02f8 0x0644 8 2
-#define MX6UL_PAD_GPIO1_IO05__ENET2_REF_CLK2                           0x0070 0x02fc 0x057c 0 1
-#define MX6UL_PAD_GPIO1_IO05__PWM4_OUT                                 0x0070 0x02fc 0x0000 1 0
-#define MX6UL_PAD_GPIO1_IO05__ANATOP_OTG2_ID                           0x0070 0x02fc 0x04bc 2 0
-#define MX6UL_PAD_GPIO1_IO05__CSI_FIELD                                0x0070 0x02fc 0x0530 3 0
-#define MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT                           0x0070 0x02fc 0x0000 4 0
-#define MX6UL_PAD_GPIO1_IO05__GPIO1_IO05                               0x0070 0x02fc 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO05__ENET2_1588_EVENT0_OUT                    0x0070 0x02fc 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO05__UART5_DCE_RX                             0x0070 0x02fc 0x0644 8 3
-#define MX6UL_PAD_GPIO1_IO05__UART5_DTE_TX                             0x0070 0x02fc 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO06__ENET1_MDIO                               0x0074 0x0300 0x0578 0 0
-#define MX6UL_PAD_GPIO1_IO06__ENET2_MDIO                               0x0074 0x0300 0x0580 1 0
-#define MX6UL_PAD_GPIO1_IO06__USB_OTG_PWR_WAKE                         0x0074 0x0300 0x0000 2 0
-#define MX6UL_PAD_GPIO1_IO06__CSI_MCLK                                 0x0074 0x0300 0x0000 3 0
-#define MX6UL_PAD_GPIO1_IO06__USDHC2_WP                                0x0074 0x0300 0x069c 4 0
-#define MX6UL_PAD_GPIO1_IO06__GPIO1_IO06                               0x0074 0x0300 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO06__CCM_WAIT                                 0x0074 0x0300 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO06__CCM_REF_EN_B                             0x0074 0x0300 0x0000 7 0
-#define MX6UL_PAD_GPIO1_IO06__UART1_DCE_CTS                            0x0074 0x0300 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO06__UART1_DTE_RTS                            0x0074 0x0300 0x0620 8 0
-#define MX6UL_PAD_GPIO1_IO07__ENET1_MDC                                0x0078 0x0304 0x0000 0 0
-#define MX6UL_PAD_GPIO1_IO07__ENET2_MDC                                0x0078 0x0304 0x0000 1 0
-#define MX6UL_PAD_GPIO1_IO07__USB_OTG_HOST_MODE                        0x0078 0x0304 0x0000 2 0
-#define MX6UL_PAD_GPIO1_IO07__CSI_PIXCLK                               0x0078 0x0304 0x0528 3 0
-#define MX6UL_PAD_GPIO1_IO07__USDHC2_CD_B                              0x0078 0x0304 0x0674 4 1
-#define MX6UL_PAD_GPIO1_IO07__GPIO1_IO07                               0x0078 0x0304 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO07__CCM_STOP                                 0x0078 0x0304 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO07__UART1_DCE_RTS                            0x0078 0x0304 0x0620 8 1
-#define MX6UL_PAD_GPIO1_IO07__UART1_DTE_CTS                            0x0078 0x0304 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO08__PWM1_OUT                                 0x007c 0x0308 0x0000 0 0
-#define MX6UL_PAD_GPIO1_IO08__WDOG1_WDOG_B                             0x007c 0x0308 0x0000 1 0
-#define MX6UL_PAD_GPIO1_IO08__SPDIF_OUT                                0x007c 0x0308 0x0000 2 0
-#define MX6UL_PAD_GPIO1_IO08__CSI_VSYNC                                0x007c 0x0308 0x052c 3 1
-#define MX6UL_PAD_GPIO1_IO08__USDHC2_VSELECT                           0x007c 0x0308 0x0000 4 0
-#define MX6UL_PAD_GPIO1_IO08__GPIO1_IO08                               0x007c 0x0308 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO08__CCM_PMIC_RDY                             0x007c 0x0308 0x04c0 6 1
-#define MX6UL_PAD_GPIO1_IO08__UART5_DCE_RTS                            0x007c 0x0308 0x0640 8 1
-#define MX6UL_PAD_GPIO1_IO08__UART5_DTE_CTS                            0x007c 0x0308 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO09__PWM2_OUT                                 0x0080 0x030c 0x0000 0 0
-#define MX6UL_PAD_GPIO1_IO09__WDOG1_WDOG_ANY                           0x0080 0x030c 0x0000 1 0
-#define MX6UL_PAD_GPIO1_IO09__SPDIF_IN                                 0x0080 0x030c 0x0618 2 0
-#define MX6UL_PAD_GPIO1_IO09__CSI_HSYNC                                0x0080 0x030c 0x0524 3 1
-#define MX6UL_PAD_GPIO1_IO09__USDHC2_RESET_B                           0x0080 0x030c 0x0000 4 0
-#define MX6UL_PAD_GPIO1_IO09__GPIO1_IO09                               0x0080 0x030c 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO09__USDHC1_RESET_B                           0x0080 0x030c 0x0000 6 0
-#define MX6UL_PAD_GPIO1_IO09__UART5_DCE_CTS                            0x0080 0x030c 0x0000 8 0
-#define MX6UL_PAD_GPIO1_IO09__UART5_DTE_RTS                            0x0080 0x030c 0x0640 8 2
-#define MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX                          0x0084 0x0310 0x0000 0 0
-#define MX6UL_PAD_UART1_TX_DATA__UART1_DTE_RX                          0x0084 0x0310 0x0624 0 2
-#define MX6UL_PAD_UART1_TX_DATA__ENET1_RDATA02                         0x0084 0x0310 0x0000 1 0
-#define MX6UL_PAD_UART1_TX_DATA__I2C3_SCL                              0x0084 0x0310 0x05b4 2 0
-#define MX6UL_PAD_UART1_TX_DATA__CSI_DATA02                            0x0084 0x0310 0x0000 3 0
-#define MX6UL_PAD_UART1_TX_DATA__GPT1_COMPARE1                         0x0084 0x0310 0x0000 4 0
-#define MX6UL_PAD_UART1_TX_DATA__GPIO1_IO16                            0x0084 0x0310 0x0000 5 0
-#define MX6UL_PAD_UART1_TX_DATA__SPDIF_OUT                             0x0084 0x0310 0x0000 8 0
-#define MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX                          0x0088 0x0314 0x0624 0 3
-#define MX6UL_PAD_UART1_RX_DATA__UART1_DTE_TX                          0x0088 0x0314 0x0000 0 0
-#define MX6UL_PAD_UART1_RX_DATA__ENET1_RDATA03                         0x0088 0x0314 0x0000 1 0
-#define MX6UL_PAD_UART1_RX_DATA__I2C3_SDA                              0x0088 0x0314 0x05b8 2 0
-#define MX6UL_PAD_UART1_RX_DATA__CSI_DATA03                            0x0088 0x0314 0x0000 3 0
-#define MX6UL_PAD_UART1_RX_DATA__GPT1_CLK                              0x0088 0x0314 0x0594 4 0
-#define MX6UL_PAD_UART1_RX_DATA__GPIO1_IO17                            0x0088 0x0314 0x0000 5 0
-#define MX6UL_PAD_UART1_RX_DATA__SPDIF_IN                              0x0088 0x0314 0x0000 8 0
-#define MX6UL_PAD_UART1_CTS_B__UART1_DCE_CTS                           0x008c 0x0318 0x0000 0 0
-#define MX6UL_PAD_UART1_CTS_B__UART1_DTE_RTS                           0x008c 0x0318 0x0620 0 2
-#define MX6UL_PAD_UART1_CTS_B__ENET1_RX_CLK                            0x008c 0x0318 0x0000 1 0
-#define MX6UL_PAD_UART1_CTS_B__USDHC1_WP                               0x008c 0x0318 0x066c 2 1
-#define MX6UL_PAD_UART1_CTS_B__CSI_DATA04                              0x008c 0x0318 0x0000 3 0
-#define MX6UL_PAD_UART1_CTS_B__ENET2_1588_EVENT1_IN                    0x008c 0x0318 0x0000 4 0
-#define MX6UL_PAD_UART1_CTS_B__GPIO1_IO18                              0x008c 0x0318 0x0000 5 0
-#define MX6UL_PAD_UART1_CTS_B__USDHC2_WP                               0x008c 0x0318 0x0000 8 0
-#define MX6UL_PAD_UART1_RTS_B__UART1_DCE_RTS                           0x0090 0x031c 0x0620 0 3
-#define MX6UL_PAD_UART1_RTS_B__UART1_DTE_CTS                           0x0090 0x031c 0x0000 0 0
-#define MX6UL_PAD_UART1_RTS_B__ENET1_TX_ER                             0x0090 0x031c 0x0000 1 0
-#define MX6UL_PAD_UART1_RTS_B__USDHC1_CD_B                             0x0090 0x031c 0x0668 2 1
-#define MX6UL_PAD_UART1_RTS_B__CSI_DATA05                              0x0090 0x031c 0x0000 3 0
-#define MX6UL_PAD_UART1_RTS_B__ENET2_1588_EVENT1_OUT                   0x0090 0x031c 0x0000 4 0
-#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19                              0x0090 0x031c 0x0000 5 0
-#define MX6UL_PAD_UART1_RTS_B__USDHC2_CD_B                             0x0090 0x031c 0x0000 8 0
-#define MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX                          0x0094 0x0320 0x0000 0 0
-#define MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX                          0x0094 0x0320 0x062c 0 0
-#define MX6UL_PAD_UART2_TX_DATA__ENET1_TDATA02                         0x0094 0x0320 0x0000 1 0
-#define MX6UL_PAD_UART2_TX_DATA__I2C4_SCL                              0x0094 0x0320 0x05bc 2 0
-#define MX6UL_PAD_UART2_TX_DATA__CSI_DATA06                            0x0094 0x0320 0x0000 3 0
-#define MX6UL_PAD_UART2_TX_DATA__GPT1_CAPTURE1                         0x0094 0x0320 0x058c 4 1
-#define MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20                            0x0094 0x0320 0x0000 5 0
-#define MX6UL_PAD_UART2_TX_DATA__ECSPI3_SS0                            0x0094 0x0320 0x0000 8 0
-#define MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX                          0x0098 0x0324 0x062c 0 1
-#define MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX                          0x0098 0x0324 0x0000 0 0
-#define MX6UL_PAD_UART2_RX_DATA__ENET1_TDATA03                         0x0098 0x0324 0x0000 1 0
-#define MX6UL_PAD_UART2_RX_DATA__I2C4_SDA                              0x0098 0x0324 0x05c0 2 0
-#define MX6UL_PAD_UART2_RX_DATA__CSI_DATA07                            0x0098 0x0324 0x0000 3 0
-#define MX6UL_PAD_UART2_RX_DATA__GPT1_CAPTURE2                         0x0098 0x0324 0x0590 4 0
-#define MX6UL_PAD_UART2_RX_DATA__GPIO1_IO21                            0x0098 0x0324 0x0000 5 0
-#define MX6UL_PAD_UART2_RX_DATA__SJC_DONE                              0x0098 0x0324 0x0000 7 0
-#define MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK                           0x0098 0x0324 0x0000 8 0
-#define MX6UL_PAD_UART2_CTS_B__UART2_DCE_CTS                           0x009c 0x0328 0x0000 0 0
-#define MX6UL_PAD_UART2_CTS_B__UART2_DTE_RTS                           0x009c 0x0328 0x0628 0 0
-#define MX6UL_PAD_UART2_CTS_B__ENET1_CRS                               0x009c 0x0328 0x0000 1 0
-#define MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX                             0x009c 0x0328 0x0000 2 0
-#define MX6UL_PAD_UART2_CTS_B__CSI_DATA08                              0x009c 0x0328 0x0000 3 0
-#define MX6UL_PAD_UART2_CTS_B__GPT1_COMPARE2                           0x009c 0x0328 0x0000 4 0
-#define MX6UL_PAD_UART2_CTS_B__GPIO1_IO22                              0x009c 0x0328 0x0000 5 0
-#define MX6UL_PAD_UART2_CTS_B__SJC_DE_B                                0x009c 0x0328 0x0000 7 0
-#define MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI                             0x009c 0x0328 0x0000 8 0
-#define MX6UL_PAD_UART2_RTS_B__UART2_DCE_RTS                           0x00a0 0x032c 0x0628 0 1
-#define MX6UL_PAD_UART2_RTS_B__UART2_DTE_CTS                           0x00a0 0x032c 0x0000 0 0
-#define MX6UL_PAD_UART2_RTS_B__ENET1_COL                               0x00a0 0x032c 0x0000 1 0
-#define MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX                             0x00a0 0x032c 0x0588 2 0
-#define MX6UL_PAD_UART2_RTS_B__CSI_DATA09                              0x00a0 0x032c 0x0000 3 0
-#define MX6UL_PAD_UART2_RTS_B__GPT1_COMPARE3                           0x00a0 0x032c 0x0000 4 0
-#define MX6UL_PAD_UART2_RTS_B__GPIO1_IO23                              0x00a0 0x032c 0x0000 5 0
-#define MX6UL_PAD_UART2_RTS_B__SJC_FAIL                                0x00a0 0x032c 0x0000 7 0
-#define MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO                             0x00a0 0x032c 0x0000 8 0
-#define MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX                          0x00a4 0x0330 0x0000 0 0
-#define MX6UL_PAD_UART3_TX_DATA__UART3_DTE_RX                          0x00a4 0x0330 0x0634 0 0
-#define MX6UL_PAD_UART3_TX_DATA__ENET2_RDATA02                         0x00a4 0x0330 0x0000 1 0
-#define MX6UL_PAD_UART3_TX_DATA__SIM1_PORT0_PD                         0x00a4 0x0330 0x0000 2 0
-#define MX6UL_PAD_UART3_TX_DATA__CSI_DATA01                            0x00a4 0x0330 0x0000 3 0
-#define MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS                         0x00a4 0x0330 0x0000 4 0
-#define MX6UL_PAD_UART3_TX_DATA__UART2_DTE_RTS                         0x00a4 0x0330 0x0628 4 2
-#define MX6UL_PAD_UART3_TX_DATA__GPIO1_IO24                            0x00a4 0x0330 0x0000 5 0
-#define MX6UL_PAD_UART3_TX_DATA__SJC_JTAG_ACT                          0x00a4 0x0330 0x0000 7 0
-#define MX6UL_PAD_UART3_TX_DATA__ANATOP_OTG1_ID                        0x00a4 0x0330 0x0000 8 0
-#define MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX                          0x00a8 0x0334 0x0634 0 1
-#define MX6UL_PAD_UART3_RX_DATA__UART3_DTE_TX                          0x00a8 0x0334 0x0000 0 0
-#define MX6UL_PAD_UART3_RX_DATA__ENET2_RDATA03                         0x00a8 0x0334 0x0000 1 0
-#define MX6UL_PAD_UART3_RX_DATA__SIM2_PORT0_PD                         0x00a8 0x0334 0x0000 2 0
-#define MX6UL_PAD_UART3_RX_DATA__CSI_DATA00                            0x00a8 0x0334 0x0000 3 0
-#define MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS                         0x00a8 0x0334 0x0628 4 3
-#define MX6UL_PAD_UART3_RX_DATA__UART2_DTE_CTS                         0x00a8 0x0334 0x0000 4 0
-#define MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25                            0x00a8 0x0334 0x0000 5 0
-#define MX6UL_PAD_UART3_RX_DATA__EPIT1_OUT                             0x00a8 0x0334 0x0000 8 0
-#define MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS                           0x00ac 0x0338 0x0000 0 0
-#define MX6UL_PAD_UART3_CTS_B__UART3_DTE_RTS                           0x00ac 0x0338 0x0630 0 0
-#define MX6UL_PAD_UART3_CTS_B__ENET2_RX_CLK                            0x00ac 0x0338 0x0000 1 0
-#define MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX                             0x00ac 0x0338 0x0000 2 0
-#define MX6UL_PAD_UART3_CTS_B__CSI_DATA10                              0x00ac 0x0338 0x0000 3 0
-#define MX6UL_PAD_UART3_CTS_B__ENET1_1588_EVENT1_IN                    0x00ac 0x0338 0x0000 4 0
-#define MX6UL_PAD_UART3_CTS_B__GPIO1_IO26                              0x00ac 0x0338 0x0000 5 0
-#define MX6UL_PAD_UART3_CTS_B__EPIT2_OUT                               0x00ac 0x0338 0x0000 8 0
-#define MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS                           0x00b0 0x033c 0x0630 0 1
-#define MX6UL_PAD_UART3_RTS_B__UART3_DTE_CTS                           0x00b0 0x033c 0x0000 0 0
-#define MX6UL_PAD_UART3_RTS_B__ENET2_TX_ER                             0x00b0 0x033c 0x0000 1 0
-#define MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX                             0x00b0 0x033c 0x0584 2 0
-#define MX6UL_PAD_UART3_RTS_B__CSI_DATA11                              0x00b0 0x033c 0x0000 3 0
-#define MX6UL_PAD_UART3_RTS_B__ENET1_1588_EVENT1_OUT                   0x00b0 0x033c 0x0000 4 0
-#define MX6UL_PAD_UART3_RTS_B__GPIO1_IO27                              0x00b0 0x033c 0x0000 5 0
-#define MX6UL_PAD_UART3_RTS_B__WDOG1_WDOG_B                            0x00b0 0x033c 0x0000 8 0
-#define MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX                          0x00b4 0x0340 0x0000 0 0
-#define MX6UL_PAD_UART4_TX_DATA__UART4_DTE_RX                          0x00b4 0x0340 0x063c 0 0
-#define MX6UL_PAD_UART4_TX_DATA__ENET2_TDATA02                         0x00b4 0x0340 0x0000 1 0
-#define MX6UL_PAD_UART4_TX_DATA__I2C1_SCL                              0x00b4 0x0340 0x05a4 2 1
-#define MX6UL_PAD_UART4_TX_DATA__CSI_DATA12                            0x00b4 0x0340 0x0000 3 0
-#define MX6UL_PAD_UART4_TX_DATA__CSU_CSU_ALARM_AUT02                   0x00b4 0x0340 0x0000 4 0
-#define MX6UL_PAD_UART4_TX_DATA__GPIO1_IO28                            0x00b4 0x0340 0x0000 5 0
-#define MX6UL_PAD_UART4_TX_DATA__ECSPI2_SCLK                           0x00b4 0x0340 0x0000 8 0
-#define MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX                          0x00b8 0x0344 0x063c 0 1
-#define MX6UL_PAD_UART4_RX_DATA__UART4_DTE_TX                          0x00b8 0x0344 0x0000 0 0
-#define MX6UL_PAD_UART4_RX_DATA__ENET2_TDATA03                         0x00b8 0x0344 0x0000 1 0
-#define MX6UL_PAD_UART4_RX_DATA__I2C1_SDA                              0x00b8 0x0344 0x05a8 2 2
-#define MX6UL_PAD_UART4_RX_DATA__CSI_DATA13                            0x00b8 0x0344 0x0000 3 0
-#define MX6UL_PAD_UART4_RX_DATA__CSU_CSU_ALARM_AUT01                   0x00b8 0x0344 0x0000 4 0
-#define MX6UL_PAD_UART4_RX_DATA__GPIO1_IO29                            0x00b8 0x0344 0x0000 5 0
-#define MX6UL_PAD_UART4_RX_DATA__ECSPI2_SS0                            0x00b8 0x0344 0x0000 8 0
-#define MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30                            0x00bc 0x0348 0x0000 5 0
-#define MX6UL_PAD_UART5_TX_DATA__ECSPI2_MOSI                           0x00bc 0x0348 0x0000 8 0
-#define MX6UL_PAD_UART5_TX_DATA__UART5_DCE_TX                          0x00bc 0x0348 0x0000 0 0
-#define MX6UL_PAD_UART5_TX_DATA__UART5_DTE_RX                          0x00bc 0x0348 0x0644 0 4
-#define MX6UL_PAD_UART5_TX_DATA__ENET2_CRS                             0x00bc 0x0348 0x0000 1 0
-#define MX6UL_PAD_UART5_TX_DATA__I2C2_SCL                              0x00bc 0x0348 0x05ac 2 2
-#define MX6UL_PAD_UART5_TX_DATA__CSI_DATA14                            0x00bc 0x0348 0x0000 3 0
-#define MX6UL_PAD_UART5_TX_DATA__CSU_CSU_ALARM_AUT00                   0x00bc 0x0348 0x0000 4 0
-#define MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX                          0x00c0 0x034c 0x0644 0 5
-#define MX6UL_PAD_UART5_RX_DATA__UART5_DTE_TX                          0x00c0 0x034c 0x0000 0 0
-#define MX6UL_PAD_UART5_RX_DATA__ENET2_COL                             0x00c0 0x034c 0x0000 1 0
-#define MX6UL_PAD_UART5_RX_DATA__I2C2_SDA                              0x00c0 0x034c 0x05b0 2 2
-#define MX6UL_PAD_UART5_RX_DATA__CSI_DATA15                            0x00c0 0x034c 0x0000 3 0
-#define MX6UL_PAD_UART5_RX_DATA__CSU_CSU_INT_DEB                       0x00c0 0x034c 0x0000 4 0
-#define MX6UL_PAD_UART5_RX_DATA__GPIO1_IO31                            0x00c0 0x034c 0x0000 5 0
-#define MX6UL_PAD_UART5_RX_DATA__ECSPI2_MISO                           0x00c0 0x034c 0x0000 8 0
-#define MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00                        0x00c4 0x0350 0x0000 0 0
-#define MX6UL_PAD_ENET1_RX_DATA0__UART4_DCE_RTS                        0x00c4 0x0350 0x0638 1 0
-#define MX6UL_PAD_ENET1_RX_DATA0__UART4_DTE_CTS                        0x00c4 0x0350 0x0000 1 0
-#define MX6UL_PAD_ENET1_RX_DATA0__PWM1_OUT                             0x00c4 0x0350 0x0000 2 0
-#define MX6UL_PAD_ENET1_RX_DATA0__CSI_DATA16                           0x00c4 0x0350 0x0000 3 0
-#define MX6UL_PAD_ENET1_RX_DATA0__FLEXCAN1_TX                          0x00c4 0x0350 0x0000 4 0
-#define MX6UL_PAD_ENET1_RX_DATA0__GPIO2_IO00                           0x00c4 0x0350 0x0000 5 0
-#define MX6UL_PAD_ENET1_RX_DATA0__KPP_ROW00                            0x00c4 0x0350 0x0000 6 0
-#define MX6UL_PAD_ENET1_RX_DATA0__USDHC1_LCTL                          0x00c4 0x0350 0x0000 8 0
-#define MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01                        0x00c8 0x0354 0x0000 0 0
-#define MX6UL_PAD_ENET1_RX_DATA1__UART4_DCE_CTS                        0x00c8 0x0354 0x0000 1 0
-#define MX6UL_PAD_ENET1_RX_DATA1__UART4_DTE_RTS                        0x00c8 0x0354 0x0638 1 1
-#define MX6UL_PAD_ENET1_RX_DATA1__PWM2_OUT                             0x00c8 0x0354 0x0000 2 0
-#define MX6UL_PAD_ENET1_RX_DATA1__CSI_DATA17                           0x00c8 0x0354 0x0000 3 0
-#define MX6UL_PAD_ENET1_RX_DATA1__FLEXCAN1_RX                          0x00c8 0x0354 0x0584 4 1
-#define MX6UL_PAD_ENET1_RX_DATA1__GPIO2_IO01                           0x00c8 0x0354 0x0000 5 0
-#define MX6UL_PAD_ENET1_RX_DATA1__KPP_COL00                            0x00c8 0x0354 0x0000 6 0
-#define MX6UL_PAD_ENET1_RX_DATA1__USDHC2_LCTL                          0x00c8 0x0354 0x0000 8 0
-#define MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN                             0x00cc 0x0358 0x0000 0 0
-#define MX6UL_PAD_ENET1_RX_EN__UART5_DCE_RTS                           0x00cc 0x0358 0x0640 1 3
-#define MX6UL_PAD_ENET1_RX_EN__UART5_DTE_CTS                           0x00cc 0x0358 0x0000 1 0
-#define MX6UL_PAD_ENET1_RX_EN__CSI_DATA18                              0x00cc 0x0358 0x0000 3 0
-#define MX6UL_PAD_ENET1_RX_EN__FLEXCAN2_TX                             0x00cc 0x0358 0x0000 4 0
-#define MX6UL_PAD_ENET1_RX_EN__GPIO2_IO02                              0x00cc 0x0358 0x0000 5 0
-#define MX6UL_PAD_ENET1_RX_EN__KPP_ROW01                               0x00cc 0x0358 0x0000 6 0
-#define MX6UL_PAD_ENET1_RX_EN__USDHC1_VSELECT                          0x00cc 0x0358 0x0000 8 0
-#define MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00                        0x00d0 0x035c 0x0000 0 0
-#define MX6UL_PAD_ENET1_TX_DATA0__UART5_DCE_CTS                        0x00d0 0x035c 0x0000 1 0
-#define MX6UL_PAD_ENET1_TX_DATA0__UART5_DTE_RTS                        0x00d0 0x035c 0x0640 1 4
-#define MX6UL_PAD_ENET1_TX_DATA0__CSI_DATA19                           0x00d0 0x035c 0x0000 3 0
-#define MX6UL_PAD_ENET1_TX_DATA0__FLEXCAN2_RX                          0x00d0 0x035c 0x0588 4 1
-#define MX6UL_PAD_ENET1_TX_DATA0__GPIO2_IO03                           0x00d0 0x035c 0x0000 5 0
-#define MX6UL_PAD_ENET1_TX_DATA0__KPP_COL01                            0x00d0 0x035c 0x0000 6 0
-#define MX6UL_PAD_ENET1_TX_DATA0__USDHC2_VSELECT                       0x00d0 0x035c 0x0000 8 0
-#define MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01                        0x00d4 0x0360 0x0000 0 0
-#define MX6UL_PAD_ENET1_TX_DATA1__UART6_DCE_CTS                        0x00d4 0x0360 0x0000 1 0
-#define MX6UL_PAD_ENET1_TX_DATA1__UART6_DTE_RTS                        0x00d4 0x0360 0x0648 1 2
-#define MX6UL_PAD_ENET1_TX_DATA1__PWM5_OUT                             0x00d4 0x0360 0x0000 2 0
-#define MX6UL_PAD_ENET1_TX_DATA1__CSI_DATA20                           0x00d4 0x0360 0x0000 3 0
-#define MX6UL_PAD_ENET1_TX_DATA1__ENET2_MDIO                           0x00d4 0x0360 0x0580 4 1
-#define MX6UL_PAD_ENET1_TX_DATA1__GPIO2_IO04                           0x00d4 0x0360 0x0000 5 0
-#define MX6UL_PAD_ENET1_TX_DATA1__KPP_ROW02                            0x00d4 0x0360 0x0000 6 0
-#define MX6UL_PAD_ENET1_TX_DATA1__WDOG1_WDOG_RST_B_DEB                 0x00d4 0x0360 0x0000 8 0
-#define MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN                             0x00d8 0x0364 0x0000 0 0
-#define MX6UL_PAD_ENET1_TX_EN__UART6_DCE_RTS                           0x00d8 0x0364 0x0648 1 3
-#define MX6UL_PAD_ENET1_TX_EN__UART6_DTE_CTS                           0x00d8 0x0364 0x0000 1 0
-#define MX6UL_PAD_ENET1_TX_EN__PWM6_OUT                                0x00d8 0x0364 0x0000 2 0
-#define MX6UL_PAD_ENET1_TX_EN__CSI_DATA21                              0x00d8 0x0364 0x0000 3 0
-#define MX6UL_PAD_ENET1_TX_EN__ENET2_MDC                               0x00d8 0x0364 0x0000 4 0
-#define MX6UL_PAD_ENET1_TX_EN__GPIO2_IO05                              0x00d8 0x0364 0x0000 5 0
-#define MX6UL_PAD_ENET1_TX_EN__KPP_COL02                               0x00d8 0x0364 0x0000 6 0
-#define MX6UL_PAD_ENET1_TX_EN__WDOG2_WDOG_RST_B_DEB                    0x00d8 0x0364 0x0000 8 0
-#define MX6UL_PAD_ENET1_TX_CLK__ENET1_TX_CLK                           0x00dc 0x0368 0x0000 0 0
-#define MX6UL_PAD_ENET1_TX_CLK__UART7_DCE_CTS                          0x00dc 0x0368 0x0000 1 0
-#define MX6UL_PAD_ENET1_TX_CLK__UART7_DTE_RTS                          0x00dc 0x0368 0x0650 1 0
-#define MX6UL_PAD_ENET1_TX_CLK__PWM7_OUT                               0x00dc 0x0368 0x0000 2 0
-#define MX6UL_PAD_ENET1_TX_CLK__CSI_DATA22                             0x00dc 0x0368 0x0000 3 0
-#define MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1                         0x00dc 0x0368 0x0574 4 2
-#define MX6UL_PAD_ENET1_TX_CLK__GPIO2_IO06                             0x00dc 0x0368 0x0000 5 0
-#define MX6UL_PAD_ENET1_TX_CLK__KPP_ROW03                              0x00dc 0x0368 0x0000 6 0
-#define MX6UL_PAD_ENET1_TX_CLK__GPT1_CLK                               0x00dc 0x0368 0x0000 8 0
-#define MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER                             0x00e0 0x036c 0x0000 0 0
-#define MX6UL_PAD_ENET1_RX_ER__UART7_DCE_RTS                           0x00e0 0x036c 0x0650 1 1
-#define MX6UL_PAD_ENET1_RX_ER__UART7_DTE_CTS                           0x00e0 0x036c 0x0000 1 0
-#define MX6UL_PAD_ENET1_RX_ER__PWM8_OUT                                0x00e0 0x036c 0x0000 2 0
-#define MX6UL_PAD_ENET1_RX_ER__CSI_DATA23                              0x00e0 0x036c 0x0000 3 0
-#define MX6UL_PAD_ENET1_RX_ER__EIM_CRE                                 0x00e0 0x036c 0x0000 4 0
-#define MX6UL_PAD_ENET1_RX_ER__GPIO2_IO07                              0x00e0 0x036c 0x0000 5 0
-#define MX6UL_PAD_ENET1_RX_ER__KPP_COL03                               0x00e0 0x036c 0x0000 6 0
-#define MX6UL_PAD_ENET1_RX_ER__GPT1_CAPTURE2                           0x00e0 0x036c 0x0000 8 0
-#define MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00                        0x00e4 0x0370 0x0000 0 0
-#define MX6UL_PAD_ENET2_RX_DATA0__UART6_DCE_TX                         0x00e4 0x0370 0x0000 1 0
-#define MX6UL_PAD_ENET2_RX_DATA0__UART6_DTE_RX                         0x00e4 0x0370 0x064c 1 1
-#define MX6UL_PAD_ENET2_RX_DATA0__SIM1_PORT0_TRXD                      0x00e4 0x0370 0x0000 2 0
-#define MX6UL_PAD_ENET2_RX_DATA0__I2C3_SCL                             0x00e4 0x0370 0x05b4 3 1
-#define MX6UL_PAD_ENET2_RX_DATA0__ENET1_MDIO                           0x00e4 0x0370 0x0578 4 1
-#define MX6UL_PAD_ENET2_RX_DATA0__GPIO2_IO08                           0x00e4 0x0370 0x0000 5 0
-#define MX6UL_PAD_ENET2_RX_DATA0__KPP_ROW04                            0x00e4 0x0370 0x0000 6 0
-#define MX6UL_PAD_ENET2_RX_DATA0__USB_OTG1_PWR                         0x00e4 0x0370 0x0000 8 0
-#define MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01                        0x00e8 0x0374 0x0000 0 0
-#define MX6UL_PAD_ENET2_RX_DATA1__UART6_DCE_RX                         0x00e8 0x0374 0x064c 1 2
-#define MX6UL_PAD_ENET2_RX_DATA1__UART6_DTE_TX                         0x00e8 0x0374 0x0000 1 0
-#define MX6UL_PAD_ENET2_RX_DATA1__SIM1_PORT0_cLK                       0x00e8 0x0374 0x0000 2 0
-#define MX6UL_PAD_ENET2_RX_DATA1__I2C3_SDA                             0x00e8 0x0374 0x05b8 3 1
-#define MX6UL_PAD_ENET2_RX_DATA1__ENET1_MDC                            0x00e8 0x0374 0x0000 4 0
-#define MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09                           0x00e8 0x0374 0x0000 5 0
-#define MX6UL_PAD_ENET2_RX_DATA1__KPP_COL04                            0x00e8 0x0374 0x0000 6 0
-#define MX6UL_PAD_ENET2_RX_DATA1__USB_OTG1_OC                          0x00e8 0x0374 0x0000 8 0
-#define MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN                             0x00ec 0x0378 0x0000 0 0
-#define MX6UL_PAD_ENET2_RX_EN__UART7_DCE_TX                            0x00ec 0x0378 0x0000 1 0
-#define MX6UL_PAD_ENET2_RX_EN__UART7_DTE_RX                            0x00ec 0x0378 0x0654 1 0
-#define MX6UL_PAD_ENET2_RX_EN__SIM1_PORT0_RST_B                        0x00ec 0x0378 0x0000 2 0
-#define MX6UL_PAD_ENET2_RX_EN__I2C4_SCL                                0x00ec 0x0378 0x05bc 3 1
-#define MX6UL_PAD_ENET2_RX_EN__EIM_ADDR26                              0x00ec 0x0378 0x0000 4 0
-#define MX6UL_PAD_ENET2_RX_EN__GPIO2_IO10                              0x00ec 0x0378 0x0000 5 0
-#define MX6UL_PAD_ENET2_RX_EN__KPP_ROW05                               0x00ec 0x0378 0x0000 6 0
-#define MX6UL_PAD_ENET2_RX_EN__ENET1_REF_CLK_25M                       0x00ec 0x0378 0x0000 8 0
-#define MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00                        0x00f0 0x037c 0x0000 0 0
-#define MX6UL_PAD_ENET2_TX_DATA0__UART7_DCE_RX                         0x00f0 0x037c 0x0654 1 1
-#define MX6UL_PAD_ENET2_TX_DATA0__UART7_DTE_TX                         0x00f0 0x037c 0x0000 1 0
-#define MX6UL_PAD_ENET2_TX_DATA0__SIM1_PORT0_SVEN                      0x00f0 0x037c 0x0000 2 0
-#define MX6UL_PAD_ENET2_TX_DATA0__I2C4_SDA                             0x00f0 0x037c 0x05c0 3 1
-#define MX6UL_PAD_ENET2_TX_DATA0__EIM_EB_B02                           0x00f0 0x037c 0x0000 4 0
-#define MX6UL_PAD_ENET2_TX_DATA0__GPIO2_IO11                           0x00f0 0x037c 0x0000 5 0
-#define MX6UL_PAD_ENET2_TX_DATA0__KPP_COL05                            0x00f0 0x037c 0x0000 6 0
-#define MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01                        0x00f4 0x0380 0x0000 0 0
-#define MX6UL_PAD_ENET2_TX_DATA1__UART8_DCE_TX                         0x00f4 0x0380 0x0000 1 0
-#define MX6UL_PAD_ENET2_TX_DATA1__UART8_DTE_RX                         0x00f4 0x0380 0x065c 1 0
-#define MX6UL_PAD_ENET2_TX_DATA1__SIM2_PORT0_TRXD                      0x00f4 0x0380 0x0000 2 0
-#define MX6UL_PAD_ENET2_TX_DATA1__ECSPI4_SCLK                          0x00f4 0x0380 0x0564 3 0
-#define MX6UL_PAD_ENET2_TX_DATA1__EIM_EB_B03                           0x00f4 0x0380 0x0000 4 0
-#define MX6UL_PAD_ENET2_TX_DATA1__GPIO2_IO12                           0x00f4 0x0380 0x0000 5 0
-#define MX6UL_PAD_ENET2_TX_DATA1__KPP_ROW06                            0x00f4 0x0380 0x0000 6 0
-#define MX6UL_PAD_ENET2_TX_DATA1__USB_OTG2_PWR                         0x00f4 0x0380 0x0000 8 0
-#define MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN                             0x00f8 0x0384 0x0000 0 0
-#define MX6UL_PAD_ENET2_TX_EN__UART8_DCE_RX                            0x00f8 0x0384 0x065c 1 1
-#define MX6UL_PAD_ENET2_TX_EN__UART8_DTE_TX                            0x00f8 0x0384 0x0000 1 0
-#define MX6UL_PAD_ENET2_TX_EN__SIM2_PORT0_cLK                          0x00f8 0x0384 0x0000 2 0
-#define MX6UL_PAD_ENET2_TX_EN__ECSPI4_MOSI                             0x00f8 0x0384 0x056c 3 0
-#define MX6UL_PAD_ENET2_TX_EN__EIM_ACLK_FREERUN                        0x00f8 0x0384 0x0000 4 0
-#define MX6UL_PAD_ENET2_TX_EN__GPIO2_IO13                              0x00f8 0x0384 0x0000 5 0
-#define MX6UL_PAD_ENET2_TX_EN__KPP_COL06                               0x00f8 0x0384 0x0000 6 0
-#define MX6UL_PAD_ENET2_TX_EN__USB_OTG2_OC                             0x00f8 0x0384 0x0000 8 0
-#define MX6UL_PAD_ENET2_TX_CLK__ENET2_TX_CLK                           0x00fc 0x0388 0x0000 0 0
-#define MX6UL_PAD_ENET2_TX_CLK__UART8_DCE_CTS                          0x00fc 0x0388 0x0000 1 0
-#define MX6UL_PAD_ENET2_TX_CLK__UART8_DTE_RTS                          0x00fc 0x0388 0x0658 1 0
-#define MX6UL_PAD_ENET2_TX_CLK__SIM2_PORT0_RST_B                       0x00fc 0x0388 0x0000 2 0
-#define MX6UL_PAD_ENET2_TX_CLK__ECSPI4_MISO                            0x00fc 0x0388 0x0568 3 0
-#define MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2                         0x00fc 0x0388 0x057c 4 2
-#define MX6UL_PAD_ENET2_TX_CLK__GPIO2_IO14                             0x00fc 0x0388 0x0000 5 0
-#define MX6UL_PAD_ENET2_TX_CLK__KPP_ROW07                              0x00fc 0x0388 0x0000 6 0
-#define MX6UL_PAD_ENET2_TX_CLK__ANATOP_OTG2_ID                         0x00fc 0x0388 0x0000 8 0
-#define MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER                             0x0100 0x038c 0x0000 0 0
-#define MX6UL_PAD_ENET2_RX_ER__UART8_DCE_RTS                           0x0100 0x038c 0x0658 1 1
-#define MX6UL_PAD_ENET2_RX_ER__UART8_DTE_CTS                           0x0100 0x038c 0x0000 1 0
-#define MX6UL_PAD_ENET2_RX_ER__SIM2_PORT0_SVEN                         0x0100 0x038c 0x0000 2 0
-#define MX6UL_PAD_ENET2_RX_ER__ECSPI4_SS0                              0x0100 0x038c 0x0000 3 0
-#define MX6UL_PAD_ENET2_RX_ER__EIM_ADDR25                              0x0100 0x038c 0x0000 4 0
-#define MX6UL_PAD_ENET2_RX_ER__GPIO2_IO15                              0x0100 0x038c 0x0000 5 0
-#define MX6UL_PAD_ENET2_RX_ER__KPP_COL07                               0x0100 0x038c 0x0000 6 0
-#define MX6UL_PAD_ENET2_RX_ER__WDOG1_WDOG_ANY                          0x0100 0x038c 0x0000 8 0
-#define MX6UL_PAD_LCD_CLK__LCDIF_CLK                                   0x0104 0x0390 0x0000 0 0
-#define MX6UL_PAD_LCD_CLK__LCDIF_WR_RWN                                0x0104 0x0390 0x0000 1 0
-#define MX6UL_PAD_LCD_CLK__UART4_DCE_TX                                0x0104 0x0390 0x0000 2 0
-#define MX6UL_PAD_LCD_CLK__UART4_DTE_RX                                0x0104 0x0390 0x063c 2 2
-#define MX6UL_PAD_LCD_CLK__SAI3_MCLK                                   0x0104 0x0390 0x0000 3 0
-#define MX6UL_PAD_LCD_CLK__EIM_CS2_B                                   0x0104 0x0390 0x0000 4 0
-#define MX6UL_PAD_LCD_CLK__GPIO3_IO00                                  0x0104 0x0390 0x0000 5 0
-#define MX6UL_PAD_LCD_CLK__WDOG1_WDOG_RST_B_DEB                        0x0104 0x0390 0x0000 8 0
-#define MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE                             0x0108 0x0394 0x0000 0 0
-#define MX6UL_PAD_LCD_ENABLE__LCDIF_RD_E                               0x0108 0x0394 0x0000 1 0
-#define MX6UL_PAD_LCD_ENABLE__UART4_DCE_RX                             0x0108 0x0394 0x063c 2 3
-#define MX6UL_PAD_LCD_ENABLE__UART4_DTE_TX                             0x0108 0x0394 0x0000 2 0
-#define MX6UL_PAD_LCD_ENABLE__SAI3_TX_SYNC                             0x0108 0x0394 0x060c 3 0
-#define MX6UL_PAD_LCD_ENABLE__EIM_CS3_B                                0x0108 0x0394 0x0000 4 0
-#define MX6UL_PAD_LCD_ENABLE__GPIO3_IO01                               0x0108 0x0394 0x0000 5 0
-#define MX6UL_PAD_LCD_ENABLE__ECSPI2_RDY                               0x0108 0x0394 0x0000 8 0
-#define MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC                               0x010c 0x0398 0x05dc 0 0
-#define MX6UL_PAD_LCD_HSYNC__LCDIF_RS                                  0x010c 0x0398 0x0000 1 0
-#define MX6UL_PAD_LCD_HSYNC__UART4_DCE_CTS                             0x010c 0x0398 0x0000 2 0
-#define MX6UL_PAD_LCD_HSYNC__UART4_DTE_RTS                             0x010c 0x0398 0x0638 2 2
-#define MX6UL_PAD_LCD_HSYNC__SAI3_TX_BCLK                              0x010c 0x0398 0x0608 3 0
-#define MX6UL_PAD_LCD_HSYNC__WDOG3_WDOG_RST_B_DEB                      0x010c 0x0398 0x0000 4 0
-#define MX6UL_PAD_LCD_HSYNC__GPIO3_IO02                                0x010c 0x0398 0x0000 5 0
-#define MX6UL_PAD_LCD_HSYNC__ECSPI2_SS1                                0x010c 0x0398 0x0000 8 0
-#define MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC                               0x0110 0x039c 0x0000 0 0
-#define MX6UL_PAD_LCD_VSYNC__LCDIF_BUSY                                0x0110 0x039c 0x05dc 1 1
-#define MX6UL_PAD_LCD_VSYNC__UART4_DCE_RTS                             0x0110 0x039c 0x0638 2 3
-#define MX6UL_PAD_LCD_VSYNC__UART4_DTE_CTS                             0x0110 0x039c 0x0000 2 0
-#define MX6UL_PAD_LCD_VSYNC__SAI3_RX_DATA                              0x0110 0x039c 0x0000 3 0
-#define MX6UL_PAD_LCD_VSYNC__WDOG2_WDOG_B                              0x0110 0x039c 0x0000 4 0
-#define MX6UL_PAD_LCD_VSYNC__GPIO3_IO03                                0x0110 0x039c 0x0000 5 0
-#define MX6UL_PAD_LCD_VSYNC__ECSPI2_SS2                                0x0110 0x039c 0x0000 8 0
-#define MX6UL_PAD_LCD_RESET__LCDIF_RESET                               0x0114 0x03a0 0x0000 0 0
-#define MX6UL_PAD_LCD_RESET__LCDIF_CS                                  0x0114 0x03a0 0x0000 1 0
-#define MX6UL_PAD_LCD_RESET__CA7_MX6UL_EVENTI                          0x0114 0x03a0 0x0000 2 0
-#define MX6UL_PAD_LCD_RESET__SAI3_TX_DATA                              0x0114 0x03a0 0x0000 3 0
-#define MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY                            0x0114 0x03a0 0x0000 4 0
-#define MX6UL_PAD_LCD_RESET__GPIO3_IO04                                0x0114 0x03a0 0x0000 5 0
-#define MX6UL_PAD_LCD_RESET__ECSPI2_SS3                                0x0114 0x03a0 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA00__LCDIF_DATA00                             0x0118 0x03a4 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA00__PWM1_OUT                                 0x0118 0x03a4 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA00__ENET1_1588_EVENT2_IN                     0x0118 0x03a4 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA00__I2C3_SDA                                 0x0118 0x03a4 0x05b8 4 2
-#define MX6UL_PAD_LCD_DATA00__GPIO3_IO05                               0x0118 0x03a4 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA00__SRC_BT_CFG00                             0x0118 0x03a4 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA00__SAI1_MCLK                                0x0118 0x03a4 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA01__LCDIF_DATA01                             0x011c 0x03a8 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA01__PWM2_OUT                                 0x011c 0x03a8 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA01__ENET1_1588_EVENT2_OUT                    0x011c 0x03a8 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA01__I2C3_SCL                                 0x011c 0x03a8 0x05b4 4 2
-#define MX6UL_PAD_LCD_DATA01__GPIO3_IO06                               0x011c 0x03a8 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA01__SRC_BT_CFG01                             0x011c 0x03a8 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA01__SAI1_TX_SYNC                             0x011c 0x03a8 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA02__LCDIF_DATA02                             0x0120 0x03ac 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA02__PWM3_OUT                                 0x0120 0x03ac 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA02__ENET1_1588_EVENT3_IN                     0x0120 0x03ac 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA02__I2C4_SDA                                 0x0120 0x03ac 0x05c0 4 2
-#define MX6UL_PAD_LCD_DATA02__GPIO3_IO07                               0x0120 0x03ac 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA02__SRC_BT_CFG02                             0x0120 0x03ac 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA02__SAI1_TX_BCLK                             0x0120 0x03ac 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA03__LCDIF_DATA03                             0x0124 0x03b0 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA03__PWM4_OUT                                 0x0124 0x03b0 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA03__ENET1_1588_EVENT3_OUT                    0x0124 0x03b0 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA03__I2C4_SCL                                 0x0124 0x03b0 0x05bc 4 2
-#define MX6UL_PAD_LCD_DATA03__GPIO3_IO08                               0x0124 0x03b0 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA03__SRC_BT_CFG03                             0x0124 0x03b0 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA03__SAI1_RX_DATA                             0x0124 0x03b0 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA04__LCDIF_DATA04                             0x0128 0x03b4 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA04__UART8_DCE_CTS                            0x0128 0x03b4 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA04__UART8_DTE_RTS                            0x0128 0x03b4 0x0658 1 2
-#define MX6UL_PAD_LCD_DATA04__ENET2_1588_EVENT2_IN                     0x0128 0x03b4 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA04__SPDIF_SR_CLK                             0x0128 0x03b4 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA04__GPIO3_IO09                               0x0128 0x03b4 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA04__SRC_BT_CFG04                             0x0128 0x03b4 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA04__SAI1_TX_DATA                             0x0128 0x03b4 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA05__LCDIF_DATA05                             0x012c 0x03b8 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA05__UART8_DCE_RTS                            0x012c 0x03b8 0x0658 1 3
-#define MX6UL_PAD_LCD_DATA05__UART8_DTE_CTS                            0x012c 0x03b8 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA05__ENET2_1588_EVENT2_OUT                    0x012c 0x03b8 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA05__SPDIF_OUT                                0x012c 0x03b8 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA05__GPIO3_IO10                               0x012c 0x03b8 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA05__SRC_BT_CFG05                             0x012c 0x03b8 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA05__ECSPI1_SS1                               0x012c 0x03b8 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA06__LCDIF_DATA06                             0x0130 0x03bc 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA06__UART7_DCE_CTS                            0x0130 0x03bc 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA06__UART7_DTE_RTS                            0x0130 0x03bc 0x0650 1 2
-#define MX6UL_PAD_LCD_DATA06__ENET2_1588_EVENT3_IN                     0x0130 0x03bc 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA06__SPDIF_LOCK                               0x0130 0x03bc 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA06__GPIO3_IO11                               0x0130 0x03bc 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA06__SRC_BT_CFG06                             0x0130 0x03bc 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA06__ECSPI1_SS2                               0x0130 0x03bc 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA07__LCDIF_DATA07                             0x0134 0x03c0 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA07__UART7_DCE_RTS                            0x0134 0x03c0 0x0650 1 3
-#define MX6UL_PAD_LCD_DATA07__UART7_DTE_CTS                            0x0134 0x03c0 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA07__ENET2_1588_EVENT3_OUT                    0x0134 0x03c0 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA07__SPDIF_EXT_CLK                            0x0134 0x03c0 0x061c 4 0
-#define MX6UL_PAD_LCD_DATA07__GPIO3_IO12                               0x0134 0x03c0 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA07__SRC_BT_CFG07                             0x0134 0x03c0 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA07__ECSPI1_SS3                               0x0134 0x03c0 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA08__LCDIF_DATA08                             0x0138 0x03c4 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA08__SPDIF_IN                                 0x0138 0x03c4 0x0618 1 2
-#define MX6UL_PAD_LCD_DATA08__CSI_DATA16                               0x0138 0x03c4 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA08__EIM_DATA00                               0x0138 0x03c4 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA08__GPIO3_IO13                               0x0138 0x03c4 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA08__SRC_BT_CFG08                             0x0138 0x03c4 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA08__FLEXCAN1_TX                              0x0138 0x03c4 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA09__LCDIF_DATA09                             0x013c 0x03c8 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA09__SAI3_MCLK                                0x013c 0x03c8 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA09__CSI_DATA17                               0x013c 0x03c8 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA09__EIM_DATA01                               0x013c 0x03c8 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA09__GPIO3_IO14                               0x013c 0x03c8 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA09__SRC_BT_CFG09                             0x013c 0x03c8 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA09__FLEXCAN1_RX                              0x013c 0x03c8 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA10__LCDIF_DATA10                             0x0140 0x03cc 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA10__SAI3_RX_SYNC                             0x0140 0x03cc 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA10__CSI_DATA18                               0x0140 0x03cc 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA10__EIM_DATA02                               0x0140 0x03cc 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA10__GPIO3_IO15                               0x0140 0x03cc 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA10__SRC_BT_CFG10                             0x0140 0x03cc 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA10__FLEXCAN2_TX                              0x0140 0x03cc 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA11__LCDIF_DATA11                             0x0144 0x03d0 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA11__SAI3_RX_BCLK                             0x0144 0x03d0 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA11__CSI_DATA19                               0x0144 0x03d0 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA11__EIM_DATA03                               0x0144 0x03d0 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA11__GPIO3_IO16                               0x0144 0x03d0 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA11__SRC_BT_CFG11                             0x0144 0x03d0 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA11__FLEXCAN2_RX                              0x0144 0x03d0 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA12__LCDIF_DATA12                             0x0148 0x03d4 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA12__SAI3_TX_SYNC                             0x0148 0x03d4 0x060c 1 1
-#define MX6UL_PAD_LCD_DATA12__CSI_DATA20                               0x0148 0x03d4 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA12__EIM_DATA04                               0x0148 0x03d4 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA12__GPIO3_IO17                               0x0148 0x03d4 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA12__SRC_BT_CFG12                             0x0148 0x03d4 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA12__ECSPI1_RDY                               0x0148 0x03d4 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA13__LCDIF_DATA13                             0x014c 0x03d8 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA13__SAI3_TX_BCLK                             0x014c 0x03d8 0x0608 1 1
-#define MX6UL_PAD_LCD_DATA13__CSI_DATA21                               0x014c 0x03d8 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA13__EIM_DATA05                               0x014c 0x03d8 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA13__GPIO3_IO18                               0x014c 0x03d8 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA13__SRC_BT_CFG13                             0x014c 0x03d8 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA13__USDHC2_RESET_B                           0x014c 0x03d8 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA14__LCDIF_DATA14                             0x0150 0x03dc 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA14__SAI3_RX_DATA                             0x0150 0x03dc 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA14__CSI_DATA22                               0x0150 0x03dc 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA14__EIM_DATA06                               0x0150 0x03dc 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA14__GPIO3_IO19                               0x0150 0x03dc 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA14__SRC_BT_CFG14                             0x0150 0x03dc 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA14__USDHC2_DATA4                             0x0150 0x03dc 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA15__LCDIF_DATA15                             0x0154 0x03e0 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA15__SAI3_TX_DATA                             0x0154 0x03e0 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA15__CSI_DATA23                               0x0154 0x03e0 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA15__EIM_DATA07                               0x0154 0x03e0 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA15__GPIO3_IO20                               0x0154 0x03e0 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA15__SRC_BT_CFG15                             0x0154 0x03e0 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA15__USDHC2_DATA5                             0x0154 0x03e0 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA16__LCDIF_DATA16                             0x0158 0x03e4 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA16__UART7_DCE_TX                             0x0158 0x03e4 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA16__UART7_DTE_RX                             0x0158 0x03e4 0x0654 1 2
-#define MX6UL_PAD_LCD_DATA16__CSI_DATA01                               0x0158 0x03e4 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA16__EIM_DATA08                               0x0158 0x03e4 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA16__GPIO3_IO21                               0x0158 0x03e4 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA16__SRC_BT_CFG24                             0x0158 0x03e4 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA16__USDHC2_DATA6                             0x0158 0x03e4 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA17__LCDIF_DATA17                             0x015c 0x03e8 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA17__UART7_DCE_RX                             0x015c 0x03e8 0x0654 1 3
-#define MX6UL_PAD_LCD_DATA17__UART7_DTE_TX                             0x015c 0x03e8 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA17__CSI_DATA00                               0x015c 0x03e8 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA17__EIM_DATA09                               0x015c 0x03e8 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA17__GPIO3_IO22                               0x015c 0x03e8 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA17__SRC_BT_CFG25                             0x015c 0x03e8 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA17__USDHC2_DATA7                             0x015c 0x03e8 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA18__LCDIF_DATA18                             0x0160 0x03ec 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA18__PWM5_OUT                                 0x0160 0x03ec 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA18__CA7_MX6UL_EVENTO                         0x0160 0x03ec 0x0000 2 0
-#define MX6UL_PAD_LCD_DATA18__CSI_DATA10                               0x0160 0x03ec 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA18__EIM_DATA10                               0x0160 0x03ec 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA18__GPIO3_IO23                               0x0160 0x03ec 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA18__SRC_BT_CFG26                             0x0160 0x03ec 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA18__USDHC2_CMD                               0x0160 0x03ec 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA19__EIM_DATA11                               0x0164 0x03f0 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA19__GPIO3_IO24                               0x0164 0x03f0 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA19__SRC_BT_CFG27                             0x0164 0x03f0 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA19__USDHC2_CLK                               0x0164 0x03f0 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA19__LCDIF_DATA19                             0x0164 0x03f0 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA19__PWM6_OUT                                 0x0164 0x03f0 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA19__WDOG1_WDOG_ANY                           0x0164 0x03f0 0x0000 2 0
-#define MX6UL_PAD_LCD_DATA19__CSI_DATA11                               0x0164 0x03f0 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA20__EIM_DATA12                               0x0168 0x03f4 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA20__GPIO3_IO25                               0x0168 0x03f4 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA20__SRC_BT_CFG28                             0x0168 0x03f4 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA20__USDHC2_DATA0                             0x0168 0x03f4 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA20__LCDIF_DATA20                             0x0168 0x03f4 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA20__UART8_DCE_TX                             0x0168 0x03f4 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA20__UART8_DTE_RX                             0x0168 0x03f4 0x065c 1 2
-#define MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK                              0x0168 0x03f4 0x0534 2 0
-#define MX6UL_PAD_LCD_DATA20__CSI_DATA12                               0x0168 0x03f4 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA21__LCDIF_DATA21                             0x016c 0x03f8 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA21__UART8_DCE_RX                             0x016c 0x03f8 0x065c 1 3
-#define MX6UL_PAD_LCD_DATA21__UART8_DTE_TX                             0x016c 0x03f8 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA21__ECSPI1_SS0                               0x016c 0x03f8 0x0000 2 0
-#define MX6UL_PAD_LCD_DATA21__CSI_DATA13                               0x016c 0x03f8 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA21__EIM_DATA13                               0x016c 0x03f8 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA21__GPIO3_IO26                               0x016c 0x03f8 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA21__SRC_BT_CFG29                             0x016c 0x03f8 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA21__USDHC2_DATA1                             0x016c 0x03f8 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA22__LCDIF_DATA22                             0x0170 0x03fc 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA22__MQS_RIGHT                                0x0170 0x03fc 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI                              0x0170 0x03fc 0x053c 2 0
-#define MX6UL_PAD_LCD_DATA22__CSI_DATA14                               0x0170 0x03fc 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA22__EIM_DATA14                               0x0170 0x03fc 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA22__GPIO3_IO27                               0x0170 0x03fc 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA22__SRC_BT_CFG30                             0x0170 0x03fc 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA22__USDHC2_DATA2                             0x0170 0x03fc 0x0000 8 0
-#define MX6UL_PAD_LCD_DATA23__LCDIF_DATA23                             0x0174 0x0400 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA23__MQS_LEFT                                 0x0174 0x0400 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA23__ECSPI1_MISO                              0x0174 0x0400 0x0538 2 0
-#define MX6UL_PAD_LCD_DATA23__CSI_DATA15                               0x0174 0x0400 0x0000 3 0
-#define MX6UL_PAD_LCD_DATA23__EIM_DATA15                               0x0174 0x0400 0x0000 4 0
-#define MX6UL_PAD_LCD_DATA23__GPIO3_IO28                               0x0174 0x0400 0x0000 5 0
-#define MX6UL_PAD_LCD_DATA23__SRC_BT_CFG31                             0x0174 0x0400 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA23__USDHC2_DATA3                             0x0174 0x0400 0x0000 8 0
-#define MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B                              0x0178 0x0404 0x0000 0 0
-#define MX6UL_PAD_NAND_RE_B__USDHC2_CLK                                0x0178 0x0404 0x0670 1 2
-#define MX6UL_PAD_NAND_RE_B__QSPI_B_SCLK                               0x0178 0x0404 0x0000 2 0
-#define MX6UL_PAD_NAND_RE_B__KPP_ROW00                                 0x0178 0x0404 0x0000 3 0
-#define MX6UL_PAD_NAND_RE_B__EIM_EB_B00                                0x0178 0x0404 0x0000 4 0
-#define MX6UL_PAD_NAND_RE_B__GPIO4_IO00                                0x0178 0x0404 0x0000 5 0
-#define MX6UL_PAD_NAND_RE_B__ECSPI3_SS2                                0x0178 0x0404 0x0000 8 0
-#define MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B                              0x017c 0x0408 0x0000 0 0
-#define MX6UL_PAD_NAND_WE_B__USDHC2_CMD                                0x017c 0x0408 0x0678 1 2
-#define MX6UL_PAD_NAND_WE_B__QSPI_B_SS0_B                              0x017c 0x0408 0x0000 2 0
-#define MX6UL_PAD_NAND_WE_B__KPP_COL00                                 0x017c 0x0408 0x0000 3 0
-#define MX6UL_PAD_NAND_WE_B__EIM_EB_B01                                0x017c 0x0408 0x0000 4 0
-#define MX6UL_PAD_NAND_WE_B__GPIO4_IO01                                0x017c 0x0408 0x0000 5 0
-#define MX6UL_PAD_NAND_WE_B__ECSPI3_SS3                                0x017c 0x0408 0x0000 8 0
-#define MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00                          0x0180 0x040c 0x0000 0 0
-#define MX6UL_PAD_NAND_DATA00__USDHC2_DATA0                            0x0180 0x040c 0x067c 1 2
-#define MX6UL_PAD_NAND_DATA00__QSPI_B_SS1_B                            0x0180 0x040c 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA00__KPP_ROW01                               0x0180 0x040c 0x0000 3 0
-#define MX6UL_PAD_NAND_DATA00__EIM_AD08                                0x0180 0x040c 0x0000 4 0
-#define MX6UL_PAD_NAND_DATA00__GPIO4_IO02                              0x0180 0x040c 0x0000 5 0
-#define MX6UL_PAD_NAND_DATA00__ECSPI4_RDY                              0x0180 0x040c 0x0000 8 0
-#define MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01                          0x0184 0x0410 0x0000 0 0
-#define MX6UL_PAD_NAND_DATA01__USDHC2_DATA1                            0x0184 0x0410 0x0680 1 2
-#define MX6UL_PAD_NAND_DATA01__QSPI_B_DQS                              0x0184 0x0410 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA01__KPP_COL01                               0x0184 0x0410 0x0000 3 0
-#define MX6UL_PAD_NAND_DATA01__EIM_AD09                                0x0184 0x0410 0x0000 4 0
-#define MX6UL_PAD_NAND_DATA01__GPIO4_IO03                              0x0184 0x0410 0x0000 5 0
-#define MX6UL_PAD_NAND_DATA01__ECSPI4_SS1                              0x0184 0x0410 0x0000 8 0
-#define MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02                          0x0188 0x0414 0x0000 0 0
-#define MX6UL_PAD_NAND_DATA02__USDHC2_DATA2                            0x0188 0x0414 0x0684 1 1
-#define MX6UL_PAD_NAND_DATA02__QSPI_B_DATA00                           0x0188 0x0414 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA02__KPP_ROW02                               0x0188 0x0414 0x0000 3 0
-#define MX6UL_PAD_NAND_DATA02__EIM_AD10                                0x0188 0x0414 0x0000 4 0
-#define MX6UL_PAD_NAND_DATA02__GPIO4_IO04                              0x0188 0x0414 0x0000 5 0
-#define MX6UL_PAD_NAND_DATA02__ECSPI4_SS2                              0x0188 0x0414 0x0000 8 0
-#define MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03                          0x018c 0x0418 0x0000 0 0
-#define MX6UL_PAD_NAND_DATA03__USDHC2_DATA3                            0x018c 0x0418 0x0688 1 2
-#define MX6UL_PAD_NAND_DATA03__QSPI_B_DATA01                           0x018c 0x0418 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA03__KPP_COL02                               0x018c 0x0418 0x0000 3 0
-#define MX6UL_PAD_NAND_DATA03__EIM_AD11                                0x018c 0x0418 0x0000 4 0
-#define MX6UL_PAD_NAND_DATA03__GPIO4_IO05                              0x018c 0x0418 0x0000 5 0
-#define MX6UL_PAD_NAND_DATA03__ECSPI4_SS3                              0x018c 0x0418 0x0000 8 0
-#define MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04                          0x0190 0x041c 0x0000 0 0
-#define MX6UL_PAD_NAND_DATA04__USDHC2_DATA4                            0x0190 0x041c 0x068c 1 1
-#define MX6UL_PAD_NAND_DATA04__QSPI_B_DATA02                           0x0190 0x041c 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA04__ECSPI4_SCLK                             0x0190 0x041c 0x0564 3 1
-#define MX6UL_PAD_NAND_DATA04__EIM_AD12                                0x0190 0x041c 0x0000 4 0
-#define MX6UL_PAD_NAND_DATA04__GPIO4_IO06                              0x0190 0x041c 0x0000 5 0
-#define MX6UL_PAD_NAND_DATA04__UART2_DCE_TX                            0x0190 0x041c 0x0000 8 0
-#define MX6UL_PAD_NAND_DATA04__UART2_DTE_RX                            0x0190 0x041c 0x062c 8 2
-#define MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05                          0x0194 0x0420 0x0000 0 0
-#define MX6UL_PAD_NAND_DATA05__USDHC2_DATA5                            0x0194 0x0420 0x0690 1 1
-#define MX6UL_PAD_NAND_DATA05__QSPI_B_DATA03                           0x0194 0x0420 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA05__ECSPI4_MOSI                             0x0194 0x0420 0x056c 3 1
-#define MX6UL_PAD_NAND_DATA05__EIM_AD13                                0x0194 0x0420 0x0000 4 0
-#define MX6UL_PAD_NAND_DATA05__GPIO4_IO07                              0x0194 0x0420 0x0000 5 0
-#define MX6UL_PAD_NAND_DATA05__UART2_DCE_RX                            0x0194 0x0420 0x062c 8 3
-#define MX6UL_PAD_NAND_DATA05__UART2_DTE_TX                            0x0194 0x0420 0x0000 8 0
-#define MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06                          0x0198 0x0424 0x0000 0 0
-#define MX6UL_PAD_NAND_DATA06__USDHC2_DATA6                            0x0198 0x0424 0x0694 1 1
-#define MX6UL_PAD_NAND_DATA06__SAI2_RX_BCLK                            0x0198 0x0424 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA06__ECSPI4_MISO                             0x0198 0x0424 0x0568 3 1
-#define MX6UL_PAD_NAND_DATA06__EIM_AD14                                0x0198 0x0424 0x0000 4 0
-#define MX6UL_PAD_NAND_DATA06__GPIO4_IO08                              0x0198 0x0424 0x0000 5 0
-#define MX6UL_PAD_NAND_DATA06__UART2_DCE_CTS                           0x0198 0x0424 0x0000 8 0
-#define MX6UL_PAD_NAND_DATA06__UART2_DTE_RTS                           0x0198 0x0424 0x0628 8 4
-#define MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07                          0x019c 0x0428 0x0000 0 0
-#define MX6UL_PAD_NAND_DATA07__USDHC2_DATA7                            0x019c 0x0428 0x0698 1 1
-#define MX6UL_PAD_NAND_DATA07__QSPI_A_SS1_B                            0x019c 0x0428 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA07__ECSPI4_SS0                              0x019c 0x0428 0x0000 3 0
-#define MX6UL_PAD_NAND_DATA07__EIM_AD15                                0x019c 0x0428 0x0000 4 0
-#define MX6UL_PAD_NAND_DATA07__GPIO4_IO09                              0x019c 0x0428 0x0000 5 0
-#define MX6UL_PAD_NAND_DATA07__UART2_DCE_RTS                           0x019c 0x0428 0x0628 8 5
-#define MX6UL_PAD_NAND_DATA07__UART2_DTE_CTS                           0x019c 0x0428 0x0000 8 0
-#define MX6UL_PAD_NAND_ALE__RAWNAND_ALE                                0x01a0 0x042c 0x0000 0 0
-#define MX6UL_PAD_NAND_ALE__USDHC2_RESET_B                             0x01a0 0x042c 0x0000 1 0
-#define MX6UL_PAD_NAND_ALE__QSPI_A_DQS                                 0x01a0 0x042c 0x0000 2 0
-#define MX6UL_PAD_NAND_ALE__PWM3_OUT                                   0x01a0 0x042c 0x0000 3 0
-#define MX6UL_PAD_NAND_ALE__EIM_ADDR17                                 0x01a0 0x042c 0x0000 4 0
-#define MX6UL_PAD_NAND_ALE__GPIO4_IO10                                 0x01a0 0x042c 0x0000 5 0
-#define MX6UL_PAD_NAND_ALE__ECSPI3_SS1                                 0x01a0 0x042c 0x0000 8 0
-#define MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B                              0x01a4 0x0430 0x0000 0 0
-#define MX6UL_PAD_NAND_WP_B__USDHC1_RESET_B                            0x01a4 0x0430 0x0000 1 0
-#define MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK                               0x01a4 0x0430 0x0000 2 0
-#define MX6UL_PAD_NAND_WP_B__PWM4_OUT                                  0x01a4 0x0430 0x0000 3 0
-#define MX6UL_PAD_NAND_WP_B__EIM_BCLK                                  0x01a4 0x0430 0x0000 4 0
-#define MX6UL_PAD_NAND_WP_B__GPIO4_IO11                                0x01a4 0x0430 0x0000 5 0
-#define MX6UL_PAD_NAND_WP_B__ECSPI3_RDY                                0x01a4 0x0430 0x0000 8 0
-#define MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B                        0x01a8 0x0434 0x0000 0 0
-#define MX6UL_PAD_NAND_READY_B__USDHC1_DATA4                           0x01a8 0x0434 0x0000 1 0
-#define MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00                          0x01a8 0x0434 0x0000 2 0
-#define MX6UL_PAD_NAND_READY_B__ECSPI3_SS0                             0x01a8 0x0434 0x0000 3 0
-#define MX6UL_PAD_NAND_READY_B__EIM_CS1_B                              0x01a8 0x0434 0x0000 4 0
-#define MX6UL_PAD_NAND_READY_B__GPIO4_IO12                             0x01a8 0x0434 0x0000 5 0
-#define MX6UL_PAD_NAND_READY_B__UART3_DCE_TX                           0x01a8 0x0434 0x0000 8 0
-#define MX6UL_PAD_NAND_READY_B__UART3_DTE_RX                           0x01a8 0x0434 0x0634 8 2
-#define MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B                            0x01ac 0x0438 0x0000 0 0
-#define MX6UL_PAD_NAND_CE0_B__USDHC1_DATA5                             0x01ac 0x0438 0x0000 1 0
-#define MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01                            0x01ac 0x0438 0x0000 2 0
-#define MX6UL_PAD_NAND_CE0_B__ECSPI3_SCLK                              0x01ac 0x0438 0x0554 3 1
-#define MX6UL_PAD_NAND_CE0_B__EIM_DTACK_B                              0x01ac 0x0438 0x0000 4 0
-#define MX6UL_PAD_NAND_CE0_B__GPIO4_IO13                               0x01ac 0x0438 0x0000 5 0
-#define MX6UL_PAD_NAND_CE0_B__UART3_DCE_RX                             0x01ac 0x0438 0x0634 8 3
-#define MX6UL_PAD_NAND_CE0_B__UART3_DTE_TX                             0x01ac 0x0438 0x0000 8 0
-#define MX6UL_PAD_NAND_CE1_B__RAWNAND_CE1_B                            0x01b0 0x043c 0x0000 0 0
-#define MX6UL_PAD_NAND_CE1_B__USDHC1_DATA6                             0x01b0 0x043c 0x0000 1 0
-#define MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02                            0x01b0 0x043c 0x0000 2 0
-#define MX6UL_PAD_NAND_CE1_B__ECSPI3_MOSI                              0x01b0 0x043c 0x055c 3 1
-#define MX6UL_PAD_NAND_CE1_B__EIM_ADDR18                               0x01b0 0x043c 0x0000 4 0
-#define MX6UL_PAD_NAND_CE1_B__GPIO4_IO14                               0x01b0 0x043c 0x0000 5 0
-#define MX6UL_PAD_NAND_CE1_B__UART3_DCE_CTS                            0x01b0 0x043c 0x0000 8 0
-#define MX6UL_PAD_NAND_CE1_B__UART3_DTE_RTS                            0x01b0 0x043c 0x0630 8 2
-#define MX6UL_PAD_NAND_CLE__RAWNAND_CLE                                0x01b4 0x0440 0x0000 0 0
-#define MX6UL_PAD_NAND_CLE__USDHC1_DATA7                               0x01b4 0x0440 0x0000 1 0
-#define MX6UL_PAD_NAND_CLE__QSPI_A_DATA03                              0x01b4 0x0440 0x0000 2 0
-#define MX6UL_PAD_NAND_CLE__ECSPI3_MISO                                0x01b4 0x0440 0x0558 3 1
-#define MX6UL_PAD_NAND_CLE__EIM_ADDR16                                 0x01b4 0x0440 0x0000 4 0
-#define MX6UL_PAD_NAND_CLE__GPIO4_IO15                                 0x01b4 0x0440 0x0000 5 0
-#define MX6UL_PAD_NAND_CLE__UART3_DCE_RTS                              0x01b4 0x0440 0x0630 8 3
-#define MX6UL_PAD_NAND_CLE__UART3_DTE_CTS                              0x01b4 0x0440 0x0000 8 0
-#define MX6UL_PAD_NAND_DQS__RAWNAND_DQS                                0x01b8 0x0444 0x0000 0 0
-#define MX6UL_PAD_NAND_DQS__CSI_FIELD                                  0x01b8 0x0444 0x0530 1 1
-#define MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B                               0x01b8 0x0444 0x0000 2 0
-#define MX6UL_PAD_NAND_DQS__PWM5_OUT                                   0x01b8 0x0444 0x0000 3 0
-#define MX6UL_PAD_NAND_DQS__EIM_WAIT                                   0x01b8 0x0444 0x0000 4 0
-#define MX6UL_PAD_NAND_DQS__GPIO4_IO16                                 0x01b8 0x0444 0x0000 5 0
-#define MX6UL_PAD_NAND_DQS__SDMA_EXT_EVENT01                           0x01b8 0x0444 0x0000 6 0
-#define MX6UL_PAD_NAND_DQS__SPDIF_EXT_CLK                              0x01b8 0x0444 0x0000 8 0
-#define MX6UL_PAD_SD1_CMD__USDHC1_CMD                                  0x01bc 0x0448 0x0000 0 0
-#define MX6UL_PAD_SD1_CMD__GPT2_COMPARE1                               0x01bc 0x0448 0x0000 1 0
-#define MX6UL_PAD_SD1_CMD__SAI2_RX_SYNC                                0x01bc 0x0448 0x0000 2 0
-#define MX6UL_PAD_SD1_CMD__SPDIF_OUT                                   0x01bc 0x0448 0x0000 3 0
-#define MX6UL_PAD_SD1_CMD__EIM_ADDR19                                  0x01bc 0x0448 0x0000 4 0
-#define MX6UL_PAD_SD1_CMD__GPIO2_IO16                                  0x01bc 0x0448 0x0000 5 0
-#define MX6UL_PAD_SD1_CMD__SDMA_EXT_EVENT00                            0x01bc 0x0448 0x0000 6 0
-#define MX6UL_PAD_SD1_CMD__USB_OTG1_PWR                                0x01bc 0x0448 0x0000 8 0
-#define MX6UL_PAD_SD1_CLK__USDHC1_CLK                                  0x01c0 0x044c 0x0000 0 0
-#define MX6UL_PAD_SD1_CLK__GPT2_COMPARE2                               0x01c0 0x044c 0x0000 1 0
-#define MX6UL_PAD_SD1_CLK__SAI2_MCLK                                   0x01c0 0x044c 0x0000 2 0
-#define MX6UL_PAD_SD1_CLK__SPDIF_IN                                    0x01c0 0x044c 0x0618 3 3
-#define MX6UL_PAD_SD1_CLK__EIM_ADDR20                                  0x01c0 0x044c 0x0000 4 0
-#define MX6UL_PAD_SD1_CLK__GPIO2_IO17                                  0x01c0 0x044c 0x0000 5 0
-#define MX6UL_PAD_SD1_CLK__USB_OTG1_OC                                 0x01c0 0x044c 0x0000 8 0
-#define MX6UL_PAD_SD1_DATA0__USDHC1_DATA0                              0x01c4 0x0450 0x0000 0 0
-#define MX6UL_PAD_SD1_DATA0__GPT2_COMPARE3                             0x01c4 0x0450 0x0000 1 0
-#define MX6UL_PAD_SD1_DATA0__SAI2_TX_SYNC                              0x01c4 0x0450 0x05fc 2 1
-#define MX6UL_PAD_SD1_DATA0__FLEXCAN1_TX                               0x01c4 0x0450 0x0000 3 0
-#define MX6UL_PAD_SD1_DATA0__EIM_ADDR21                                0x01c4 0x0450 0x0000 4 0
-#define MX6UL_PAD_SD1_DATA0__GPIO2_IO18                                0x01c4 0x0450 0x0000 5 0
-#define MX6UL_PAD_SD1_DATA0__ANATOP_OTG1_ID                            0x01c4 0x0450 0x0000 8 0
-#define MX6UL_PAD_SD1_DATA1__USDHC1_DATA1                              0x01c8 0x0454 0x0000 0 0
-#define MX6UL_PAD_SD1_DATA1__GPT2_CLK                                  0x01c8 0x0454 0x05a0 1 1
-#define MX6UL_PAD_SD1_DATA1__SAI2_TX_BCLK                              0x01c8 0x0454 0x05f8 2 1
-#define MX6UL_PAD_SD1_DATA1__FLEXCAN1_RX                               0x01c8 0x0454 0x0584 3 3
-#define MX6UL_PAD_SD1_DATA1__EIM_ADDR22                                0x01c8 0x0454 0x0000 4 0
-#define MX6UL_PAD_SD1_DATA1__GPIO2_IO19                                0x01c8 0x0454 0x0000 5 0
-#define MX6UL_PAD_SD1_DATA1__USB_OTG2_PWR                              0x01c8 0x0454 0x0000 8 0
-#define MX6UL_PAD_SD1_DATA2__USDHC1_DATA2                              0x01cc 0x0458 0x0000 0 0
-#define MX6UL_PAD_SD1_DATA2__GPT2_CAPTURE1                             0x01cc 0x0458 0x0598 1 1
-#define MX6UL_PAD_SD1_DATA2__SAI2_RX_DATA                              0x01cc 0x0458 0x05f4 2 1
-#define MX6UL_PAD_SD1_DATA2__FLEXCAN2_TX                               0x01cc 0x0458 0x0000 3 0
-#define MX6UL_PAD_SD1_DATA2__EIM_ADDR23                                0x01cc 0x0458 0x0000 4 0
-#define MX6UL_PAD_SD1_DATA2__GPIO2_IO20                                0x01cc 0x0458 0x0000 5 0
-#define MX6UL_PAD_SD1_DATA2__CCM_CLKO1                                 0x01cc 0x0458 0x0000 6 0
-#define MX6UL_PAD_SD1_DATA2__USB_OTG2_OC                               0x01cc 0x0458 0x0000 8 0
-#define MX6UL_PAD_SD1_DATA3__USDHC1_DATA3                              0x01d0 0x045c 0x0000 0 0
-#define MX6UL_PAD_SD1_DATA3__GPT2_CAPTURE2                             0x01d0 0x045c 0x059c 1 1
-#define MX6UL_PAD_SD1_DATA3__SAI2_TX_DATA                              0x01d0 0x045c 0x0000 2 0
-#define MX6UL_PAD_SD1_DATA3__FLEXCAN2_RX                               0x01d0 0x045c 0x0588 3 3
-#define MX6UL_PAD_SD1_DATA3__EIM_ADDR24                                0x01d0 0x045c 0x0000 4 0
-#define MX6UL_PAD_SD1_DATA3__GPIO2_IO21                                0x01d0 0x045c 0x0000 5 0
-#define MX6UL_PAD_SD1_DATA3__CCM_CLKO2                                 0x01d0 0x045c 0x0000 6 0
-#define MX6UL_PAD_SD1_DATA3__ANATOP_OTG2_ID                            0x01d0 0x045c 0x0000 8 0
-#define MX6UL_PAD_CSI_MCLK__CSI_MCLK                                   0x01d4 0x0460 0x0000 0 0
-#define MX6UL_PAD_CSI_MCLK__USDHC2_CD_B                                0x01d4 0x0460 0x0674 1 0
-#define MX6UL_PAD_CSI_MCLK__RAWNAND_CE2_B                              0x01d4 0x0460 0x0000 2 0
-#define MX6UL_PAD_CSI_MCLK__I2C1_SDA                                   0x01d4 0x0460 0x05a8 3 0
-#define MX6UL_PAD_CSI_MCLK__EIM_CS0_B                                  0x01d4 0x0460 0x0000 4 0
-#define MX6UL_PAD_CSI_MCLK__GPIO4_IO17                                 0x01d4 0x0460 0x0000 5 0
-#define MX6UL_PAD_CSI_MCLK__SNVS_HP_VIO_5_CTL                          0x01d4 0x0460 0x0000 6 0
-#define MX6UL_PAD_CSI_MCLK__UART6_DCE_TX                               0x01d4 0x0460 0x0000 8 0
-#define MX6UL_PAD_CSI_MCLK__UART6_DTE_RX                               0x01d4 0x0460 0x064c 8 0
-#define MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK                               0x01d8 0x0464 0x0528 0 1
-#define MX6UL_PAD_CSI_PIXCLK__USDHC2_WP                                0x01d8 0x0464 0x069c 1 2
-#define MX6UL_PAD_CSI_PIXCLK__RAWNAND_CE3_B                            0x01d8 0x0464 0x0000 2 0
-#define MX6UL_PAD_CSI_PIXCLK__I2C1_SCL                                 0x01d8 0x0464 0x05a4 3 2
-#define MX6UL_PAD_CSI_PIXCLK__EIM_OE                                   0x01d8 0x0464 0x0000 4 0
-#define MX6UL_PAD_CSI_PIXCLK__GPIO4_IO18                               0x01d8 0x0464 0x0000 5 0
-#define MX6UL_PAD_CSI_PIXCLK__SNVS_HP_VIO_5                            0x01d8 0x0464 0x0000 6 0
-#define MX6UL_PAD_CSI_PIXCLK__UART6_DCE_RX                             0x01d8 0x0464 0x064c 8 3
-#define MX6UL_PAD_CSI_PIXCLK__UART6_DTE_TX                             0x01d8 0x0464 0x0000 8 0
-#define MX6UL_PAD_CSI_VSYNC__CSI_VSYNC                                 0x01dc 0x0468 0x052c 0 0
-#define MX6UL_PAD_CSI_VSYNC__USDHC2_CLK                                0x01dc 0x0468 0x0670 1 0
-#define MX6UL_PAD_CSI_VSYNC__SIM1_PORT1_CLK                            0x01dc 0x0468 0x0000 2 0
-#define MX6UL_PAD_CSI_VSYNC__I2C2_SDA                                  0x01dc 0x0468 0x05b0 3 0
-#define MX6UL_PAD_CSI_VSYNC__EIM_RW                                    0x01dc 0x0468 0x0000 4 0
-#define MX6UL_PAD_CSI_VSYNC__GPIO4_IO19                                0x01dc 0x0468 0x0000 5 0
-#define MX6UL_PAD_CSI_VSYNC__PWM7_OUT                                  0x01dc 0x0468 0x0000 6 0
-#define MX6UL_PAD_CSI_VSYNC__UART6_DCE_RTS                             0x01dc 0x0468 0x0648 8 0
-#define MX6UL_PAD_CSI_VSYNC__UART6_DTE_CTS                             0x01dc 0x0468 0x0000 8 0
-#define MX6UL_PAD_CSI_HSYNC__CSI_HSYNC                                 0x01e0 0x046c 0x0524 0 0
-#define MX6UL_PAD_CSI_HSYNC__USDHC2_CMD                                0x01e0 0x046c 0x0678 1 0
-#define MX6UL_PAD_CSI_HSYNC__SIM1_PORT1_PD                             0x01e0 0x046c 0x0000 2 0
-#define MX6UL_PAD_CSI_HSYNC__I2C2_SCL                                  0x01e0 0x046c 0x05ac 3 0
-#define MX6UL_PAD_CSI_HSYNC__EIM_LBA_B                                 0x01e0 0x046c 0x0000 4 0
-#define MX6UL_PAD_CSI_HSYNC__GPIO4_IO20                                0x01e0 0x046c 0x0000 5 0
-#define MX6UL_PAD_CSI_HSYNC__PWM8_OUT                                  0x01e0 0x046c 0x0000 6 0
-#define MX6UL_PAD_CSI_HSYNC__UART6_DCE_CTS                             0x01e0 0x046c 0x0000 8 0
-#define MX6UL_PAD_CSI_HSYNC__UART6_DTE_RTS                             0x01e0 0x046c 0x0648 8 1
-#define MX6UL_PAD_CSI_DATA00__CSI_DATA02                               0x01e4 0x0470 0x04c4 0 0
-#define MX6UL_PAD_CSI_DATA00__USDHC2_DATA0                             0x01e4 0x0470 0x067c 1 0
-#define MX6UL_PAD_CSI_DATA00__SIM1_PORT1_RST_B                         0x01e4 0x0470 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA00__ECSPI2_SCLK                              0x01e4 0x0470 0x0544 3 0
-#define MX6UL_PAD_CSI_DATA00__EIM_AD00                                 0x01e4 0x0470 0x0000 4 0
-#define MX6UL_PAD_CSI_DATA00__GPIO4_IO21                               0x01e4 0x0470 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA00__SRC_INT_BOOT                             0x01e4 0x0470 0x0000 6 0
-#define MX6UL_PAD_CSI_DATA00__UART5_DCE_TX                             0x01e4 0x0470 0x0000 8 0
-#define MX6UL_PAD_CSI_DATA00__UART5_DTE_RX                             0x01e4 0x0470 0x0644 8 0
-#define MX6UL_PAD_CSI_DATA01__CSI_DATA03                               0x01e8 0x0474 0x04c8 0 0
-#define MX6UL_PAD_CSI_DATA01__USDHC2_DATA1                             0x01e8 0x0474 0x0680 1 0
-#define MX6UL_PAD_CSI_DATA01__SIM1_PORT1_SVEN                          0x01e8 0x0474 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA01__ECSPI2_SS0                               0x01e8 0x0474 0x0000 3 0
-#define MX6UL_PAD_CSI_DATA01__EIM_AD01                                 0x01e8 0x0474 0x0000 4 0
-#define MX6UL_PAD_CSI_DATA01__GPIO4_IO22                               0x01e8 0x0474 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA01__SAI1_MCLK                                0x01e8 0x0474 0x0000 6 0
-#define MX6UL_PAD_CSI_DATA01__UART5_DCE_RX                             0x01e8 0x0474 0x0644 8 1
-#define MX6UL_PAD_CSI_DATA01__UART5_DTE_TX                             0x01e8 0x0474 0x0000 8 0
-#define MX6UL_PAD_CSI_DATA02__CSI_DATA04                               0x01ec 0x0478 0x04d8 0 1
-#define MX6UL_PAD_CSI_DATA02__USDHC2_DATA2                             0x01ec 0x0478 0x0684 1 2
-#define MX6UL_PAD_CSI_DATA02__SIM1_PORT1_TRXD                          0x01ec 0x0478 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA02__ECSPI2_MOSI                              0x01ec 0x0478 0x054c 3 1
-#define MX6UL_PAD_CSI_DATA02__EIM_AD02                                 0x01ec 0x0478 0x0000 4 0
-#define MX6UL_PAD_CSI_DATA02__GPIO4_IO23                               0x01ec 0x0478 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA02__SAI1_RX_SYNC                             0x01ec 0x0478 0x0000 6 0
-#define MX6UL_PAD_CSI_DATA02__UART5_DCE_RTS                            0x01ec 0x0478 0x0640 8 5
-#define MX6UL_PAD_CSI_DATA02__UART5_DTE_CTS                            0x01ec 0x0478 0x0000 8 0
-#define MX6UL_PAD_CSI_DATA03__CSI_DATA05                               0x01f0 0x047c 0x04cc 0 0
-#define MX6UL_PAD_CSI_DATA03__USDHC2_DATA3                             0x01f0 0x047c 0x0688 1 0
-#define MX6UL_PAD_CSI_DATA03__SIM2_PORT1_PD                            0x01f0 0x047c 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA03__ECSPI2_MISO                              0x01f0 0x047c 0x0548 3 0
-#define MX6UL_PAD_CSI_DATA03__EIM_AD03                                 0x01f0 0x047c 0x0000 4 0
-#define MX6UL_PAD_CSI_DATA03__GPIO4_IO24                               0x01f0 0x047c 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA03__SAI1_RX_BCLK                             0x01f0 0x047c 0x0000 6 0
-#define MX6UL_PAD_CSI_DATA03__UART5_DCE_CTS                            0x01f0 0x047c 0x0000 8 0
-#define MX6UL_PAD_CSI_DATA03__UART5_DTE_RTS                            0x01f0 0x047c 0x0640 8 0
-#define MX6UL_PAD_CSI_DATA04__CSI_DATA06                               0x01f4 0x0480 0x04dc 0 1
-#define MX6UL_PAD_CSI_DATA04__USDHC2_DATA4                             0x01f4 0x0480 0x068c 1 2
-#define MX6UL_PAD_CSI_DATA04__SIM2_PORT1_CLK                           0x01f4 0x0480 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK                              0x01f4 0x0480 0x0534 3 1
-#define MX6UL_PAD_CSI_DATA04__EIM_AD04                                 0x01f4 0x0480 0x0000 4 0
-#define MX6UL_PAD_CSI_DATA04__GPIO4_IO25                               0x01f4 0x0480 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA04__SAI1_TX_SYNC                             0x01f4 0x0480 0x05ec 6 1
-#define MX6UL_PAD_CSI_DATA04__USDHC1_WP                                0x01f4 0x0480 0x0000 8 0
-#define MX6UL_PAD_CSI_DATA05__CSI_DATA07                               0x01f8 0x0484 0x04e0 0 1
-#define MX6UL_PAD_CSI_DATA05__USDHC2_DATA5                             0x01f8 0x0484 0x0690 1 2
-#define MX6UL_PAD_CSI_DATA05__SIM2_PORT1_RST_B                         0x01f8 0x0484 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA05__ECSPI1_SS0                               0x01f8 0x0484 0x0000 3 0
-#define MX6UL_PAD_CSI_DATA05__EIM_AD05                                 0x01f8 0x0484 0x0000 4 0
-#define MX6UL_PAD_CSI_DATA05__GPIO4_IO26                               0x01f8 0x0484 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA05__SAI1_TX_BCLK                             0x01f8 0x0484 0x05e8 6 1
-#define MX6UL_PAD_CSI_DATA05__USDHC1_CD_B                              0x01f8 0x0484 0x0000 8 0
-#define MX6UL_PAD_CSI_DATA06__CSI_DATA08                               0x01fc 0x0488 0x04e4 0 1
-#define MX6UL_PAD_CSI_DATA06__USDHC2_DATA6                             0x01fc 0x0488 0x0694 1 2
-#define MX6UL_PAD_CSI_DATA06__SIM2_PORT1_SVEN                          0x01fc 0x0488 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI                              0x01fc 0x0488 0x053c 3 1
-#define MX6UL_PAD_CSI_DATA06__EIM_AD06                                 0x01fc 0x0488 0x0000 4 0
-#define MX6UL_PAD_CSI_DATA06__GPIO4_IO27                               0x01fc 0x0488 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA06__SAI1_RX_DATA                             0x01fc 0x0488 0x0000 6 0
-#define MX6UL_PAD_CSI_DATA06__USDHC1_RESET_B                           0x01fc 0x0488 0x0000 8 0
-#define MX6UL_PAD_CSI_DATA07__CSI_DATA09                               0x0200 0x048c 0x04e8 0 1
-#define MX6UL_PAD_CSI_DATA07__USDHC2_DATA7                             0x0200 0x048c 0x0698 1 2
-#define MX6UL_PAD_CSI_DATA07__SIM2_PORT1_TRXD                          0x0200 0x048c 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA07__ECSPI1_MISO                              0x0200 0x048c 0x0538 3 1
-#define MX6UL_PAD_CSI_DATA07__EIM_AD07                                 0x0200 0x048c 0x0000 4 0
-#define MX6UL_PAD_CSI_DATA07__GPIO4_IO28                               0x0200 0x048c 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA07__SAI1_TX_DATA                             0x0200 0x048c 0x0000 6 0
-#define MX6UL_PAD_CSI_DATA07__USDHC1_VSELECT                           0x0200 0x048c 0x0000 8 0
+#define MX6UL_PAD_JTAG_MOD__SJC_MOD                    0x0044 0x02d0 0x0000 0 0
+#define MX6UL_PAD_JTAG_MOD__GPT2_CLK                   0x0044 0x02d0 0x05a0 1 0
+#define MX6UL_PAD_JTAG_MOD__SPDIF_OUT                  0x0044 0x02d0 0x0000 2 0
+#define MX6UL_PAD_JTAG_MOD__ENET1_REF_CLK_25M          0x0044 0x02d0 0x0000 3 0
+#define MX6UL_PAD_JTAG_MOD__CCM_PMIC_RDY               0x0044 0x02d0 0x04c0 4 0
+#define MX6UL_PAD_JTAG_MOD__GPIO1_IO10                 0x0044 0x02d0 0x0000 5 0
+#define MX6UL_PAD_JTAG_MOD__SDMA_EXT_EVENT00           0x0044 0x02d0 0x0000 6 0
+#define MX6UL_PAD_JTAG_TMS__SJC_TMS                    0x0048 0x02d4 0x0000 0 0
+#define MX6UL_PAD_JTAG_TMS__GPT2_CAPTURE1              0x0048 0x02d4 0x0598 1 0
+#define MX6UL_PAD_JTAG_TMS__SAI2_MCLK                  0x0048 0x02d4 0x0000 2 0
+#define MX6UL_PAD_JTAG_TMS__CCM_CLKO1                  0x0048 0x02d4 0x0000 3 0
+#define MX6UL_PAD_JTAG_TMS__CCM_WAIT                   0x0048 0x02d4 0x0000 4 0
+#define MX6UL_PAD_JTAG_TMS__GPIO1_IO11                 0x0048 0x02d4 0x0000 5 0
+#define MX6UL_PAD_JTAG_TMS__SDMA_EXT_EVENT01           0x0048 0x02d4 0x0000 6 0
+#define MX6UL_PAD_JTAG_TMS__EPIT1_OUT                  0x0048 0x02d4 0x0000 8 0
+#define MX6UL_PAD_JTAG_TDO__SJC_TDO                    0x004c 0x02d8 0x0000 0 0
+#define MX6UL_PAD_JTAG_TDO__GPT2_CAPTURE2              0x004c 0x02d8 0x059c 1 0
+#define MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC               0x004c 0x02d8 0x05fc 2 0
+#define MX6UL_PAD_JTAG_TDO__CCM_CLKO2                  0x004c 0x02d8 0x0000 3 0
+#define MX6UL_PAD_JTAG_TDO__CCM_STOP                   0x004c 0x02d8 0x0000 4 0
+#define MX6UL_PAD_JTAG_TDO__GPIO1_IO12                 0x004c 0x02d8 0x0000 5 0
+#define MX6UL_PAD_JTAG_TDO__MQS_RIGHT                  0x004c 0x02d8 0x0000 6 0
+#define MX6UL_PAD_JTAG_TDO__EPIT2_OUT                  0x004c 0x02d8 0x0000 8 0
+#define MX6UL_PAD_JTAG_TDI__SJC_TDI                    0x0050 0x02dc 0x0000 0 0
+#define MX6UL_PAD_JTAG_TDI__GPT2_COMPARE1              0x0050 0x02dc 0x0000 1 0
+#define MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK               0x0050 0x02dc 0x05f8 2 0
+#define MX6UL_PAD_JTAG_TDI__PWM6_OUT                   0x0050 0x02dc 0x0000 4 0
+#define MX6UL_PAD_JTAG_TDI__GPIO1_IO13                 0x0050 0x02dc 0x0000 5 0
+#define MX6UL_PAD_JTAG_TDI__MQS_LEFT                   0x0050 0x02dc 0x0000 6 0
+#define MX6UL_PAD_JTAG_TDI__SIM1_POWER_FAIL            0x0050 0x02dc 0x0000 8 0
+#define MX6UL_PAD_JTAG_TCK__SJC_TCK                    0x0054 0x02e0 0x0000 0 0
+#define MX6UL_PAD_JTAG_TCK__GPT2_COMPARE2              0x0054 0x02e0 0x0000 1 0
+#define MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA               0x0054 0x02e0 0x05f4 2 0
+#define MX6UL_PAD_JTAG_TCK__PWM7_OUT                   0x0054 0x02e0 0x0000 4 0
+#define MX6UL_PAD_JTAG_TCK__GPIO1_IO14                 0x0054 0x02e0 0x0000 5 0
+#define MX6UL_PAD_JTAG_TCK__SIM2_POWER_FAIL            0x0054 0x02e0 0x0000 8 0
+#define MX6UL_PAD_JTAG_TRST_B__SJC_TRSTB               0x0058 0x02e4 0x0000 0 0
+#define MX6UL_PAD_JTAG_TRST_B__GPT2_COMPARE3           0x0058 0x02e4 0x0000 1 0
+#define MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA            0x0058 0x02e4 0x0000 2 0
+#define MX6UL_PAD_JTAG_TRST_B__PWM8_OUT                        0x0058 0x02e4 0x0000 4 0
+#define MX6UL_PAD_JTAG_TRST_B__GPIO1_IO15              0x0058 0x02e4 0x0000 5 0
+#define MX6UL_PAD_JTAG_TRST_B__CAAM_RNG_OSC_OBS                0x0058 0x02e4 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO00__I2C2_SCL                 0x005c 0x02e8 0x05ac 0 1
+#define MX6UL_PAD_GPIO1_IO00__GPT1_CAPTURE1            0x005c 0x02e8 0x058c 1 0
+#define MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID           0x005c 0x02e8 0x04b8 2 0
+#define MX6UL_PAD_GPIO1_IO00__ENET1_REF_CLK1           0x005c 0x02e8 0x0574 3 0
+#define MX6UL_PAD_GPIO1_IO00__MQS_RIGHT                        0x005c 0x02e8 0x0000 4 0
+#define MX6UL_PAD_GPIO1_IO00__GPIO1_IO00               0x005c 0x02e8 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO00__ENET1_1588_EVENT0_IN     0x005c 0x02e8 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO00__SRC_SYSTEM_RESET         0x005c 0x02e8 0x0000 7 0
+#define MX6UL_PAD_GPIO1_IO00__WDOG3_WDOG_B             0x005c 0x02e8 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO01__I2C2_SDA                 0x0060 0x02ec 0x05b0 0 1
+#define MX6UL_PAD_GPIO1_IO01__GPT1_COMPARE1            0x0060 0x02ec 0x0000 1 0
+#define MX6UL_PAD_GPIO1_IO01__USB_OTG1_OC              0x0060 0x02ec 0x0664 2 0
+#define MX6UL_PAD_GPIO1_IO01__ENET2_REF_CLK2           0x0060 0x02ec 0x057c 3 0
+#define MX6UL_PAD_GPIO1_IO01__MQS_LEFT                 0x0060 0x02ec 0x0000 4 0
+#define MX6UL_PAD_GPIO1_IO01__GPIO1_IO01               0x0060 0x02ec 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO01__ENET1_1588_EVENT0_OUT    0x0060 0x02ec 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO01__SRC_EARLY_RESET          0x0060 0x02ec 0x0000 7 0
+#define MX6UL_PAD_GPIO1_IO01__WDOG1_WDOG_B             0x0060 0x02ec 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO02__I2C1_SCL                 0x0064 0x02f0 0x05a4 0 0
+#define MX6UL_PAD_GPIO1_IO02__GPT1_COMPARE2            0x0064 0x02f0 0x0000 1 0
+#define MX6UL_PAD_GPIO1_IO02__USB_OTG2_PWR             0x0064 0x02f0 0x0000 2 0
+#define MX6UL_PAD_GPIO1_IO02__ENET1_REF_CLK_25M                0x0064 0x02f0 0x0000 3 0
+#define MX6UL_PAD_GPIO1_IO02__USDHC1_WP                        0x0064 0x02f0 0x066c 4 0
+#define MX6UL_PAD_GPIO1_IO02__GPIO1_IO02               0x0064 0x02f0 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO02__SDMA_EXT_EVENT00         0x0064 0x02f0 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO02__SRC_ANY_PU_RESET         0x0064 0x02f0 0x0000 7 0
+#define MX6UL_PAD_GPIO1_IO02__UART1_DCE_TX             0x0064 0x02f0 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO02__UART1_DTE_RX             0x0064 0x02f0 0x0624 8 0
+#define MX6UL_PAD_GPIO1_IO03__I2C1_SDA                 0x0068 0x02f4 0x05a8 0 1
+#define MX6UL_PAD_GPIO1_IO03__GPT1_COMPARE3            0x0068 0x02f4 0x0000 1 0
+#define MX6UL_PAD_GPIO1_IO03__USB_OTG2_OC              0x0068 0x02f4 0x0660 2 0
+#define MX6UL_PAD_GPIO1_IO03__USDHC1_CD_B              0x0068 0x02f4 0x0668 4 0
+#define MX6UL_PAD_GPIO1_IO03__GPIO1_IO03               0x0068 0x02f4 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO03__CCM_DI0_eXT_CLK          0x0068 0x02f4 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO03__SRC_TESTER_ACK           0x0068 0x02f4 0x0000 7 0
+#define MX6UL_PAD_GPIO1_IO03__UART1_DTE_TX             0x0068 0x02f4 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO03__UART1_DCE_RX             0x0068 0x02f4 0x0624 8 1
+#define MX6UL_PAD_GPIO1_IO04__ENET1_REF_CLK1           0x006c 0x02f8 0x0574 0 1
+#define MX6UL_PAD_GPIO1_IO04__PWM3_OUT                 0x006c 0x02f8 0x0000 1 0
+#define MX6UL_PAD_GPIO1_IO04__USB_OTG1_PWR             0x006c 0x02f8 0x0000 2 0
+#define MX6UL_PAD_GPIO1_IO04__USDHC1_RESET_B           0x006c 0x02f8 0x0000 4 0
+#define MX6UL_PAD_GPIO1_IO04__GPIO1_IO04               0x006c 0x02f8 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO04__ENET2_1588_EVENT0_IN     0x006c 0x02f8 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO04__UART5_DCE_TX             0x006c 0x02f8 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO04__UART5_DTE_RX             0x006c 0x02f8 0x0644 8 2
+#define MX6UL_PAD_GPIO1_IO05__ENET2_REF_CLK2           0x0070 0x02fc 0x057c 0 1
+#define MX6UL_PAD_GPIO1_IO05__PWM4_OUT                 0x0070 0x02fc 0x0000 1 0
+#define MX6UL_PAD_GPIO1_IO05__ANATOP_OTG2_ID           0x0070 0x02fc 0x04bc 2 0
+#define MX6UL_PAD_GPIO1_IO05__CSI_FIELD                        0x0070 0x02fc 0x0530 3 0
+#define MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT           0x0070 0x02fc 0x0000 4 0
+#define MX6UL_PAD_GPIO1_IO05__GPIO1_IO05               0x0070 0x02fc 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO05__ENET2_1588_EVENT0_OUT    0x0070 0x02fc 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO05__UART5_DCE_RX             0x0070 0x02fc 0x0644 8 3
+#define MX6UL_PAD_GPIO1_IO05__UART5_DTE_TX             0x0070 0x02fc 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO06__ENET1_MDIO               0x0074 0x0300 0x0578 0 0
+#define MX6UL_PAD_GPIO1_IO06__ENET2_MDIO               0x0074 0x0300 0x0580 1 0
+#define MX6UL_PAD_GPIO1_IO06__USB_OTG_PWR_WAKE         0x0074 0x0300 0x0000 2 0
+#define MX6UL_PAD_GPIO1_IO06__CSI_MCLK                 0x0074 0x0300 0x0000 3 0
+#define MX6UL_PAD_GPIO1_IO06__USDHC2_WP                        0x0074 0x0300 0x069c 4 0
+#define MX6UL_PAD_GPIO1_IO06__GPIO1_IO06               0x0074 0x0300 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO06__CCM_WAIT                 0x0074 0x0300 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO06__CCM_REF_EN_B             0x0074 0x0300 0x0000 7 0
+#define MX6UL_PAD_GPIO1_IO06__UART1_DCE_CTS            0x0074 0x0300 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO06__UART1_DTE_RTS            0x0074 0x0300 0x0620 8 0
+#define MX6UL_PAD_GPIO1_IO07__ENET1_MDC                        0x0078 0x0304 0x0000 0 0
+#define MX6UL_PAD_GPIO1_IO07__ENET2_MDC                        0x0078 0x0304 0x0000 1 0
+#define MX6UL_PAD_GPIO1_IO07__USB_OTG_HOST_MODE                0x0078 0x0304 0x0000 2 0
+#define MX6UL_PAD_GPIO1_IO07__CSI_PIXCLK               0x0078 0x0304 0x0528 3 0
+#define MX6UL_PAD_GPIO1_IO07__USDHC2_CD_B              0x0078 0x0304 0x0674 4 1
+#define MX6UL_PAD_GPIO1_IO07__GPIO1_IO07               0x0078 0x0304 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO07__CCM_STOP                 0x0078 0x0304 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO07__UART1_DCE_RTS            0x0078 0x0304 0x0620 8 1
+#define MX6UL_PAD_GPIO1_IO07__UART1_DTE_CTS            0x0078 0x0304 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO08__PWM1_OUT                 0x007c 0x0308 0x0000 0 0
+#define MX6UL_PAD_GPIO1_IO08__WDOG1_WDOG_B             0x007c 0x0308 0x0000 1 0
+#define MX6UL_PAD_GPIO1_IO08__SPDIF_OUT                        0x007c 0x0308 0x0000 2 0
+#define MX6UL_PAD_GPIO1_IO08__CSI_VSYNC                        0x007c 0x0308 0x052c 3 1
+#define MX6UL_PAD_GPIO1_IO08__USDHC2_VSELECT           0x007c 0x0308 0x0000 4 0
+#define MX6UL_PAD_GPIO1_IO08__GPIO1_IO08               0x007c 0x0308 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO08__CCM_PMIC_RDY             0x007c 0x0308 0x04c0 6 1
+#define MX6UL_PAD_GPIO1_IO08__UART5_DCE_RTS            0x007c 0x0308 0x0640 8 1
+#define MX6UL_PAD_GPIO1_IO08__UART5_DTE_CTS            0x007c 0x0308 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO09__PWM2_OUT                 0x0080 0x030c 0x0000 0 0
+#define MX6UL_PAD_GPIO1_IO09__WDOG1_WDOG_ANY           0x0080 0x030c 0x0000 1 0
+#define MX6UL_PAD_GPIO1_IO09__SPDIF_IN                 0x0080 0x030c 0x0618 2 0
+#define MX6UL_PAD_GPIO1_IO09__CSI_HSYNC                        0x0080 0x030c 0x0524 3 1
+#define MX6UL_PAD_GPIO1_IO09__USDHC2_RESET_B           0x0080 0x030c 0x0000 4 0
+#define MX6UL_PAD_GPIO1_IO09__GPIO1_IO09               0x0080 0x030c 0x0000 5 0
+#define MX6UL_PAD_GPIO1_IO09__USDHC1_RESET_B           0x0080 0x030c 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO09__UART5_DCE_CTS            0x0080 0x030c 0x0000 8 0
+#define MX6UL_PAD_GPIO1_IO09__UART5_DTE_RTS            0x0080 0x030c 0x0640 8 2
+#define MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX          0x0084 0x0310 0x0000 0 0
+#define MX6UL_PAD_UART1_TX_DATA__UART1_DTE_RX          0x0084 0x0310 0x0624 0 2
+#define MX6UL_PAD_UART1_TX_DATA__ENET1_RDATA02         0x0084 0x0310 0x0000 1 0
+#define MX6UL_PAD_UART1_TX_DATA__I2C3_SCL              0x0084 0x0310 0x05b4 2 0
+#define MX6UL_PAD_UART1_TX_DATA__CSI_DATA02            0x0084 0x0310 0x04c4 3 1
+#define MX6UL_PAD_UART1_TX_DATA__GPT1_COMPARE1         0x0084 0x0310 0x0000 4 0
+#define MX6UL_PAD_UART1_TX_DATA__GPIO1_IO16            0x0084 0x0310 0x0000 5 0
+#define MX6UL_PAD_UART1_TX_DATA__SPDIF_OUT             0x0084 0x0310 0x0000 8 0
+#define MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX          0x0088 0x0314 0x0624 0 3
+#define MX6UL_PAD_UART1_RX_DATA__UART1_DTE_TX          0x0088 0x0314 0x0000 0 0
+#define MX6UL_PAD_UART1_RX_DATA__ENET1_RDATA03         0x0088 0x0314 0x0000 1 0
+#define MX6UL_PAD_UART1_RX_DATA__I2C3_SDA              0x0088 0x0314 0x05b8 2 0
+#define MX6UL_PAD_UART1_RX_DATA__CSI_DATA03            0x0088 0x0314 0x04c8 3 1
+#define MX6UL_PAD_UART1_RX_DATA__GPT1_CLK              0x0088 0x0314 0x0594 4 0
+#define MX6UL_PAD_UART1_RX_DATA__GPIO1_IO17            0x0088 0x0314 0x0000 5 0
+#define MX6UL_PAD_UART1_RX_DATA__SPDIF_IN              0x0088 0x0314 0x0618 8 1
+#define MX6UL_PAD_UART1_CTS_B__UART1_DCE_CTS           0x008c 0x0318 0x0000 0 0
+#define MX6UL_PAD_UART1_CTS_B__UART1_DTE_RTS           0x008c 0x0318 0x0620 0 2
+#define MX6UL_PAD_UART1_CTS_B__ENET1_RX_CLK            0x008c 0x0318 0x0000 1 0
+#define MX6UL_PAD_UART1_CTS_B__USDHC1_WP               0x008c 0x0318 0x066c 2 1
+#define MX6UL_PAD_UART1_CTS_B__CSI_DATA04              0x008c 0x0318 0x04d8 3 0
+#define MX6UL_PAD_UART1_CTS_B__ENET2_1588_EVENT1_IN    0x008c 0x0318 0x0000 4 0
+#define MX6UL_PAD_UART1_CTS_B__GPIO1_IO18              0x008c 0x0318 0x0000 5 0
+#define MX6UL_PAD_UART1_CTS_B__USDHC2_WP               0x008c 0x0318 0x069c 8 1
+#define MX6UL_PAD_UART1_RTS_B__UART1_DCE_RTS           0x0090 0x031c 0x0620 0 3
+#define MX6UL_PAD_UART1_RTS_B__UART1_DTE_CTS           0x0090 0x031c 0x0000 0 0
+#define MX6UL_PAD_UART1_RTS_B__ENET1_TX_ER             0x0090 0x031c 0x0000 1 0
+#define MX6UL_PAD_UART1_RTS_B__USDHC1_CD_B             0x0090 0x031c 0x0668 2 1
+#define MX6UL_PAD_UART1_RTS_B__CSI_DATA05              0x0090 0x031c 0x04cc 3 1
+#define MX6UL_PAD_UART1_RTS_B__ENET2_1588_EVENT1_OUT   0x0090 0x031c 0x0000 4 0
+#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19              0x0090 0x031c 0x0000 5 0
+#define MX6UL_PAD_UART1_RTS_B__USDHC2_CD_B             0x0090 0x031c 0x0674 8 2
+#define MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX          0x0094 0x0320 0x0000 0 0
+#define MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX          0x0094 0x0320 0x062c 0 0
+#define MX6UL_PAD_UART2_TX_DATA__ENET1_TDATA02         0x0094 0x0320 0x0000 1 0
+#define MX6UL_PAD_UART2_TX_DATA__I2C4_SCL              0x0094 0x0320 0x05bc 2 0
+#define MX6UL_PAD_UART2_TX_DATA__CSI_DATA06            0x0094 0x0320 0x04dc 3 0
+#define MX6UL_PAD_UART2_TX_DATA__GPT1_CAPTURE1         0x0094 0x0320 0x058c 4 1
+#define MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20            0x0094 0x0320 0x0000 5 0
+#define MX6UL_PAD_UART2_TX_DATA__ECSPI3_SS0            0x0094 0x0320 0x0000 8 0
+#define MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX          0x0098 0x0324 0x062c 0 1
+#define MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX          0x0098 0x0324 0x0000 0 0
+#define MX6UL_PAD_UART2_RX_DATA__ENET1_TDATA03         0x0098 0x0324 0x0000 1 0
+#define MX6UL_PAD_UART2_RX_DATA__I2C4_SDA              0x0098 0x0324 0x05c0 2 0
+#define MX6UL_PAD_UART2_RX_DATA__CSI_DATA07            0x0098 0x0324 0x04e0 3 0
+#define MX6UL_PAD_UART2_RX_DATA__GPT1_CAPTURE2         0x0098 0x0324 0x0590 4 0
+#define MX6UL_PAD_UART2_RX_DATA__GPIO1_IO21            0x0098 0x0324 0x0000 5 0
+#define MX6UL_PAD_UART2_RX_DATA__SJC_DONE              0x0098 0x0324 0x0000 7 0
+#define MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK           0x0098 0x0324 0x0554 8 0
+#define MX6UL_PAD_UART2_CTS_B__UART2_DCE_CTS           0x009c 0x0328 0x0000 0 0
+#define MX6UL_PAD_UART2_CTS_B__UART2_DTE_RTS           0x009c 0x0328 0x0628 0 0
+#define MX6UL_PAD_UART2_CTS_B__ENET1_CRS               0x009c 0x0328 0x0000 1 0
+#define MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX             0x009c 0x0328 0x0000 2 0
+#define MX6UL_PAD_UART2_CTS_B__CSI_DATA08              0x009c 0x0328 0x04e4 3 0
+#define MX6UL_PAD_UART2_CTS_B__GPT1_COMPARE2           0x009c 0x0328 0x0000 4 0
+#define MX6UL_PAD_UART2_CTS_B__GPIO1_IO22              0x009c 0x0328 0x0000 5 0
+#define MX6UL_PAD_UART2_CTS_B__SJC_DE_B                        0x009c 0x0328 0x0000 7 0
+#define MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI             0x009c 0x0328 0x055c 8 0
+#define MX6UL_PAD_UART2_RTS_B__UART2_DCE_RTS           0x00a0 0x032c 0x0628 0 1
+#define MX6UL_PAD_UART2_RTS_B__UART2_DTE_CTS           0x00a0 0x032c 0x0000 0 0
+#define MX6UL_PAD_UART2_RTS_B__ENET1_COL               0x00a0 0x032c 0x0000 1 0
+#define MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX             0x00a0 0x032c 0x0588 2 0
+#define MX6UL_PAD_UART2_RTS_B__CSI_DATA09              0x00a0 0x032c 0x04e8 3 0
+#define MX6UL_PAD_UART2_RTS_B__GPT1_COMPARE3           0x00a0 0x032c 0x0000 4 0
+#define MX6UL_PAD_UART2_RTS_B__GPIO1_IO23              0x00a0 0x032c 0x0000 5 0
+#define MX6UL_PAD_UART2_RTS_B__SJC_FAIL                        0x00a0 0x032c 0x0000 7 0
+#define MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO             0x00a0 0x032c 0x0558 8 0
+#define MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX          0x00a4 0x0330 0x0000 0 0
+#define MX6UL_PAD_UART3_TX_DATA__UART3_DTE_RX          0x00a4 0x0330 0x0634 0 0
+#define MX6UL_PAD_UART3_TX_DATA__ENET2_RDATA02         0x00a4 0x0330 0x0000 1 0
+#define MX6UL_PAD_UART3_TX_DATA__SIM1_PORT0_PD         0x00a4 0x0330 0x0000 2 0
+#define MX6UL_PAD_UART3_TX_DATA__CSI_DATA01            0x00a4 0x0330 0x0000 3 0
+#define MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS         0x00a4 0x0330 0x0000 4 0
+#define MX6UL_PAD_UART3_TX_DATA__UART2_DTE_RTS         0x00a4 0x0330 0x0628 4 2
+#define MX6UL_PAD_UART3_TX_DATA__GPIO1_IO24            0x00a4 0x0330 0x0000 5 0
+#define MX6UL_PAD_UART3_TX_DATA__SJC_JTAG_ACT          0x00a4 0x0330 0x0000 7 0
+#define MX6UL_PAD_UART3_TX_DATA__ANATOP_OTG1_ID                0x00a4 0x0330 0x04b8 8 1
+#define MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX          0x00a8 0x0334 0x0634 0 1
+#define MX6UL_PAD_UART3_RX_DATA__UART3_DTE_TX          0x00a8 0x0334 0x0000 0 0
+#define MX6UL_PAD_UART3_RX_DATA__ENET2_RDATA03         0x00a8 0x0334 0x0000 1 0
+#define MX6UL_PAD_UART3_RX_DATA__SIM2_PORT0_PD         0x00a8 0x0334 0x0000 2 0
+#define MX6UL_PAD_UART3_RX_DATA__CSI_DATA00            0x00a8 0x0334 0x0000 3 0
+#define MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS         0x00a8 0x0334 0x0628 4 3
+#define MX6UL_PAD_UART3_RX_DATA__UART2_DTE_CTS         0x00a8 0x0334 0x0000 4 0
+#define MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25            0x00a8 0x0334 0x0000 5 0
+#define MX6UL_PAD_UART3_RX_DATA__EPIT1_OUT             0x00a8 0x0334 0x0000 8 0
+#define MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS           0x00ac 0x0338 0x0000 0 0
+#define MX6UL_PAD_UART3_CTS_B__UART3_DTE_RTS           0x00ac 0x0338 0x0630 0 0
+#define MX6UL_PAD_UART3_CTS_B__ENET2_RX_CLK            0x00ac 0x0338 0x0000 1 0
+#define MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX             0x00ac 0x0338 0x0000 2 0
+#define MX6UL_PAD_UART3_CTS_B__CSI_DATA10              0x00ac 0x0338 0x0000 3 0
+#define MX6UL_PAD_UART3_CTS_B__ENET1_1588_EVENT1_IN    0x00ac 0x0338 0x0000 4 0
+#define MX6UL_PAD_UART3_CTS_B__GPIO1_IO26              0x00ac 0x0338 0x0000 5 0
+#define MX6UL_PAD_UART3_CTS_B__EPIT2_OUT               0x00ac 0x0338 0x0000 8 0
+#define MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS           0x00b0 0x033c 0x0630 0 1
+#define MX6UL_PAD_UART3_RTS_B__UART3_DTE_CTS           0x00b0 0x033c 0x0000 0 0
+#define MX6UL_PAD_UART3_RTS_B__ENET2_TX_ER             0x00b0 0x033c 0x0000 1 0
+#define MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX             0x00b0 0x033c 0x0584 2 0
+#define MX6UL_PAD_UART3_RTS_B__CSI_DATA11              0x00b0 0x033c 0x0000 3 0
+#define MX6UL_PAD_UART3_RTS_B__ENET1_1588_EVENT1_OUT   0x00b0 0x033c 0x0000 4 0
+#define MX6UL_PAD_UART3_RTS_B__GPIO1_IO27              0x00b0 0x033c 0x0000 5 0
+#define MX6UL_PAD_UART3_RTS_B__WDOG1_WDOG_B            0x00b0 0x033c 0x0000 8 0
+#define MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX          0x00b4 0x0340 0x0000 0 0
+#define MX6UL_PAD_UART4_TX_DATA__UART4_DTE_RX          0x00b4 0x0340 0x063c 0 0
+#define MX6UL_PAD_UART4_TX_DATA__ENET2_TDATA02         0x00b4 0x0340 0x0000 1 0
+#define MX6UL_PAD_UART4_TX_DATA__I2C1_SCL              0x00b4 0x0340 0x05a4 2 1
+#define MX6UL_PAD_UART4_TX_DATA__CSI_DATA12            0x00b4 0x0340 0x0000 3 0
+#define MX6UL_PAD_UART4_TX_DATA__CSU_CSU_ALARM_AUT02   0x00b4 0x0340 0x0000 4 0
+#define MX6UL_PAD_UART4_TX_DATA__GPIO1_IO28            0x00b4 0x0340 0x0000 5 0
+#define MX6UL_PAD_UART4_TX_DATA__ECSPI2_SCLK           0x00b4 0x0340 0x0544 8 1
+#define MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX          0x00b8 0x0344 0x063c 0 1
+#define MX6UL_PAD_UART4_RX_DATA__UART4_DTE_TX          0x00b8 0x0344 0x0000 0 0
+#define MX6UL_PAD_UART4_RX_DATA__ENET2_TDATA03         0x00b8 0x0344 0x0000 1 0
+#define MX6UL_PAD_UART4_RX_DATA__I2C1_SDA              0x00b8 0x0344 0x05a8 2 2
+#define MX6UL_PAD_UART4_RX_DATA__CSI_DATA13            0x00b8 0x0344 0x0000 3 0
+#define MX6UL_PAD_UART4_RX_DATA__CSU_CSU_ALARM_AUT01   0x00b8 0x0344 0x0000 4 0
+#define MX6UL_PAD_UART4_RX_DATA__GPIO1_IO29            0x00b8 0x0344 0x0000 5 0
+#define MX6UL_PAD_UART4_RX_DATA__ECSPI2_SS0            0x00b8 0x0344 0x0000 8 0
+#define MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30            0x00bc 0x0348 0x0000 5 0
+#define MX6UL_PAD_UART5_TX_DATA__ECSPI2_MOSI           0x00bc 0x0348 0x054c 8 0
+#define MX6UL_PAD_UART5_TX_DATA__UART5_DCE_TX          0x00bc 0x0348 0x0000 0 0
+#define MX6UL_PAD_UART5_TX_DATA__UART5_DTE_RX          0x00bc 0x0348 0x0644 0 4
+#define MX6UL_PAD_UART5_TX_DATA__ENET2_CRS             0x00bc 0x0348 0x0000 1 0
+#define MX6UL_PAD_UART5_TX_DATA__I2C2_SCL              0x00bc 0x0348 0x05ac 2 2
+#define MX6UL_PAD_UART5_TX_DATA__CSI_DATA14            0x00bc 0x0348 0x0000 3 0
+#define MX6UL_PAD_UART5_TX_DATA__CSU_CSU_ALARM_AUT00   0x00bc 0x0348 0x0000 4 0
+#define MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX          0x00c0 0x034c 0x0644 0 5
+#define MX6UL_PAD_UART5_RX_DATA__UART5_DTE_TX          0x00c0 0x034c 0x0000 0 0
+#define MX6UL_PAD_UART5_RX_DATA__ENET2_COL             0x00c0 0x034c 0x0000 1 0
+#define MX6UL_PAD_UART5_RX_DATA__I2C2_SDA              0x00c0 0x034c 0x05b0 2 2
+#define MX6UL_PAD_UART5_RX_DATA__CSI_DATA15            0x00c0 0x034c 0x0000 3 0
+#define MX6UL_PAD_UART5_RX_DATA__CSU_CSU_INT_DEB       0x00c0 0x034c 0x0000 4 0
+#define MX6UL_PAD_UART5_RX_DATA__GPIO1_IO31            0x00c0 0x034c 0x0000 5 0
+#define MX6UL_PAD_UART5_RX_DATA__ECSPI2_MISO           0x00c0 0x034c 0x0548 8 1
+#define MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00                0x00c4 0x0350 0x0000 0 0
+#define MX6UL_PAD_ENET1_RX_DATA0__UART4_DCE_RTS                0x00c4 0x0350 0x0638 1 0
+#define MX6UL_PAD_ENET1_RX_DATA0__UART4_DTE_CTS                0x00c4 0x0350 0x0000 1 0
+#define MX6UL_PAD_ENET1_RX_DATA0__PWM1_OUT             0x00c4 0x0350 0x0000 2 0
+#define MX6UL_PAD_ENET1_RX_DATA0__CSI_DATA16           0x00c4 0x0350 0x0000 3 0
+#define MX6UL_PAD_ENET1_RX_DATA0__FLEXCAN1_TX          0x00c4 0x0350 0x0000 4 0
+#define MX6UL_PAD_ENET1_RX_DATA0__GPIO2_IO00           0x00c4 0x0350 0x0000 5 0
+#define MX6UL_PAD_ENET1_RX_DATA0__KPP_ROW00            0x00c4 0x0350 0x0000 6 0
+#define MX6UL_PAD_ENET1_RX_DATA0__USDHC1_LCTL          0x00c4 0x0350 0x0000 8 0
+#define MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01                0x00c8 0x0354 0x0000 0 0
+#define MX6UL_PAD_ENET1_RX_DATA1__UART4_DCE_CTS                0x00c8 0x0354 0x0000 1 0
+#define MX6UL_PAD_ENET1_RX_DATA1__UART4_DTE_RTS                0x00c8 0x0354 0x0638 1 1
+#define MX6UL_PAD_ENET1_RX_DATA1__PWM2_OUT             0x00c8 0x0354 0x0000 2 0
+#define MX6UL_PAD_ENET1_RX_DATA1__CSI_DATA17           0x00c8 0x0354 0x0000 3 0
+#define MX6UL_PAD_ENET1_RX_DATA1__FLEXCAN1_RX          0x00c8 0x0354 0x0584 4 1
+#define MX6UL_PAD_ENET1_RX_DATA1__GPIO2_IO01           0x00c8 0x0354 0x0000 5 0
+#define MX6UL_PAD_ENET1_RX_DATA1__KPP_COL00            0x00c8 0x0354 0x0000 6 0
+#define MX6UL_PAD_ENET1_RX_DATA1__USDHC2_LCTL          0x00c8 0x0354 0x0000 8 0
+#define MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN             0x00cc 0x0358 0x0000 0 0
+#define MX6UL_PAD_ENET1_RX_EN__UART5_DCE_RTS           0x00cc 0x0358 0x0640 1 3
+#define MX6UL_PAD_ENET1_RX_EN__UART5_DTE_CTS           0x00cc 0x0358 0x0000 1 0
+#define MX6UL_PAD_ENET1_RX_EN__CSI_DATA18              0x00cc 0x0358 0x0000 3 0
+#define MX6UL_PAD_ENET1_RX_EN__FLEXCAN2_TX             0x00cc 0x0358 0x0000 4 0
+#define MX6UL_PAD_ENET1_RX_EN__GPIO2_IO02              0x00cc 0x0358 0x0000 5 0
+#define MX6UL_PAD_ENET1_RX_EN__KPP_ROW01               0x00cc 0x0358 0x0000 6 0
+#define MX6UL_PAD_ENET1_RX_EN__USDHC1_VSELECT          0x00cc 0x0358 0x0000 8 0
+#define MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00                0x00d0 0x035c 0x0000 0 0
+#define MX6UL_PAD_ENET1_TX_DATA0__UART5_DCE_CTS                0x00d0 0x035c 0x0000 1 0
+#define MX6UL_PAD_ENET1_TX_DATA0__UART5_DTE_RTS                0x00d0 0x035c 0x0640 1 4
+#define MX6UL_PAD_ENET1_TX_DATA0__CSI_DATA19           0x00d0 0x035c 0x0000 3 0
+#define MX6UL_PAD_ENET1_TX_DATA0__FLEXCAN2_RX          0x00d0 0x035c 0x0588 4 1
+#define MX6UL_PAD_ENET1_TX_DATA0__GPIO2_IO03           0x00d0 0x035c 0x0000 5 0
+#define MX6UL_PAD_ENET1_TX_DATA0__KPP_COL01            0x00d0 0x035c 0x0000 6 0
+#define MX6UL_PAD_ENET1_TX_DATA0__USDHC2_VSELECT       0x00d0 0x035c 0x0000 8 0
+#define MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01                0x00d4 0x0360 0x0000 0 0
+#define MX6UL_PAD_ENET1_TX_DATA1__UART6_DCE_CTS                0x00d4 0x0360 0x0000 1 0
+#define MX6UL_PAD_ENET1_TX_DATA1__UART6_DTE_RTS                0x00d4 0x0360 0x0648 1 2
+#define MX6UL_PAD_ENET1_TX_DATA1__PWM5_OUT             0x00d4 0x0360 0x0000 2 0
+#define MX6UL_PAD_ENET1_TX_DATA1__CSI_DATA20           0x00d4 0x0360 0x0000 3 0
+#define MX6UL_PAD_ENET1_TX_DATA1__ENET2_MDIO           0x00d4 0x0360 0x0580 4 1
+#define MX6UL_PAD_ENET1_TX_DATA1__GPIO2_IO04           0x00d4 0x0360 0x0000 5 0
+#define MX6UL_PAD_ENET1_TX_DATA1__KPP_ROW02            0x00d4 0x0360 0x0000 6 0
+#define MX6UL_PAD_ENET1_TX_DATA1__WDOG1_WDOG_RST_B_DEB 0x00d4 0x0360 0x0000 8 0
+#define MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN             0x00d8 0x0364 0x0000 0 0
+#define MX6UL_PAD_ENET1_TX_EN__UART6_DCE_RTS           0x00d8 0x0364 0x0648 1 3
+#define MX6UL_PAD_ENET1_TX_EN__UART6_DTE_CTS           0x00d8 0x0364 0x0000 1 0
+#define MX6UL_PAD_ENET1_TX_EN__PWM6_OUT                        0x00d8 0x0364 0x0000 2 0
+#define MX6UL_PAD_ENET1_TX_EN__CSI_DATA21              0x00d8 0x0364 0x0000 3 0
+#define MX6UL_PAD_ENET1_TX_EN__ENET2_MDC               0x00d8 0x0364 0x0000 4 0
+#define MX6UL_PAD_ENET1_TX_EN__GPIO2_IO05              0x00d8 0x0364 0x0000 5 0
+#define MX6UL_PAD_ENET1_TX_EN__KPP_COL02               0x00d8 0x0364 0x0000 6 0
+#define MX6UL_PAD_ENET1_TX_EN__WDOG2_WDOG_RST_B_DEB    0x00d8 0x0364 0x0000 8 0
+#define MX6UL_PAD_ENET1_TX_CLK__ENET1_TX_CLK           0x00dc 0x0368 0x0000 0 0
+#define MX6UL_PAD_ENET1_TX_CLK__UART7_DCE_CTS          0x00dc 0x0368 0x0000 1 0
+#define MX6UL_PAD_ENET1_TX_CLK__UART7_DTE_RTS          0x00dc 0x0368 0x0650 1 0
+#define MX6UL_PAD_ENET1_TX_CLK__PWM7_OUT               0x00dc 0x0368 0x0000 2 0
+#define MX6UL_PAD_ENET1_TX_CLK__CSI_DATA22             0x00dc 0x0368 0x0000 3 0
+#define MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1         0x00dc 0x0368 0x0574 4 2
+#define MX6UL_PAD_ENET1_TX_CLK__GPIO2_IO06             0x00dc 0x0368 0x0000 5 0
+#define MX6UL_PAD_ENET1_TX_CLK__KPP_ROW03              0x00dc 0x0368 0x0000 6 0
+#define MX6UL_PAD_ENET1_TX_CLK__GPT1_CLK               0x00dc 0x0368 0x0594 8 1
+#define MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER             0x00e0 0x036c 0x0000 0 0
+#define MX6UL_PAD_ENET1_RX_ER__UART7_DCE_RTS           0x00e0 0x036c 0x0650 1 1
+#define MX6UL_PAD_ENET1_RX_ER__UART7_DTE_CTS           0x00e0 0x036c 0x0000 1 0
+#define MX6UL_PAD_ENET1_RX_ER__PWM8_OUT                        0x00e0 0x036c 0x0000 2 0
+#define MX6UL_PAD_ENET1_RX_ER__CSI_DATA23              0x00e0 0x036c 0x0000 3 0
+#define MX6UL_PAD_ENET1_RX_ER__EIM_CRE                 0x00e0 0x036c 0x0000 4 0
+#define MX6UL_PAD_ENET1_RX_ER__GPIO2_IO07              0x00e0 0x036c 0x0000 5 0
+#define MX6UL_PAD_ENET1_RX_ER__KPP_COL03               0x00e0 0x036c 0x0000 6 0
+#define MX6UL_PAD_ENET1_RX_ER__GPT1_CAPTURE2           0x00e0 0x036c 0x0590 8 1
+#define MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00                0x00e4 0x0370 0x0000 0 0
+#define MX6UL_PAD_ENET2_RX_DATA0__UART6_DCE_TX         0x00e4 0x0370 0x0000 1 0
+#define MX6UL_PAD_ENET2_RX_DATA0__UART6_DTE_RX         0x00e4 0x0370 0x064c 1 1
+#define MX6UL_PAD_ENET2_RX_DATA0__SIM1_PORT0_TRXD      0x00e4 0x0370 0x0000 2 0
+#define MX6UL_PAD_ENET2_RX_DATA0__I2C3_SCL             0x00e4 0x0370 0x05b4 3 1
+#define MX6UL_PAD_ENET2_RX_DATA0__ENET1_MDIO           0x00e4 0x0370 0x0578 4 1
+#define MX6UL_PAD_ENET2_RX_DATA0__GPIO2_IO08           0x00e4 0x0370 0x0000 5 0
+#define MX6UL_PAD_ENET2_RX_DATA0__KPP_ROW04            0x00e4 0x0370 0x0000 6 0
+#define MX6UL_PAD_ENET2_RX_DATA0__USB_OTG1_PWR         0x00e4 0x0370 0x0000 8 0
+#define MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01                0x00e8 0x0374 0x0000 0 0
+#define MX6UL_PAD_ENET2_RX_DATA1__UART6_DCE_RX         0x00e8 0x0374 0x064c 1 2
+#define MX6UL_PAD_ENET2_RX_DATA1__UART6_DTE_TX         0x00e8 0x0374 0x0000 1 0
+#define MX6UL_PAD_ENET2_RX_DATA1__SIM1_PORT0_cLK       0x00e8 0x0374 0x0000 2 0
+#define MX6UL_PAD_ENET2_RX_DATA1__I2C3_SDA             0x00e8 0x0374 0x05b8 3 1
+#define MX6UL_PAD_ENET2_RX_DATA1__ENET1_MDC            0x00e8 0x0374 0x0000 4 0
+#define MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09           0x00e8 0x0374 0x0000 5 0
+#define MX6UL_PAD_ENET2_RX_DATA1__KPP_COL04            0x00e8 0x0374 0x0000 6 0
+#define MX6UL_PAD_ENET2_RX_DATA1__USB_OTG1_OC          0x00e8 0x0374 0x0664 8 1
+#define MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN             0x00ec 0x0378 0x0000 0 0
+#define MX6UL_PAD_ENET2_RX_EN__UART7_DCE_TX            0x00ec 0x0378 0x0000 1 0
+#define MX6UL_PAD_ENET2_RX_EN__UART7_DTE_RX            0x00ec 0x0378 0x0654 1 0
+#define MX6UL_PAD_ENET2_RX_EN__SIM1_PORT0_RST_B                0x00ec 0x0378 0x0000 2 0
+#define MX6UL_PAD_ENET2_RX_EN__I2C4_SCL                        0x00ec 0x0378 0x05bc 3 1
+#define MX6UL_PAD_ENET2_RX_EN__EIM_ADDR26              0x00ec 0x0378 0x0000 4 0
+#define MX6UL_PAD_ENET2_RX_EN__GPIO2_IO10              0x00ec 0x0378 0x0000 5 0
+#define MX6UL_PAD_ENET2_RX_EN__KPP_ROW05               0x00ec 0x0378 0x0000 6 0
+#define MX6UL_PAD_ENET2_RX_EN__ENET1_REF_CLK_25M       0x00ec 0x0378 0x0000 8 0
+#define MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00                0x00f0 0x037c 0x0000 0 0
+#define MX6UL_PAD_ENET2_TX_DATA0__UART7_DCE_RX         0x00f0 0x037c 0x0654 1 1
+#define MX6UL_PAD_ENET2_TX_DATA0__UART7_DTE_TX         0x00f0 0x037c 0x0000 1 0
+#define MX6UL_PAD_ENET2_TX_DATA0__SIM1_PORT0_SVEN      0x00f0 0x037c 0x0000 2 0
+#define MX6UL_PAD_ENET2_TX_DATA0__I2C4_SDA             0x00f0 0x037c 0x05c0 3 1
+#define MX6UL_PAD_ENET2_TX_DATA0__EIM_EB_B02           0x00f0 0x037c 0x0000 4 0
+#define MX6UL_PAD_ENET2_TX_DATA0__GPIO2_IO11           0x00f0 0x037c 0x0000 5 0
+#define MX6UL_PAD_ENET2_TX_DATA0__KPP_COL05            0x00f0 0x037c 0x0000 6 0
+#define MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01                0x00f4 0x0380 0x0000 0 0
+#define MX6UL_PAD_ENET2_TX_DATA1__UART8_DCE_TX         0x00f4 0x0380 0x0000 1 0
+#define MX6UL_PAD_ENET2_TX_DATA1__UART8_DTE_RX         0x00f4 0x0380 0x065c 1 0
+#define MX6UL_PAD_ENET2_TX_DATA1__SIM2_PORT0_TRXD      0x00f4 0x0380 0x0000 2 0
+#define MX6UL_PAD_ENET2_TX_DATA1__ECSPI4_SCLK          0x00f4 0x0380 0x0564 3 0
+#define MX6UL_PAD_ENET2_TX_DATA1__EIM_EB_B03           0x00f4 0x0380 0x0000 4 0
+#define MX6UL_PAD_ENET2_TX_DATA1__GPIO2_IO12           0x00f4 0x0380 0x0000 5 0
+#define MX6UL_PAD_ENET2_TX_DATA1__KPP_ROW06            0x00f4 0x0380 0x0000 6 0
+#define MX6UL_PAD_ENET2_TX_DATA1__USB_OTG2_PWR         0x00f4 0x0380 0x0000 8 0
+#define MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN             0x00f8 0x0384 0x0000 0 0
+#define MX6UL_PAD_ENET2_TX_EN__UART8_DCE_RX            0x00f8 0x0384 0x065c 1 1
+#define MX6UL_PAD_ENET2_TX_EN__UART8_DTE_TX            0x00f8 0x0384 0x0000 1 0
+#define MX6UL_PAD_ENET2_TX_EN__SIM2_PORT0_cLK          0x00f8 0x0384 0x0000 2 0
+#define MX6UL_PAD_ENET2_TX_EN__ECSPI4_MOSI             0x00f8 0x0384 0x056c 3 0
+#define MX6UL_PAD_ENET2_TX_EN__EIM_ACLK_FREERUN                0x00f8 0x0384 0x0000 4 0
+#define MX6UL_PAD_ENET2_TX_EN__GPIO2_IO13              0x00f8 0x0384 0x0000 5 0
+#define MX6UL_PAD_ENET2_TX_EN__KPP_COL06               0x00f8 0x0384 0x0000 6 0
+#define MX6UL_PAD_ENET2_TX_EN__USB_OTG2_OC             0x00f8 0x0384 0x0660 8 1
+#define MX6UL_PAD_ENET2_TX_CLK__ENET2_TX_CLK           0x00fc 0x0388 0x0000 0 0
+#define MX6UL_PAD_ENET2_TX_CLK__UART8_DCE_CTS          0x00fc 0x0388 0x0000 1 0
+#define MX6UL_PAD_ENET2_TX_CLK__UART8_DTE_RTS          0x00fc 0x0388 0x0658 1 0
+#define MX6UL_PAD_ENET2_TX_CLK__SIM2_PORT0_RST_B       0x00fc 0x0388 0x0000 2 0
+#define MX6UL_PAD_ENET2_TX_CLK__ECSPI4_MISO            0x00fc 0x0388 0x0568 3 0
+#define MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2         0x00fc 0x0388 0x057c 4 2
+#define MX6UL_PAD_ENET2_TX_CLK__GPIO2_IO14             0x00fc 0x0388 0x0000 5 0
+#define MX6UL_PAD_ENET2_TX_CLK__KPP_ROW07              0x00fc 0x0388 0x0000 6 0
+#define MX6UL_PAD_ENET2_TX_CLK__ANATOP_OTG2_ID         0x00fc 0x0388 0x04bc 8 1
+#define MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER             0x0100 0x038c 0x0000 0 0
+#define MX6UL_PAD_ENET2_RX_ER__UART8_DCE_RTS           0x0100 0x038c 0x0658 1 1
+#define MX6UL_PAD_ENET2_RX_ER__UART8_DTE_CTS           0x0100 0x038c 0x0000 1 0
+#define MX6UL_PAD_ENET2_RX_ER__SIM2_PORT0_SVEN         0x0100 0x038c 0x0000 2 0
+#define MX6UL_PAD_ENET2_RX_ER__ECSPI4_SS0              0x0100 0x038c 0x0000 3 0
+#define MX6UL_PAD_ENET2_RX_ER__EIM_ADDR25              0x0100 0x038c 0x0000 4 0
+#define MX6UL_PAD_ENET2_RX_ER__GPIO2_IO15              0x0100 0x038c 0x0000 5 0
+#define MX6UL_PAD_ENET2_RX_ER__KPP_COL07               0x0100 0x038c 0x0000 6 0
+#define MX6UL_PAD_ENET2_RX_ER__WDOG1_WDOG_ANY          0x0100 0x038c 0x0000 8 0
+#define MX6UL_PAD_LCD_CLK__LCDIF_CLK                   0x0104 0x0390 0x0000 0 0
+#define MX6UL_PAD_LCD_CLK__LCDIF_WR_RWN                        0x0104 0x0390 0x0000 1 0
+#define MX6UL_PAD_LCD_CLK__UART4_DCE_TX                        0x0104 0x0390 0x0000 2 0
+#define MX6UL_PAD_LCD_CLK__UART4_DTE_RX                        0x0104 0x0390 0x063c 2 2
+#define MX6UL_PAD_LCD_CLK__SAI3_MCLK                   0x0104 0x0390 0x0000 3 0
+#define MX6UL_PAD_LCD_CLK__EIM_CS2_B                   0x0104 0x0390 0x0000 4 0
+#define MX6UL_PAD_LCD_CLK__GPIO3_IO00                  0x0104 0x0390 0x0000 5 0
+#define MX6UL_PAD_LCD_CLK__WDOG1_WDOG_RST_B_DEB                0x0104 0x0390 0x0000 8 0
+#define MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE             0x0108 0x0394 0x0000 0 0
+#define MX6UL_PAD_LCD_ENABLE__LCDIF_RD_E               0x0108 0x0394 0x0000 1 0
+#define MX6UL_PAD_LCD_ENABLE__UART4_DCE_RX             0x0108 0x0394 0x063c 2 3
+#define MX6UL_PAD_LCD_ENABLE__UART4_DTE_TX             0x0108 0x0394 0x0000 2 0
+#define MX6UL_PAD_LCD_ENABLE__SAI3_TX_SYNC             0x0108 0x0394 0x060c 3 0
+#define MX6UL_PAD_LCD_ENABLE__EIM_CS3_B                        0x0108 0x0394 0x0000 4 0
+#define MX6UL_PAD_LCD_ENABLE__GPIO3_IO01               0x0108 0x0394 0x0000 5 0
+#define MX6UL_PAD_LCD_ENABLE__ECSPI2_RDY               0x0108 0x0394 0x0000 8 0
+#define MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC               0x010c 0x0398 0x05dc 0 0
+#define MX6UL_PAD_LCD_HSYNC__LCDIF_RS                  0x010c 0x0398 0x0000 1 0
+#define MX6UL_PAD_LCD_HSYNC__UART4_DCE_CTS             0x010c 0x0398 0x0000 2 0
+#define MX6UL_PAD_LCD_HSYNC__UART4_DTE_RTS             0x010c 0x0398 0x0638 2 2
+#define MX6UL_PAD_LCD_HSYNC__SAI3_TX_BCLK              0x010c 0x0398 0x0608 3 0
+#define MX6UL_PAD_LCD_HSYNC__WDOG3_WDOG_RST_B_DEB      0x010c 0x0398 0x0000 4 0
+#define MX6UL_PAD_LCD_HSYNC__GPIO3_IO02                        0x010c 0x0398 0x0000 5 0
+#define MX6UL_PAD_LCD_HSYNC__ECSPI2_SS1                        0x010c 0x0398 0x0000 8 0
+#define MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC               0x0110 0x039c 0x0000 0 0
+#define MX6UL_PAD_LCD_VSYNC__LCDIF_BUSY                        0x0110 0x039c 0x05dc 1 1
+#define MX6UL_PAD_LCD_VSYNC__UART4_DCE_RTS             0x0110 0x039c 0x0638 2 3
+#define MX6UL_PAD_LCD_VSYNC__UART4_DTE_CTS             0x0110 0x039c 0x0000 2 0
+#define MX6UL_PAD_LCD_VSYNC__SAI3_RX_DATA              0x0110 0x039c 0x0000 3 0
+#define MX6UL_PAD_LCD_VSYNC__WDOG2_WDOG_B              0x0110 0x039c 0x0000 4 0
+#define MX6UL_PAD_LCD_VSYNC__GPIO3_IO03                        0x0110 0x039c 0x0000 5 0
+#define MX6UL_PAD_LCD_VSYNC__ECSPI2_SS2                        0x0110 0x039c 0x0000 8 0
+#define MX6UL_PAD_LCD_RESET__LCDIF_RESET               0x0114 0x03a0 0x0000 0 0
+#define MX6UL_PAD_LCD_RESET__LCDIF_CS                  0x0114 0x03a0 0x0000 1 0
+#define MX6UL_PAD_LCD_RESET__CA7_MX6UL_EVENTI          0x0114 0x03a0 0x0000 2 0
+#define MX6UL_PAD_LCD_RESET__SAI3_TX_DATA              0x0114 0x03a0 0x0000 3 0
+#define MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY            0x0114 0x03a0 0x0000 4 0
+#define MX6UL_PAD_LCD_RESET__GPIO3_IO04                        0x0114 0x03a0 0x0000 5 0
+#define MX6UL_PAD_LCD_RESET__ECSPI2_SS3                        0x0114 0x03a0 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA00__LCDIF_DATA00             0x0118 0x03a4 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA00__PWM1_OUT                 0x0118 0x03a4 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA00__ENET1_1588_EVENT2_IN     0x0118 0x03a4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA00__I2C3_SDA                 0x0118 0x03a4 0x05b8 4 2
+#define MX6UL_PAD_LCD_DATA00__GPIO3_IO05               0x0118 0x03a4 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA00__SRC_BT_CFG00             0x0118 0x03a4 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA00__SAI1_MCLK                        0x0118 0x03a4 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA01__LCDIF_DATA01             0x011c 0x03a8 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA01__PWM2_OUT                 0x011c 0x03a8 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA01__ENET1_1588_EVENT2_OUT    0x011c 0x03a8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA01__I2C3_SCL                 0x011c 0x03a8 0x05b4 4 2
+#define MX6UL_PAD_LCD_DATA01__GPIO3_IO06               0x011c 0x03a8 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA01__SRC_BT_CFG01             0x011c 0x03a8 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA01__SAI1_TX_SYNC             0x011c 0x03a8 0x05ec 8 0
+#define MX6UL_PAD_LCD_DATA02__LCDIF_DATA02             0x0120 0x03ac 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA02__PWM3_OUT                 0x0120 0x03ac 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA02__ENET1_1588_EVENT3_IN     0x0120 0x03ac 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA02__I2C4_SDA                 0x0120 0x03ac 0x05c0 4 2
+#define MX6UL_PAD_LCD_DATA02__GPIO3_IO07               0x0120 0x03ac 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA02__SRC_BT_CFG02             0x0120 0x03ac 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA02__SAI1_TX_BCLK             0x0120 0x03ac 0x05e8 8 0
+#define MX6UL_PAD_LCD_DATA03__LCDIF_DATA03             0x0124 0x03b0 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA03__PWM4_OUT                 0x0124 0x03b0 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA03__ENET1_1588_EVENT3_OUT    0x0124 0x03b0 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA03__I2C4_SCL                 0x0124 0x03b0 0x05bc 4 2
+#define MX6UL_PAD_LCD_DATA03__GPIO3_IO08               0x0124 0x03b0 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA03__SRC_BT_CFG03             0x0124 0x03b0 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA03__SAI1_RX_DATA             0x0124 0x03b0 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA04__LCDIF_DATA04             0x0128 0x03b4 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA04__UART8_DCE_CTS            0x0128 0x03b4 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA04__UART8_DTE_RTS            0x0128 0x03b4 0x0658 1 2
+#define MX6UL_PAD_LCD_DATA04__ENET2_1588_EVENT2_IN     0x0128 0x03b4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA04__SPDIF_SR_CLK             0x0128 0x03b4 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA04__GPIO3_IO09               0x0128 0x03b4 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA04__SRC_BT_CFG04             0x0128 0x03b4 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA04__SAI1_TX_DATA             0x0128 0x03b4 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA05__LCDIF_DATA05             0x012c 0x03b8 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA05__UART8_DCE_RTS            0x012c 0x03b8 0x0658 1 3
+#define MX6UL_PAD_LCD_DATA05__UART8_DTE_CTS            0x012c 0x03b8 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA05__ENET2_1588_EVENT2_OUT    0x012c 0x03b8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA05__SPDIF_OUT                        0x012c 0x03b8 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA05__GPIO3_IO10               0x012c 0x03b8 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA05__SRC_BT_CFG05             0x012c 0x03b8 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA05__ECSPI1_SS1               0x012c 0x03b8 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA06__LCDIF_DATA06             0x0130 0x03bc 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA06__UART7_DCE_CTS            0x0130 0x03bc 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA06__UART7_DTE_RTS            0x0130 0x03bc 0x0650 1 2
+#define MX6UL_PAD_LCD_DATA06__ENET2_1588_EVENT3_IN     0x0130 0x03bc 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA06__SPDIF_LOCK               0x0130 0x03bc 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA06__GPIO3_IO11               0x0130 0x03bc 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA06__SRC_BT_CFG06             0x0130 0x03bc 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA06__ECSPI1_SS2               0x0130 0x03bc 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA07__LCDIF_DATA07             0x0134 0x03c0 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA07__UART7_DCE_RTS            0x0134 0x03c0 0x0650 1 3
+#define MX6UL_PAD_LCD_DATA07__UART7_DTE_CTS            0x0134 0x03c0 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA07__ENET2_1588_EVENT3_OUT    0x0134 0x03c0 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA07__SPDIF_EXT_CLK            0x0134 0x03c0 0x061c 4 0
+#define MX6UL_PAD_LCD_DATA07__GPIO3_IO12               0x0134 0x03c0 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA07__SRC_BT_CFG07             0x0134 0x03c0 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA07__ECSPI1_SS3               0x0134 0x03c0 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA08__LCDIF_DATA08             0x0138 0x03c4 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA08__SPDIF_IN                 0x0138 0x03c4 0x0618 1 2
+#define MX6UL_PAD_LCD_DATA08__CSI_DATA16               0x0138 0x03c4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA08__EIM_DATA00               0x0138 0x03c4 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA08__GPIO3_IO13               0x0138 0x03c4 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA08__SRC_BT_CFG08             0x0138 0x03c4 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA08__FLEXCAN1_TX              0x0138 0x03c4 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA09__LCDIF_DATA09             0x013c 0x03c8 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA09__SAI3_MCLK                        0x013c 0x03c8 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA09__CSI_DATA17               0x013c 0x03c8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA09__EIM_DATA01               0x013c 0x03c8 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA09__GPIO3_IO14               0x013c 0x03c8 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA09__SRC_BT_CFG09             0x013c 0x03c8 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA09__FLEXCAN1_RX              0x013c 0x03c8 0x0584 8 2
+#define MX6UL_PAD_LCD_DATA10__LCDIF_DATA10             0x0140 0x03cc 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA10__SAI3_RX_SYNC             0x0140 0x03cc 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA10__CSI_DATA18               0x0140 0x03cc 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA10__EIM_DATA02               0x0140 0x03cc 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA10__GPIO3_IO15               0x0140 0x03cc 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA10__SRC_BT_CFG10             0x0140 0x03cc 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA10__FLEXCAN2_TX              0x0140 0x03cc 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA11__LCDIF_DATA11             0x0144 0x03d0 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA11__SAI3_RX_BCLK             0x0144 0x03d0 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA11__CSI_DATA19               0x0144 0x03d0 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA11__EIM_DATA03               0x0144 0x03d0 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA11__GPIO3_IO16               0x0144 0x03d0 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA11__SRC_BT_CFG11             0x0144 0x03d0 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA11__FLEXCAN2_RX              0x0144 0x03d0 0x0588 8 2
+#define MX6UL_PAD_LCD_DATA12__LCDIF_DATA12             0x0148 0x03d4 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA12__SAI3_TX_SYNC             0x0148 0x03d4 0x060c 1 1
+#define MX6UL_PAD_LCD_DATA12__CSI_DATA20               0x0148 0x03d4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA12__EIM_DATA04               0x0148 0x03d4 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA12__GPIO3_IO17               0x0148 0x03d4 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA12__SRC_BT_CFG12             0x0148 0x03d4 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA12__ECSPI1_RDY               0x0148 0x03d4 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA13__LCDIF_DATA13             0x014c 0x03d8 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA13__SAI3_TX_BCLK             0x014c 0x03d8 0x0608 1 1
+#define MX6UL_PAD_LCD_DATA13__CSI_DATA21               0x014c 0x03d8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA13__EIM_DATA05               0x014c 0x03d8 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA13__GPIO3_IO18               0x014c 0x03d8 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA13__SRC_BT_CFG13             0x014c 0x03d8 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA13__USDHC2_RESET_B           0x014c 0x03d8 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA14__LCDIF_DATA14             0x0150 0x03dc 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA14__SAI3_RX_DATA             0x0150 0x03dc 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA14__CSI_DATA22               0x0150 0x03dc 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA14__EIM_DATA06               0x0150 0x03dc 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA14__GPIO3_IO19               0x0150 0x03dc 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA14__SRC_BT_CFG14             0x0150 0x03dc 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA14__USDHC2_DATA4             0x0150 0x03dc 0x068c 8 0
+#define MX6UL_PAD_LCD_DATA15__LCDIF_DATA15             0x0154 0x03e0 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA15__SAI3_TX_DATA             0x0154 0x03e0 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA15__CSI_DATA23               0x0154 0x03e0 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA15__EIM_DATA07               0x0154 0x03e0 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA15__GPIO3_IO20               0x0154 0x03e0 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA15__SRC_BT_CFG15             0x0154 0x03e0 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA15__USDHC2_DATA5             0x0154 0x03e0 0x0690 8 0
+#define MX6UL_PAD_LCD_DATA16__LCDIF_DATA16             0x0158 0x03e4 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA16__UART7_DCE_TX             0x0158 0x03e4 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA16__UART7_DTE_RX             0x0158 0x03e4 0x0654 1 2
+#define MX6UL_PAD_LCD_DATA16__CSI_DATA01               0x0158 0x03e4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA16__EIM_DATA08               0x0158 0x03e4 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA16__GPIO3_IO21               0x0158 0x03e4 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA16__SRC_BT_CFG24             0x0158 0x03e4 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA16__USDHC2_DATA6             0x0158 0x03e4 0x0694 8 0
+#define MX6UL_PAD_LCD_DATA17__LCDIF_DATA17             0x015c 0x03e8 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA17__UART7_DCE_RX             0x015c 0x03e8 0x0654 1 3
+#define MX6UL_PAD_LCD_DATA17__UART7_DTE_TX             0x015c 0x03e8 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA17__CSI_DATA00               0x015c 0x03e8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA17__EIM_DATA09               0x015c 0x03e8 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA17__GPIO3_IO22               0x015c 0x03e8 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA17__SRC_BT_CFG25             0x015c 0x03e8 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA17__USDHC2_DATA7             0x015c 0x03e8 0x0698 8 0
+#define MX6UL_PAD_LCD_DATA18__LCDIF_DATA18             0x0160 0x03ec 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA18__PWM5_OUT                 0x0160 0x03ec 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA18__CA7_MX6UL_EVENTO         0x0160 0x03ec 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA18__CSI_DATA10               0x0160 0x03ec 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA18__EIM_DATA10               0x0160 0x03ec 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA18__GPIO3_IO23               0x0160 0x03ec 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA18__SRC_BT_CFG26             0x0160 0x03ec 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA18__USDHC2_CMD               0x0160 0x03ec 0x0678 8 1
+#define MX6UL_PAD_LCD_DATA19__EIM_DATA11               0x0164 0x03f0 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA19__GPIO3_IO24               0x0164 0x03f0 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA19__SRC_BT_CFG27             0x0164 0x03f0 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA19__USDHC2_CLK               0x0164 0x03f0 0x0670 8 1
+#define MX6UL_PAD_LCD_DATA19__LCDIF_DATA19             0x0164 0x03f0 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA19__PWM6_OUT                 0x0164 0x03f0 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA19__WDOG1_WDOG_ANY           0x0164 0x03f0 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA19__CSI_DATA11               0x0164 0x03f0 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA20__EIM_DATA12               0x0168 0x03f4 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA20__GPIO3_IO25               0x0168 0x03f4 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA20__SRC_BT_CFG28             0x0168 0x03f4 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA20__USDHC2_DATA0             0x0168 0x03f4 0x067c 8 1
+#define MX6UL_PAD_LCD_DATA20__LCDIF_DATA20             0x0168 0x03f4 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA20__UART8_DCE_TX             0x0168 0x03f4 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA20__UART8_DTE_RX             0x0168 0x03f4 0x065c 1 2
+#define MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK              0x0168 0x03f4 0x0534 2 0
+#define MX6UL_PAD_LCD_DATA20__CSI_DATA12               0x0168 0x03f4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA21__LCDIF_DATA21             0x016c 0x03f8 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA21__UART8_DCE_RX             0x016c 0x03f8 0x065c 1 3
+#define MX6UL_PAD_LCD_DATA21__UART8_DTE_TX             0x016c 0x03f8 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA21__ECSPI1_SS0               0x016c 0x03f8 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA21__CSI_DATA13               0x016c 0x03f8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA21__EIM_DATA13               0x016c 0x03f8 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA21__GPIO3_IO26               0x016c 0x03f8 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA21__SRC_BT_CFG29             0x016c 0x03f8 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA21__USDHC2_DATA1             0x016c 0x03f8 0x0680 8 1
+#define MX6UL_PAD_LCD_DATA22__LCDIF_DATA22             0x0170 0x03fc 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA22__MQS_RIGHT                        0x0170 0x03fc 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI              0x0170 0x03fc 0x053c 2 0
+#define MX6UL_PAD_LCD_DATA22__CSI_DATA14               0x0170 0x03fc 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA22__EIM_DATA14               0x0170 0x03fc 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA22__GPIO3_IO27               0x0170 0x03fc 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA22__SRC_BT_CFG30             0x0170 0x03fc 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA22__USDHC2_DATA2             0x0170 0x03fc 0x0684 8 0
+#define MX6UL_PAD_LCD_DATA23__LCDIF_DATA23             0x0174 0x0400 0x0000 0 0
+#define MX6UL_PAD_LCD_DATA23__MQS_LEFT                 0x0174 0x0400 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA23__ECSPI1_MISO              0x0174 0x0400 0x0538 2 0
+#define MX6UL_PAD_LCD_DATA23__CSI_DATA15               0x0174 0x0400 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA23__EIM_DATA15               0x0174 0x0400 0x0000 4 0
+#define MX6UL_PAD_LCD_DATA23__GPIO3_IO28               0x0174 0x0400 0x0000 5 0
+#define MX6UL_PAD_LCD_DATA23__SRC_BT_CFG31             0x0174 0x0400 0x0000 6 0
+#define MX6UL_PAD_LCD_DATA23__USDHC2_DATA3             0x0174 0x0400 0x0688 8 1
+#define MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B              0x0178 0x0404 0x0000 0 0
+#define MX6UL_PAD_NAND_RE_B__USDHC2_CLK                        0x0178 0x0404 0x0670 1 2
+#define MX6UL_PAD_NAND_RE_B__QSPI_B_SCLK               0x0178 0x0404 0x0000 2 0
+#define MX6UL_PAD_NAND_RE_B__KPP_ROW00                 0x0178 0x0404 0x0000 3 0
+#define MX6UL_PAD_NAND_RE_B__EIM_EB_B00                        0x0178 0x0404 0x0000 4 0
+#define MX6UL_PAD_NAND_RE_B__GPIO4_IO00                        0x0178 0x0404 0x0000 5 0
+#define MX6UL_PAD_NAND_RE_B__ECSPI3_SS2                        0x0178 0x0404 0x0000 8 0
+#define MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B              0x017c 0x0408 0x0000 0 0
+#define MX6UL_PAD_NAND_WE_B__USDHC2_CMD                        0x017c 0x0408 0x0678 1 2
+#define MX6UL_PAD_NAND_WE_B__QSPI_B_SS0_B              0x017c 0x0408 0x0000 2 0
+#define MX6UL_PAD_NAND_WE_B__KPP_COL00                 0x017c 0x0408 0x0000 3 0
+#define MX6UL_PAD_NAND_WE_B__EIM_EB_B01                        0x017c 0x0408 0x0000 4 0
+#define MX6UL_PAD_NAND_WE_B__GPIO4_IO01                        0x017c 0x0408 0x0000 5 0
+#define MX6UL_PAD_NAND_WE_B__ECSPI3_SS3                        0x017c 0x0408 0x0000 8 0
+#define MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00          0x0180 0x040c 0x0000 0 0
+#define MX6UL_PAD_NAND_DATA00__USDHC2_DATA0            0x0180 0x040c 0x067c 1 2
+#define MX6UL_PAD_NAND_DATA00__QSPI_B_SS1_B            0x0180 0x040c 0x0000 2 0
+#define MX6UL_PAD_NAND_DATA00__KPP_ROW01               0x0180 0x040c 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA00__EIM_AD08                        0x0180 0x040c 0x0000 4 0
+#define MX6UL_PAD_NAND_DATA00__GPIO4_IO02              0x0180 0x040c 0x0000 5 0
+#define MX6UL_PAD_NAND_DATA00__ECSPI4_RDY              0x0180 0x040c 0x0000 8 0
+#define MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01          0x0184 0x0410 0x0000 0 0
+#define MX6UL_PAD_NAND_DATA01__USDHC2_DATA1            0x0184 0x0410 0x0680 1 2
+#define MX6UL_PAD_NAND_DATA01__QSPI_B_DQS              0x0184 0x0410 0x0000 2 0
+#define MX6UL_PAD_NAND_DATA01__KPP_COL01               0x0184 0x0410 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA01__EIM_AD09                        0x0184 0x0410 0x0000 4 0
+#define MX6UL_PAD_NAND_DATA01__GPIO4_IO03              0x0184 0x0410 0x0000 5 0
+#define MX6UL_PAD_NAND_DATA01__ECSPI4_SS1              0x0184 0x0410 0x0000 8 0
+#define MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02          0x0188 0x0414 0x0000 0 0
+#define MX6UL_PAD_NAND_DATA02__USDHC2_DATA2            0x0188 0x0414 0x0684 1 1
+#define MX6UL_PAD_NAND_DATA02__QSPI_B_DATA00           0x0188 0x0414 0x0000 2 0
+#define MX6UL_PAD_NAND_DATA02__KPP_ROW02               0x0188 0x0414 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA02__EIM_AD10                        0x0188 0x0414 0x0000 4 0
+#define MX6UL_PAD_NAND_DATA02__GPIO4_IO04              0x0188 0x0414 0x0000 5 0
+#define MX6UL_PAD_NAND_DATA02__ECSPI4_SS2              0x0188 0x0414 0x0000 8 0
+#define MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03          0x018c 0x0418 0x0000 0 0
+#define MX6UL_PAD_NAND_DATA03__USDHC2_DATA3            0x018c 0x0418 0x0688 1 2
+#define MX6UL_PAD_NAND_DATA03__QSPI_B_DATA01           0x018c 0x0418 0x0000 2 0
+#define MX6UL_PAD_NAND_DATA03__KPP_COL02               0x018c 0x0418 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA03__EIM_AD11                        0x018c 0x0418 0x0000 4 0
+#define MX6UL_PAD_NAND_DATA03__GPIO4_IO05              0x018c 0x0418 0x0000 5 0
+#define MX6UL_PAD_NAND_DATA03__ECSPI4_SS3              0x018c 0x0418 0x0000 8 0
+#define MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04          0x0190 0x041c 0x0000 0 0
+#define MX6UL_PAD_NAND_DATA04__USDHC2_DATA4            0x0190 0x041c 0x068c 1 1
+#define MX6UL_PAD_NAND_DATA04__QSPI_B_DATA02           0x0190 0x041c 0x0000 2 0
+#define MX6UL_PAD_NAND_DATA04__ECSPI4_SCLK             0x0190 0x041c 0x0564 3 1
+#define MX6UL_PAD_NAND_DATA04__EIM_AD12                        0x0190 0x041c 0x0000 4 0
+#define MX6UL_PAD_NAND_DATA04__GPIO4_IO06              0x0190 0x041c 0x0000 5 0
+#define MX6UL_PAD_NAND_DATA04__UART2_DCE_TX            0x0190 0x041c 0x0000 8 0
+#define MX6UL_PAD_NAND_DATA04__UART2_DTE_RX            0x0190 0x041c 0x062c 8 2
+#define MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05          0x0194 0x0420 0x0000 0 0
+#define MX6UL_PAD_NAND_DATA05__USDHC2_DATA5            0x0194 0x0420 0x0690 1 1
+#define MX6UL_PAD_NAND_DATA05__QSPI_B_DATA03           0x0194 0x0420 0x0000 2 0
+#define MX6UL_PAD_NAND_DATA05__ECSPI4_MOSI             0x0194 0x0420 0x056c 3 1
+#define MX6UL_PAD_NAND_DATA05__EIM_AD13                        0x0194 0x0420 0x0000 4 0
+#define MX6UL_PAD_NAND_DATA05__GPIO4_IO07              0x0194 0x0420 0x0000 5 0
+#define MX6UL_PAD_NAND_DATA05__UART2_DCE_RX            0x0194 0x0420 0x062c 8 3
+#define MX6UL_PAD_NAND_DATA05__UART2_DTE_TX            0x0194 0x0420 0x0000 8 0
+#define MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06          0x0198 0x0424 0x0000 0 0
+#define MX6UL_PAD_NAND_DATA06__USDHC2_DATA6            0x0198 0x0424 0x0694 1 1
+#define MX6UL_PAD_NAND_DATA06__SAI2_RX_BCLK            0x0198 0x0424 0x0000 2 0
+#define MX6UL_PAD_NAND_DATA06__ECSPI4_MISO             0x0198 0x0424 0x0568 3 1
+#define MX6UL_PAD_NAND_DATA06__EIM_AD14                        0x0198 0x0424 0x0000 4 0
+#define MX6UL_PAD_NAND_DATA06__GPIO4_IO08              0x0198 0x0424 0x0000 5 0
+#define MX6UL_PAD_NAND_DATA06__UART2_DCE_CTS           0x0198 0x0424 0x0000 8 0
+#define MX6UL_PAD_NAND_DATA06__UART2_DTE_RTS           0x0198 0x0424 0x0628 8 4
+#define MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07          0x019c 0x0428 0x0000 0 0
+#define MX6UL_PAD_NAND_DATA07__USDHC2_DATA7            0x019c 0x0428 0x0698 1 1
+#define MX6UL_PAD_NAND_DATA07__QSPI_A_SS1_B            0x019c 0x0428 0x0000 2 0
+#define MX6UL_PAD_NAND_DATA07__ECSPI4_SS0              0x019c 0x0428 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA07__EIM_AD15                        0x019c 0x0428 0x0000 4 0
+#define MX6UL_PAD_NAND_DATA07__GPIO4_IO09              0x019c 0x0428 0x0000 5 0
+#define MX6UL_PAD_NAND_DATA07__UART2_DCE_RTS           0x019c 0x0428 0x0628 8 5
+#define MX6UL_PAD_NAND_DATA07__UART2_DTE_CTS           0x019c 0x0428 0x0000 8 0
+#define MX6UL_PAD_NAND_ALE__RAWNAND_ALE                        0x01a0 0x042c 0x0000 0 0
+#define MX6UL_PAD_NAND_ALE__USDHC2_RESET_B             0x01a0 0x042c 0x0000 1 0
+#define MX6UL_PAD_NAND_ALE__QSPI_A_DQS                 0x01a0 0x042c 0x0000 2 0
+#define MX6UL_PAD_NAND_ALE__PWM3_OUT                   0x01a0 0x042c 0x0000 3 0
+#define MX6UL_PAD_NAND_ALE__EIM_ADDR17                 0x01a0 0x042c 0x0000 4 0
+#define MX6UL_PAD_NAND_ALE__GPIO4_IO10                 0x01a0 0x042c 0x0000 5 0
+#define MX6UL_PAD_NAND_ALE__ECSPI3_SS1                 0x01a0 0x042c 0x0000 8 0
+#define MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B              0x01a4 0x0430 0x0000 0 0
+#define MX6UL_PAD_NAND_WP_B__USDHC1_RESET_B            0x01a4 0x0430 0x0000 1 0
+#define MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK               0x01a4 0x0430 0x0000 2 0
+#define MX6UL_PAD_NAND_WP_B__PWM4_OUT                  0x01a4 0x0430 0x0000 3 0
+#define MX6UL_PAD_NAND_WP_B__EIM_BCLK                  0x01a4 0x0430 0x0000 4 0
+#define MX6UL_PAD_NAND_WP_B__GPIO4_IO11                        0x01a4 0x0430 0x0000 5 0
+#define MX6UL_PAD_NAND_WP_B__ECSPI3_RDY                        0x01a4 0x0430 0x0000 8 0
+#define MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B                0x01a8 0x0434 0x0000 0 0
+#define MX6UL_PAD_NAND_READY_B__USDHC1_DATA4           0x01a8 0x0434 0x0000 1 0
+#define MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00          0x01a8 0x0434 0x0000 2 0
+#define MX6UL_PAD_NAND_READY_B__ECSPI3_SS0             0x01a8 0x0434 0x0000 3 0
+#define MX6UL_PAD_NAND_READY_B__EIM_CS1_B              0x01a8 0x0434 0x0000 4 0
+#define MX6UL_PAD_NAND_READY_B__GPIO4_IO12             0x01a8 0x0434 0x0000 5 0
+#define MX6UL_PAD_NAND_READY_B__UART3_DCE_TX           0x01a8 0x0434 0x0000 8 0
+#define MX6UL_PAD_NAND_READY_B__UART3_DTE_RX           0x01a8 0x0434 0x0634 8 2
+#define MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B            0x01ac 0x0438 0x0000 0 0
+#define MX6UL_PAD_NAND_CE0_B__USDHC1_DATA5             0x01ac 0x0438 0x0000 1 0
+#define MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01            0x01ac 0x0438 0x0000 2 0
+#define MX6UL_PAD_NAND_CE0_B__ECSPI3_SCLK              0x01ac 0x0438 0x0554 3 1
+#define MX6UL_PAD_NAND_CE0_B__EIM_DTACK_B              0x01ac 0x0438 0x0000 4 0
+#define MX6UL_PAD_NAND_CE0_B__GPIO4_IO13               0x01ac 0x0438 0x0000 5 0
+#define MX6UL_PAD_NAND_CE0_B__UART3_DCE_RX             0x01ac 0x0438 0x0634 8 3
+#define MX6UL_PAD_NAND_CE0_B__UART3_DTE_TX             0x01ac 0x0438 0x0000 8 0
+#define MX6UL_PAD_NAND_CE1_B__RAWNAND_CE1_B            0x01b0 0x043c 0x0000 0 0
+#define MX6UL_PAD_NAND_CE1_B__USDHC1_DATA6             0x01b0 0x043c 0x0000 1 0
+#define MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02            0x01b0 0x043c 0x0000 2 0
+#define MX6UL_PAD_NAND_CE1_B__ECSPI3_MOSI              0x01b0 0x043c 0x055c 3 1
+#define MX6UL_PAD_NAND_CE1_B__EIM_ADDR18               0x01b0 0x043c 0x0000 4 0
+#define MX6UL_PAD_NAND_CE1_B__GPIO4_IO14               0x01b0 0x043c 0x0000 5 0
+#define MX6UL_PAD_NAND_CE1_B__UART3_DCE_CTS            0x01b0 0x043c 0x0000 8 0
+#define MX6UL_PAD_NAND_CE1_B__UART3_DTE_RTS            0x01b0 0x043c 0x0630 8 2
+#define MX6UL_PAD_NAND_CLE__RAWNAND_CLE                        0x01b4 0x0440 0x0000 0 0
+#define MX6UL_PAD_NAND_CLE__USDHC1_DATA7               0x01b4 0x0440 0x0000 1 0
+#define MX6UL_PAD_NAND_CLE__QSPI_A_DATA03              0x01b4 0x0440 0x0000 2 0
+#define MX6UL_PAD_NAND_CLE__ECSPI3_MISO                        0x01b4 0x0440 0x0558 3 1
+#define MX6UL_PAD_NAND_CLE__EIM_ADDR16                 0x01b4 0x0440 0x0000 4 0
+#define MX6UL_PAD_NAND_CLE__GPIO4_IO15                 0x01b4 0x0440 0x0000 5 0
+#define MX6UL_PAD_NAND_CLE__UART3_DCE_RTS              0x01b4 0x0440 0x0630 8 3
+#define MX6UL_PAD_NAND_CLE__UART3_DTE_CTS              0x01b4 0x0440 0x0000 8 0
+#define MX6UL_PAD_NAND_DQS__RAWNAND_DQS                        0x01b8 0x0444 0x0000 0 0
+#define MX6UL_PAD_NAND_DQS__CSI_FIELD                  0x01b8 0x0444 0x0530 1 1
+#define MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B               0x01b8 0x0444 0x0000 2 0
+#define MX6UL_PAD_NAND_DQS__PWM5_OUT                   0x01b8 0x0444 0x0000 3 0
+#define MX6UL_PAD_NAND_DQS__EIM_WAIT                   0x01b8 0x0444 0x0000 4 0
+#define MX6UL_PAD_NAND_DQS__GPIO4_IO16                 0x01b8 0x0444 0x0000 5 0
+#define MX6UL_PAD_NAND_DQS__SDMA_EXT_EVENT01           0x01b8 0x0444 0x0000 6 0
+#define MX6UL_PAD_NAND_DQS__SPDIF_EXT_CLK              0x01b8 0x0444 0x061c 8 1
+#define MX6UL_PAD_SD1_CMD__USDHC1_CMD                  0x01bc 0x0448 0x0000 0 0
+#define MX6UL_PAD_SD1_CMD__GPT2_COMPARE1               0x01bc 0x0448 0x0000 1 0
+#define MX6UL_PAD_SD1_CMD__SAI2_RX_SYNC                        0x01bc 0x0448 0x0000 2 0
+#define MX6UL_PAD_SD1_CMD__SPDIF_OUT                   0x01bc 0x0448 0x0000 3 0
+#define MX6UL_PAD_SD1_CMD__EIM_ADDR19                  0x01bc 0x0448 0x0000 4 0
+#define MX6UL_PAD_SD1_CMD__GPIO2_IO16                  0x01bc 0x0448 0x0000 5 0
+#define MX6UL_PAD_SD1_CMD__SDMA_EXT_EVENT00            0x01bc 0x0448 0x0000 6 0
+#define MX6UL_PAD_SD1_CMD__USB_OTG1_PWR                        0x01bc 0x0448 0x0000 8 0
+#define MX6UL_PAD_SD1_CLK__USDHC1_CLK                  0x01c0 0x044c 0x0000 0 0
+#define MX6UL_PAD_SD1_CLK__GPT2_COMPARE2               0x01c0 0x044c 0x0000 1 0
+#define MX6UL_PAD_SD1_CLK__SAI2_MCLK                   0x01c0 0x044c 0x0000 2 0
+#define MX6UL_PAD_SD1_CLK__SPDIF_IN                    0x01c0 0x044c 0x0618 3 3
+#define MX6UL_PAD_SD1_CLK__EIM_ADDR20                  0x01c0 0x044c 0x0000 4 0
+#define MX6UL_PAD_SD1_CLK__GPIO2_IO17                  0x01c0 0x044c 0x0000 5 0
+#define MX6UL_PAD_SD1_CLK__USB_OTG1_OC                 0x01c0 0x044c 0x0664 8 2
+#define MX6UL_PAD_SD1_DATA0__USDHC1_DATA0              0x01c4 0x0450 0x0000 0 0
+#define MX6UL_PAD_SD1_DATA0__GPT2_COMPARE3             0x01c4 0x0450 0x0000 1 0
+#define MX6UL_PAD_SD1_DATA0__SAI2_TX_SYNC              0x01c4 0x0450 0x05fc 2 1
+#define MX6UL_PAD_SD1_DATA0__FLEXCAN1_TX               0x01c4 0x0450 0x0000 3 0
+#define MX6UL_PAD_SD1_DATA0__EIM_ADDR21                        0x01c4 0x0450 0x0000 4 0
+#define MX6UL_PAD_SD1_DATA0__GPIO2_IO18                        0x01c4 0x0450 0x0000 5 0
+#define MX6UL_PAD_SD1_DATA0__ANATOP_OTG1_ID            0x01c4 0x0450 0x04b8 8 2
+#define MX6UL_PAD_SD1_DATA1__USDHC1_DATA1              0x01c8 0x0454 0x0000 0 0
+#define MX6UL_PAD_SD1_DATA1__GPT2_CLK                  0x01c8 0x0454 0x05a0 1 1
+#define MX6UL_PAD_SD1_DATA1__SAI2_TX_BCLK              0x01c8 0x0454 0x05f8 2 1
+#define MX6UL_PAD_SD1_DATA1__FLEXCAN1_RX               0x01c8 0x0454 0x0584 3 3
+#define MX6UL_PAD_SD1_DATA1__EIM_ADDR22                        0x01c8 0x0454 0x0000 4 0
+#define MX6UL_PAD_SD1_DATA1__GPIO2_IO19                        0x01c8 0x0454 0x0000 5 0
+#define MX6UL_PAD_SD1_DATA1__USB_OTG2_PWR              0x01c8 0x0454 0x0000 8 0
+#define MX6UL_PAD_SD1_DATA2__USDHC1_DATA2              0x01cc 0x0458 0x0000 0 0
+#define MX6UL_PAD_SD1_DATA2__GPT2_CAPTURE1             0x01cc 0x0458 0x0598 1 1
+#define MX6UL_PAD_SD1_DATA2__SAI2_RX_DATA              0x01cc 0x0458 0x05f4 2 1
+#define MX6UL_PAD_SD1_DATA2__FLEXCAN2_TX               0x01cc 0x0458 0x0000 3 0
+#define MX6UL_PAD_SD1_DATA2__EIM_ADDR23                        0x01cc 0x0458 0x0000 4 0
+#define MX6UL_PAD_SD1_DATA2__GPIO2_IO20                        0x01cc 0x0458 0x0000 5 0
+#define MX6UL_PAD_SD1_DATA2__CCM_CLKO1                 0x01cc 0x0458 0x0000 6 0
+#define MX6UL_PAD_SD1_DATA2__USB_OTG2_OC               0x01cc 0x0458 0x0660 8 2
+#define MX6UL_PAD_SD1_DATA3__USDHC1_DATA3              0x01d0 0x045c 0x0000 0 0
+#define MX6UL_PAD_SD1_DATA3__GPT2_CAPTURE2             0x01d0 0x045c 0x059c 1 1
+#define MX6UL_PAD_SD1_DATA3__SAI2_TX_DATA              0x01d0 0x045c 0x0000 2 0
+#define MX6UL_PAD_SD1_DATA3__FLEXCAN2_RX               0x01d0 0x045c 0x0588 3 3
+#define MX6UL_PAD_SD1_DATA3__EIM_ADDR24                        0x01d0 0x045c 0x0000 4 0
+#define MX6UL_PAD_SD1_DATA3__GPIO2_IO21                        0x01d0 0x045c 0x0000 5 0
+#define MX6UL_PAD_SD1_DATA3__CCM_CLKO2                 0x01d0 0x045c 0x0000 6 0
+#define MX6UL_PAD_SD1_DATA3__ANATOP_OTG2_ID            0x01d0 0x045c 0x04bc 8 2
+#define MX6UL_PAD_CSI_MCLK__CSI_MCLK                   0x01d4 0x0460 0x0000 0 0
+#define MX6UL_PAD_CSI_MCLK__USDHC2_CD_B                        0x01d4 0x0460 0x0674 1 0
+#define MX6UL_PAD_CSI_MCLK__RAWNAND_CE2_B              0x01d4 0x0460 0x0000 2 0
+#define MX6UL_PAD_CSI_MCLK__I2C1_SDA                   0x01d4 0x0460 0x05a8 3 0
+#define MX6UL_PAD_CSI_MCLK__EIM_CS0_B                  0x01d4 0x0460 0x0000 4 0
+#define MX6UL_PAD_CSI_MCLK__GPIO4_IO17                 0x01d4 0x0460 0x0000 5 0
+#define MX6UL_PAD_CSI_MCLK__SNVS_HP_VIO_5_CTL          0x01d4 0x0460 0x0000 6 0
+#define MX6UL_PAD_CSI_MCLK__UART6_DCE_TX               0x01d4 0x0460 0x0000 8 0
+#define MX6UL_PAD_CSI_MCLK__UART6_DTE_RX               0x01d4 0x0460 0x064c 8 0
+#define MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK               0x01d8 0x0464 0x0528 0 1
+#define MX6UL_PAD_CSI_PIXCLK__USDHC2_WP                        0x01d8 0x0464 0x069c 1 2
+#define MX6UL_PAD_CSI_PIXCLK__RAWNAND_CE3_B            0x01d8 0x0464 0x0000 2 0
+#define MX6UL_PAD_CSI_PIXCLK__I2C1_SCL                 0x01d8 0x0464 0x05a4 3 2
+#define MX6UL_PAD_CSI_PIXCLK__EIM_OE                   0x01d8 0x0464 0x0000 4 0
+#define MX6UL_PAD_CSI_PIXCLK__GPIO4_IO18               0x01d8 0x0464 0x0000 5 0
+#define MX6UL_PAD_CSI_PIXCLK__SNVS_HP_VIO_5            0x01d8 0x0464 0x0000 6 0
+#define MX6UL_PAD_CSI_PIXCLK__UART6_DCE_RX             0x01d8 0x0464 0x064c 8 3
+#define MX6UL_PAD_CSI_PIXCLK__UART6_DTE_TX             0x01d8 0x0464 0x0000 8 0
+#define MX6UL_PAD_CSI_VSYNC__CSI_VSYNC                 0x01dc 0x0468 0x052c 0 0
+#define MX6UL_PAD_CSI_VSYNC__USDHC2_CLK                        0x01dc 0x0468 0x0670 1 0
+#define MX6UL_PAD_CSI_VSYNC__SIM1_PORT1_CLK            0x01dc 0x0468 0x0000 2 0
+#define MX6UL_PAD_CSI_VSYNC__I2C2_SDA                  0x01dc 0x0468 0x05b0 3 0
+#define MX6UL_PAD_CSI_VSYNC__EIM_RW                    0x01dc 0x0468 0x0000 4 0
+#define MX6UL_PAD_CSI_VSYNC__GPIO4_IO19                        0x01dc 0x0468 0x0000 5 0
+#define MX6UL_PAD_CSI_VSYNC__PWM7_OUT                  0x01dc 0x0468 0x0000 6 0
+#define MX6UL_PAD_CSI_VSYNC__UART6_DCE_RTS             0x01dc 0x0468 0x0648 8 0
+#define MX6UL_PAD_CSI_VSYNC__UART6_DTE_CTS             0x01dc 0x0468 0x0000 8 0
+#define MX6UL_PAD_CSI_HSYNC__CSI_HSYNC                 0x01e0 0x046c 0x0524 0 0
+#define MX6UL_PAD_CSI_HSYNC__USDHC2_CMD                        0x01e0 0x046c 0x0678 1 0
+#define MX6UL_PAD_CSI_HSYNC__SIM1_PORT1_PD             0x01e0 0x046c 0x0000 2 0
+#define MX6UL_PAD_CSI_HSYNC__I2C2_SCL                  0x01e0 0x046c 0x05ac 3 0
+#define MX6UL_PAD_CSI_HSYNC__EIM_LBA_B                 0x01e0 0x046c 0x0000 4 0
+#define MX6UL_PAD_CSI_HSYNC__GPIO4_IO20                        0x01e0 0x046c 0x0000 5 0
+#define MX6UL_PAD_CSI_HSYNC__PWM8_OUT                  0x01e0 0x046c 0x0000 6 0
+#define MX6UL_PAD_CSI_HSYNC__UART6_DCE_CTS             0x01e0 0x046c 0x0000 8 0
+#define MX6UL_PAD_CSI_HSYNC__UART6_DTE_RTS             0x01e0 0x046c 0x0648 8 1
+#define MX6UL_PAD_CSI_DATA00__CSI_DATA02               0x01e4 0x0470 0x04c4 0 0
+#define MX6UL_PAD_CSI_DATA00__USDHC2_DATA0             0x01e4 0x0470 0x067c 1 0
+#define MX6UL_PAD_CSI_DATA00__SIM1_PORT1_RST_B         0x01e4 0x0470 0x0000 2 0
+#define MX6UL_PAD_CSI_DATA00__ECSPI2_SCLK              0x01e4 0x0470 0x0544 3 0
+#define MX6UL_PAD_CSI_DATA00__EIM_AD00                 0x01e4 0x0470 0x0000 4 0
+#define MX6UL_PAD_CSI_DATA00__GPIO4_IO21               0x01e4 0x0470 0x0000 5 0
+#define MX6UL_PAD_CSI_DATA00__SRC_INT_BOOT             0x01e4 0x0470 0x0000 6 0
+#define MX6UL_PAD_CSI_DATA00__UART5_DCE_TX             0x01e4 0x0470 0x0000 8 0
+#define MX6UL_PAD_CSI_DATA00__UART5_DTE_RX             0x01e4 0x0470 0x0644 8 0
+#define MX6UL_PAD_CSI_DATA01__CSI_DATA03               0x01e8 0x0474 0x04c8 0 0
+#define MX6UL_PAD_CSI_DATA01__USDHC2_DATA1             0x01e8 0x0474 0x0680 1 0
+#define MX6UL_PAD_CSI_DATA01__SIM1_PORT1_SVEN          0x01e8 0x0474 0x0000 2 0
+#define MX6UL_PAD_CSI_DATA01__ECSPI2_SS0               0x01e8 0x0474 0x0000 3 0
+#define MX6UL_PAD_CSI_DATA01__EIM_AD01                 0x01e8 0x0474 0x0000 4 0
+#define MX6UL_PAD_CSI_DATA01__GPIO4_IO22               0x01e8 0x0474 0x0000 5 0
+#define MX6UL_PAD_CSI_DATA01__SAI1_MCLK                        0x01e8 0x0474 0x0000 6 0
+#define MX6UL_PAD_CSI_DATA01__UART5_DCE_RX             0x01e8 0x0474 0x0644 8 1
+#define MX6UL_PAD_CSI_DATA01__UART5_DTE_TX             0x01e8 0x0474 0x0000 8 0
+#define MX6UL_PAD_CSI_DATA02__CSI_DATA04               0x01ec 0x0478 0x04d8 0 1
+#define MX6UL_PAD_CSI_DATA02__USDHC2_DATA2             0x01ec 0x0478 0x0684 1 2
+#define MX6UL_PAD_CSI_DATA02__SIM1_PORT1_TRXD          0x01ec 0x0478 0x0000 2 0
+#define MX6UL_PAD_CSI_DATA02__ECSPI2_MOSI              0x01ec 0x0478 0x054c 3 1
+#define MX6UL_PAD_CSI_DATA02__EIM_AD02                 0x01ec 0x0478 0x0000 4 0
+#define MX6UL_PAD_CSI_DATA02__GPIO4_IO23               0x01ec 0x0478 0x0000 5 0
+#define MX6UL_PAD_CSI_DATA02__SAI1_RX_SYNC             0x01ec 0x0478 0x0000 6 0
+#define MX6UL_PAD_CSI_DATA02__UART5_DCE_RTS            0x01ec 0x0478 0x0640 8 5
+#define MX6UL_PAD_CSI_DATA02__UART5_DTE_CTS            0x01ec 0x0478 0x0000 8 0
+#define MX6UL_PAD_CSI_DATA03__CSI_DATA05               0x01f0 0x047c 0x04cc 0 0
+#define MX6UL_PAD_CSI_DATA03__USDHC2_DATA3             0x01f0 0x047c 0x0688 1 0
+#define MX6UL_PAD_CSI_DATA03__SIM2_PORT1_PD            0x01f0 0x047c 0x0000 2 0
+#define MX6UL_PAD_CSI_DATA03__ECSPI2_MISO              0x01f0 0x047c 0x0548 3 0
+#define MX6UL_PAD_CSI_DATA03__EIM_AD03                 0x01f0 0x047c 0x0000 4 0
+#define MX6UL_PAD_CSI_DATA03__GPIO4_IO24               0x01f0 0x047c 0x0000 5 0
+#define MX6UL_PAD_CSI_DATA03__SAI1_RX_BCLK             0x01f0 0x047c 0x0000 6 0
+#define MX6UL_PAD_CSI_DATA03__UART5_DCE_CTS            0x01f0 0x047c 0x0000 8 0
+#define MX6UL_PAD_CSI_DATA03__UART5_DTE_RTS            0x01f0 0x047c 0x0640 8 0
+#define MX6UL_PAD_CSI_DATA04__CSI_DATA06               0x01f4 0x0480 0x04dc 0 1
+#define MX6UL_PAD_CSI_DATA04__USDHC2_DATA4             0x01f4 0x0480 0x068c 1 2
+#define MX6UL_PAD_CSI_DATA04__SIM2_PORT1_CLK           0x01f4 0x0480 0x0000 2 0
+#define MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK              0x01f4 0x0480 0x0534 3 1
+#define MX6UL_PAD_CSI_DATA04__EIM_AD04                 0x01f4 0x0480 0x0000 4 0
+#define MX6UL_PAD_CSI_DATA04__GPIO4_IO25               0x01f4 0x0480 0x0000 5 0
+#define MX6UL_PAD_CSI_DATA04__SAI1_TX_SYNC             0x01f4 0x0480 0x05ec 6 1
+#define MX6UL_PAD_CSI_DATA04__USDHC1_WP                        0x01f4 0x0480 0x066c 8 2
+#define MX6UL_PAD_CSI_DATA05__CSI_DATA07               0x01f8 0x0484 0x04e0 0 1
+#define MX6UL_PAD_CSI_DATA05__USDHC2_DATA5             0x01f8 0x0484 0x0690 1 2
+#define MX6UL_PAD_CSI_DATA05__SIM2_PORT1_RST_B         0x01f8 0x0484 0x0000 2 0
+#define MX6UL_PAD_CSI_DATA05__ECSPI1_SS0               0x01f8 0x0484 0x0000 3 0
+#define MX6UL_PAD_CSI_DATA05__EIM_AD05                 0x01f8 0x0484 0x0000 4 0
+#define MX6UL_PAD_CSI_DATA05__GPIO4_IO26               0x01f8 0x0484 0x0000 5 0
+#define MX6UL_PAD_CSI_DATA05__SAI1_TX_BCLK             0x01f8 0x0484 0x05e8 6 1
+#define MX6UL_PAD_CSI_DATA05__USDHC1_CD_B              0x01f8 0x0484 0x0668 8 2
+#define MX6UL_PAD_CSI_DATA06__CSI_DATA08               0x01fc 0x0488 0x04e4 0 1
+#define MX6UL_PAD_CSI_DATA06__USDHC2_DATA6             0x01fc 0x0488 0x0694 1 2
+#define MX6UL_PAD_CSI_DATA06__SIM2_PORT1_SVEN          0x01fc 0x0488 0x0000 2 0
+#define MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI              0x01fc 0x0488 0x053c 3 1
+#define MX6UL_PAD_CSI_DATA06__EIM_AD06                 0x01fc 0x0488 0x0000 4 0
+#define MX6UL_PAD_CSI_DATA06__GPIO4_IO27               0x01fc 0x0488 0x0000 5 0
+#define MX6UL_PAD_CSI_DATA06__SAI1_RX_DATA             0x01fc 0x0488 0x0000 6 0
+#define MX6UL_PAD_CSI_DATA06__USDHC1_RESET_B           0x01fc 0x0488 0x0000 8 0
+#define MX6UL_PAD_CSI_DATA07__CSI_DATA09               0x0200 0x048c 0x04e8 0 1
+#define MX6UL_PAD_CSI_DATA07__USDHC2_DATA7             0x0200 0x048c 0x0698 1 2
+#define MX6UL_PAD_CSI_DATA07__SIM2_PORT1_TRXD          0x0200 0x048c 0x0000 2 0
+#define MX6UL_PAD_CSI_DATA07__ECSPI1_MISO              0x0200 0x048c 0x0538 3 1
+#define MX6UL_PAD_CSI_DATA07__EIM_AD07                 0x0200 0x048c 0x0000 4 0
+#define MX6UL_PAD_CSI_DATA07__GPIO4_IO28               0x0200 0x048c 0x0000 5 0
+#define MX6UL_PAD_CSI_DATA07__SAI1_TX_DATA             0x0200 0x048c 0x0000 6 0
+#define MX6UL_PAD_CSI_DATA07__USDHC1_VSELECT           0x0200 0x048c 0x0000 8 0
 
 #endif /* __DTS_IMX6UL_PINFUNC_H */
index 99b6465..7177899 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <dt-bindings/clock/imx6ul-clock.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include "imx6ul-pinfunc.h"
 #include "skeleton.dtsi"
                        reg = <0x00900000 0x20000>;
                };
 
+               dma_apbh: dma-apbh@01804000 {
+                       compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh";
+                       reg = <0x01804000 0x2000>;
+                       interrupts = <0 13 IRQ_TYPE_LEVEL_HIGH>,
+                                    <0 13 IRQ_TYPE_LEVEL_HIGH>,
+                                    <0 13 IRQ_TYPE_LEVEL_HIGH>,
+                                    <0 13 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "gpmi0", "gpmi1", "gpmi2", "gpmi3";
+                       #dma-cells = <1>;
+                       dma-channels = <4>;
+                       clocks = <&clks IMX6UL_CLK_APBHDMA>;
+               };
+
+               gpmi: gpmi-nand@01806000         {
+                       compatible = "fsl,imx6q-gpmi-nand";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x01806000 0x2000>, <0x01808000 0x2000>;
+                       reg-names = "gpmi-nand", "bch";
+                       interrupts = <0 15 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "bch";
+                       clocks = <&clks IMX6UL_CLK_GPMI_IO>,
+                                <&clks IMX6UL_CLK_GPMI_APB>,
+                                <&clks IMX6UL_CLK_GPMI_BCH>,
+                                <&clks IMX6UL_CLK_GPMI_BCH_APB>,
+                                <&clks IMX6UL_CLK_PER_BCH>;
+                       clock-names = "gpmi_io", "gpmi_apb", "gpmi_bch",
+                                     "gpmi_bch_apb", "per1_bch";
+                       dmas = <&dma_apbh 0>;
+                       dma-names = "rx-tx";
+                       status = "disabled";
+               };
+
                aips1: aips-bus@02000000 {
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                                        clock-names = "ipg", "per";
                                        status = "disabled";
                                };
+
+                               sai1: sai@02028000 {
+                                       #sound-dai-cells = <0>;
+                                       compatible = "fsl,imx6ul-sai", "fsl,imx6sx-sai";
+                                       reg = <0x02028000 0x4000>;
+                                       interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+                                       clocks = <&clks IMX6UL_CLK_SAI1_IPG>,
+                                                <&clks IMX6UL_CLK_SAI1>,
+                                                <&clks IMX6UL_CLK_DUMMY>, <&clks IMX6UL_CLK_DUMMY>;
+                                       clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                                       dmas = <&sdma 35 24 0>,
+                                              <&sdma 36 24 0>;
+                                       dma-names = "rx", "tx";
+                                       status = "disabled";
+                               };
+
+                               sai2: sai@0202c000 {
+                                       #sound-dai-cells = <0>;
+                                       compatible = "fsl,imx6ul-sai", "fsl,imx6sx-sai";
+                                       reg = <0x0202c000 0x4000>;
+                                       interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+                                       clocks = <&clks IMX6UL_CLK_SAI2_IPG>,
+                                                <&clks IMX6UL_CLK_SAI2>,
+                                                <&clks IMX6UL_CLK_DUMMY>, <&clks IMX6UL_CLK_DUMMY>;
+                                       clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                                       dmas = <&sdma 37 24 0>,
+                                              <&sdma 38 24 0>;
+                                       dma-names = "rx", "tx";
+                                       status = "disabled";
+                               };
+
+                               sai3: sai@02030000 {
+                                       #sound-dai-cells = <0>;
+                                       compatible = "fsl,imx6ul-sai", "fsl,imx6sx-sai";
+                                       reg = <0x02030000 0x4000>;
+                                       interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+                                       clocks = <&clks IMX6UL_CLK_SAI3_IPG>,
+                                                <&clks IMX6UL_CLK_SAI3>,
+                                                <&clks IMX6UL_CLK_DUMMY>, <&clks IMX6UL_CLK_DUMMY>;
+                                       clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                                       dmas = <&sdma 39 24 0>,
+                                              <&sdma 40 24 0>;
+                                       dma-names = "rx", "tx";
+                                       status = "disabled";
+                               };
+                       };
+
+                       tsc: tsc@02040000 {
+                               compatible = "fsl,imx6ul-tsc";
+                               reg = <0x02040000 0x4000>, <0x0219c000 0x4000>;
+                               interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_IPG>,
+                                        <&clks IMX6UL_CLK_ADC2>;
+                               clock-names = "tsc", "adc";
+                               status = "disabled";
+                       };
+
+                       pwm1: pwm@02080000 {
+                               compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
+                               reg = <0x02080000 0x4000>;
+                               interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_PWM1>,
+                                        <&clks IMX6UL_CLK_PWM1>;
+                               clock-names = "ipg", "per";
+                               #pwm-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       pwm2: pwm@02084000 {
+                               compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
+                               reg = <0x02084000 0x4000>;
+                               interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_PWM2>,
+                                        <&clks IMX6UL_CLK_PWM2>;
+                               clock-names = "ipg", "per";
+                               #pwm-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       pwm3: pwm@02088000 {
+                               compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
+                               reg = <0x02088000 0x4000>;
+                               interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_PWM3>,
+                                        <&clks IMX6UL_CLK_PWM3>;
+                               clock-names = "ipg", "per";
+                               #pwm-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       pwm4: pwm@0208c000 {
+                               compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
+                               reg = <0x0208c000 0x4000>;
+                               interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_PWM4>,
+                                        <&clks IMX6UL_CLK_PWM4>;
+                               clock-names = "ipg", "per";
+                               #pwm-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       can1: flexcan@02090000 {
+                               compatible = "fsl,imx6ul-flexcan", "fsl,imx6q-flexcan";
+                               reg = <0x02090000 0x4000>;
+                               interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_CAN1_IPG>,
+                                        <&clks IMX6UL_CLK_CAN1_SERIAL>;
+                               clock-names = "ipg", "per";
+                               status = "disabled";
+                       };
+
+                       can2: flexcan@02094000 {
+                               compatible = "fsl,imx6ul-flexcan", "fsl,imx6q-flexcan";
+                               reg = <0x02094000 0x4000>;
+                               interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_CAN2_IPG>,
+                                        <&clks IMX6UL_CLK_CAN2_SERIAL>;
+                               clock-names = "ipg", "per";
+                               status = "disabled";
                        };
 
                        gpt1: gpt@02098000 {
                                status = "disabled";
                        };
 
+                       kpp: kpp@020b8000 {
+                               compatible = "fsl,imx6ul-kpp", "fsl,imx6q-kpp", "fsl,imx21-kpp";
+                               reg = <0x020b8000 0x4000>;
+                               interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_KPP>;
+                               status = "disabled";
+                       };
+
                        wdog1: wdog@020bc000 {
                                compatible = "fsl,imx6ul-wdt", "fsl,imx21-wdt";
                                reg = <0x020bc000 0x4000>;
                                compatible = "fsl,imx6ul-gpt", "fsl,imx6sx-gpt";
                                reg = <0x020e8000 0x4000>;
                                interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6UL_CLK_DUMMY>,
-                                        <&clks IMX6UL_CLK_DUMMY>;
+                               clocks = <&clks IMX6UL_CLK_GPT2_BUS>,
+                                        <&clks IMX6UL_CLK_GPT2_SERIAL>;
                                clock-names = "ipg", "per";
                        };
 
+                       sdma: sdma@020ec000 {
+                               compatible = "fsl,imx6ul-sdma", "fsl,imx6q-sdma",
+                                            "fsl,imx35-sdma";
+                               reg = <0x020ec000 0x4000>;
+                               interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_SDMA>,
+                                        <&clks IMX6UL_CLK_SDMA>;
+                               clock-names = "ipg", "ahb";
+                               #dma-cells = <3>;
+                               fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin";
+                       };
+
                        pwm5: pwm@020f0000 {
                                compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
                                reg = <0x020f0000 0x4000>;
                                interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6UL_CLK_DUMMY>,
-                                        <&clks IMX6UL_CLK_DUMMY>;
+                               clocks = <&clks IMX6UL_CLK_PWM5>,
+                                        <&clks IMX6UL_CLK_PWM5>;
                                clock-names = "ipg", "per";
                                #pwm-cells = <2>;
+                               status = "disabled";
                        };
 
                        pwm6: pwm@020f4000 {
                                compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
                                reg = <0x020f4000 0x4000>;
                                interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6UL_CLK_DUMMY>,
-                                        <&clks IMX6UL_CLK_DUMMY>;
+                               clocks = <&clks IMX6UL_CLK_PWM6>,
+                                        <&clks IMX6UL_CLK_PWM6>;
                                clock-names = "ipg", "per";
                                #pwm-cells = <2>;
+                               status = "disabled";
                        };
 
                        pwm7: pwm@020f8000 {
                                compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
                                reg = <0x020f8000 0x4000>;
                                interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6UL_CLK_DUMMY>,
-                                        <&clks IMX6UL_CLK_DUMMY>;
+                               clocks = <&clks IMX6UL_CLK_PWM7>,
+                                        <&clks IMX6UL_CLK_PWM7>;
                                clock-names = "ipg", "per";
                                #pwm-cells = <2>;
+                               status = "disabled";
                        };
 
                        pwm8: pwm@020fc000 {
                                compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
                                reg = <0x020fc000 0x4000>;
                                interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6UL_CLK_DUMMY>,
-                                        <&clks IMX6UL_CLK_DUMMY>;
+                               clocks = <&clks IMX6UL_CLK_PWM8>,
+                                        <&clks IMX6UL_CLK_PWM8>;
                                clock-names = "ipg", "per";
                                #pwm-cells = <2>;
+                               status = "disabled";
                        };
                };
 
                                status = "disabled";
                        };
 
-                       tsc: tsc@02040000 {
-                               compatible = "fsl,imx6ul-tsc";
-                               reg = <0x02040000 0x4000>, <0x0219c000 0x4000>;
-                               interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
-                                            <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6UL_CLK_IPG>,
-                                        <&clks IMX6UL_CLK_ADC2>;
-                               clock-names = "tsc", "adc";
-                               status = "disabled";
-                       };
-
                        usdhc1: usdhc@02190000 {
                                compatible = "fsl,imx6ul-usdhc", "fsl,imx6sx-usdhc";
                                reg = <0x02190000 0x4000>;
                                reg = <0x021b0000 0x4000>;
                        };
 
+                       lcdif: lcdif@021c8000 {
+                               compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif";
+                               reg = <0x021c8000 0x4000>;
+                               interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,
+                                        <&clks IMX6UL_CLK_LCDIF_APB>,
+                                        <&clks IMX6UL_CLK_DUMMY>;
+                               clock-names = "pix", "axi", "disp_axi";
+                               status = "disabled";
+                       };
+
                        qspi: qspi@021e0000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
index d63c597..f8a8685 100644 (file)
@@ -22,7 +22,7 @@
        pinctrl-0 = <&pinctrl_usdhc1>;
        cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
-       enable-sdio-wakeup;
+       wakeup-source;
        status = "okay";
 };
 
index b2c4536..b267f79 100644 (file)
        pinctrl-0 = <&pinctrl_usdhc1>;
        cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
-       enable-sdio-wakeup;
+       wakeup-source;
        keep-power-in-suspend;
        status = "okay";
 };
index 25ad309..b5a50e0 100644 (file)
                clock-output-names = "osc";
        };
 
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               interrupt-parent = <&intc>;
+       };
+
        etr@30086000 {
                compatible = "arm,coresight-tmc", "arm,primecell";
                reg = <0x30086000 0x1000>;
index ecf12dc..726372d 100644 (file)
                        dr_mode = "host";
                        snps,quirk-frame-length-adjustment = <0x20>;
                };
+
+               pcie@3400000 {
+                       compatible = "fsl,ls1021a-pcie", "snps,dw-pcie";
+                       reg = <0x00 0x03400000 0x0 0x00010000   /* controller registers */
+                              0x40 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+                       interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
+                       fsl,pcie-scfg = <&scfg 0>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       num-lanes = <4>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic GIC_SPI 91  IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 2 &gic GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 3 &gic GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 4 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               pcie@3500000 {
+                       compatible = "fsl,ls1021a-pcie", "snps,dw-pcie";
+                       reg = <0x00 0x03500000 0x0 0x00010000   /* controller registers */
+                              0x48 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+                       interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+                       fsl,pcie-scfg = <&scfg 1>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       num-lanes = <4>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic GIC_SPI 92  IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 2 &gic GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 3 &gic GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0000 0 0 4 &gic GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+               };
        };
 };
index ea9301a..61a0955 100644 (file)
 /include/ "skeleton.dtsi"
 
 / {
+       clocks {
+               refclk: ref {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+               };
+       };
+
        soc: soc {
                compatible = "simple-bus";
                #address-cells = <1>;
                ranges;
                interrupt-parent = <&intc>;
 
-               extbus: extbus {
-                       compatible = "simple-bus";
-                       #address-cells = <2>;
-                       #size-cells = <1>;
-               };
-
                serial0: serial@54006800 {
                        compatible = "socionext,uniphier-uart";
                        status = "disabled";
                        clocks = <&uart_clk>;
                };
 
-               system-bus-controller@58c00000 {
-                       compatible = "socionext,uniphier-system-bus-controller";
-                       reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
+               system_bus: system-bus@58c00000 {
+                       compatible = "socionext,uniphier-system-bus";
+                       status = "disabled";
+                       reg = <0x58c00000 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+               };
+
+               smpctrl@59800000 {
+                       compatible = "socionext,uniphier-smpctrl";
+                       reg = <0x59801000 0x400>;
                };
 
                timer@60000200 {
index f1e9d40..ec94b7a 100644 (file)
        };
 };
 
-&extbus {
-       ranges = <1 0x00000000 0x42000000 0x02000000>;
-};
-
-&support_card {
-       ranges = <0x00000000 1 0x01f00000 0x00100000>;
-};
-
 &ethsc {
        interrupts = <0 49 4>;
 };
index 34f0d8d..dadd860 100644 (file)
 
 };
 
+&refclk {
+       clock-frequency = <24576000>;
+};
+
 &serial3 {
        interrupts = <0 29 4>;
 };
index 5baa9fc..b8134c6 100644 (file)
        };
 };
 
-&extbus {
-       ranges = <1 0x00000000 0x42000000 0x02000000>;
-};
-
-&support_card {
-       ranges = <0x00000000 1 0x01f00000 0x00100000>;
-};
-
 &ethsc {
        interrupts = <0 52 4>;
 };
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4-ace.dts b/arch/arm/boot/dts/uniphier-ph1-pro4-ace.dts
new file mode 100644 (file)
index 0000000..d343586
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Device Tree Source for UniPhier PH1-Pro4 Ace Board
+ *
+ * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "uniphier-ph1-pro4.dtsi"
+
+/ {
+       model = "UniPhier PH1-Pro4 Ace Board";
+       compatible = "socionext,ph1-pro4-ace", "socionext,ph1-pro4";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x40000000>;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       aliases {
+               serial0 = &serial0;
+               serial1 = &serial1;
+               serial2 = &serial2;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+               i2c5 = &i2c5;
+               i2c6 = &i2c6;
+       };
+};
+
+&serial0 {
+       status = "okay";
+};
+
+&serial1 {
+       status = "okay";
+};
+
+&serial2 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+
+       eeprom@54 {
+               compatible = "st,24c64";
+               reg = <0x54>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+};
+
+&usb2 {
+       status = "okay";
+};
+
+&usb3 {
+       status = "okay";
+};
index 2462668..95f631a 100644 (file)
        };
 };
 
-&extbus {
-       ranges = <1 0x00000000 0x42000000 0x02000000>;
-};
-
-&support_card {
-       ranges = <0x00000000 1 0x01f00000 0x00100000>;
-};
-
 &ethsc {
        interrupts = <0 50 4>;
 };
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4-sanji.dts b/arch/arm/boot/dts/uniphier-ph1-pro4-sanji.dts
new file mode 100644 (file)
index 0000000..7c3a1fc
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Device Tree Source for UniPhier PH1-Pro4 Sanji Board
+ *
+ * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "uniphier-ph1-pro4.dtsi"
+
+/ {
+       model = "UniPhier PH1-Pro4 Sanji Board";
+       compatible = "socionext,ph1-pro4-sanji", "socionext,ph1-pro4";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x80000000>;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       aliases {
+               serial0 = &serial0;
+               serial1 = &serial1;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+               i2c5 = &i2c5;
+               i2c6 = &i2c6;
+       };
+};
+
+&serial0 {
+       status = "okay";
+};
+
+&serial1 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+
+       eeprom@54 {
+               compatible = "st,24c64";
+               reg = <0x54>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+};
+
+&usb2 {
+       status = "okay";
+};
+
+&usb3 {
+       status = "okay";
+};
index d78142f..20f3f2a 100644 (file)
        };
 };
 
+&refclk {
+       clock-frequency = <25000000>;
+};
+
 &pinctrl {
        compatible = "socionext,ph1-pro4-pinctrl", "syscon";
 };
index 2f389ea..24f6f66 100644 (file)
        };
 };
 
+&refclk {
+       clock-frequency = <20000000>;
+};
+
 &pinctrl {
        compatible = "socionext,ph1-pro5-pinctrl", "syscon";
 };
index b7a0321..acb4204 100644 (file)
        };
 };
 
-&extbus {
-       ranges = <1 0x00000000 0x42000000 0x02000000>;
-};
-
-&support_card {
-       ranges = <0x00000000 1 0x01f00000 0x00100000>;
-};
-
 &ethsc {
        interrupts = <0 49 4>;
 };
index 691a17d..03292f4 100644 (file)
        };
 
        clocks {
+               refclk: ref {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <24576000>;
+               };
+
                arm_timer_clk: arm_timer_clk {
                        #clock-cells = <0>;
                        compatible = "fixed-clock";
                ranges;
                interrupt-parent = <&intc>;
 
-               extbus: extbus {
-                       compatible = "simple-bus";
-                       #address-cells = <2>;
-                       #size-cells = <1>;
-               };
-
                timer@20000200 {
                        compatible = "arm,cortex-a9-global-timer";
                        reg = <0x20000200 0x20>;
                        clock-frequency = <400000>;
                };
 
-               system-bus-controller@58c00000 {
-                       compatible = "socionext,uniphier-system-bus-controller";
-                       reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
+               system_bus: system-bus@58c00000 {
+                       compatible = "socionext,uniphier-system-bus";
+                       status = "disabled";
+                       reg = <0x58c00000 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+               };
+
+               smpctrl@59800000 {
+                       compatible = "socionext,uniphier-smpctrl";
+                       reg = <0x59801000 0x400>;
                };
 
                usb0: usb@5a800100 {
index fc7250c..d594f40 100644 (file)
        };
 };
 
-&extbus {
-       ranges = <1 0x00000000 0x42000000 0x02000000>;
-};
-
-&support_card {
-       ranges = <0x00000000 1 0x01f00000 0x00100000>;
-};
-
 &ethsc {
        interrupts = <0 48 4>;
 };
index 7d06a1c..6bfd29a 100644 (file)
        };
 };
 
+&refclk {
+       clock-frequency = <25000000>;
+};
+
 &serial3 {
        interrupts = <0 29 4>;
 };
index f67445f..2459279 100644 (file)
                function = "i2c3";
        };
 
+       pinctrl_i2c4: i2c4_grp {
+               groups = "i2c4";
+               function = "i2c4";
+       };
+
        pinctrl_uart0: uart0_grp {
                groups = "uart0";
                function = "uart0";
index 9d7ec5c..bf2619e 100644 (file)
@@ -63,6 +63,7 @@
                serial1 = &serial1;
                serial2 = &serial2;
                i2c0 = &i2c0;
+               i2c2 = &i2c2;
                i2c4 = &i2c4;
                i2c5 = &i2c5;
                i2c6 = &i2c6;
 
 &i2c0 {
        status = "okay";
+
+       eeprom@54 {
+               compatible = "st,24c64";
+               reg = <0x54>;
+       };
+};
+
+&i2c2 {
+       status = "okay";
 };
index 6bd353f..4ac484c 100644 (file)
        };
 };
 
+&refclk {
+       clock-frequency = <25000000>;
+};
+
 &pinctrl {
        compatible = "socionext,proxstream2-pinctrl", "syscon";
 };
index 3d29d28..f7df088 100644 (file)
@@ -43,7 +43,7 @@
  */
 
 &i2c0 {
-       eeprom {
+       eeprom@50 {
                compatible = "microchip,24lc128";
                reg = <0x50>;
        };
index da271e3..51ecc9b 100644 (file)
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-&extbus {
+&system_bus {
+       status = "okay";
+       ranges = <1 0x00000000 0x42000000 0x02000000>;
+
        support_card: support_card {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
+               ranges = <0x00000000 1 0x01f00000 0x00100000>;
 
                ethsc: ethernet@00000000 {
                        compatible = "smsc,lan9118", "smsc,lan9115";
index ed65e0f..4d8b7f6 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2014 Toradex AG
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 / {
                clock-frequency = <16000000>;
        };
 
-       regulators {
-               compatible = "simple-bus";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               sys_5v0_reg: regulator@0 {
-                       compatible = "regulator-fixed";
-                       reg = <0>;
-                       regulator-name = "5v0";
-                       regulator-min-microvolt = <5000000>;
-                       regulator-max-microvolt = <5000000>;
-                       regulator-always-on;
-               };
+       reg_3v3: regulator-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "3.3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
 
-               /* USBH_PEN */
-               usbh_vbus_reg: regulator@1 {
-                       compatible = "regulator-fixed";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_usbh1_reg>;
-                       reg = <1>;
-                       regulator-name = "usbh_vbus";
-                       regulator-min-microvolt = <5000000>;
-                       regulator-max-microvolt = <5000000>;
-                       gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
-                       vin-supply = <&sys_5v0_reg>;
-               };
+       reg_5v0: regulator-5v0 {
+               compatible = "regulator-fixed";
+               regulator-name = "5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       reg_usbh_vbus: regulator-usbh-vbus {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbh1_reg>;
+               regulator-name = "VCC_USB[1-4]";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio2 19 GPIO_ACTIVE_LOW>; /* USBH_PEN resp. USBH_P_EN */
+               vin-supply = <&reg_5v0>;
        };
 };
 
 &bl {
        brightness-levels = <0 4 8 16 32 64 128 255>;
        default-brightness-level = <6>;
+       power-supply = <&reg_3v3>;
        status  = "okay";
 };
 
        status = "okay";
 };
 
+&reg_module_3v3 {
+       vin-supply = <&reg_3v3>;
+};
+
 &uart0 {
        status = "okay";
 };
 };
 
 &usbh1 {
-       vbus-supply = <&usbh_vbus_reg>;
+       vbus-supply = <&reg_usbh_vbus>;
 };
 
 &iomuxc {
index 6e556be..fda7f28 100644 (file)
@@ -1,26 +1,77 @@
 /*
  * Copyright 2014 Toradex AG
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 / {
        bl: backlight {
                compatible = "pwm-backlight";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_bl_on>;
                pwms = <&pwm0 0 5000000 0>;
+               enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
                status = "disabled";
        };
+
+       reg_module_3v3: regulator-module-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "+V3.3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       reg_module_3v3_avdd: regulator-module-3v3-avdd {
+               compatible = "regulator-fixed";
+               regulator-name = "+V3.3_AVDD_AUDIO";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
 };
 
 &adc0 {
        status = "okay";
+       vref-supply = <&reg_module_3v3_avdd>;
 };
 
 &adc1 {
        status = "okay";
+       vref-supply = <&reg_module_3v3_avdd>;
 };
 
 &can0 {
        status = "disabled";
 };
 
+&clks {
+       assigned-clocks = <&clks VF610_CLK_ENET_SEL>,
+                         <&clks VF610_CLK_ENET_TS_SEL>;
+       assigned-clock-parents = <&clks VF610_CLK_ENET_50M>,
+                                <&clks VF610_CLK_ENET_50M>;
+};
+
 &dspi1 {
        bus-num = <1>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
        bus-width = <4>;
        cd-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+       disable-wp;
 };
 
 &fec1 {
        phy-mode = "rmii";
+       phy-supply = <&reg_module_3v3>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec1>;
 };
                        >;
                };
 
+               pinctrl_gpio_bl_on: gpio_bl_on {
+                       fsl,pins = <
+                               VF610_PAD_PTC0__GPIO_45         0x22ef
+                       >;
+               };
+
                pinctrl_i2c0: i2c0grp {
                        fsl,pins = <
                                VF610_PAD_PTB14__I2C0_SCL               0x37ff
                        fsl,pins = <
                                VF610_PAD_PTB10__UART0_TX               0x21a2
                                VF610_PAD_PTB11__UART0_RX               0x21a1
+                               VF610_PAD_PTB12__UART0_RTS              0x21a2
+                               VF610_PAD_PTB13__UART0_CTS              0x21a1
                        >;
                };
 
index c3173fc..b3aeab5 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2014 Toradex AG
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
index 84f091d..3fe1f48 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2014 Toradex AG
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "vf500.dtsi"
index e976d2f..9d37272 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2013 Freescale Semiconductor, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "skeleton.dtsi"
                                clocks = <&clks VF610_CLK_PLATFORM_BUS>;
                        };
                };
+
+               aips-bus@40080000 {
+                       pmu@40089000 {
+                               compatible = "arm,cortex-a5-pmu";
+                               interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-affinity = <&a5_cpu>;
+                       };
+               };
+
        };
 };
 
index 10ebe99..dbca4f8 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2014 Toradex AG
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
@@ -14,4 +46,4 @@
 / {
        model = "Toradex Colibri VF61 on Colibri Evaluation Board";
        compatible = "toradex,vf610-colibri_vf61-on-eval", "toradex,vf610-colibri_vf61", "fsl,vf610";
-};
\ No newline at end of file
+};
index 2d7eab7..ab4a29f 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2014 Toradex AG
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "vf610.dtsi"
index 5438ee4..cdc1007 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2013 Freescale Semiconductor, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
 &clks {
        clocks = <&sxosc>, <&fxosc>, <&enet_ext>, <&audio_ext>;
        clock-names = "sxosc", "fxosc", "enet_ext", "audio_ext";
+       assigned-clocks = <&clks VF610_CLK_ENET_SEL>,
+                         <&clks VF610_CLK_ENET_TS_SEL>;
+       assigned-clock-parents = <&clks VF610_CLK_ENET_EXT>,
+                                <&clks VF610_CLK_ENET_EXT>;
 };
 
 &dspi0 {
index 58bc6e4..0cfc060 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2013 Freescale Semiconductor, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "vf500.dtsi"
index 4539f8d..5c09754 100644 (file)
@@ -1,10 +1,42 @@
 /*
  * Copyright 2013 Freescale Semiconductor, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 as published by the Free Software Foundation.
+ *
+ *     This file is distributed in the hope that it will be useful
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "vf610-pinfunc.h"
@@ -16,6 +48,8 @@
        aliases {
                can0 = &can0;
                can1 = &can1;
+               ethernet0 = &fec0;
+               ethernet1 = &fec1;
                serial0 = &uart0;
                serial1 = &uart1;
                serial2 = &uart2;
                                status = "disabled";
                        };
 
+                       sai0: sai@4002f000 {
+                               compatible = "fsl,vf610-sai";
+                               reg = <0x4002f000 0x1000>;
+                               interrupts = <84 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks VF610_CLK_SAI0>,
+                                       <&clks VF610_CLK_SAI0_DIV>,
+                                       <&clks 0>, <&clks 0>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dma-names = "tx", "rx";
+                               dmas = <&edma0 0 17>,
+                                       <&edma0 0 16>;
+                               status = "disabled";
+                       };
+
+                       sai1: sai@40030000 {
+                               compatible = "fsl,vf610-sai";
+                               reg = <0x40030000 0x1000>;
+                               interrupts = <85 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks VF610_CLK_SAI1>,
+                                       <&clks VF610_CLK_SAI1_DIV>,
+                                       <&clks 0>, <&clks 0>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dma-names = "tx", "rx";
+                               dmas = <&edma0 0 19>,
+                                       <&edma0 0 18>;
+                               status = "disabled";
+                       };
+
                        sai2: sai@40031000 {
                                compatible = "fsl,vf610-sai";
                                reg = <0x40031000 0x1000>;
                                status = "disabled";
                        };
 
+                       sai3: sai@40032000 {
+                               compatible = "fsl,vf610-sai";
+                               reg = <0x40032000 0x1000>;
+                               interrupts = <87 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks VF610_CLK_SAI3>,
+                                       <&clks VF610_CLK_SAI3_DIV>,
+                                       <&clks 0>, <&clks 0>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dma-names = "tx", "rx";
+                               dmas = <&edma0 1 9>,
+                                       <&edma0 1 8>;
+                               status = "disabled";
+                       };
+
                        pit: pit@40037000 {
                                compatible = "fsl,vf610-pit";
                                reg = <0x40037000 0x1000>;
                                status = "disabled";
                        };
 
+                       dac0: dac@400cc000 {
+                               compatible = "fsl,vf610-dac";
+                               reg = <0x400cc000 1000>;
+                               interrupts = <55 IRQ_TYPE_LEVEL_HIGH>;
+                               clock-names = "dac";
+                               clocks = <&clks VF610_CLK_DAC0>;
+                               status = "disabled";
+                       };
+
+                       dac1: dac@400cd000 {
+                               compatible = "fsl,vf610-dac";
+                               reg = <0x400cd000 1000>;
+                               interrupts = <56 IRQ_TYPE_LEVEL_HIGH>;
+                               clock-names = "dac";
+                               clocks = <&clks VF610_CLK_DAC1>;
+                               status = "disabled";
+                       };
+
                        fec0: ethernet@400d0000 {
                                compatible = "fsl,mvf600-fec";
                                reg = <0x400d0000 0x1000>;
index 5abaf5b..bf19912 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef __ASM_ARM_EXCEPTION_H
 #define __ASM_ARM_EXCEPTION_H
 
-#include <linux/ftrace.h>
+#include <linux/interrupt.h>
 
 #define __exception    __attribute__((section(".exception.text")))
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
index d1b162a..503f488 100644 (file)
@@ -17,9 +17,6 @@
 #define KTHREAD_SIZE PAGE_SIZE
 #endif
  
-#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)     free_page(addr)
-
 #define clear_page(page)       memset((page), 0, PAGE_SIZE)
 #define copy_page(to,from)     memcpy((to), (from), PAGE_SIZE)
 
index 1fab979..e2c6da0 100644 (file)
@@ -108,6 +108,7 @@ SECTIONS
                        *(.exception.text)
                        __exception_text_end = .;
                        IRQENTRY_TEXT
+                       SOFTIRQENTRY_TEXT
                        TEXT_TEXT
                        SCHED_TEXT
                        LOCK_TEXT
index b53d4ff..84baa16 100644 (file)
@@ -727,15 +727,6 @@ static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set)
                        return -ENOMEM;
        }
 
-       if (set->ecc_layout) {
-               ptr = kmemdup(set->ecc_layout,
-                             sizeof(struct nand_ecclayout), GFP_KERNEL);
-               set->ecc_layout = ptr;
-
-               if (!ptr)
-                       return -ENOMEM;
-       }
-
        return 0;
 }
 
index 8d72771..299b67e 100644 (file)
@@ -1,4 +1,4 @@
-dtb-$(CONFIG_ARCH_UNIPHIER) += uniphier-ph1-ld10-ref.dtb
+dtb-$(CONFIG_ARCH_UNIPHIER) += uniphier-ph1-ld20-ref.dtb
 
 always         := $(dtb-y)
 clean-files    := *.dtb
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10-ref.dts b/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10-ref.dts
deleted file mode 100644 (file)
index 3e53317..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Device Tree Source for UniPhier PH1-LD10 Reference Board
- *
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/dts-v1/;
-/include/ "uniphier-ph1-ld10.dtsi"
-/include/ "uniphier-support-card.dtsi"
-
-/ {
-       model = "UniPhier PH1-LD10 Reference Board";
-       compatible = "socionext,ph1-ld10-ref", "socionext,ph1-ld10";
-
-       memory {
-               device_type = "memory";
-               reg = <0 0x80000000 0 0xc0000000>;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       aliases {
-               serial0 = &serial0;
-               serial1 = &serial1;
-               serial2 = &serial2;
-               serial3 = &serial3;
-               i2c0 = &i2c0;
-               i2c1 = &i2c1;
-               i2c2 = &i2c2;
-               i2c3 = &i2c3;
-               i2c4 = &i2c4;
-               i2c5 = &i2c5;
-               i2c6 = &i2c6;
-       };
-};
-
-&extbus {
-       ranges = <1 0x00000000 0x42000000 0x02000000>;
-};
-
-&support_card {
-       ranges = <0x00000000 1 0x01f00000 0x00100000>;
-};
-
-&ethsc {
-       interrupts = <0 48 4>;
-};
-
-&serial0 {
-       status = "okay";
-};
-
-&i2c0 {
-       status = "okay";
-};
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10.dtsi
deleted file mode 100644 (file)
index 0296af9..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Device Tree Source for UniPhier PH1-LD10 SoC
- *
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/ {
-       compatible = "socionext,ph1-ld10";
-       #address-cells = <2>;
-       #size-cells = <2>;
-       interrupt-parent = <&gic>;
-
-       cpus {
-               #address-cells = <2>;
-               #size-cells = <0>;
-
-               cpu-map {
-                       cluster0 {
-                               core0 {
-                                       cpu = <&cpu0>;
-                               };
-                               core1 {
-                                       cpu = <&cpu1>;
-                               };
-                       };
-
-                       cluster1 {
-                               core0 {
-                                       cpu = <&cpu2>;
-                               };
-                               core1 {
-                                       cpu = <&cpu3>;
-                               };
-                       };
-               };
-
-               cpu0: cpu@0 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a72", "arm,armv8";
-                       reg = <0 0x000>;
-                       enable-method = "spin-table";
-                       cpu-release-addr = <0 0x80000100>;
-               };
-
-               cpu1: cpu@1 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a72", "arm,armv8";
-                       reg = <0 0x001>;
-                       enable-method = "spin-table";
-                       cpu-release-addr = <0 0x80000100>;
-               };
-
-               cpu2: cpu@100 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53", "arm,armv8";
-                       reg = <0 0x100>;
-                       enable-method = "spin-table";
-                       cpu-release-addr = <0 0x80000100>;
-               };
-
-               cpu3: cpu@101 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53", "arm,armv8";
-                       reg = <0 0x101>;
-                       enable-method = "spin-table";
-                       cpu-release-addr = <0 0x80000100>;
-               };
-       };
-
-       clocks {
-               uart_clk: uart_clk {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <58820000>;
-               };
-
-               i2c_clk: i2c_clk {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <50000000>;
-               };
-       };
-
-       timer {
-               compatible = "arm,armv8-timer";
-               interrupts = <1 13 0xf01>,
-                            <1 14 0xf01>,
-                            <1 11 0xf01>,
-                            <1 10 0xf01>;
-       };
-
-       soc {
-               compatible = "simple-bus";
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0 0 0xffffffff>;
-
-               extbus: extbus {
-                       compatible = "simple-bus";
-                       #address-cells = <2>;
-                       #size-cells = <1>;
-               };
-
-               serial0: serial@54006800 {
-                       compatible = "socionext,uniphier-uart";
-                       status = "disabled";
-                       reg = <0x54006800 0x40>;
-                       interrupts = <0 33 4>;
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_uart0>;
-                       clocks = <&uart_clk>;
-               };
-
-               serial1: serial@54006900 {
-                       compatible = "socionext,uniphier-uart";
-                       status = "disabled";
-                       reg = <0x54006900 0x40>;
-                       interrupts = <0 35 4>;
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_uart1>;
-                       clocks = <&uart_clk>;
-               };
-
-               serial2: serial@54006a00 {
-                       compatible = "socionext,uniphier-uart";
-                       status = "disabled";
-                       reg = <0x54006a00 0x40>;
-                       interrupts = <0 37 4>;
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_uart2>;
-                       clocks = <&uart_clk>;
-               };
-
-               serial3: serial@54006b00 {
-                       compatible = "socionext,uniphier-uart";
-                       status = "disabled";
-                       reg = <0x54006b00 0x40>;
-                       interrupts = <0 177 4>;
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_uart3>;
-                       clocks = <&uart_clk>;
-               };
-
-               i2c0: i2c@58780000 {
-                       compatible = "socionext,uniphier-fi2c";
-                       status = "disabled";
-                       reg = <0x58780000 0x80>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <0 41 4>;
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_i2c0>;
-                       clocks = <&i2c_clk>;
-                       clock-frequency = <100000>;
-               };
-
-               i2c1: i2c@58781000 {
-                       compatible = "socionext,uniphier-fi2c";
-                       status = "disabled";
-                       reg = <0x58781000 0x80>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <0 42 4>;
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_i2c1>;
-                       clocks = <&i2c_clk>;
-                       clock-frequency = <100000>;
-               };
-
-               i2c2: i2c@58782000 {
-                       compatible = "socionext,uniphier-fi2c";
-                       status = "disabled";
-                       reg = <0x58782000 0x80>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <0 43 4>;
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_i2c2>;
-                       clocks = <&i2c_clk>;
-                       clock-frequency = <100000>;
-               };
-
-               i2c3: i2c@58783000 {
-                       compatible = "socionext,uniphier-fi2c";
-                       status = "disabled";
-                       reg = <0x58783000 0x80>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <0 44 4>;
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_i2c3>;
-                       clocks = <&i2c_clk>;
-                       clock-frequency = <100000>;
-               };
-
-               i2c4: i2c@58784000 {
-                       compatible = "socionext,uniphier-fi2c";
-                       reg = <0x58784000 0x80>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <0 45 4>;
-                       clocks = <&i2c_clk>;
-                       clock-frequency = <400000>;
-               };
-
-               i2c5: i2c@58785000 {
-                       compatible = "socionext,uniphier-fi2c";
-                       reg = <0x58785000 0x80>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <0 25 4>;
-                       clocks = <&i2c_clk>;
-                       clock-frequency = <400000>;
-               };
-
-               i2c6: i2c@58786000 {
-                       compatible = "socionext,uniphier-fi2c";
-                       reg = <0x58786000 0x80>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <0 26 4>;
-                       clocks = <&i2c_clk>;
-                       clock-frequency = <400000>;
-               };
-
-               pinctrl: pinctrl@5f801000 {
-                       compatible = "socionext,ph1-ld10-pinctrl", "syscon";
-                       reg = <0x5f801000 0xe00>;
-               };
-
-               gic: interrupt-controller@5fe00000 {
-                       compatible = "arm,gic-v3";
-                       reg = <0x5fe00000 0x10000>,     /* GICD */
-                             <0x5fe80000 0x80000>;     /* GICR */
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       interrupts = <1 9 4>;
-               };
-       };
-};
-
-/include/ "uniphier-pinctrl.dtsi"
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld20-ref.dts b/arch/arm64/boot/dts/socionext/uniphier-ph1-ld20-ref.dts
new file mode 100644 (file)
index 0000000..727ae5f
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Device Tree Source for UniPhier PH1-LD20 Reference Board
+ *
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "uniphier-ph1-ld20.dtsi"
+/include/ "uniphier-support-card.dtsi"
+
+/ {
+       model = "UniPhier PH1-LD20 Reference Board";
+       compatible = "socionext,ph1-ld20-ref", "socionext,ph1-ld20";
+
+       memory {
+               device_type = "memory";
+               reg = <0 0x80000000 0 0xc0000000>;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       aliases {
+               serial0 = &serial0;
+               serial1 = &serial1;
+               serial2 = &serial2;
+               serial3 = &serial3;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+               i2c4 = &i2c4;
+               i2c5 = &i2c5;
+               i2c6 = &i2c6;
+       };
+};
+
+&ethsc {
+       interrupts = <0 48 4>;
+};
+
+&serial0 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld20.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ph1-ld20.dtsi
new file mode 100644 (file)
index 0000000..e682a3f
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Device Tree Source for UniPhier PH1-LD20 SoC
+ *
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/ {
+       compatible = "socionext,ph1-ld20";
+       #address-cells = <2>;
+       #size-cells = <2>;
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&cpu0>;
+                               };
+                               core1 {
+                                       cpu = <&cpu1>;
+                               };
+                       };
+
+                       cluster1 {
+                               core0 {
+                                       cpu = <&cpu2>;
+                               };
+                               core1 {
+                                       cpu = <&cpu3>;
+                               };
+                       };
+               };
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72", "arm,armv8";
+                       reg = <0 0x000>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0 0x80000100>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72", "arm,armv8";
+                       reg = <0 0x001>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0 0x80000100>;
+               };
+
+               cpu2: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53", "arm,armv8";
+                       reg = <0 0x100>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0 0x80000100>;
+               };
+
+               cpu3: cpu@101 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53", "arm,armv8";
+                       reg = <0 0x101>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0 0x80000100>;
+               };
+       };
+
+       clocks {
+               uart_clk: uart_clk {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <58820000>;
+               };
+
+               i2c_clk: i2c_clk {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <50000000>;
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <1 13 0xf01>,
+                            <1 14 0xf01>,
+                            <1 11 0xf01>,
+                            <1 10 0xf01>;
+       };
+
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0 0 0xffffffff>;
+
+               serial0: serial@54006800 {
+                       compatible = "socionext,uniphier-uart";
+                       status = "disabled";
+                       reg = <0x54006800 0x40>;
+                       interrupts = <0 33 4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_uart0>;
+                       clocks = <&uart_clk>;
+               };
+
+               serial1: serial@54006900 {
+                       compatible = "socionext,uniphier-uart";
+                       status = "disabled";
+                       reg = <0x54006900 0x40>;
+                       interrupts = <0 35 4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_uart1>;
+                       clocks = <&uart_clk>;
+               };
+
+               serial2: serial@54006a00 {
+                       compatible = "socionext,uniphier-uart";
+                       status = "disabled";
+                       reg = <0x54006a00 0x40>;
+                       interrupts = <0 37 4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_uart2>;
+                       clocks = <&uart_clk>;
+               };
+
+               serial3: serial@54006b00 {
+                       compatible = "socionext,uniphier-uart";
+                       status = "disabled";
+                       reg = <0x54006b00 0x40>;
+                       interrupts = <0 177 4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_uart3>;
+                       clocks = <&uart_clk>;
+               };
+
+               i2c0: i2c@58780000 {
+                       compatible = "socionext,uniphier-fi2c";
+                       status = "disabled";
+                       reg = <0x58780000 0x80>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <0 41 4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_i2c0>;
+                       clocks = <&i2c_clk>;
+                       clock-frequency = <100000>;
+               };
+
+               i2c1: i2c@58781000 {
+                       compatible = "socionext,uniphier-fi2c";
+                       status = "disabled";
+                       reg = <0x58781000 0x80>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <0 42 4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_i2c1>;
+                       clocks = <&i2c_clk>;
+                       clock-frequency = <100000>;
+               };
+
+               i2c2: i2c@58782000 {
+                       compatible = "socionext,uniphier-fi2c";
+                       status = "disabled";
+                       reg = <0x58782000 0x80>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <0 43 4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_i2c2>;
+                       clocks = <&i2c_clk>;
+                       clock-frequency = <100000>;
+               };
+
+               i2c3: i2c@58783000 {
+                       compatible = "socionext,uniphier-fi2c";
+                       status = "disabled";
+                       reg = <0x58783000 0x80>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <0 44 4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_i2c3>;
+                       clocks = <&i2c_clk>;
+                       clock-frequency = <100000>;
+               };
+
+               i2c4: i2c@58784000 {
+                       compatible = "socionext,uniphier-fi2c";
+                       reg = <0x58784000 0x80>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <0 45 4>;
+                       clocks = <&i2c_clk>;
+                       clock-frequency = <400000>;
+               };
+
+               i2c5: i2c@58785000 {
+                       compatible = "socionext,uniphier-fi2c";
+                       reg = <0x58785000 0x80>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <0 25 4>;
+                       clocks = <&i2c_clk>;
+                       clock-frequency = <400000>;
+               };
+
+               i2c6: i2c@58786000 {
+                       compatible = "socionext,uniphier-fi2c";
+                       reg = <0x58786000 0x80>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <0 26 4>;
+                       clocks = <&i2c_clk>;
+                       clock-frequency = <400000>;
+               };
+
+               system_bus: system-bus@58c00000 {
+                       compatible = "socionext,uniphier-system-bus";
+                       status = "disabled";
+                       reg = <0x58c00000 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+               };
+
+               smpctrl@59800000 {
+                       compatible = "socionext,uniphier-smpctrl";
+                       reg = <0x59801000 0x400>;
+               };
+
+               pinctrl: pinctrl@5f801000 {
+                       compatible = "socionext,ph1-ld20-pinctrl", "syscon";
+                       reg = <0x5f801000 0xe00>;
+               };
+
+               gic: interrupt-controller@5fe00000 {
+                       compatible = "arm,gic-v3";
+                       reg = <0x5fe00000 0x10000>,     /* GICD */
+                             <0x5fe80000 0x80000>;     /* GICR */
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       interrupts = <1 9 4>;
+               };
+       };
+};
+
+/include/ "uniphier-pinctrl.dtsi"
index f705051..a44ef99 100644 (file)
@@ -68,11 +68,13 @@ CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_CMA=y
 CONFIG_XEN=y
-CONFIG_CMDLINE="console=ttyAMA0"
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_COMPAT=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_ARM_BIG_LITTLE_CPUFREQ=y
+CONFIG_ARM_SCPI_CPUFREQ=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -80,7 +82,6 @@ CONFIG_INET=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 CONFIG_BPF_JIT=y
 # CONFIG_WIRELESS is not set
@@ -144,16 +145,18 @@ CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
 CONFIG_SERIAL_MVEBU_UART=y
 CONFIG_VIRTIO_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
 CONFIG_I2C_MV64XXX=y
 CONFIG_I2C_QUP=y
+CONFIG_I2C_TEGRA=y
 CONFIG_I2C_UNIPHIER_F=y
 CONFIG_I2C_RCAR=y
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_SPI_QUP=y
 CONFIG_SPMI=y
+CONFIG_PINCTRL_SINGLE=y
 CONFIG_PINCTRL_MSM8916=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
@@ -196,6 +199,7 @@ CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC2=y
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_UDC=y
 CONFIG_USB_CHIPIDEA_HOST=y
@@ -205,19 +209,20 @@ CONFIG_USB_MSM_OTG=y
 CONFIG_USB_ULPI=y
 CONFIG_USB_GADGET=y
 CONFIG_MMC=y
-CONFIG_MMC_BLOCK_MINORS=16
+CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_ARMMMCI=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_SDHCI_MSM=y
 CONFIG_MMC_SPI=y
-CONFIG_MMC_SUNXI=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_EXYNOS=y
-CONFIG_MMC_BLOCK_MINORS=16
+CONFIG_MMC_DW_K3=y
+CONFIG_MMC_SUNXI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_SYSCON=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
@@ -229,8 +234,8 @@ CONFIG_RTC_DRV_PL031=y
 CONFIG_RTC_DRV_SUN6I=y
 CONFIG_RTC_DRV_XGENE=y
 CONFIG_DMADEVICES=y
-CONFIG_QCOM_BAM_DMA=y
 CONFIG_TEGRA20_APB_DMA=y
+CONFIG_QCOM_BAM_DMA=y
 CONFIG_RCAR_DMAC=y
 CONFIG_VFIO=y
 CONFIG_VFIO_PCI=y
@@ -239,20 +244,26 @@ CONFIG_VIRTIO_BALLOON=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_XEN_GNTDEV=y
 CONFIG_XEN_GRANT_DEV_ALLOC=y
+CONFIG_COMMON_CLK_SCPI=y
 CONFIG_COMMON_CLK_CS2000_CP=y
 CONFIG_COMMON_CLK_QCOM=y
 CONFIG_MSM_GCC_8916=y
 CONFIG_HWSPINLOCK_QCOM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_MHU=y
+CONFIG_HI6220_MBOX=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
 CONFIG_QCOM_SMD_RPM=y
 CONFIG_ARCH_TEGRA_132_SOC=y
 CONFIG_ARCH_TEGRA_210_SOC=y
-CONFIG_HISILICON_IRQ_MBIGEN=y
 CONFIG_EXTCON_USB_GPIO=y
+CONFIG_COMMON_RESET_HI6220=y
 CONFIG_PHY_RCAR_GEN3_USB2=y
+CONFIG_PHY_HI6220_USB=y
 CONFIG_PHY_XGENE=y
+CONFIG_ARM_SCPI_PROTOCOL=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 CONFIG_FANOTIFY=y
@@ -264,6 +275,7 @@ CONFIG_CUSE=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_HUGETLBFS=y
+CONFIG_CONFIGFS_FS=y
 CONFIG_EFIVAR_FS=y
 CONFIG_SQUASHFS=y
 CONFIG_NFS_FS=y
index 22dda61..c64268d 100644 (file)
@@ -116,13 +116,6 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
-static inline void __local_flush_icache_all(void)
-{
-       asm("ic iallu");
-       dsb(nsh);
-       isb();
-}
-
 static inline void __flush_icache_all(void)
 {
        asm("ic ialluis");
index 6cb7e1a..0c2eec4 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __ASM_EXCEPTION_H
 #define __ASM_EXCEPTION_H
 
-#include <linux/ftrace.h>
+#include <linux/interrupt.h>
 
 #define __exception    __attribute__((section(".exception.text")))
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
index 227ed47..b7e82a7 100644 (file)
@@ -27,7 +27,6 @@
 #include <asm/kvm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
-#include <asm/kvm_perf_event.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
 
index a46b019..44eaff7 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/compiler.h>
 #include <linux/kvm_host.h>
 #include <asm/kvm_mmu.h>
-#include <asm/kvm_perf_event.h>
 #include <asm/sysreg.h>
 
 #define __hyp_text __section(.hyp.text) notrace
diff --git a/arch/arm64/include/asm/kvm_perf_event.h b/arch/arm64/include/asm/kvm_perf_event.h
deleted file mode 100644 (file)
index c18fdeb..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __ASM_KVM_PERF_EVENT_H
-#define __ASM_KVM_PERF_EVENT_H
-
-#define        ARMV8_PMU_MAX_COUNTERS  32
-#define        ARMV8_PMU_COUNTER_MASK  (ARMV8_PMU_MAX_COUNTERS - 1)
-
-/*
- * Per-CPU PMCR: config reg
- */
-#define ARMV8_PMU_PMCR_E       (1 << 0) /* Enable all counters */
-#define ARMV8_PMU_PMCR_P       (1 << 1) /* Reset all counters */
-#define ARMV8_PMU_PMCR_C       (1 << 2) /* Cycle counter reset */
-#define ARMV8_PMU_PMCR_D       (1 << 3) /* CCNT counts every 64th cpu cycle */
-#define ARMV8_PMU_PMCR_X       (1 << 4) /* Export to ETM */
-#define ARMV8_PMU_PMCR_DP      (1 << 5) /* Disable CCNT if non-invasive debug*/
-/* Determines which bit of PMCCNTR_EL0 generates an overflow */
-#define ARMV8_PMU_PMCR_LC      (1 << 6)
-#define        ARMV8_PMU_PMCR_N_SHIFT  11       /* Number of counters supported */
-#define        ARMV8_PMU_PMCR_N_MASK   0x1f
-#define        ARMV8_PMU_PMCR_MASK     0x7f     /* Mask for writable bits */
-
-/*
- * PMOVSR: counters overflow flag status reg
- */
-#define        ARMV8_PMU_OVSR_MASK             0xffffffff      /* Mask for writable bits */
-#define        ARMV8_PMU_OVERFLOWED_MASK       ARMV8_PMU_OVSR_MASK
-
-/*
- * PMXEVTYPER: Event selection reg
- */
-#define        ARMV8_PMU_EVTYPE_MASK   0xc80003ff      /* Mask for writable bits */
-#define        ARMV8_PMU_EVTYPE_EVENT  0x3ff           /* Mask for EVENT bits */
-
-#define ARMV8_PMU_EVTYPE_EVENT_SW_INCR 0       /* Software increment event */
-
-/*
- * Event filters for PMUv3
- */
-#define        ARMV8_PMU_EXCLUDE_EL1   (1 << 31)
-#define        ARMV8_PMU_EXCLUDE_EL0   (1 << 30)
-#define        ARMV8_PMU_INCLUDE_EL2   (1 << 27)
-
-/*
- * PMUSERENR: user enable reg
- */
-#define ARMV8_PMU_USERENR_MASK 0xf             /* Mask for writable bits */
-#define ARMV8_PMU_USERENR_EN   (1 << 0) /* PMU regs can be accessed at EL0 */
-#define ARMV8_PMU_USERENR_SW   (1 << 1) /* PMSWINC can be written at EL0 */
-#define ARMV8_PMU_USERENR_CR   (1 << 2) /* Cycle counter can be read at EL0 */
-#define ARMV8_PMU_USERENR_ER   (1 << 3) /* Event counter can be read at EL0 */
-
-#endif
index 4e603ea..123f45d 100644 (file)
@@ -1 +1,5 @@
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define CONFIG_CPU_ENDIAN_BE8 CONFIG_CPU_BIG_ENDIAN
+#endif
+
 #include <../../arm/include/asm/opcodes.h>
index 7bd3cdb..2065f46 100644 (file)
 #ifndef __ASM_PERF_EVENT_H
 #define __ASM_PERF_EVENT_H
 
+#define        ARMV8_PMU_MAX_COUNTERS  32
+#define        ARMV8_PMU_COUNTER_MASK  (ARMV8_PMU_MAX_COUNTERS - 1)
+
+/*
+ * Per-CPU PMCR: config reg
+ */
+#define ARMV8_PMU_PMCR_E       (1 << 0) /* Enable all counters */
+#define ARMV8_PMU_PMCR_P       (1 << 1) /* Reset all counters */
+#define ARMV8_PMU_PMCR_C       (1 << 2) /* Cycle counter reset */
+#define ARMV8_PMU_PMCR_D       (1 << 3) /* CCNT counts every 64th cpu cycle */
+#define ARMV8_PMU_PMCR_X       (1 << 4) /* Export to ETM */
+#define ARMV8_PMU_PMCR_DP      (1 << 5) /* Disable CCNT if non-invasive debug*/
+#define ARMV8_PMU_PMCR_LC      (1 << 6) /* Overflow on 64 bit cycle counter */
+#define        ARMV8_PMU_PMCR_N_SHIFT  11       /* Number of counters supported */
+#define        ARMV8_PMU_PMCR_N_MASK   0x1f
+#define        ARMV8_PMU_PMCR_MASK     0x7f     /* Mask for writable bits */
+
+/*
+ * PMOVSR: counters overflow flag status reg
+ */
+#define        ARMV8_PMU_OVSR_MASK             0xffffffff      /* Mask for writable bits */
+#define        ARMV8_PMU_OVERFLOWED_MASK       ARMV8_PMU_OVSR_MASK
+
+/*
+ * PMXEVTYPER: Event selection reg
+ */
+#define        ARMV8_PMU_EVTYPE_MASK   0xc800ffff      /* Mask for writable bits */
+#define        ARMV8_PMU_EVTYPE_EVENT  0xffff          /* Mask for EVENT bits */
+
+#define ARMV8_PMU_EVTYPE_EVENT_SW_INCR 0       /* Software increment event */
+
+/*
+ * Event filters for PMUv3
+ */
+#define        ARMV8_PMU_EXCLUDE_EL1   (1 << 31)
+#define        ARMV8_PMU_EXCLUDE_EL0   (1 << 30)
+#define        ARMV8_PMU_INCLUDE_EL2   (1 << 27)
+
+/*
+ * PMUSERENR: user enable reg
+ */
+#define ARMV8_PMU_USERENR_MASK 0xf             /* Mask for writable bits */
+#define ARMV8_PMU_USERENR_EN   (1 << 0) /* PMU regs can be accessed at EL0 */
+#define ARMV8_PMU_USERENR_SW   (1 << 1) /* PMSWINC can be written at EL0 */
+#define ARMV8_PMU_USERENR_CR   (1 << 2) /* Cycle counter can be read at EL0 */
+#define ARMV8_PMU_USERENR_ER   (1 << 3) /* Event counter can be read at EL0 */
+
 #ifdef CONFIG_PERF_EVENTS
 struct pt_regs;
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
index 1f7f5a2..12e8d2b 100644 (file)
@@ -277,7 +277,7 @@ END(vectors)
  * Invalid mode handlers
  */
        .macro  inv_entry, el, reason, regsize = 64
-       kernel_entry el, \regsize
+       kernel_entry \el, \regsize
        mov     x0, sp
        mov     x1, #\reason
        mrs     x2, esr_el1
index 6ebd204..4203d5f 100644 (file)
@@ -758,7 +758,7 @@ ENTRY(__early_cpu_boot_status)
  */
        .section        ".idmap.text", "ax"
 __enable_mmu:
-       mrs     x18, sctlr_el1                  // preserve old SCTLR_EL1 value
+       mrs     x22, sctlr_el1                  // preserve old SCTLR_EL1 value
        mrs     x1, ID_AA64MMFR0_EL1
        ubfx    x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4
        cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
@@ -786,14 +786,15 @@ __enable_mmu:
         * to take into account by discarding the current kernel mapping and
         * creating a new one.
         */
-       msr     sctlr_el1, x18                  // disable the MMU
+       msr     sctlr_el1, x22                  // disable the MMU
        isb
        bl      __create_page_tables            // recreate kernel mapping
 
        msr     sctlr_el1, x19                  // re-enable the MMU
        isb
-       ic      ialluis                         // flush instructions fetched
-       isb                                     // via old mapping
+       ic      iallu                           // flush instructions fetched
+       dsb     nsh                             // via old mapping
+       isb
        add     x27, x27, x23                   // relocated __mmap_switched
 #endif
        br      x27
index 767c4f6..f419a7c 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <asm/irq_regs.h>
+#include <asm/perf_event.h>
 #include <asm/virt.h>
 
 #include <linux/of.h>
@@ -384,9 +385,6 @@ static const struct attribute_group *armv8_pmuv3_attr_groups[] = {
 #define        ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
        (ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
 
-#define        ARMV8_MAX_COUNTERS      32
-#define        ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
-
 /*
  * ARMv8 low level PMU access
  */
@@ -395,40 +393,7 @@ static const struct attribute_group *armv8_pmuv3_attr_groups[] = {
  * Perf Event to low level counters mapping
  */
 #define        ARMV8_IDX_TO_COUNTER(x) \
-       (((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
-
-/*
- * Per-CPU PMCR: config reg
- */
-#define ARMV8_PMCR_E           (1 << 0) /* Enable all counters */
-#define ARMV8_PMCR_P           (1 << 1) /* Reset all counters */
-#define ARMV8_PMCR_C           (1 << 2) /* Cycle counter reset */
-#define ARMV8_PMCR_D           (1 << 3) /* CCNT counts every 64th cpu cycle */
-#define ARMV8_PMCR_X           (1 << 4) /* Export to ETM */
-#define ARMV8_PMCR_DP          (1 << 5) /* Disable CCNT if non-invasive debug*/
-#define ARMV8_PMCR_LC          (1 << 6) /* Overflow on 64 bit cycle counter */
-#define        ARMV8_PMCR_N_SHIFT      11       /* Number of counters supported */
-#define        ARMV8_PMCR_N_MASK       0x1f
-#define        ARMV8_PMCR_MASK         0x7f     /* Mask for writable bits */
-
-/*
- * PMOVSR: counters overflow flag status reg
- */
-#define        ARMV8_OVSR_MASK         0xffffffff      /* Mask for writable bits */
-#define        ARMV8_OVERFLOWED_MASK   ARMV8_OVSR_MASK
-
-/*
- * PMXEVTYPER: Event selection reg
- */
-#define        ARMV8_EVTYPE_MASK       0xc800ffff      /* Mask for writable bits */
-#define        ARMV8_EVTYPE_EVENT      0xffff          /* Mask for EVENT bits */
-
-/*
- * Event filters for PMUv3
- */
-#define        ARMV8_EXCLUDE_EL1       (1 << 31)
-#define        ARMV8_EXCLUDE_EL0       (1 << 30)
-#define        ARMV8_INCLUDE_EL2       (1 << 27)
+       (((x) - ARMV8_IDX_COUNTER0) & ARMV8_PMU_COUNTER_MASK)
 
 static inline u32 armv8pmu_pmcr_read(void)
 {
@@ -439,14 +404,14 @@ static inline u32 armv8pmu_pmcr_read(void)
 
 static inline void armv8pmu_pmcr_write(u32 val)
 {
-       val &= ARMV8_PMCR_MASK;
+       val &= ARMV8_PMU_PMCR_MASK;
        isb();
        asm volatile("msr pmcr_el0, %0" :: "r" (val));
 }
 
 static inline int armv8pmu_has_overflowed(u32 pmovsr)
 {
-       return pmovsr & ARMV8_OVERFLOWED_MASK;
+       return pmovsr & ARMV8_PMU_OVERFLOWED_MASK;
 }
 
 static inline int armv8pmu_counter_valid(struct arm_pmu *cpu_pmu, int idx)
@@ -512,7 +477,7 @@ static inline void armv8pmu_write_counter(struct perf_event *event, u32 value)
 static inline void armv8pmu_write_evtype(int idx, u32 val)
 {
        if (armv8pmu_select_counter(idx) == idx) {
-               val &= ARMV8_EVTYPE_MASK;
+               val &= ARMV8_PMU_EVTYPE_MASK;
                asm volatile("msr pmxevtyper_el0, %0" :: "r" (val));
        }
 }
@@ -558,7 +523,7 @@ static inline u32 armv8pmu_getreset_flags(void)
        asm volatile("mrs %0, pmovsclr_el0" : "=r" (value));
 
        /* Write to clear flags */
-       value &= ARMV8_OVSR_MASK;
+       value &= ARMV8_PMU_OVSR_MASK;
        asm volatile("msr pmovsclr_el0, %0" :: "r" (value));
 
        return value;
@@ -696,7 +661,7 @@ static void armv8pmu_start(struct arm_pmu *cpu_pmu)
 
        raw_spin_lock_irqsave(&events->pmu_lock, flags);
        /* Enable all counters */
-       armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMCR_E);
+       armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E);
        raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
@@ -707,7 +672,7 @@ static void armv8pmu_stop(struct arm_pmu *cpu_pmu)
 
        raw_spin_lock_irqsave(&events->pmu_lock, flags);
        /* Disable all counters */
-       armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMCR_E);
+       armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E);
        raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
@@ -717,7 +682,7 @@ static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc,
        int idx;
        struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
        struct hw_perf_event *hwc = &event->hw;
-       unsigned long evtype = hwc->config_base & ARMV8_EVTYPE_EVENT;
+       unsigned long evtype = hwc->config_base & ARMV8_PMU_EVTYPE_EVENT;
 
        /* Always place a cycle counter into the cycle counter. */
        if (evtype == ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES) {
@@ -754,11 +719,11 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event,
            attr->exclude_kernel != attr->exclude_hv)
                return -EINVAL;
        if (attr->exclude_user)
-               config_base |= ARMV8_EXCLUDE_EL0;
+               config_base |= ARMV8_PMU_EXCLUDE_EL0;
        if (!is_kernel_in_hyp_mode() && attr->exclude_kernel)
-               config_base |= ARMV8_EXCLUDE_EL1;
+               config_base |= ARMV8_PMU_EXCLUDE_EL1;
        if (!attr->exclude_hv)
-               config_base |= ARMV8_INCLUDE_EL2;
+               config_base |= ARMV8_PMU_INCLUDE_EL2;
 
        /*
         * Install the filter into config_base as this is used to
@@ -784,35 +749,36 @@ static void armv8pmu_reset(void *info)
         * Initialize & Reset PMNC. Request overflow interrupt for
         * 64 bit cycle counter but cheat in armv8pmu_write_counter().
         */
-       armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C | ARMV8_PMCR_LC);
+       armv8pmu_pmcr_write(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C |
+                           ARMV8_PMU_PMCR_LC);
 }
 
 static int armv8_pmuv3_map_event(struct perf_event *event)
 {
        return armpmu_map_event(event, &armv8_pmuv3_perf_map,
                                &armv8_pmuv3_perf_cache_map,
-                               ARMV8_EVTYPE_EVENT);
+                               ARMV8_PMU_EVTYPE_EVENT);
 }
 
 static int armv8_a53_map_event(struct perf_event *event)
 {
        return armpmu_map_event(event, &armv8_a53_perf_map,
                                &armv8_a53_perf_cache_map,
-                               ARMV8_EVTYPE_EVENT);
+                               ARMV8_PMU_EVTYPE_EVENT);
 }
 
 static int armv8_a57_map_event(struct perf_event *event)
 {
        return armpmu_map_event(event, &armv8_a57_perf_map,
                                &armv8_a57_perf_cache_map,
-                               ARMV8_EVTYPE_EVENT);
+                               ARMV8_PMU_EVTYPE_EVENT);
 }
 
 static int armv8_thunder_map_event(struct perf_event *event)
 {
        return armpmu_map_event(event, &armv8_thunder_perf_map,
                                &armv8_thunder_perf_cache_map,
-                               ARMV8_EVTYPE_EVENT);
+                               ARMV8_PMU_EVTYPE_EVENT);
 }
 
 static void armv8pmu_read_num_pmnc_events(void *info)
@@ -820,7 +786,7 @@ static void armv8pmu_read_num_pmnc_events(void *info)
        int *nb_cnt = info;
 
        /* Read the nb of CNTx counters supported from PMNC */
-       *nb_cnt = (armv8pmu_pmcr_read() >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
+       *nb_cnt = (armv8pmu_pmcr_read() >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
 
        /* Add the CPU cycles counter */
        *nb_cnt += 1;
index 37f624d..5a1939a 100644 (file)
@@ -103,6 +103,7 @@ SECTIONS
                        *(.exception.text)
                        __exception_text_end = .;
                        IRQENTRY_TEXT
+                       SOFTIRQENTRY_TEXT
                        TEXT_TEXT
                        SCHED_TEXT
                        LOCK_TEXT
index 60585bd..dbd12ea 100644 (file)
@@ -58,17 +58,13 @@ static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
  * Copy user data from/to a page which is mapped into a different processes
  * address space.  Really, we want to allow our "user space" model to handle
  * this.
- *
- * Note that this code needs to run on the current CPU.
  */
 void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
                       unsigned long uaddr, void *dst, const void *src,
                       unsigned long len)
 {
-       preempt_disable();
        memcpy(dst, src, len);
        flush_ptrace_access(vma, page, uaddr, dst, len);
-       preempt_enable();
 }
 
 void __sync_icache_dcache(pte_t pte, unsigned long addr)
index 61a38ea..ea989d8 100644 (file)
@@ -362,42 +362,38 @@ void __init mem_init(void)
 #define MLG(b, t) b, t, ((t) - (b)) >> 30
 #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
 
-       pr_notice("Virtual kernel memory layout:\n"
+       pr_notice("Virtual kernel memory layout:\n");
 #ifdef CONFIG_KASAN
-                 "    kasan   : 0x%16lx - 0x%16lx   (%6ld GB)\n"
+       pr_cont("    kasan   : 0x%16lx - 0x%16lx   (%6ld GB)\n",
+               MLG(KASAN_SHADOW_START, KASAN_SHADOW_END));
 #endif
-                 "    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n"
-                 "    vmalloc : 0x%16lx - 0x%16lx   (%6ld GB)\n"
-                 "      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n"
-                 "    .rodata : 0x%p" " - 0x%p" "   (%6ld KB)\n"
-                 "      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n"
-                 "      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n"
+       pr_cont("    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n",
+               MLM(MODULES_VADDR, MODULES_END));
+       pr_cont("    vmalloc : 0x%16lx - 0x%16lx   (%6ld GB)\n",
+               MLG(VMALLOC_START, VMALLOC_END));
+       pr_cont("      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n"
+               "    .rodata : 0x%p" " - 0x%p" "   (%6ld KB)\n"
+               "      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n"
+               "      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n",
+               MLK_ROUNDUP(_text, __start_rodata),
+               MLK_ROUNDUP(__start_rodata, _etext),
+               MLK_ROUNDUP(__init_begin, __init_end),
+               MLK_ROUNDUP(_sdata, _edata));
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-                 "    vmemmap : 0x%16lx - 0x%16lx   (%6ld GB maximum)\n"
-                 "              0x%16lx - 0x%16lx   (%6ld MB actual)\n"
+       pr_cont("    vmemmap : 0x%16lx - 0x%16lx   (%6ld GB maximum)\n"
+               "              0x%16lx - 0x%16lx   (%6ld MB actual)\n",
+               MLG(VMEMMAP_START,
+                   VMEMMAP_START + VMEMMAP_SIZE),
+               MLM((unsigned long)phys_to_page(memblock_start_of_DRAM()),
+                   (unsigned long)virt_to_page(high_memory)));
 #endif
-                 "    fixed   : 0x%16lx - 0x%16lx   (%6ld KB)\n"
-                 "    PCI I/O : 0x%16lx - 0x%16lx   (%6ld MB)\n"
-                 "    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n",
-#ifdef CONFIG_KASAN
-                 MLG(KASAN_SHADOW_START, KASAN_SHADOW_END),
-#endif
-                 MLM(MODULES_VADDR, MODULES_END),
-                 MLG(VMALLOC_START, VMALLOC_END),
-                 MLK_ROUNDUP(_text, __start_rodata),
-                 MLK_ROUNDUP(__start_rodata, _etext),
-                 MLK_ROUNDUP(__init_begin, __init_end),
-                 MLK_ROUNDUP(_sdata, _edata),
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
-                 MLG(VMEMMAP_START,
-                     VMEMMAP_START + VMEMMAP_SIZE),
-                 MLM((unsigned long)phys_to_page(memblock_start_of_DRAM()),
-                     (unsigned long)virt_to_page(high_memory)),
-#endif
-                 MLK(FIXADDR_START, FIXADDR_TOP),
-                 MLM(PCI_IO_START, PCI_IO_END),
-                 MLM(__phys_to_virt(memblock_start_of_DRAM()),
-                     (unsigned long)high_memory));
+       pr_cont("    fixed   : 0x%16lx - 0x%16lx   (%6ld KB)\n",
+               MLK(FIXADDR_START, FIXADDR_TOP));
+       pr_cont("    PCI I/O : 0x%16lx - 0x%16lx   (%6ld MB)\n",
+               MLM(PCI_IO_START, PCI_IO_END));
+       pr_cont("    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n",
+               MLM(__phys_to_virt(memblock_start_of_DRAM()),
+                   (unsigned long)high_memory));
 
 #undef MLK
 #undef MLM
index d2d8b8c..f3e5c74 100644 (file)
@@ -211,8 +211,7 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
                if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
                      block_mappings_allowed(pgtable_alloc)) {
                        pmd_t old_pmd =*pmd;
-                       set_pmd(pmd, __pmd(phys |
-                                          pgprot_val(mk_sect_prot(prot))));
+                       pmd_set_huge(pmd, phys, prot);
                        /*
                         * Check for previous table entries created during
                         * boot (__create_page_tables) and flush them.
@@ -272,8 +271,7 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
                if (use_1G_block(addr, next, phys) &&
                    block_mappings_allowed(pgtable_alloc)) {
                        pud_t old_pud = *pud;
-                       set_pud(pud, __pud(phys |
-                                          pgprot_val(mk_sect_prot(prot))));
+                       pud_set_huge(pud, phys, prot);
 
                        /*
                         * If we have an old value for a pud, it will
index c9eec84..d920b95 100644 (file)
@@ -35,6 +35,7 @@ SECTIONS
 #endif
                LOCK_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                KPROBES_TEXT
 #ifdef CONFIG_ROMKERNEL
                __sinittext = .;
index 5a6e141..50bc10f 100644 (file)
@@ -72,6 +72,7 @@ SECTIONS
                SCHED_TEXT
                LOCK_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                KPROBES_TEXT
                *(.fixup)
                *(.gnu.warning)
index 688d807..ec5eebc 100644 (file)
@@ -8,9 +8,6 @@
 
 #ifndef __ASSEMBLY__
 
-#define get_user_page(vaddr)                   __get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)             free_page(addr)
-
 #define clear_page(pgaddr)                     memset((pgaddr), 0, PAGE_SIZE)
 #define copy_page(to,from)                     memcpy((to), (from), PAGE_SIZE)
 
index 4ce9fa8..6ae884b 100644 (file)
                reg = <0xffff78 8>;
                interrupts = <88 0>, <89 0>, <90 0>, <91 0>;
                clocks = <&fclk>;
-               clock-names = "sci_ick";
+               clock-names = "fck";
        };
        sci1: serial@ffff80 {
                compatible = "renesas,sci";
                reg = <0xffff80 8>;
                interrupts = <92 0>, <93 0>, <94 0>, <95 0>;
                clocks = <&fclk>;
-               clock-names = "sci_ick";
+               clock-names = "fck";
        };
        sci2: serial@ffff88 {
                compatible = "renesas,sci";
                reg = <0xffff88 8>;
                interrupts = <96 0>, <97 0>, <98 0>, <99 0>;
                clocks = <&fclk>;
-               clock-names = "sci_ick";
+               clock-names = "fck";
        };
 };
index 545bfb5..9c733d9 100644 (file)
@@ -83,7 +83,7 @@
                reg = <0xffffb0 8>;
                interrupts = <52 0>, <53 0>, <54 0>, <55 0>;
                clocks = <&fclk>;
-               clock-names = "sci_ick";
+               clock-names = "fck";
        };
 
        sci1: serial@ffffb8 {
@@ -91,6 +91,6 @@
                reg = <0xffffb8 8>;
                interrupts = <56 0>, <57 0>, <58 0>, <59 0>;
                clocks = <&fclk>;
-               clock-names = "sci_ick";
+               clock-names = "fck";
        };
 };
index bcedba5..97e1f4b 100644 (file)
                reg = <0xffff78 8>;
                interrupts = <88 0>, <89 0>, <90 0>, <91 0>;
                clocks = <&fclk>;
-               clock-names = "sci_ick";
+               clock-names = "fck";
        };
        sci1: serial@ffff80 {
                compatible = "renesas,sci";
                reg = <0xffff80 8>;
                interrupts = <92 0>, <93 0>, <94 0>, <95 0>;
                clocks = <&fclk>;
-               clock-names = "sci_ick";
+               clock-names = "fck";
        };
 };
index 067bfe9..80624f4 100644 (file)
@@ -34,7 +34,7 @@ CONFIG_BINFMT_FLAT=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_SH_SCI_EARLYCON=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_USB_SUPPORT is not set
index e4985df..c8c25a4 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
@@ -137,11 +135,6 @@ void __init setup_arch(char **cmdline_p)
        parse_early_param();
 
        bootmem_init();
-#if defined(CONFIG_H8300H_SIM) || defined(CONFIG_H8S_SIM)
-       sim_console_register();
-#endif
-
-       early_platform_driver_probe("earlyprintk", 1, 0);
        /*
         * get kmalloc into gear
         */
index a15edf0..46138f5 100644 (file)
@@ -1,79 +1,30 @@
 /*
- * arch/h8300/kernel/early_printk.c
+ * arch/h8300/kernel/sim-console.c
  *
- *  Copyright (C) 2009 Yoshinori Sato <ysato@users.sourceforge.jp>
+ *  Copyright (C) 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
 #include <linux/console.h>
-#include <linux/tty.h>
 #include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
+#include <linux/serial_core.h>
 
-static void sim_write(struct console *co, const char *ptr,
-                                unsigned len)
+static void sim_write(struct console *con, const char *s, unsigned n)
 {
        register const int fd __asm__("er0") = 1; /* stdout */
-       register const char *_ptr __asm__("er1") = ptr;
-       register const unsigned _len __asm__("er2") = len;
+       register const char *_ptr __asm__("er1") = s;
+       register const unsigned _len __asm__("er2") = n;
 
        __asm__(".byte 0x5e,0x00,0x00,0xc7\n\t" /* jsr @0xc7 (sys_write) */
                : : "g"(fd), "g"(_ptr), "g"(_len));
 }
 
-static struct console sim_console = {
-       .name           = "sim_console",
-       .write          = sim_write,
-       .setup          = NULL,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-static char sim_console_buf[32];
-
-static int sim_probe(struct platform_device *pdev)
-{
-       if (sim_console.data)
-               return -EEXIST;
-
-       if (!strstr(sim_console_buf, "keep"))
-               sim_console.flags |= CON_BOOT;
-
-       register_console(&sim_console);
-       return 0;
-}
-
-static int sim_remove(struct platform_device *pdev)
+static int __init sim_setup(struct earlycon_device *device, const char *opt)
 {
+       device->con->write = sim_write;
        return 0;
 }
 
-static struct platform_driver sim_driver = {
-       .probe          = sim_probe,
-       .remove         = sim_remove,
-       .driver         = {
-               .name   = "h8300-sim",
-               .owner  = THIS_MODULE,
-       },
-};
-
-early_platform_init_buffer("earlyprintk", &sim_driver,
-                          sim_console_buf, ARRAY_SIZE(sim_console_buf));
-
-static struct platform_device sim_console_device = {
-       .name           = "h8300-sim",
-       .id             = 0,
-};
-
-static struct platform_device *devices[] __initdata = {
-       &sim_console_device,
-};
-
-void __init sim_console_register(void)
-{
-       early_platform_add_devices(devices,
-                                  ARRAY_SIZE(devices));
-}
+EARLYCON_DECLARE(h8sim, sim_setup);
index 6a86850..8c85209 100644 (file)
@@ -11,7 +11,7 @@
 
 
 
-#define NR_syscalls                    324 /* length of syscall table */
+#define NR_syscalls                    326 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 41369a1..ea5363d 100644 (file)
 #define __NR_kcmp                      1345
 #define __NR_mlock2                    1346
 #define __NR_copy_file_range           1347
+#define __NR_preadv2                   1348
+#define __NR_pwritev2                  1349
 
 #endif /* _UAPI_ASM_IA64_UNISTD_H */
index 477c55e..cfaa7b2 100644 (file)
@@ -1773,5 +1773,7 @@ sys_call_table:
        data8 sys_kcmp                          // 1345
        data8 sys_mlock2
        data8 sys_copy_file_range
+       data8 sys_preadv2
+       data8 sys_pwritev2
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
index 5029f73..e7a1946 100644 (file)
@@ -6,9 +6,6 @@
 #include <linux/compiler.h>
 #include <asm/module.h>
 
-#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)     free_page(addr)
-
 /*
  * We don't need to check for alignment etc.
  */
index ef20916..fa7f32d 100644 (file)
@@ -6,9 +6,6 @@
 extern unsigned long memory_start;
 extern unsigned long memory_end;
 
-#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)     free_page(addr)
-
 #define clear_page(page)       memset((page), 0, PAGE_SIZE)
 #define copy_page(to,from)     memcpy((to), (from), PAGE_SIZE)
 
index e12055e..150ace9 100644 (file)
@@ -24,6 +24,7 @@ SECTIONS
        LOCK_TEXT
        KPROBES_TEXT
        IRQENTRY_TEXT
+       SOFTIRQENTRY_TEXT
        *(.text.*)
        *(.gnu.warning)
        }
index be9488d..0a47f04 100644 (file)
@@ -36,6 +36,7 @@ SECTIONS {
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                . = ALIGN (4) ;
                _etext = . ;
        }
index 79cff26..398733e 100644 (file)
@@ -25,8 +25,6 @@ struct jz_nand_platform_data {
        int                     num_partitions;
        struct mtd_partition    *partitions;
 
-       struct nand_ecclayout   *ecc_layout;
-
        unsigned char banks[JZ_NAND_NUM_BANKS];
 
        void (*ident_callback)(struct platform_device *, struct nand_chip *,
index 0a93e83..54d653e 100644 (file)
@@ -58,6 +58,7 @@ SECTIONS
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                *(.text.*)
                *(.fixup)
                *(.gnu.warning)
index 718dd19..367c542 100644 (file)
@@ -97,8 +97,7 @@ static int __init early_init_dt_scan_serial(unsigned long node,
                return 0;
 #endif
 
-       *addr64 = fdt_translate_address((const void *)initial_boot_params,
-               node);
+       *addr64 = of_flat_dt_translate_address(node);
 
        return *addr64 == OF_BAD_ADDR ? 0 : 1;
 }
index 326fab4..e23e895 100644 (file)
@@ -39,6 +39,7 @@ SECTIONS
                SCHED_TEXT
                LOCK_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                KPROBES_TEXT
        } =0
        _etext = .;
index 108906f..e613d36 100644 (file)
@@ -40,9 +40,6 @@
 
 #ifndef __ASSEMBLY__
 
-#define get_user_page(vaddr)            __get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)      free_page(addr)
-
 #define clear_page(page)       memset((page), 0, PAGE_SIZE)
 #define copy_page(to, from)    memcpy((to), (from), PAGE_SIZE)
 
index 2d69a85..d936de4 100644 (file)
@@ -50,6 +50,7 @@ SECTIONS
          LOCK_TEXT
          KPROBES_TEXT
          IRQENTRY_TEXT
+         SOFTIRQENTRY_TEXT
          *(.fixup)
          *(.text.__*)
          _etext = .;
index 14f655c..bd3c873 100644 (file)
@@ -11,6 +11,7 @@ config PARISC
        select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
        select BUG
+       select BUILDTIME_EXTABLE_SORT
        select HAVE_PERF_EVENTS
        select GENERIC_ATOMIC64 if !64BIT
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
@@ -29,6 +30,7 @@ config PARISC
        select TTY # Needed for pdc_cons.c
        select HAVE_DEBUG_STACKOVERFLOW
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_SECCOMP_FILTER
        select ARCH_NO_COHERENT_DMA_MMAP
 
        help
index b3069fd..60e6f07 100644 (file)
         */
 #define ASM_EXCEPTIONTABLE_ENTRY(fault_addr, except_addr)      \
        .section __ex_table,"aw"                        !       \
-       ASM_ULONG_INSN  fault_addr, except_addr         !       \
+       .word (fault_addr - .), (except_addr - .)       !       \
        .previous
 
 
index 0448a2c..3387307 100644 (file)
@@ -183,6 +183,13 @@ typedef struct compat_siginfo {
                        int _band;      /* POLL_IN, POLL_OUT, POLL_MSG */
                        int _fd;
                } _sigpoll;
+
+               /* SIGSYS */
+               struct {
+                       compat_uptr_t _call_addr; /* calling user insn */
+                       int _syscall;   /* triggering system call number */
+                       compat_uint_t _arch;    /* AUDIT_ARCH_* of syscall */
+               } _sigsys;
        } _sifields;
 } compat_siginfo_t;
 
index a5eba95..637ce8d 100644 (file)
@@ -39,6 +39,19 @@ static inline void syscall_get_arguments(struct task_struct *tsk,
        }
 }
 
+static inline void syscall_set_return_value(struct task_struct *task,
+                                           struct pt_regs *regs,
+                                           int error, long val)
+{
+       regs->gr[28] = error ? error : val;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+                                   struct pt_regs *regs)
+{
+       /* do nothing */
+}
+
 static inline int syscall_get_arch(void)
 {
        int arch = AUDIT_ARCH_PARISC;
index 0abdd4c..d4dd6e5 100644 (file)
@@ -60,14 +60,15 @@ static inline long access_ok(int type, const void __user * addr,
  * use a 32bit (unsigned int) address here.
  */
 
+#define ARCH_HAS_RELATIVE_EXTABLE
 struct exception_table_entry {
-       unsigned long insn;     /* address of insn that is allowed to fault. */
-       unsigned long fixup;    /* fixup routine */
+       int insn;       /* relative address of insn that is allowed to fault. */
+       int fixup;      /* relative address of fixup routine */
 };
 
 #define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\
        ".section __ex_table,\"aw\"\n"                     \
-       ASM_WORD_INSN #fault_addr ", " #except_addr "\n\t" \
+       ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \
        ".previous\n"
 
 /*
index b75039f..cc0ce92 100644 (file)
 #define __NR_io_getevents       (__NR_Linux + 217)
 #define __NR_io_submit          (__NR_Linux + 218)
 #define __NR_io_cancel          (__NR_Linux + 219)
-#define __NR_alloc_hugepages    (__NR_Linux + 220)
-#define __NR_free_hugepages     (__NR_Linux + 221)
+#define __NR_alloc_hugepages    (__NR_Linux + 220) /* not used */
+#define __NR_free_hugepages     (__NR_Linux + 221) /* not used */
 #define __NR_exit_group         (__NR_Linux + 222)
 #define __NR_lookup_dcookie     (__NR_Linux + 223)
 #define __NR_epoll_create       (__NR_Linux + 224)
 #define __NR_userfaultfd       (__NR_Linux + 344)
 #define __NR_mlock2            (__NR_Linux + 345)
 #define __NR_copy_file_range   (__NR_Linux + 346)
+#define __NR_preadv2           (__NR_Linux + 347)
+#define __NR_pwritev2          (__NR_Linux + 348)
 
-#define __NR_Linux_syscalls    (__NR_copy_file_range + 1)
+#define __NR_Linux_syscalls    (__NR_pwritev2 + 1)
 
 
 #define __IGNORE_select                /* newselect */
index ce0b2b4..8fb81a3 100644 (file)
@@ -270,7 +270,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 long do_syscall_trace_enter(struct pt_regs *regs)
 {
        /* Do the secure computing check first. */
-       secure_computing_strict(regs->gr[20]);
+       if (secure_computing() == -1)
+               return -1;
 
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
            tracehook_report_syscall_entry(regs)) {
@@ -296,7 +297,11 @@ long do_syscall_trace_enter(struct pt_regs *regs)
                        regs->gr[23] & 0xffffffff);
 
 out:
-       return regs->gr[20];
+       /*
+        * Sign extend the syscall number to 64bit since it may have been
+        * modified by a compat ptrace call
+        */
+       return (int) ((u32) regs->gr[20]);
 }
 
 void do_syscall_trace_exit(struct pt_regs *regs)
index 984abbe..c342b2e 100644 (file)
@@ -371,6 +371,11 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from)
                        val = (compat_int_t)from->si_int;
                        err |= __put_user(val, &to->si_int);
                        break;
+               case __SI_SYS >> 16:
+                       err |= __put_user(ptr_to_compat(from->si_call_addr), &to->si_call_addr);
+                       err |= __put_user(from->si_syscall, &to->si_syscall);
+                       err |= __put_user(from->si_arch, &to->si_arch);
+                       break;
                }
        }
        return err;
index 5aba01a..0a393a0 100644 (file)
@@ -368,16 +368,6 @@ asmlinkage long parisc_fallocate(int fd, int mode, u32 offhi, u32 offlo,
                              ((u64)lenhi << 32) | lenlo);
 }
 
-asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag)
-{
-       return -ENOMEM;
-}
-
-asmlinkage int sys_free_hugepages(unsigned long addr)
-{
-       return -EINVAL;
-}
-
 long parisc_personality(unsigned long personality)
 {
        long err;
index fbafa0d..c976ebf 100644 (file)
@@ -329,6 +329,7 @@ tracesys_next:
 
        ldo     -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
        LDREG   TI_TASK(%r1), %r1
+       LDREG   TASK_PT_GR28(%r1), %r28         /* Restore return value */
        LDREG   TASK_PT_GR26(%r1), %r26         /* Restore the users args */
        LDREG   TASK_PT_GR25(%r1), %r25
        LDREG   TASK_PT_GR24(%r1), %r24
@@ -342,6 +343,7 @@ tracesys_next:
        stw     %r21, -56(%r30)                 /* 6th argument */
 #endif
 
+       cmpib,COND(=),n -1,%r20,tracesys_exit /* seccomp may have returned -1 */
        comiclr,>>=     __NR_Linux_syscalls, %r20, %r0
        b,n     .Ltracesys_nosys
 
index 585d50f..3cfef1d 100644 (file)
        ENTRY_COMP(io_getevents)
        ENTRY_COMP(io_submit)
        ENTRY_SAME(io_cancel)
-       ENTRY_SAME(alloc_hugepages)     /* 220 */
-       ENTRY_SAME(free_hugepages)
+       ENTRY_SAME(ni_syscall)          /* 220: was alloc_hugepages */
+       ENTRY_SAME(ni_syscall)          /* was free_hugepages */
        ENTRY_SAME(exit_group)
        ENTRY_COMP(lookup_dcookie)
        ENTRY_SAME(epoll_create)
        ENTRY_SAME(userfaultfd)
        ENTRY_SAME(mlock2)              /* 345 */
        ENTRY_SAME(copy_file_range)
+       ENTRY_COMP(preadv2)
+       ENTRY_COMP(pwritev2)
 
 
 .ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b))
index 553b098..16e0735 100644 (file)
@@ -284,11 +284,8 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
        if (in_interrupt())
                panic("Fatal exception in interrupt");
 
-       if (panic_on_oops) {
-               printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
-               ssleep(5);
+       if (panic_on_oops)
                panic("Fatal exception");
-       }
 
        oops_exit();
        do_exit(SIGSEGV);
index 308f290..f3ead0b 100644 (file)
@@ -72,6 +72,7 @@ SECTIONS
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                *(.text.do_softirq)
                *(.text.sys_exit)
                *(.text.do_sigaltstack)
index a762864..26fac9c 100644 (file)
@@ -140,12 +140,6 @@ int fixup_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *fix;
 
-       /* If we only stored 32bit addresses in the exception table we can drop
-        * out if we faulted on a 64bit address. */
-       if ((sizeof(regs->iaoq[0]) > sizeof(fix->insn))
-               && (regs->iaoq[0] >> 32))
-                       return 0;
-
        fix = search_exception_tables(regs->iaoq[0]);
        if (fix) {
                struct exception_data *d;
@@ -154,7 +148,8 @@ int fixup_exception(struct pt_regs *regs)
                d->fault_space = regs->isr;
                d->fault_addr = regs->ior;
 
-               regs->iaoq[0] = ((fix->fixup) & ~3);
+               regs->iaoq[0] = (unsigned long)&fix->fixup + fix->fixup;
+               regs->iaoq[0] &= ~3;
                /*
                 * NOTE: In some cases the faulting instruction
                 * may be in the delay slot of a branch. We
index 8ab8a1a..009fab1 100644 (file)
@@ -246,7 +246,7 @@ struct thread_struct {
 #endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_VSX
        /* VSR status */
-       int             used_vsr;       /* set if process has used altivec */
+       int             used_vsr;       /* set if process has used VSX */
 #endif /* CONFIG_VSX */
 #ifdef CONFIG_SPE
        unsigned long   evr[32];        /* upper 32-bits of SPE regs */
index 612df30..b8500b4 100644 (file)
@@ -983,7 +983,7 @@ void restore_tm_state(struct pt_regs *regs)
 static inline void save_sprs(struct thread_struct *t)
 {
 #ifdef CONFIG_ALTIVEC
-       if (cpu_has_feature(cpu_has_feature(CPU_FTR_ALTIVEC)))
+       if (cpu_has_feature(CPU_FTR_ALTIVEC))
                t->vrsave = mfspr(SPRN_VRSAVE);
 #endif
 #ifdef CONFIG_PPC_BOOK3S_64
index d41fd0a..2dd91f7 100644 (file)
@@ -55,6 +55,7 @@ SECTIONS
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
 
 #ifdef CONFIG_PPC32
                *(.got1)
index 6dd272b..d991b9e 100644 (file)
@@ -413,13 +413,13 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte)
 {
        struct hugepd_freelist **batchp;
 
-       batchp = this_cpu_ptr(&hugepd_freelist_cur);
+       batchp = &get_cpu_var(hugepd_freelist_cur);
 
        if (atomic_read(&tlb->mm->mm_users) < 2 ||
            cpumask_equal(mm_cpumask(tlb->mm),
                          cpumask_of(smp_processor_id()))) {
                kmem_cache_free(hugepte_cache, hugepte);
-        put_cpu_var(hugepd_freelist_cur);
+               put_cpu_var(hugepd_freelist_cur);
                return;
        }
 
index b9df8d1..aad23e3 100644 (file)
@@ -59,6 +59,9 @@ config PCI_QUIRKS
 config ARCH_SUPPORTS_UPROBES
        def_bool y
 
+config DEBUG_RODATA
+       def_bool y
+
 config S390
        def_bool y
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
index b8045b9..d750cc0 100644 (file)
@@ -669,11 +669,13 @@ static const struct file_operations prng_tdes_fops = {
 static struct miscdevice prng_sha512_dev = {
        .name   = "prandom",
        .minor  = MISC_DYNAMIC_MINOR,
+       .mode   = 0644,
        .fops   = &prng_sha512_fops,
 };
 static struct miscdevice prng_tdes_dev = {
        .name   = "prandom",
        .minor  = MISC_DYNAMIC_MINOR,
+       .mode   = 0644,
        .fops   = &prng_tdes_fops,
 };
 
index 4d7ccac..22da3b3 100644 (file)
@@ -15,4 +15,7 @@
 
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
+/* Read-only memory is marked before mark_rodata_ro() is called. */
+#define __ro_after_init __read_mostly
+
 #endif
index ab3aa68..4384bc7 100644 (file)
 #define __NR_shutdown          373
 #define __NR_mlock2            374
 #define __NR_copy_file_range   375
-#define NR_syscalls 376
+#define __NR_preadv2           376
+#define __NR_pwritev2          377
+#define NR_syscalls 378
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index 58bf457..62f066b 100644 (file)
@@ -670,6 +670,7 @@ static int cpumf_pmu_notifier(struct notifier_block *self, unsigned long action,
 
        switch (action & ~CPU_TASKS_FROZEN) {
        case CPU_ONLINE:
+       case CPU_DOWN_FAILED:
                flags = PMC_INIT;
                smp_call_function_single(cpu, setup_pmc_cpu, &flags, 1);
                break;
index 1a43474..eaab9a7 100644 (file)
@@ -1521,7 +1521,7 @@ static int cpumf_pmu_notifier(struct notifier_block *self,
 
        switch (action & ~CPU_TASKS_FROZEN) {
        case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
+       case CPU_DOWN_FAILED:
                flags = PMC_INIT;
                smp_call_function_single(cpu, setup_pmc_cpu, &flags, 1);
                break;
index 293d8b9..9b59e62 100644 (file)
@@ -384,3 +384,5 @@ SYSCALL(sys_recvmsg,compat_sys_recvmsg)
 SYSCALL(sys_shutdown,sys_shutdown)
 SYSCALL(sys_mlock2,compat_sys_mlock2)
 SYSCALL(sys_copy_file_range,compat_sys_copy_file_range) /* 375 */
+SYSCALL(sys_preadv2,compat_sys_preadv2)
+SYSCALL(sys_pwritev2,compat_sys_pwritev2)
index 445657f..0f41a82 100644 (file)
@@ -28,6 +28,7 @@ SECTIONS
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                *(.fixup)
                *(.gnu.warning)
        } :text = 0x0700
index 49a1c84..a8a6765 100644 (file)
@@ -20,9 +20,9 @@
 static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
                unsigned long end, int write, struct page **pages, int *nr)
 {
+       struct page *head, *page;
        unsigned long mask;
        pte_t *ptep, pte;
-       struct page *page;
 
        mask = (write ? _PAGE_PROTECT : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
 
@@ -37,12 +37,14 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
                        return 0;
                VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
                page = pte_page(pte);
-               if (!page_cache_get_speculative(page))
+               head = compound_head(page);
+               if (!page_cache_get_speculative(head))
                        return 0;
                if (unlikely(pte_val(pte) != pte_val(*ptep))) {
-                       put_page(page);
+                       put_page(head);
                        return 0;
                }
+               VM_BUG_ON_PAGE(compound_head(page) != head, page);
                pages[*nr] = page;
                (*nr)++;
 
index 73e2903..c7b0451 100644 (file)
@@ -108,6 +108,13 @@ void __init paging_init(void)
        free_area_init_nodes(max_zone_pfns);
 }
 
+void mark_rodata_ro(void)
+{
+       /* Text and rodata are already protected. Nothing to do here. */
+       pr_info("Write protecting the kernel read-only data: %luk\n",
+               ((unsigned long)&_eshared - (unsigned long)&_stext) >> 10);
+}
+
 void __init mem_init(void)
 {
        if (MACHINE_HAS_TLB_LC)
@@ -126,9 +133,6 @@ void __init mem_init(void)
        setup_zero_pages();     /* Setup zeroed pages. */
 
        mem_init_print_info(NULL);
-       printk("Write protected kernel read-only data: %#lx - %#lx\n",
-              (unsigned long)&_stext,
-              PFN_ALIGN((unsigned long)&_eshared) - 1);
 }
 
 void free_initmem(void)
index 21591dd..1a4512c 100644 (file)
@@ -176,8 +176,7 @@ static int clp_query_pci_fn(struct zpci_dev *zdev, u32 fh)
                rc = clp_store_query_pci_fn(zdev, &rrb->response);
                if (rc)
                        goto out;
-               if (rrb->response.pfgid)
-                       rc = clp_query_pci_fngrp(zdev, rrb->response.pfgid);
+               rc = clp_query_pci_fngrp(zdev, rrb->response.pfgid);
        } else {
                zpci_err("Q PCI FN:\n");
                zpci_err_clp(rrb->response.hdr.rsp, rc);
index db88cbf..235a410 100644 (file)
@@ -39,6 +39,7 @@ SECTIONS
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                *(.fixup)
                *(.gnu.warning)
                _etext = .;             /* End of text section */
index 9ed1f12..4b027b1 100644 (file)
@@ -6,17 +6,17 @@
 
 #ifdef CONFIG_COMPAT
 struct __new_sigaction32 {
-       unsigned                sa_handler;
+       unsigned int            sa_handler;
        unsigned int            sa_flags;
-       unsigned                sa_restorer;     /* not used by Linux/SPARC yet */
+       unsigned int            sa_restorer;     /* not used by Linux/SPARC yet */
        compat_sigset_t         sa_mask;
 };
 
 struct __old_sigaction32 {
-       unsigned                sa_handler;
+       unsigned int            sa_handler;
        compat_old_sigset_t     sa_mask;
        unsigned int            sa_flags;
-       unsigned                sa_restorer;     /* not used by Linux/SPARC yet */
+       unsigned int            sa_restorer;     /* not used by Linux/SPARC yet */
 };
 #endif
 
index 910c1d9..426ad75 100644 (file)
@@ -117,9 +117,9 @@ static inline void bw_clear_intr_mask(int sbus_level, int mask)
                              "i" (ASI_M_CTL));
 }
 
-static inline unsigned bw_get_prof_limit(int cpu)
+static inline unsigned int bw_get_prof_limit(int cpu)
 {
-       unsigned limit;
+       unsigned int limit;
        
        __asm__ __volatile__ ("lda [%1] %2, %0" :
                              "=r" (limit) :
@@ -128,7 +128,7 @@ static inline unsigned bw_get_prof_limit(int cpu)
        return limit;
 }
 
-static inline void bw_set_prof_limit(int cpu, unsigned limit)
+static inline void bw_set_prof_limit(int cpu, unsigned int limit)
 {
        __asm__ __volatile__ ("sta %0, [%1] %2" : :
                              "r" (limit),
@@ -136,9 +136,9 @@ static inline void bw_set_prof_limit(int cpu, unsigned limit)
                              "i" (ASI_M_CTL));
 }
 
-static inline unsigned bw_get_ctrl(int cpu)
+static inline unsigned int bw_get_ctrl(int cpu)
 {
-       unsigned ctrl;
+       unsigned int ctrl;
        
        __asm__ __volatile__ ("lda [%1] %2, %0" :
                              "=r" (ctrl) :
@@ -147,7 +147,7 @@ static inline unsigned bw_get_ctrl(int cpu)
        return ctrl;
 }
 
-static inline void bw_set_ctrl(int cpu, unsigned ctrl)
+static inline void bw_set_ctrl(int cpu, unsigned int ctrl)
 {
        __asm__ __volatile__ ("sta %0, [%1] %2" : :
                              "r" (ctrl),
@@ -155,9 +155,9 @@ static inline void bw_set_ctrl(int cpu, unsigned ctrl)
                              "i" (ASI_M_CTL));
 }
 
-static inline unsigned cc_get_ipen(void)
+static inline unsigned int cc_get_ipen(void)
 {
-       unsigned pending;
+       unsigned int pending;
        
        __asm__ __volatile__ ("lduha [%1] %2, %0" :
                              "=r" (pending) :
@@ -166,7 +166,7 @@ static inline unsigned cc_get_ipen(void)
        return pending;
 }
 
-static inline void cc_set_iclr(unsigned clear)
+static inline void cc_set_iclr(unsigned int clear)
 {
        __asm__ __volatile__ ("stha %0, [%1] %2" : :
                              "r" (clear),
@@ -174,9 +174,9 @@ static inline void cc_set_iclr(unsigned clear)
                              "i" (ASI_M_MXCC));
 }
 
-static inline unsigned cc_get_imsk(void)
+static inline unsigned int cc_get_imsk(void)
 {
-       unsigned mask;
+       unsigned int mask;
        
        __asm__ __volatile__ ("lduha [%1] %2, %0" :
                              "=r" (mask) :
@@ -185,7 +185,7 @@ static inline unsigned cc_get_imsk(void)
        return mask;
 }
 
-static inline void cc_set_imsk(unsigned mask)
+static inline void cc_set_imsk(unsigned int mask)
 {
        __asm__ __volatile__ ("stha %0, [%1] %2" : :
                              "r" (mask),
@@ -193,9 +193,9 @@ static inline void cc_set_imsk(unsigned mask)
                              "i" (ASI_M_MXCC));
 }
 
-static inline unsigned cc_get_imsk_other(int cpuid)
+static inline unsigned int cc_get_imsk_other(int cpuid)
 {
-       unsigned mask;
+       unsigned int mask;
        
        __asm__ __volatile__ ("lduha [%1] %2, %0" :
                              "=r" (mask) :
@@ -204,7 +204,7 @@ static inline unsigned cc_get_imsk_other(int cpuid)
        return mask;
 }
 
-static inline void cc_set_imsk_other(int cpuid, unsigned mask)
+static inline void cc_set_imsk_other(int cpuid, unsigned int mask)
 {
        __asm__ __volatile__ ("stha %0, [%1] %2" : :
                              "r" (mask),
@@ -212,7 +212,7 @@ static inline void cc_set_imsk_other(int cpuid, unsigned mask)
                              "i" (ASI_M_CTL));
 }
 
-static inline void cc_set_igen(unsigned gen)
+static inline void cc_set_igen(unsigned int gen)
 {
        __asm__ __volatile__ ("sta %0, [%1] %2" : :
                              "r" (gen),
index 47eaafa..63374c4 100644 (file)
@@ -29,12 +29,12 @@ struct linux_dev_v0_funcs {
 /* V2 and later prom device operations. */
 struct linux_dev_v2_funcs {
        phandle (*v2_inst2pkg)(int d);  /* Convert ihandle to phandle */
-       char * (*v2_dumb_mem_alloc)(char *va, unsigned sz);
-       void (*v2_dumb_mem_free)(char *va, unsigned sz);
+       char * (*v2_dumb_mem_alloc)(char *va, unsigned int sz);
+       void (*v2_dumb_mem_free)(char *va, unsigned int sz);
 
        /* To map devices into virtual I/O space. */
-       char * (*v2_dumb_mmap)(char *virta, int which_io, unsigned paddr, unsigned sz);
-       void (*v2_dumb_munmap)(char *virta, unsigned size);
+       char * (*v2_dumb_mmap)(char *virta, int which_io, unsigned int paddr, unsigned int sz);
+       void (*v2_dumb_munmap)(char *virta, unsigned int size);
 
        int (*v2_dev_open)(char *devpath);
        void (*v2_dev_close)(int d);
@@ -50,7 +50,7 @@ struct linux_dev_v2_funcs {
 struct linux_mlist_v0 {
        struct linux_mlist_v0 *theres_more;
        unsigned int start_adr;
-       unsigned num_bytes;
+       unsigned int num_bytes;
 };
 
 struct linux_mem_v0 {
index 7a38d6a..f089cfa 100644 (file)
@@ -218,7 +218,7 @@ extern pgprot_t PAGE_KERNEL_LOCKED;
 extern pgprot_t PAGE_COPY;
 extern pgprot_t PAGE_SHARED;
 
-/* XXX This uglyness is for the atyfb driver's sparc mmap() support. XXX */
+/* XXX This ugliness is for the atyfb driver's sparc mmap() support. XXX */
 extern unsigned long _PAGE_IE;
 extern unsigned long _PAGE_E;
 extern unsigned long _PAGE_CACHE;
index 6924bde..ce2595c 100644 (file)
@@ -201,7 +201,7 @@ unsigned long get_wchan(struct task_struct *task);
 #define KSTK_ESP(tsk)  (task_pt_regs(tsk)->u_regs[UREG_FP])
 
 /* Please see the commentary in asm/backoff.h for a description of
- * what these instructions are doing and how they have been choosen.
+ * what these instructions are doing and how they have been chosen.
  * To make a long story short, we are trying to yield the current cpu
  * strand during busy loops.
  */
index fc2df1e..f4eb630 100644 (file)
@@ -25,7 +25,7 @@ struct sigcontext32 {
        int sigc_oswins;       /* outstanding windows */
 
        /* stack ptrs for each regwin buf */
-       unsigned sigc_spbuf[__SUNOS_MAXWIN];
+       unsigned int sigc_spbuf[__SUNOS_MAXWIN];
 
        /* Windows to restore after signal */
        struct reg_window32 sigc_wbuf[__SUNOS_MAXWIN];
index ecb49cf..c6a155c 100644 (file)
@@ -149,7 +149,7 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
         * page size in question.  So for PMD mappings (which fall on
         * bit 23, for 8MB per PMD) we must propagate bit 22 for a
         * 4MB huge page.  For huge PUDs (which fall on bit 33, for
-        * 8GB per PUD), we have to accomodate 256MB and 2GB huge
+        * 8GB per PUD), we have to accommodate 256MB and 2GB huge
         * pages.  So for those we propagate bits 32 to 28.
         */
 #define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL)       \
index a232e9e..2f0583a 100644 (file)
@@ -6,13 +6,13 @@
 #if defined(__sparc__) && defined(__arch64__)
 /* 64 bit sparc */
 struct stat {
-       unsigned   st_dev;
+       unsigned int st_dev;
        ino_t   st_ino;
        mode_t  st_mode;
        short   st_nlink;
        uid_t   st_uid;
        gid_t   st_gid;
-       unsigned   st_rdev;
+       unsigned int st_rdev;
        off_t   st_size;
        time_t  st_atime;
        time_t  st_mtime;
index 24361b4..2585c1e 100644 (file)
@@ -5,27 +5,27 @@
 
 #include "kernel.h"
 
-static unsigned dir_class[] = {
+static unsigned int dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
 ~0U
 };
 
-static unsigned read_class[] = {
+static unsigned int read_class[] = {
 #include <asm-generic/audit_read.h>
 ~0U
 };
 
-static unsigned write_class[] = {
+static unsigned int write_class[] = {
 #include <asm-generic/audit_write.h>
 ~0U
 };
 
-static unsigned chattr_class[] = {
+static unsigned int chattr_class[] = {
 #include <asm-generic/audit_change_attr.h>
 ~0U
 };
 
-static unsigned signal_class[] = {
+static unsigned int signal_class[] = {
 #include <asm-generic/audit_signal.h>
 ~0U
 };
@@ -39,7 +39,7 @@ int audit_classify_arch(int arch)
        return 0;
 }
 
-int audit_classify_syscall(int abi, unsigned syscall)
+int audit_classify_syscall(int abi, unsigned int syscall)
 {
 #ifdef CONFIG_COMPAT
        if (abi == AUDIT_ARCH_SPARC)
index 7062263..e5611cd 100644 (file)
@@ -2,32 +2,32 @@
 #include <asm/unistd.h>
 #include "kernel.h"
 
-unsigned sparc32_dir_class[] = {
+unsigned int sparc32_dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
 ~0U
 };
 
-unsigned sparc32_chattr_class[] = {
+unsigned int sparc32_chattr_class[] = {
 #include <asm-generic/audit_change_attr.h>
 ~0U
 };
 
-unsigned sparc32_write_class[] = {
+unsigned int sparc32_write_class[] = {
 #include <asm-generic/audit_write.h>
 ~0U
 };
 
-unsigned sparc32_read_class[] = {
+unsigned int sparc32_read_class[] = {
 #include <asm-generic/audit_read.h>
 ~0U
 };
 
-unsigned sparc32_signal_class[] = {
+unsigned int sparc32_signal_class[] = {
 #include <asm-generic/audit_signal.h>
 ~0U
 };
 
-int sparc32_classify_syscall(unsigned syscall)
+int sparc32_classify_syscall(unsigned int syscall)
 {
        switch(syscall) {
        case __NR_open:
index a83707c..51aa6e8 100644 (file)
@@ -1255,7 +1255,7 @@ flush_patch_exception:
 kuw_patch1_7win:       sll     %o3, 6, %o3
 
        /* No matter how much overhead this routine has in the worst
-        * case scenerio, it is several times better than taking the
+        * case scenario, it is several times better than taking the
         * traps with the old method of just doing flush_user_windows().
         */
 kill_user_windows:
index 28fed53..ffd5ff4 100644 (file)
@@ -131,7 +131,7 @@ void __iomem *ioremap(unsigned long offset, unsigned long size)
 EXPORT_SYMBOL(ioremap);
 
 /*
- * Comlimentary to ioremap().
+ * Complementary to ioremap().
  */
 void iounmap(volatile void __iomem *virtual)
 {
@@ -233,7 +233,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz)
 }
 
 /*
- * Comlimentary to _sparc_ioremap().
+ * Complementary to _sparc_ioremap().
  */
 static void _sparc_free_io(struct resource *res)
 {
@@ -532,7 +532,7 @@ static void pci32_unmap_page(struct device *dev, dma_addr_t ba, size_t size,
 }
 
 /* Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
+ * mode for DMA.  This is the scatter-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
  * elements are each tagged with the appropriate dma address
  * and length.  They are obtained via sg_dma_{address,length}(SG).
index e7f652b..5057ec2 100644 (file)
@@ -54,12 +54,12 @@ void do_signal32(struct pt_regs * regs);
 asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp);
 
 /* compat_audit.c */
-extern unsigned sparc32_dir_class[];
-extern unsigned sparc32_chattr_class[];
-extern unsigned sparc32_write_class[];
-extern unsigned sparc32_read_class[];
-extern unsigned sparc32_signal_class[];
-int sparc32_classify_syscall(unsigned syscall);
+extern unsigned int sparc32_dir_class[];
+extern unsigned int sparc32_chattr_class[];
+extern unsigned int sparc32_write_class[];
+extern unsigned int sparc32_read_class[];
+extern unsigned int sparc32_signal_class[];
+int sparc32_classify_syscall(unsigned int syscall);
 #endif
 
 #ifdef CONFIG_SPARC32
index 42efcf8..33cd171 100644 (file)
@@ -203,7 +203,7 @@ static struct irq_chip leon_irq = {
 
 /*
  * Build a LEON IRQ for the edge triggered LEON IRQ controller:
- *  Edge (normal) IRQ           - handle_simple_irq, ack=DONT-CARE, never ack
+ *  Edge (normal) IRQ           - handle_simple_irq, ack=DON'T-CARE, never ack
  *  Level IRQ (PCI|Level-GPIO)  - handle_fasteoi_irq, ack=1, ack after ISR
  *  Per-CPU Edge                - handle_percpu_irq, ack=0
  */
index 46a5964..c16ef1a 100644 (file)
@@ -103,7 +103,7 @@ static void show_regwindow32(struct pt_regs *regs)
        mm_segment_t old_fs;
        
        __asm__ __volatile__ ("flushw");
-       rw = compat_ptr((unsigned)regs->u_regs[14]);
+       rw = compat_ptr((unsigned int)regs->u_regs[14]);
        old_fs = get_fs();
        set_fs (USER_DS);
        if (copy_from_user (&r_w, rw, sizeof(r_w))) {
index baef495..69d75ff 100644 (file)
@@ -109,7 +109,7 @@ unsigned long cmdline_memory_size __initdata = 0;
 unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */
 
 static void
-prom_console_write(struct console *con, const char *s, unsigned n)
+prom_console_write(struct console *con, const char *s, unsigned int n)
 {
        prom_write(s, n);
 }
index f3185e2..26db95b 100644 (file)
@@ -77,7 +77,7 @@ struct screen_info screen_info = {
 };
 
 static void
-prom_console_write(struct console *con, const char *s, unsigned n)
+prom_console_write(struct console *con, const char *s, unsigned int n)
 {
        prom_write(s, n);
 }
index 4eed773..3c25241 100644 (file)
@@ -144,7 +144,7 @@ void do_sigreturn32(struct pt_regs *regs)
        compat_uptr_t fpu_save;
        compat_uptr_t rwin_save;
        unsigned int psr;
-       unsigned pc, npc;
+       unsigned int pc, npc;
        sigset_t set;
        compat_sigset_t seta;
        int err, i;
index b489e97..fe8b8ee 100644 (file)
@@ -337,10 +337,10 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
                switch (call) {
                case SEMOP:
                        err = sys_semtimedop(first, ptr,
-                                            (unsigned)second, NULL);
+                                            (unsigned int)second, NULL);
                        goto out;
                case SEMTIMEDOP:
-                       err = sys_semtimedop(first, ptr, (unsigned)second,
+                       err = sys_semtimedop(first, ptr, (unsigned int)second,
                                (const struct timespec __user *)
                                             (unsigned long) fifth);
                        goto out;
index 7f41d40..fa8e21a 100644 (file)
@@ -1,4 +1,4 @@
-/* sysfs.c: Toplogy sysfs support code for sparc64.
+/* sysfs.c: Topology sysfs support code for sparc64.
  *
  * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
  */
index d89e97b..9aacb91 100644 (file)
@@ -209,8 +209,8 @@ static inline int do_int_store(int reg_num, int size, unsigned long *dst_addr,
        if (size == 16) {
                size = 8;
                zero = (((long)(reg_num ?
-                       (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) |
-                       (unsigned)fetch_reg(reg_num + 1, regs);
+                       (unsigned int)fetch_reg(reg_num, regs) : 0)) << 32) |
+                       (unsigned int)fetch_reg(reg_num + 1, regs);
        } else if (reg_num) {
                src_val_p = fetch_reg_addr(reg_num, regs);
        }
index f1a2f68..aadd321 100644 (file)
@@ -48,6 +48,7 @@ SECTIONS
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                *(.gnu.warning)
        } = 0
        _etext = .;
index c399e7b..b6c559c 100644 (file)
@@ -303,10 +303,10 @@ no_context:
                fixup = search_extables_range(regs->pc, &g2);
                /* Values below 10 are reserved for other things */
                if (fixup > 10) {
-                       extern const unsigned __memset_start[];
-                       extern const unsigned __memset_end[];
-                       extern const unsigned __csum_partial_copy_start[];
-                       extern const unsigned __csum_partial_copy_end[];
+                       extern const unsigned int __memset_start[];
+                       extern const unsigned int __memset_end[];
+                       extern const unsigned int __csum_partial_copy_start[];
+                       extern const unsigned int __csum_partial_copy_end[];
 
 #ifdef DEBUG_EXCEPTIONS
                        printk("Exception: PC<%08lx> faddr<%08lx>\n",
index 3e6e05a..a6d9204 100644 (file)
@@ -351,7 +351,7 @@ do {        *prog++ = BR_OPC | WDISP22(OFF);                \
  *
  * Sometimes we need to emit a branch earlier in the code
  * sequence.  And in these situations we adjust "destination"
- * to accomodate this difference.  For example, if we needed
+ * to accommodate this difference.  For example, if we needed
  * to emit a branch (and it's delay slot) right before the
  * final instruction emitted for a BPF opcode, we'd use
  * "destination + 4" instead of just plain "destination" above.
index c97e416..ff7f50f 100644 (file)
@@ -211,7 +211,7 @@ _gxio_mpipe_link_mac_t;
  *  request shared data permission on the same link.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA,
- *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed.
  */
 #define GXIO_MPIPE_LINK_DATA               0x00000001UL
@@ -219,7 +219,7 @@ _gxio_mpipe_link_mac_t;
 /** Do not request data permission on the specified link.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA,
- *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed.
  */
 #define GXIO_MPIPE_LINK_NO_DATA            0x00000002UL
@@ -230,7 +230,7 @@ _gxio_mpipe_link_mac_t;
  *  data permission on it, this open will fail.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA,
- *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed.
  */
 #define GXIO_MPIPE_LINK_EXCL_DATA          0x00000004UL
@@ -241,7 +241,7 @@ _gxio_mpipe_link_mac_t;
  *  permission on the same link.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS,
- *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed.
  */
 #define GXIO_MPIPE_LINK_STATS              0x00000008UL
@@ -249,7 +249,7 @@ _gxio_mpipe_link_mac_t;
 /** Do not request stats permission on the specified link.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS,
- *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed.
  */
 #define GXIO_MPIPE_LINK_NO_STATS           0x00000010UL
@@ -267,7 +267,7 @@ _gxio_mpipe_link_mac_t;
  *  reset by other statistics programs.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS,
- *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed.
  */
 #define GXIO_MPIPE_LINK_EXCL_STATS         0x00000020UL
@@ -278,7 +278,7 @@ _gxio_mpipe_link_mac_t;
  *  permission on the same link.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL,
- *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed.
  */
 #define GXIO_MPIPE_LINK_CTL                0x00000040UL
@@ -286,7 +286,7 @@ _gxio_mpipe_link_mac_t;
 /** Do not request control permission on the specified link.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL,
- *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed.
  */
 #define GXIO_MPIPE_LINK_NO_CTL             0x00000080UL
@@ -301,7 +301,7 @@ _gxio_mpipe_link_mac_t;
  *  it prevents programs like mpipe-link from configuring the link.
  *
  *  No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL,
- *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specifed in a gxio_mpipe_link_open()
+ *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed.
  */
 #define GXIO_MPIPE_LINK_EXCL_CTL           0x00000100UL
@@ -311,7 +311,7 @@ _gxio_mpipe_link_mac_t;
  *  change the desired state of the link when it is closed or the process
  *  exits.  No more than one of ::GXIO_MPIPE_LINK_AUTO_UP,
  *  ::GXIO_MPIPE_LINK_AUTO_UPDOWN, ::GXIO_MPIPE_LINK_AUTO_DOWN, or
- *  ::GXIO_MPIPE_LINK_AUTO_NONE may be specifed in a gxio_mpipe_link_open()
+ *  ::GXIO_MPIPE_LINK_AUTO_NONE may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed.
  */
 #define GXIO_MPIPE_LINK_AUTO_UP            0x00000200UL
@@ -322,7 +322,7 @@ _gxio_mpipe_link_mac_t;
  *  open, set the desired state of the link to down.  No more than one of
  *  ::GXIO_MPIPE_LINK_AUTO_UP, ::GXIO_MPIPE_LINK_AUTO_UPDOWN,
  *  ::GXIO_MPIPE_LINK_AUTO_DOWN, or ::GXIO_MPIPE_LINK_AUTO_NONE may be
- *  specifed in a gxio_mpipe_link_open() call.  If none are specified,
+ *  specified in a gxio_mpipe_link_open() call.  If none are specified,
  *  ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed.
  */
 #define GXIO_MPIPE_LINK_AUTO_UPDOWN        0x00000400UL
@@ -332,7 +332,7 @@ _gxio_mpipe_link_mac_t;
  *  process has the link open, set the desired state of the link to down.
  *  No more than one of ::GXIO_MPIPE_LINK_AUTO_UP,
  *  ::GXIO_MPIPE_LINK_AUTO_UPDOWN, ::GXIO_MPIPE_LINK_AUTO_DOWN, or
- *  ::GXIO_MPIPE_LINK_AUTO_NONE may be specifed in a gxio_mpipe_link_open()
+ *  ::GXIO_MPIPE_LINK_AUTO_NONE may be specified in a gxio_mpipe_link_open()
  *  call.  If none are specified, ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed.
  */
 #define GXIO_MPIPE_LINK_AUTO_DOWN          0x00000800UL
@@ -342,7 +342,7 @@ _gxio_mpipe_link_mac_t;
  *  closed or the process exits.  No more than one of
  *  ::GXIO_MPIPE_LINK_AUTO_UP, ::GXIO_MPIPE_LINK_AUTO_UPDOWN,
  *  ::GXIO_MPIPE_LINK_AUTO_DOWN, or ::GXIO_MPIPE_LINK_AUTO_NONE may be
- *  specifed in a gxio_mpipe_link_open() call.  If none are specified,
+ *  specified in a gxio_mpipe_link_open() call.  If none are specified,
  *  ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed.
  */
 #define GXIO_MPIPE_LINK_AUTO_NONE          0x00001000UL
index a506c2c..9247d6b 100644 (file)
@@ -126,15 +126,15 @@ void
 sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
 {
        struct pt_regs *thread_regs;
+       const int NGPRS = TREG_LAST_GPR + 1;
 
        if (task == NULL)
                return;
 
-       /* Initialize to zero. */
-       memset(gdb_regs, 0, NUMREGBYTES);
-
        thread_regs = task_pt_regs(task);
-       memcpy(gdb_regs, thread_regs, TREG_LAST_GPR * sizeof(unsigned long));
+       memcpy(gdb_regs, thread_regs, NGPRS * sizeof(unsigned long));
+       memset(&gdb_regs[NGPRS], 0,
+              (TILEGX_PC_REGNUM - NGPRS) * sizeof(unsigned long));
        gdb_regs[TILEGX_PC_REGNUM] = thread_regs->pc;
        gdb_regs[TILEGX_FAULTNUM_REGNUM] = thread_regs->faultnum;
 }
@@ -433,9 +433,9 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
 struct kgdb_arch arch_kgdb_ops;
 
 /*
- * kgdb_arch_init - Perform any architecture specific initalization.
+ * kgdb_arch_init - Perform any architecture specific initialization.
  *
- * This function will handle the initalization of any architecture
+ * This function will handle the initialization of any architecture
  * specific callbacks.
  */
 int kgdb_arch_init(void)
@@ -447,9 +447,9 @@ int kgdb_arch_init(void)
 }
 
 /*
- * kgdb_arch_exit - Perform any architecture specific uninitalization.
+ * kgdb_arch_exit - Perform any architecture specific uninitialization.
  *
- * This function will handle the uninitalization of any architecture
+ * This function will handle the uninitialization of any architecture
  * specific callbacks, for dynamic registration and unregistration.
  */
 void kgdb_arch_exit(void)
index 4c017d0..aa2b44c 100644 (file)
@@ -1326,7 +1326,7 @@ invalid_device:
 
 
 /*
- * See tile_cfg_read() for relevent comments.
+ * See tile_cfg_read() for relevant comments.
  * Note that "val" is the value to write, not a pointer to that value.
  */
 static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset,
index 0e059a0..378f5d8 100644 (file)
@@ -45,6 +45,7 @@ SECTIONS
     LOCK_TEXT
     KPROBES_TEXT
     IRQENTRY_TEXT
+    SOFTIRQENTRY_TEXT
     __fix_text_end = .;   /* tile-cpack won't rearrange before this */
     ALIGN_FUNCTION();
     *(.hottext*)
index bf8b35d..fbc5e92 100644 (file)
@@ -47,6 +47,15 @@ static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src,
                BUG();
 }
 
+static inline int arch_memcpy_from_pmem(void *dst, const void __pmem *src,
+               size_t n)
+{
+       if (static_cpu_has(X86_FEATURE_MCE_RECOVERY))
+               return memcpy_mcsafe(dst, (void __force *) src, n);
+       memcpy(dst, (void __force *) src, n);
+       return 0;
+}
+
 /**
  * arch_wmb_pmem - synchronize writes to persistent memory
  *
index c24b422..1fde8d5 100644 (file)
@@ -319,12 +319,6 @@ static inline void reset_lazy_tlbstate(void)
 
 #endif /* SMP */
 
-/* Not inlined due to inc_irq_stat not being defined yet */
-#define flush_tlb_local() {            \
-       inc_irq_stat(irq_tlb_count);    \
-       local_flush_tlb();              \
-}
-
 #ifndef CONFIG_PARAVIRT
 #define flush_tlb_others(mask, mm, start, end) \
        native_flush_tlb_others(mask, mm, start, end)
index adaae2c..616ebd2 100644 (file)
@@ -19,6 +19,7 @@ endif
 KASAN_SANITIZE_head$(BITS).o                           := n
 KASAN_SANITIZE_dumpstack.o                             := n
 KASAN_SANITIZE_dumpstack_$(BITS).o                     := n
+KASAN_SANITIZE_stacktrace.o := n
 
 OBJECT_FILES_NON_STANDARD_head_$(BITS).o               := y
 OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o    := y
index 0b445c2..ac780ca 100644 (file)
@@ -384,6 +384,9 @@ static void intel_thermal_interrupt(void)
 {
        __u64 msr_val;
 
+       if (static_cpu_has(X86_FEATURE_HWP))
+               wrmsrl_safe(MSR_HWP_STATUS, 0);
+
        rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
 
        /* Check for violation of core thermal thresholds*/
index d239639..4c941f8 100644 (file)
@@ -101,6 +101,7 @@ SECTIONS
                KPROBES_TEXT
                ENTRY_TEXT
                IRQENTRY_TEXT
+               SOFTIRQENTRY_TEXT
                *(.fixup)
                *(.gnu.warning)
                /* End of text section */
index 8f4cc3d..fe9b9f7 100644 (file)
@@ -104,10 +104,8 @@ static void flush_tlb_func(void *info)
 
        inc_irq_stat(irq_tlb_count);
 
-       if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm))
+       if (f->flush_mm && f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm))
                return;
-       if (!f->flush_end)
-               f->flush_end = f->flush_start + PAGE_SIZE;
 
        count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
        if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
@@ -135,12 +133,20 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
                                 unsigned long end)
 {
        struct flush_tlb_info info;
+
+       if (end == 0)
+               end = start + PAGE_SIZE;
        info.flush_mm = mm;
        info.flush_start = start;
        info.flush_end = end;
 
        count_vm_tlb_event(NR_TLB_REMOTE_FLUSH);
-       trace_tlb_flush(TLB_REMOTE_SEND_IPI, end - start);
+       if (end == TLB_FLUSH_ALL)
+               trace_tlb_flush(TLB_REMOTE_SEND_IPI, TLB_FLUSH_ALL);
+       else
+               trace_tlb_flush(TLB_REMOTE_SEND_IPI,
+                               (end - start) >> PAGE_SHIFT);
+
        if (is_uv_system()) {
                unsigned int cpu;
 
index 431fdda..4ea4dd8 100644 (file)
@@ -416,12 +416,14 @@ void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx)
 static void blk_mq_sysfs_init(struct request_queue *q)
 {
        struct blk_mq_ctx *ctx;
-       int i;
+       int cpu;
 
        kobject_init(&q->mq_kobj, &blk_mq_ktype);
 
-       queue_for_each_ctx(q, ctx, i)
+       for_each_possible_cpu(cpu) {
+               ctx = per_cpu_ptr(q->queue_ctx, cpu);
                kobject_init(&ctx->kobj, &blk_mq_ctx_ktype);
+       }
 }
 
 int blk_mq_register_disk(struct gendisk *disk)
index 050f7a1..1699baf 100644 (file)
@@ -1798,11 +1798,12 @@ static void blk_mq_map_swqueue(struct request_queue *q,
        /*
         * Map software to hardware queues
         */
-       queue_for_each_ctx(q, ctx, i) {
+       for_each_possible_cpu(i) {
                /* If the cpu isn't online, the cpu is mapped to first hctx */
                if (!cpumask_test_cpu(i, online_mask))
                        continue;
 
+               ctx = per_cpu_ptr(q->queue_ctx, i);
                hctx = q->mq_ops->map_queue(q, i);
 
                cpumask_set_cpu(i, hctx->cpumask);
index 3bbdcc7..7d7a39b 100644 (file)
@@ -178,6 +178,8 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
        int cached_ret = -ENOKEY;
        int ret;
 
+       *_trusted = false;
+
        for (p = pkcs7->certs; p; p = p->next)
                p->seen = false;
 
index d0aad06..f245bf3 100644 (file)
@@ -145,6 +145,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
        { "AMD0010", APD_ADDR(cz_i2c_desc) },
        { "AMDI0010", APD_ADDR(cz_i2c_desc) },
        { "AMD0020", APD_ADDR(cz_uart_desc) },
+       { "AMDI0020", APD_ADDR(cz_uart_desc) },
        { "AMD0030", },
 #endif
 #ifdef CONFIG_ARM64
index b5e54f2..0d92d0f 100644 (file)
@@ -491,6 +491,58 @@ static void acpi_processor_remove(struct acpi_device *device)
 }
 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
 
+#ifdef CONFIG_X86
+static bool acpi_hwp_native_thermal_lvt_set;
+static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle,
+                                                         u32 lvl,
+                                                         void *context,
+                                                         void **rv)
+{
+       u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953";
+       u32 capbuf[2];
+       struct acpi_osc_context osc_context = {
+               .uuid_str = sb_uuid_str,
+               .rev = 1,
+               .cap.length = 8,
+               .cap.pointer = capbuf,
+       };
+
+       if (acpi_hwp_native_thermal_lvt_set)
+               return AE_CTRL_TERMINATE;
+
+       capbuf[0] = 0x0000;
+       capbuf[1] = 0x1000; /* set bit 12 */
+
+       if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) {
+               if (osc_context.ret.pointer && osc_context.ret.length > 1) {
+                       u32 *capbuf_ret = osc_context.ret.pointer;
+
+                       if (capbuf_ret[1] & 0x1000) {
+                               acpi_handle_info(handle,
+                                       "_OSC native thermal LVT Acked\n");
+                               acpi_hwp_native_thermal_lvt_set = true;
+                       }
+               }
+               kfree(osc_context.ret.pointer);
+       }
+
+       return AE_OK;
+}
+
+void __init acpi_early_processor_osc(void)
+{
+       if (boot_cpu_has(X86_FEATURE_HWP)) {
+               acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
+                                   ACPI_UINT32_MAX,
+                                   acpi_hwp_native_thermal_lvt_osc,
+                                   NULL, NULL, NULL);
+               acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID,
+                                acpi_hwp_native_thermal_lvt_osc,
+                                NULL, NULL);
+       }
+}
+#endif
+
 /*
  * The following ACPI IDs are known to be suitable for representing as
  * processor devices.
index 0e85678..c068c82 100644 (file)
@@ -1019,6 +1019,9 @@ static int __init acpi_bus_init(void)
                goto error1;
        }
 
+       /* Set capability bits for _OSC under processor scope */
+       acpi_early_processor_osc();
+
        /*
         * _OSC method may exist in module level code,
         * so it must be run after ACPI_FULL_INITIALIZATION
index a37508e..7c18847 100644 (file)
@@ -145,6 +145,12 @@ void acpi_early_processor_set_pdc(void);
 static inline void acpi_early_processor_set_pdc(void) {}
 #endif
 
+#ifdef CONFIG_X86
+void acpi_early_processor_osc(void);
+#else
+static inline void acpi_early_processor_osc(void) {}
+#endif
+
 /* --------------------------------------------------------------------------
                                   Embedded Controller
    -------------------------------------------------------------------------- */
index 2aee416..f2fd3fe 100644 (file)
@@ -816,6 +816,7 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
                        next = adev->node.next;
                        if (next == head) {
                                child = NULL;
+                               adev = ACPI_COMPANION(dev);
                                goto nondev;
                        }
                        adev = list_entry(next, struct acpi_device, node);
index d02fd53..56241eb 100644 (file)
 
 #ifdef CONFIG_X86
 #define valid_IRQ(i) (((i) != 0) && ((i) != 2))
+static inline bool acpi_iospace_resource_valid(struct resource *res)
+{
+       /* On X86 IO space is limited to the [0 - 64K] IO port range */
+       return res->end < 0x10003;
+}
 #else
 #define valid_IRQ(i) (true)
+/*
+ * ACPI IO descriptors on arches other than X86 contain MMIO CPU physical
+ * addresses mapping IO space in CPU physical address space, IO space
+ * resources can be placed anywhere in the 64-bit physical address space.
+ */
+static inline bool
+acpi_iospace_resource_valid(struct resource *res) { return true; }
 #endif
 
 static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
@@ -127,7 +139,7 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
        if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
                res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
-       if (res->end >= 0x10003)
+       if (!acpi_iospace_resource_valid(res))
                res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
        if (io_decode == ACPI_DECODE_16)
index fbfcce3..2a8b596 100644 (file)
@@ -748,6 +748,7 @@ static int acpi_hibernation_enter(void)
 
 static void acpi_hibernation_leave(void)
 {
+       pm_set_resume_via_firmware();
        /*
         * If ACPI is not enabled by the BIOS and the boot kernel, we need to
         * enable it here.
index f12a724..050673f 100644 (file)
@@ -692,7 +692,7 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
                mask = obj->integer.value;
        else if (obj->type == ACPI_TYPE_BUFFER)
                for (i = 0; i < obj->buffer.length && i < 8; i++)
-                       mask |= (((u8)obj->buffer.pointer[i]) << (i * 8));
+                       mask |= (((u64)obj->buffer.pointer[i]) << (i * 8));
        ACPI_FREE(obj);
 
        /*
index 272a52e..0e64a1b 100644 (file)
@@ -137,6 +137,62 @@ int pm_clk_add_clk(struct device *dev, struct clk *clk)
        return __pm_clk_add(dev, NULL, clk);
 }
 
+
+/**
+ * of_pm_clk_add_clks - Start using device clock(s) for power management.
+ * @dev: Device whose clock(s) is going to be used for power management.
+ *
+ * Add a series of clocks described in the 'clocks' device-tree node for
+ * a device to the list of clocks used for the power management of @dev.
+ * On success, returns the number of clocks added. Returns a negative
+ * error code if there are no clocks in the device node for the device
+ * or if adding a clock fails.
+ */
+int of_pm_clk_add_clks(struct device *dev)
+{
+       struct clk **clks;
+       unsigned int i, count;
+       int ret;
+
+       if (!dev || !dev->of_node)
+               return -EINVAL;
+
+       count = of_count_phandle_with_args(dev->of_node, "clocks",
+                                          "#clock-cells");
+       if (count == 0)
+               return -ENODEV;
+
+       clks = kcalloc(count, sizeof(*clks), GFP_KERNEL);
+       if (!clks)
+               return -ENOMEM;
+
+       for (i = 0; i < count; i++) {
+               clks[i] = of_clk_get(dev->of_node, i);
+               if (IS_ERR(clks[i])) {
+                       ret = PTR_ERR(clks[i]);
+                       goto error;
+               }
+
+               ret = pm_clk_add_clk(dev, clks[i]);
+               if (ret) {
+                       clk_put(clks[i]);
+                       goto error;
+               }
+       }
+
+       kfree(clks);
+
+       return i;
+
+error:
+       while (i--)
+               pm_clk_remove_clk(dev, clks[i]);
+
+       kfree(clks);
+
+       return ret;
+}
+
 /**
  * __pm_clk_remove - Destroy PM clock entry.
  * @ce: PM clock entry to destroy.
@@ -197,6 +253,39 @@ void pm_clk_remove(struct device *dev, const char *con_id)
        __pm_clk_remove(ce);
 }
 
+/**
+ * pm_clk_remove_clk - Stop using a device clock for power management.
+ * @dev: Device whose clock should not be used for PM any more.
+ * @clk: Clock pointer
+ *
+ * Remove the clock pointed to by @clk from the list of clocks used for
+ * the power management of @dev.
+ */
+void pm_clk_remove_clk(struct device *dev, struct clk *clk)
+{
+       struct pm_subsys_data *psd = dev_to_psd(dev);
+       struct pm_clock_entry *ce;
+
+       if (!psd || !clk)
+               return;
+
+       spin_lock_irq(&psd->lock);
+
+       list_for_each_entry(ce, &psd->clock_list, node) {
+               if (clk == ce->clk)
+                       goto remove;
+       }
+
+       spin_unlock_irq(&psd->lock);
+       return;
+
+ remove:
+       list_del(&ce->node);
+       spin_unlock_irq(&psd->lock);
+
+       __pm_clk_remove(ce);
+}
+
 /**
  * pm_clk_init - Initialize a device's list of power management clocks.
  * @dev: Device to initialize the list of PM clocks for.
index cc2e71d..25824c1 100644 (file)
@@ -2051,7 +2051,7 @@ static int exec_drive_taskfile(struct driver_data *dd,
                                         outbuf,
                                         taskout,
                                         DMA_TO_DEVICE);
-               if (outbuf_dma == 0) {
+               if (pci_dma_mapping_error(dd->pdev, outbuf_dma)) {
                        err = -ENOMEM;
                        goto abort;
                }
@@ -2068,7 +2068,7 @@ static int exec_drive_taskfile(struct driver_data *dd,
                inbuf_dma = pci_map_single(dd->pdev,
                                         inbuf,
                                         taskin, DMA_FROM_DEVICE);
-               if (inbuf_dma == 0) {
+               if (pci_dma_mapping_error(dd->pdev, inbuf_dma)) {
                        err = -ENOMEM;
                        goto abort;
                }
index 64a7b59..cab9759 100644 (file)
@@ -742,10 +742,11 @@ static int null_add_dev(void)
 
        add_disk(disk);
 
+done:
        mutex_lock(&lock);
        list_add_tail(&nullb->list, &nullb_list);
        mutex_unlock(&lock);
-done:
+
        return 0;
 
 out_cleanup_lightnvm:
index 4a87678..9c62344 100644 (file)
@@ -1847,14 +1847,12 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
        if (osd_req->r_result < 0)
                obj_request->result = osd_req->r_result;
 
-       rbd_assert(osd_req->r_num_ops <= CEPH_OSD_MAX_OP);
-
        /*
         * We support a 64-bit length, but ultimately it has to be
         * passed to the block layer, which just supports a 32-bit
         * length field.
         */
-       obj_request->xferred = osd_req->r_reply_op_len[0];
+       obj_request->xferred = osd_req->r_ops[0].outdata_len;
        rbd_assert(obj_request->xferred < (u64)UINT_MAX);
 
        opcode = osd_req->r_ops[0].op;
@@ -5643,18 +5641,12 @@ static void rbd_sysfs_cleanup(void)
 static int rbd_slab_init(void)
 {
        rbd_assert(!rbd_img_request_cache);
-       rbd_img_request_cache = kmem_cache_create("rbd_img_request",
-                                       sizeof (struct rbd_img_request),
-                                       __alignof__(struct rbd_img_request),
-                                       0, NULL);
+       rbd_img_request_cache = KMEM_CACHE(rbd_img_request, 0);
        if (!rbd_img_request_cache)
                return -ENOMEM;
 
        rbd_assert(!rbd_obj_request_cache);
-       rbd_obj_request_cache = kmem_cache_create("rbd_obj_request",
-                                       sizeof (struct rbd_obj_request),
-                                       __alignof__(struct rbd_obj_request),
-                                       0, NULL);
+       rbd_obj_request_cache = KMEM_CACHE(rbd_obj_request, 0);
        if (!rbd_obj_request_cache)
                goto out_err;
 
index d233688..f8a483c 100644 (file)
@@ -286,7 +286,7 @@ static int register_device(int minor, struct pp_struct *pp)
        struct parport *port;
        struct pardevice *pdev = NULL;
        char *name;
-       struct pardev_cb ppdev_cb;
+       int fl;
 
        name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor);
        if (name == NULL)
@@ -299,11 +299,9 @@ static int register_device(int minor, struct pp_struct *pp)
                return -ENXIO;
        }
 
-       memset(&ppdev_cb, 0, sizeof(ppdev_cb));
-       ppdev_cb.irq_func = pp_irq;
-       ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
-       ppdev_cb.private = pp;
-       pdev = parport_register_dev_model(port, name, &ppdev_cb, minor);
+       fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+       pdev = parport_register_device(port, name, NULL,
+                                      NULL, pp_irq, fl, pp);
        parport_put_port(port);
 
        if (!pdev) {
@@ -801,23 +799,10 @@ static void pp_detach(struct parport *port)
        device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
 }
 
-static int pp_probe(struct pardevice *par_dev)
-{
-       struct device_driver *drv = par_dev->dev.driver;
-       int len = strlen(drv->name);
-
-       if (strncmp(par_dev->name, drv->name, len))
-               return -ENODEV;
-
-       return 0;
-}
-
 static struct parport_driver pp_driver = {
        .name           = CHRDEV,
-       .probe          = pp_probe,
-       .match_port     = pp_attach,
+       .attach         = pp_attach,
        .detach         = pp_detach,
-       .devmodel       = true,
 };
 
 static int __init ppdev_init(void)
index 9e9fe4b..309049d 100644 (file)
@@ -57,7 +57,7 @@ static int mtk_reset(struct reset_controller_dev *rcdev,
        return mtk_reset_deassert(rcdev, id);
 }
 
-static struct reset_control_ops mtk_reset_ops = {
+static const struct reset_control_ops mtk_reset_ops = {
        .assert = mtk_reset_assert,
        .deassert = mtk_reset_deassert,
        .reset = mtk_reset,
index b54da1f..b4e4d6a 100644 (file)
@@ -74,7 +74,7 @@ static int mmp_clk_reset_deassert(struct reset_controller_dev *rcdev,
        return 0;
 }
 
-static struct reset_control_ops mmp_clk_reset_ops = {
+static const struct reset_control_ops mmp_clk_reset_ops = {
        .assert         = mmp_clk_reset_assert,
        .deassert       = mmp_clk_reset_deassert,
 };
index 5428efb..3cd1af0 100644 (file)
@@ -129,20 +129,10 @@ static const char * const gcc_xo_ddr_500_200[] = {
 };
 
 #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
-#define P_XO 0
-#define FE_PLL_200 1
-#define FE_PLL_500 2
-#define DDRC_PLL_666  3
-
-#define DDRC_PLL_666_SDCC  1
-#define FE_PLL_125_DLY 1
-
-#define FE_PLL_WCSS2G 1
-#define FE_PLL_WCSS5G 1
 
 static const struct freq_tbl ftbl_gcc_audio_pwm_clk[] = {
        F(48000000, P_XO, 1, 0, 0),
-       F(200000000, FE_PLL_200, 1, 0, 0),
+       F(200000000, P_FEPLL200, 1, 0, 0),
        { }
 };
 
@@ -334,15 +324,15 @@ static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
 };
 
 static const struct freq_tbl ftbl_gcc_blsp1_uart1_2_apps_clk[] = {
-       F(1843200, FE_PLL_200, 1, 144, 15625),
-       F(3686400, FE_PLL_200, 1, 288, 15625),
-       F(7372800, FE_PLL_200, 1, 576, 15625),
-       F(14745600, FE_PLL_200, 1, 1152, 15625),
-       F(16000000, FE_PLL_200, 1, 2, 25),
+       F(1843200, P_FEPLL200, 1, 144, 15625),
+       F(3686400, P_FEPLL200, 1, 288, 15625),
+       F(7372800, P_FEPLL200, 1, 576, 15625),
+       F(14745600, P_FEPLL200, 1, 1152, 15625),
+       F(16000000, P_FEPLL200, 1, 2, 25),
        F(24000000, P_XO, 1, 1, 2),
-       F(32000000, FE_PLL_200, 1, 4, 25),
-       F(40000000, FE_PLL_200, 1, 1, 5),
-       F(46400000, FE_PLL_200, 1, 29, 125),
+       F(32000000, P_FEPLL200, 1, 4, 25),
+       F(40000000, P_FEPLL200, 1, 1, 5),
+       F(46400000, P_FEPLL200, 1, 29, 125),
        F(48000000, P_XO, 1, 0, 0),
        { }
 };
@@ -410,9 +400,9 @@ static struct clk_branch gcc_blsp1_uart2_apps_clk = {
 };
 
 static const struct freq_tbl ftbl_gcc_gp_clk[] = {
-       F(1250000,  FE_PLL_200, 1, 16, 0),
-       F(2500000,  FE_PLL_200, 1,  8, 0),
-       F(5000000,  FE_PLL_200, 1,  4, 0),
+       F(1250000,  P_FEPLL200, 1, 16, 0),
+       F(2500000,  P_FEPLL200, 1,  8, 0),
+       F(5000000,  P_FEPLL200, 1,  4, 0),
        { }
 };
 
@@ -512,11 +502,11 @@ static struct clk_branch gcc_gp3_clk = {
 static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = {
        F(144000,    P_XO,                      1,  3, 240),
        F(400000,    P_XO,                      1,  1, 0),
-       F(20000000,  FE_PLL_500,                1,  1, 25),
-       F(25000000,  FE_PLL_500,                1,  1, 20),
-       F(50000000,  FE_PLL_500,                1,  1, 10),
-       F(100000000, FE_PLL_500,                1,  1, 5),
-       F(193000000, DDRC_PLL_666_SDCC,         1,  0, 0),
+       F(20000000,  P_FEPLL500,                1,  1, 25),
+       F(25000000,  P_FEPLL500,                1,  1, 20),
+       F(50000000,  P_FEPLL500,                1,  1, 10),
+       F(100000000, P_FEPLL500,                1,  1, 5),
+       F(193000000, P_DDRPLL,          1,  0, 0),
        { }
 };
 
@@ -536,9 +526,9 @@ static struct clk_rcg2  sdcc1_apps_clk_src = {
 
 static const struct freq_tbl ftbl_gcc_apps_clk[] = {
        F(48000000, P_XO,          1, 0, 0),
-       F(200000000, FE_PLL_200,   1, 0, 0),
-       F(500000000, FE_PLL_500,   1, 0, 0),
-       F(626000000, DDRC_PLL_666, 1, 0, 0),
+       F(200000000, P_FEPLL200,   1, 0, 0),
+       F(500000000, P_FEPLL500,   1, 0, 0),
+       F(626000000, P_DDRPLLAPSS, 1, 0, 0),
        { }
 };
 
@@ -557,7 +547,7 @@ static struct clk_rcg2 apps_clk_src = {
 
 static const struct freq_tbl ftbl_gcc_apps_ahb_clk[] = {
        F(48000000, P_XO,          1, 0, 0),
-       F(100000000, FE_PLL_200,   2, 0, 0),
+       F(100000000, P_FEPLL200,   2, 0, 0),
        { }
 };
 
@@ -940,7 +930,7 @@ static struct clk_branch gcc_usb2_mock_utmi_clk = {
 };
 
 static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = {
-       F(2000000, FE_PLL_200, 10, 0, 0),
+       F(2000000, P_FEPLL200, 10, 0, 0),
        { }
 };
 
@@ -1007,7 +997,7 @@ static struct clk_branch gcc_usb3_mock_utmi_clk = {
 };
 
 static const struct freq_tbl ftbl_gcc_fephy_dly_clk[] = {
-       F(125000000, FE_PLL_125_DLY, 1, 0, 0),
+       F(125000000, P_FEPLL125DLY, 1, 0, 0),
        { }
 };
 
@@ -1027,7 +1017,7 @@ static struct clk_rcg2 fephy_125m_dly_clk_src = {
 
 static const struct freq_tbl ftbl_gcc_wcss2g_clk[] = {
        F(48000000, P_XO, 1, 0, 0),
-       F(250000000, FE_PLL_WCSS2G, 1, 0, 0),
+       F(250000000, P_FEPLLWCSS2G, 1, 0, 0),
        { }
 };
 
@@ -1097,7 +1087,7 @@ static struct clk_branch gcc_wcss2g_rtc_clk = {
 
 static const struct freq_tbl ftbl_gcc_wcss5g_clk[] = {
        F(48000000, P_XO, 1, 0, 0),
-       F(250000000, FE_PLL_WCSS5G, 1, 0, 0),
+       F(250000000, P_FEPLLWCSS5G, 1, 0, 0),
        { }
 };
 
@@ -1325,6 +1315,16 @@ MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table);
 
 static int gcc_ipq4019_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
+
+       clk_register_fixed_rate(dev, "fepll125", "xo", 0, 200000000);
+       clk_register_fixed_rate(dev, "fepll125dly", "xo", 0, 200000000);
+       clk_register_fixed_rate(dev, "fepllwcss2g", "xo", 0, 200000000);
+       clk_register_fixed_rate(dev, "fepllwcss5g", "xo", 0, 200000000);
+       clk_register_fixed_rate(dev, "fepll200", "xo", 0, 200000000);
+       clk_register_fixed_rate(dev, "fepll500", "xo", 0, 200000000);
+       clk_register_fixed_rate(dev, "ddrpllapss", "xo", 0, 666000000);
+
        return qcom_cc_probe(pdev, &gcc_ipq4019_desc);
 }
 
index 6c977d3..0324d8d 100644 (file)
@@ -55,7 +55,7 @@ qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
        return regmap_update_bits(rst->regmap, map->reg, mask, 0);
 }
 
-struct reset_control_ops qcom_reset_ops = {
+const struct reset_control_ops qcom_reset_ops = {
        .reset = qcom_reset,
        .assert = qcom_reset_assert,
        .deassert = qcom_reset_deassert,
index 0e11e21..cda8779 100644 (file)
@@ -32,6 +32,6 @@ struct qcom_reset_controller {
 #define to_qcom_reset_controller(r) \
        container_of(r, struct qcom_reset_controller, rcdev);
 
-extern struct reset_control_ops qcom_reset_ops;
+extern const struct reset_control_ops qcom_reset_ops;
 
 #endif
index 552f7bb..2121898 100644 (file)
@@ -81,7 +81,7 @@ static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev,
        return 0;
 }
 
-static struct reset_control_ops rockchip_softrst_ops = {
+static const struct reset_control_ops rockchip_softrst_ops = {
        .assert         = rockchip_softrst_assert,
        .deassert       = rockchip_softrst_deassert,
 };
index 957aae6..d0c6c9a 100644 (file)
@@ -1423,7 +1423,7 @@ static int atlas7_reset_module(struct reset_controller_dev *rcdev,
        return 0;
 }
 
-static struct reset_control_ops atlas7_rst_ops = {
+static const struct reset_control_ops atlas7_rst_ops = {
        .reset = atlas7_reset_module,
 };
 
index 044c171..d9ea22e 100644 (file)
@@ -85,7 +85,7 @@ static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,
        return 0;
 }
 
-static struct reset_control_ops sunxi_ve_reset_ops = {
+static const struct reset_control_ops sunxi_ve_reset_ops = {
        .assert         = sunxi_ve_reset_assert,
        .deassert       = sunxi_ve_reset_deassert,
 };
index a9b1761..028dd83 100644 (file)
@@ -83,7 +83,7 @@ static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
        return 0;
 }
 
-static struct reset_control_ops sun9i_mmc_reset_ops = {
+static const struct reset_control_ops sun9i_mmc_reset_ops = {
        .assert         = sun9i_mmc_reset_assert,
        .deassert       = sun9i_mmc_reset_deassert,
 };
index 5432b1c..fe0c3d1 100644 (file)
@@ -76,7 +76,7 @@ static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev,
        return 0;
 }
 
-static struct reset_control_ops sunxi_usb_reset_ops = {
+static const struct reset_control_ops sunxi_usb_reset_ops = {
        .assert         = sunxi_usb_reset_assert,
        .deassert       = sunxi_usb_reset_deassert,
 };
index 2a3a4fe..f60fe2e 100644 (file)
@@ -271,7 +271,7 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
        }
 }
 
-static struct reset_control_ops rst_ops = {
+static const struct reset_control_ops rst_ops = {
        .assert = tegra_clk_rst_assert,
        .deassert = tegra_clk_rst_deassert,
 };
index 59a7b38..fb57121 100644 (file)
@@ -245,7 +245,7 @@ static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data)
        }
 }
 
-u32 cpu_freq_read_intel(struct acpi_pct_register *not_used)
+static u32 cpu_freq_read_intel(struct acpi_pct_register *not_used)
 {
        u32 val, dummy;
 
@@ -253,7 +253,7 @@ u32 cpu_freq_read_intel(struct acpi_pct_register *not_used)
        return val;
 }
 
-void cpu_freq_write_intel(struct acpi_pct_register *not_used, u32 val)
+static void cpu_freq_write_intel(struct acpi_pct_register *not_used, u32 val)
 {
        u32 lo, hi;
 
@@ -262,7 +262,7 @@ void cpu_freq_write_intel(struct acpi_pct_register *not_used, u32 val)
        wrmsr(MSR_IA32_PERF_CTL, lo, hi);
 }
 
-u32 cpu_freq_read_amd(struct acpi_pct_register *not_used)
+static u32 cpu_freq_read_amd(struct acpi_pct_register *not_used)
 {
        u32 val, dummy;
 
@@ -270,12 +270,12 @@ u32 cpu_freq_read_amd(struct acpi_pct_register *not_used)
        return val;
 }
 
-void cpu_freq_write_amd(struct acpi_pct_register *not_used, u32 val)
+static void cpu_freq_write_amd(struct acpi_pct_register *not_used, u32 val)
 {
        wrmsr(MSR_AMD_PERF_CTL, val, 0);
 }
 
-u32 cpu_freq_read_io(struct acpi_pct_register *reg)
+static u32 cpu_freq_read_io(struct acpi_pct_register *reg)
 {
        u32 val;
 
@@ -283,7 +283,7 @@ u32 cpu_freq_read_io(struct acpi_pct_register *reg)
        return val;
 }
 
-void cpu_freq_write_io(struct acpi_pct_register *reg, u32 val)
+static void cpu_freq_write_io(struct acpi_pct_register *reg, u32 val)
 {
        acpi_os_write_port(reg->address, val, reg->bit_width);
 }
@@ -514,8 +514,10 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
         */
 
        switch (action) {
-       case CPU_UP_PREPARE:
-       case CPU_UP_PREPARE_FROZEN:
+       case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
+       case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
                break;
 
index 4c78258..b87596b 100644 (file)
@@ -76,6 +76,7 @@ static inline bool has_target(void)
 /* internal prototypes */
 static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
 static unsigned int __cpufreq_get(struct cpufreq_policy *policy);
+static int cpufreq_start_governor(struct cpufreq_policy *policy);
 
 /**
  * Two notifier lists: the "policy" list is involved in the
@@ -964,10 +965,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
        cpumask_set_cpu(cpu, policy->cpus);
 
        if (has_target()) {
-               ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
-               if (!ret)
-                       ret = cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
-
+               ret = cpufreq_start_governor(policy);
                if (ret)
                        pr_err("%s: Failed to start governor\n", __func__);
        }
@@ -1308,10 +1306,7 @@ static void cpufreq_offline(unsigned int cpu)
        /* Start governor again for active policy */
        if (!policy_is_inactive(policy)) {
                if (has_target()) {
-                       ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
-                       if (!ret)
-                               ret = cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
-
+                       ret = cpufreq_start_governor(policy);
                        if (ret)
                                pr_err("%s: Failed to start governor\n", __func__);
                }
@@ -1401,9 +1396,17 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
 {
        struct cpufreq_policy *policy;
        unsigned int ret_freq = 0;
+       unsigned long flags;
 
-       if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get)
-               return cpufreq_driver->get(cpu);
+       read_lock_irqsave(&cpufreq_driver_lock, flags);
+
+       if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get) {
+               ret_freq = cpufreq_driver->get(cpu);
+               read_unlock_irqrestore(&cpufreq_driver_lock, flags);
+               return ret_freq;
+       }
+
+       read_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
        policy = cpufreq_cpu_get(cpu);
        if (policy) {
@@ -1484,6 +1487,24 @@ unsigned int cpufreq_get(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_get);
 
+static unsigned int cpufreq_update_current_freq(struct cpufreq_policy *policy)
+{
+       unsigned int new_freq;
+
+       new_freq = cpufreq_driver->get(policy->cpu);
+       if (!new_freq)
+               return 0;
+
+       if (!policy->cur) {
+               pr_debug("cpufreq: Driver did not initialize current freq\n");
+               policy->cur = new_freq;
+       } else if (policy->cur != new_freq && has_target()) {
+               cpufreq_out_of_sync(policy, new_freq);
+       }
+
+       return new_freq;
+}
+
 static struct subsys_interface cpufreq_interface = {
        .name           = "cpufreq",
        .subsys         = &cpu_subsys,
@@ -1583,9 +1604,7 @@ void cpufreq_resume(void)
                                policy);
                } else {
                        down_write(&policy->rwsem);
-                       ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
-                       if (!ret)
-                               cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+                       ret = cpufreq_start_governor(policy);
                        up_write(&policy->rwsem);
 
                        if (ret)
@@ -1593,17 +1612,6 @@ void cpufreq_resume(void)
                                       __func__, policy);
                }
        }
-
-       /*
-        * schedule call cpufreq_update_policy() for first-online CPU, as that
-        * wouldn't be hotplugged-out on suspend. It will verify that the
-        * current freq is in sync with what we believe it to be.
-        */
-       policy = cpufreq_cpu_get_raw(cpumask_first(cpu_online_mask));
-       if (WARN_ON(!policy))
-               return;
-
-       schedule_work(&policy->update);
 }
 
 /**
@@ -1927,6 +1935,17 @@ static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
        return ret;
 }
 
+static int cpufreq_start_governor(struct cpufreq_policy *policy)
+{
+       int ret;
+
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy)
+               cpufreq_update_current_freq(policy);
+
+       ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
+       return ret ? ret : cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+}
+
 int cpufreq_register_governor(struct cpufreq_governor *governor)
 {
        int err;
@@ -2063,8 +2082,10 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
                return cpufreq_driver->setpolicy(new_policy);
        }
 
-       if (new_policy->governor == policy->governor)
-               goto out;
+       if (new_policy->governor == policy->governor) {
+               pr_debug("cpufreq: governor limits update\n");
+               return cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+       }
 
        pr_debug("governor switch\n");
 
@@ -2092,10 +2113,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
        policy->governor = new_policy->governor;
        ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
        if (!ret) {
-               ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
-               if (!ret)
-                       goto out;
-
+               ret = cpufreq_start_governor(policy);
+               if (!ret) {
+                       pr_debug("cpufreq: governor change\n");
+                       return 0;
+               }
                cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
        }
 
@@ -2106,14 +2128,10 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
                if (cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT))
                        policy->governor = NULL;
                else
-                       cpufreq_governor(policy, CPUFREQ_GOV_START);
+                       cpufreq_start_governor(policy);
        }
 
        return ret;
-
- out:
-       pr_debug("governor: change or update limits\n");
-       return cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
 }
 
 /**
@@ -2144,19 +2162,11 @@ int cpufreq_update_policy(unsigned int cpu)
         * -> ask driver for current freq and notify governors about a change
         */
        if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
-               new_policy.cur = cpufreq_driver->get(cpu);
+               new_policy.cur = cpufreq_update_current_freq(policy);
                if (WARN_ON(!new_policy.cur)) {
                        ret = -EIO;
                        goto unlock;
                }
-
-               if (!policy->cur) {
-                       pr_debug("Driver did not initialize current freq\n");
-                       policy->cur = new_policy.cur;
-               } else {
-                       if (policy->cur != new_policy.cur && has_target())
-                               cpufreq_out_of_sync(policy, new_policy.cur);
-               }
        }
 
        ret = cpufreq_set_policy(policy, &new_policy);
index 1c25ef4..10a5cfe 100644 (file)
@@ -329,7 +329,7 @@ static void dbs_irq_work(struct irq_work *irq_work)
        struct policy_dbs_info *policy_dbs;
 
        policy_dbs = container_of(irq_work, struct policy_dbs_info, irq_work);
-       schedule_work(&policy_dbs->work);
+       schedule_work_on(smp_processor_id(), &policy_dbs->work);
 }
 
 static void dbs_update_util_handler(struct update_util_data *data, u64 time,
index cb56074..4b64452 100644 (file)
@@ -134,7 +134,7 @@ struct pstate_funcs {
        int (*get_min)(void);
        int (*get_turbo)(void);
        int (*get_scaling)(void);
-       void (*set)(struct cpudata*, int pstate);
+       u64 (*get_val)(struct cpudata*, int pstate);
        void (*get_vid)(struct cpudata *);
        int32_t (*get_target_pstate)(struct cpudata *);
 };
@@ -565,7 +565,7 @@ static int atom_get_turbo_pstate(void)
        return value & 0x7F;
 }
 
-static void atom_set_pstate(struct cpudata *cpudata, int pstate)
+static u64 atom_get_val(struct cpudata *cpudata, int pstate)
 {
        u64 val;
        int32_t vid_fp;
@@ -585,9 +585,7 @@ static void atom_set_pstate(struct cpudata *cpudata, int pstate)
        if (pstate > cpudata->pstate.max_pstate)
                vid = cpudata->vid.turbo;
 
-       val |= vid;
-
-       wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
+       return val | vid;
 }
 
 static int silvermont_get_scaling(void)
@@ -711,7 +709,7 @@ static inline int core_get_scaling(void)
        return 100000;
 }
 
-static void core_set_pstate(struct cpudata *cpudata, int pstate)
+static u64 core_get_val(struct cpudata *cpudata, int pstate)
 {
        u64 val;
 
@@ -719,7 +717,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
        if (limits->no_turbo && !limits->turbo_disabled)
                val |= (u64)1 << 32;
 
-       wrmsrl(MSR_IA32_PERF_CTL, val);
+       return val;
 }
 
 static int knl_get_turbo_pstate(void)
@@ -750,7 +748,7 @@ static struct cpu_defaults core_params = {
                .get_min = core_get_min_pstate,
                .get_turbo = core_get_turbo_pstate,
                .get_scaling = core_get_scaling,
-               .set = core_set_pstate,
+               .get_val = core_get_val,
                .get_target_pstate = get_target_pstate_use_performance,
        },
 };
@@ -769,7 +767,7 @@ static struct cpu_defaults silvermont_params = {
                .get_max_physical = atom_get_max_pstate,
                .get_min = atom_get_min_pstate,
                .get_turbo = atom_get_turbo_pstate,
-               .set = atom_set_pstate,
+               .get_val = atom_get_val,
                .get_scaling = silvermont_get_scaling,
                .get_vid = atom_get_vid,
                .get_target_pstate = get_target_pstate_use_cpu_load,
@@ -790,7 +788,7 @@ static struct cpu_defaults airmont_params = {
                .get_max_physical = atom_get_max_pstate,
                .get_min = atom_get_min_pstate,
                .get_turbo = atom_get_turbo_pstate,
-               .set = atom_set_pstate,
+               .get_val = atom_get_val,
                .get_scaling = airmont_get_scaling,
                .get_vid = atom_get_vid,
                .get_target_pstate = get_target_pstate_use_cpu_load,
@@ -812,7 +810,7 @@ static struct cpu_defaults knl_params = {
                .get_min = core_get_min_pstate,
                .get_turbo = knl_get_turbo_pstate,
                .get_scaling = core_get_scaling,
-               .set = core_set_pstate,
+               .get_val = core_get_val,
                .get_target_pstate = get_target_pstate_use_performance,
        },
 };
@@ -839,25 +837,24 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
        *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
 }
 
-static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate, bool force)
+static inline void intel_pstate_record_pstate(struct cpudata *cpu, int pstate)
 {
-       int max_perf, min_perf;
-
-       if (force) {
-               update_turbo_state();
-
-               intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
-
-               pstate = clamp_t(int, pstate, min_perf, max_perf);
-
-               if (pstate == cpu->pstate.current_pstate)
-                       return;
-       }
        trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
-
        cpu->pstate.current_pstate = pstate;
+}
 
-       pstate_funcs.set(cpu, pstate);
+static void intel_pstate_set_min_pstate(struct cpudata *cpu)
+{
+       int pstate = cpu->pstate.min_pstate;
+
+       intel_pstate_record_pstate(cpu, pstate);
+       /*
+        * Generally, there is no guarantee that this code will always run on
+        * the CPU being updated, so force the register update to run on the
+        * right CPU.
+        */
+       wrmsrl_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL,
+                     pstate_funcs.get_val(cpu, pstate));
 }
 
 static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
@@ -870,7 +867,8 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
 
        if (pstate_funcs.get_vid)
                pstate_funcs.get_vid(cpu);
-       intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate, false);
+
+       intel_pstate_set_min_pstate(cpu);
 }
 
 static inline void intel_pstate_calc_busy(struct cpudata *cpu)
@@ -997,6 +995,21 @@ static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
        return cpu->pstate.current_pstate - pid_calc(&cpu->pid, core_busy);
 }
 
+static inline void intel_pstate_update_pstate(struct cpudata *cpu, int pstate)
+{
+       int max_perf, min_perf;
+
+       update_turbo_state();
+
+       intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
+       pstate = clamp_t(int, pstate, min_perf, max_perf);
+       if (pstate == cpu->pstate.current_pstate)
+               return;
+
+       intel_pstate_record_pstate(cpu, pstate);
+       wrmsrl(MSR_IA32_PERF_CTL, pstate_funcs.get_val(cpu, pstate));
+}
+
 static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
 {
        int from, target_pstate;
@@ -1006,7 +1019,7 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
 
        target_pstate = pstate_funcs.get_target_pstate(cpu);
 
-       intel_pstate_set_pstate(cpu, target_pstate, true);
+       intel_pstate_update_pstate(cpu, target_pstate);
 
        sample = &cpu->sample;
        trace_pstate_sample(fp_toint(sample->core_pct_busy),
@@ -1180,7 +1193,7 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
        if (hwp_active)
                return;
 
-       intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate, false);
+       intel_pstate_set_min_pstate(cpu);
 }
 
 static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
@@ -1255,7 +1268,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)
        pstate_funcs.get_min   = funcs->get_min;
        pstate_funcs.get_turbo = funcs->get_turbo;
        pstate_funcs.get_scaling = funcs->get_scaling;
-       pstate_funcs.set       = funcs->set;
+       pstate_funcs.get_val   = funcs->get_val;
        pstate_funcs.get_vid   = funcs->get_vid;
        pstate_funcs.get_target_pstate = funcs->get_target_pstate;
 
index 50bf120..39ac78c 100644 (file)
@@ -44,7 +44,6 @@
 
 static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
 static bool rebooting, throttled, occ_reset;
-static unsigned int *core_to_chip_map;
 
 static const char * const throttle_reason[] = {
        "No throttling",
@@ -55,6 +54,16 @@ static const char * const throttle_reason[] = {
        "OCC Reset"
 };
 
+enum throttle_reason_type {
+       NO_THROTTLE = 0,
+       POWERCAP,
+       CPU_OVERTEMP,
+       POWER_SUPPLY_FAILURE,
+       OVERCURRENT,
+       OCC_RESET_THROTTLE,
+       OCC_MAX_REASON
+};
+
 static struct chip {
        unsigned int id;
        bool throttled;
@@ -62,9 +71,13 @@ static struct chip {
        u8 throttle_reason;
        cpumask_t mask;
        struct work_struct throttle;
+       int throttle_turbo;
+       int throttle_sub_turbo;
+       int reason[OCC_MAX_REASON];
 } *chips;
 
 static int nr_chips;
+static DEFINE_PER_CPU(struct chip *, chip_info);
 
 /*
  * Note: The set of pstates consists of contiguous integers, the
@@ -196,6 +209,42 @@ static struct freq_attr *powernv_cpu_freq_attr[] = {
        NULL,
 };
 
+#define throttle_attr(name, member)                                    \
+static ssize_t name##_show(struct cpufreq_policy *policy, char *buf)   \
+{                                                                      \
+       struct chip *chip = per_cpu(chip_info, policy->cpu);            \
+                                                                       \
+       return sprintf(buf, "%u\n", chip->member);                      \
+}                                                                      \
+                                                                       \
+static struct freq_attr throttle_attr_##name = __ATTR_RO(name)         \
+
+throttle_attr(unthrottle, reason[NO_THROTTLE]);
+throttle_attr(powercap, reason[POWERCAP]);
+throttle_attr(overtemp, reason[CPU_OVERTEMP]);
+throttle_attr(supply_fault, reason[POWER_SUPPLY_FAILURE]);
+throttle_attr(overcurrent, reason[OVERCURRENT]);
+throttle_attr(occ_reset, reason[OCC_RESET_THROTTLE]);
+throttle_attr(turbo_stat, throttle_turbo);
+throttle_attr(sub_turbo_stat, throttle_sub_turbo);
+
+static struct attribute *throttle_attrs[] = {
+       &throttle_attr_unthrottle.attr,
+       &throttle_attr_powercap.attr,
+       &throttle_attr_overtemp.attr,
+       &throttle_attr_supply_fault.attr,
+       &throttle_attr_overcurrent.attr,
+       &throttle_attr_occ_reset.attr,
+       &throttle_attr_turbo_stat.attr,
+       &throttle_attr_sub_turbo_stat.attr,
+       NULL,
+};
+
+static const struct attribute_group throttle_attr_grp = {
+       .name   = "throttle_stats",
+       .attrs  = throttle_attrs,
+};
+
 /* Helper routines */
 
 /* Access helpers to power mgt SPR */
@@ -324,34 +373,35 @@ static inline unsigned int get_nominal_index(void)
 
 static void powernv_cpufreq_throttle_check(void *data)
 {
+       struct chip *chip;
        unsigned int cpu = smp_processor_id();
-       unsigned int chip_id = core_to_chip_map[cpu_core_index_of_thread(cpu)];
        unsigned long pmsr;
-       int pmsr_pmax, i;
+       int pmsr_pmax;
 
        pmsr = get_pmspr(SPRN_PMSR);
-
-       for (i = 0; i < nr_chips; i++)
-               if (chips[i].id == chip_id)
-                       break;
+       chip = this_cpu_read(chip_info);
 
        /* Check for Pmax Capping */
        pmsr_pmax = (s8)PMSR_MAX(pmsr);
        if (pmsr_pmax != powernv_pstate_info.max) {
-               if (chips[i].throttled)
+               if (chip->throttled)
                        goto next;
-               chips[i].throttled = true;
-               if (pmsr_pmax < powernv_pstate_info.nominal)
+               chip->throttled = true;
+               if (pmsr_pmax < powernv_pstate_info.nominal) {
                        pr_warn_once("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
-                                    cpu, chips[i].id, pmsr_pmax,
+                                    cpu, chip->id, pmsr_pmax,
                                     powernv_pstate_info.nominal);
-               trace_powernv_throttle(chips[i].id,
-                                     throttle_reason[chips[i].throttle_reason],
+                       chip->throttle_sub_turbo++;
+               } else {
+                       chip->throttle_turbo++;
+               }
+               trace_powernv_throttle(chip->id,
+                                     throttle_reason[chip->throttle_reason],
                                      pmsr_pmax);
-       } else if (chips[i].throttled) {
-               chips[i].throttled = false;
-               trace_powernv_throttle(chips[i].id,
-                                     throttle_reason[chips[i].throttle_reason],
+       } else if (chip->throttled) {
+               chip->throttled = false;
+               trace_powernv_throttle(chip->id,
+                                     throttle_reason[chip->throttle_reason],
                                      pmsr_pmax);
        }
 
@@ -411,6 +461,21 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
        for (i = 0; i < threads_per_core; i++)
                cpumask_set_cpu(base + i, policy->cpus);
 
+       if (!policy->driver_data) {
+               int ret;
+
+               ret = sysfs_create_group(&policy->kobj, &throttle_attr_grp);
+               if (ret) {
+                       pr_info("Failed to create throttle stats directory for cpu %d\n",
+                               policy->cpu);
+                       return ret;
+               }
+               /*
+                * policy->driver_data is used as a flag for one-time
+                * creation of throttle sysfs files.
+                */
+               policy->driver_data = policy;
+       }
        return cpufreq_table_validate_and_show(policy, powernv_freqs);
 }
 
@@ -517,8 +582,10 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
                                break;
 
                if (omsg.throttle_status >= 0 &&
-                   omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS)
+                   omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS) {
                        chips[i].throttle_reason = omsg.throttle_status;
+                       chips[i].reason[omsg.throttle_status]++;
+               }
 
                if (!omsg.throttle_status)
                        chips[i].restore = true;
@@ -558,47 +625,34 @@ static int init_chip_info(void)
        unsigned int chip[256];
        unsigned int cpu, i;
        unsigned int prev_chip_id = UINT_MAX;
-       cpumask_t cpu_mask;
-       int ret = -ENOMEM;
-
-       core_to_chip_map = kcalloc(cpu_nr_cores(), sizeof(unsigned int),
-                                  GFP_KERNEL);
-       if (!core_to_chip_map)
-               goto out;
 
-       cpumask_copy(&cpu_mask, cpu_possible_mask);
-       for_each_cpu(cpu, &cpu_mask) {
+       for_each_possible_cpu(cpu) {
                unsigned int id = cpu_to_chip_id(cpu);
 
                if (prev_chip_id != id) {
                        prev_chip_id = id;
                        chip[nr_chips++] = id;
                }
-               core_to_chip_map[cpu_core_index_of_thread(cpu)] = id;
-               cpumask_andnot(&cpu_mask, &cpu_mask, cpu_sibling_mask(cpu));
        }
 
        chips = kcalloc(nr_chips, sizeof(struct chip), GFP_KERNEL);
        if (!chips)
-               goto free_chip_map;
+               return -ENOMEM;
 
        for (i = 0; i < nr_chips; i++) {
                chips[i].id = chip[i];
                cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i]));
                INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn);
+               for_each_cpu(cpu, &chips[i].mask)
+                       per_cpu(chip_info, cpu) =  &chips[i];
        }
 
        return 0;
-free_chip_map:
-       kfree(core_to_chip_map);
-out:
-       return ret;
 }
 
 static inline void clean_chip_info(void)
 {
        kfree(chips);
-       kfree(core_to_chip_map);
 }
 
 static inline void unregister_all_notifiers(void)
index 27fc733..03d38c2 100644 (file)
@@ -196,7 +196,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
  * of points is below a threshold. If it is... then use the
  * average of these 8 points as the estimated value.
  */
-static void get_typical_interval(struct menu_device *data)
+static unsigned int get_typical_interval(struct menu_device *data)
 {
        int i, divisor;
        unsigned int max, thresh, avg;
@@ -253,9 +253,7 @@ again:
        if (likely(variance <= U64_MAX/36)) {
                if ((((u64)avg*avg > variance*36) && (divisor * 4 >= INTERVALS * 3))
                                                        || variance <= 400) {
-                       if (data->next_timer_us > avg)
-                               data->predicted_us = avg;
-                       return;
+                       return avg;
                }
        }
 
@@ -269,7 +267,7 @@ again:
         * with sporadic activity with a bunch of short pauses.
         */
        if ((divisor * 4) <= INTERVALS * 3)
-               return;
+               return UINT_MAX;
 
        thresh = max - 1;
        goto again;
@@ -286,6 +284,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
        int i;
        unsigned int interactivity_req;
+       unsigned int expected_interval;
        unsigned long nr_iowaiters, cpu_load;
 
        if (data->needs_update) {
@@ -312,31 +311,42 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                                         data->correction_factor[data->bucket],
                                         RESOLUTION * DECAY);
 
-       get_typical_interval(data);
-
-       /*
-        * Performance multiplier defines a minimum predicted idle
-        * duration / latency ratio. Adjust the latency limit if
-        * necessary.
-        */
-       interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load);
-       if (latency_req > interactivity_req)
-               latency_req = interactivity_req;
+       expected_interval = get_typical_interval(data);
+       expected_interval = min(expected_interval, data->next_timer_us);
 
        if (CPUIDLE_DRIVER_STATE_START > 0) {
-               data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1;
+               struct cpuidle_state *s = &drv->states[CPUIDLE_DRIVER_STATE_START];
+               unsigned int polling_threshold;
+
                /*
                 * We want to default to C1 (hlt), not to busy polling
-                * unless the timer is happening really really soon.
+                * unless the timer is happening really really soon, or
+                * C1's exit latency exceeds the user configured limit.
                 */
-               if (interactivity_req > 20 &&
-                   !drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
-                       dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
+               polling_threshold = max_t(unsigned int, 20, s->target_residency);
+               if (data->next_timer_us > polling_threshold &&
+                   latency_req > s->exit_latency && !s->disabled &&
+                   !dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable)
                        data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
+               else
+                       data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1;
        } else {
                data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
        }
 
+       /*
+        * Use the lowest expected idle interval to pick the idle state.
+        */
+       data->predicted_us = min(data->predicted_us, expected_interval);
+
+       /*
+        * Use the performance multiplier and the user-configurable
+        * latency_req to determine the maximum exit latency.
+        */
+       interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load);
+       if (latency_req > interactivity_req)
+               latency_req = interactivity_req;
+
        /*
         * Find the idle state with the lowest power while satisfying
         * our constraints.
index 64281bb..4de78c5 100644 (file)
@@ -61,7 +61,7 @@ config DEVFREQ_GOV_USERSPACE
          Sets the frequency at the user specified one.
          This governor returns the user configured frequency if there
          has been an input to /sys/devices/.../power/devfreq_set_freq.
-         Otherwise, the governor does not change the frequnecy
+         Otherwise, the governor does not change the frequency
          given at the initialization.
 
 comment "DEVFREQ Drivers"
index 9810d1d..4a2c07e 100644 (file)
@@ -259,6 +259,7 @@ static long dma_buf_ioctl(struct file *file,
        struct dma_buf *dmabuf;
        struct dma_buf_sync sync;
        enum dma_data_direction direction;
+       int ret;
 
        dmabuf = file->private_data;
 
@@ -285,11 +286,11 @@ static long dma_buf_ioctl(struct file *file,
                }
 
                if (sync.flags & DMA_BUF_SYNC_END)
-                       dma_buf_end_cpu_access(dmabuf, direction);
+                       ret = dma_buf_end_cpu_access(dmabuf, direction);
                else
-                       dma_buf_begin_cpu_access(dmabuf, direction);
+                       ret = dma_buf_begin_cpu_access(dmabuf, direction);
 
-               return 0;
+               return ret;
        default:
                return -ENOTTY;
        }
@@ -611,15 +612,19 @@ EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
  * @dmabuf:    [in]    buffer to complete cpu access for.
  * @direction: [in]    length of range for cpu access.
  *
- * This call must always succeed.
+ * Can return negative error values, returns 0 on success.
  */
-void dma_buf_end_cpu_access(struct dma_buf *dmabuf,
-                           enum dma_data_direction direction)
+int dma_buf_end_cpu_access(struct dma_buf *dmabuf,
+                          enum dma_data_direction direction)
 {
+       int ret = 0;
+
        WARN_ON(!dmabuf);
 
        if (dmabuf->ops->end_cpu_access)
-               dmabuf->ops->end_cpu_access(dmabuf, direction);
+               ret = dmabuf->ops->end_cpu_access(dmabuf, direction);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
 
index dc68744..6b81687 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 #include "virt-dma.h"
 
index 8a46077..631c977 100644 (file)
@@ -446,14 +446,16 @@ static void
 bus_reset_irq_handler(struct pcilynx *lynx)
 {
        struct client *client;
-       struct timeval tv;
+       struct timespec64 ts64;
+       u32    timestamp;
 
-       do_gettimeofday(&tv);
+       ktime_get_real_ts64(&ts64);
+       timestamp = ts64.tv_nsec / NSEC_PER_USEC;
 
        spin_lock(&lynx->client_list_lock);
 
        list_for_each_entry(client, &lynx->client_list, link)
-               packet_buffer_put(&client->buffer, &tv.tv_usec, 4);
+               packet_buffer_put(&client->buffer, &timestamp, 4);
 
        spin_unlock(&lynx->client_list_lock);
 }
index a68e199..c5c9599 100644 (file)
@@ -37,7 +37,6 @@ struct men_z127_gpio {
        void __iomem *reg_base;
        struct mcb_device *mdev;
        struct resource *mem;
-       spinlock_t lock;
 };
 
 static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
@@ -69,7 +68,7 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
                debounce /= 50;
        }
 
-       spin_lock(&priv->lock);
+       spin_lock(&gc->bgpio_lock);
 
        db_en = readl(priv->reg_base + MEN_Z127_DBER);
 
@@ -84,7 +83,7 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
        writel(db_en, priv->reg_base + MEN_Z127_DBER);
        writel(db_cnt, priv->reg_base + GPIO_TO_DBCNT_REG(gpio));
 
-       spin_unlock(&priv->lock);
+       spin_unlock(&gc->bgpio_lock);
 
        return 0;
 }
@@ -97,7 +96,7 @@ static int men_z127_request(struct gpio_chip *gc, unsigned gpio_pin)
        if (gpio_pin >= gc->ngpio)
                return -EINVAL;
 
-       spin_lock(&priv->lock);
+       spin_lock(&gc->bgpio_lock);
        od_en = readl(priv->reg_base + MEN_Z127_ODER);
 
        if (gpiochip_line_is_open_drain(gc, gpio_pin))
@@ -106,7 +105,7 @@ static int men_z127_request(struct gpio_chip *gc, unsigned gpio_pin)
                od_en &= ~BIT(gpio_pin);
 
        writel(od_en, priv->reg_base + MEN_Z127_ODER);
-       spin_unlock(&priv->lock);
+       spin_unlock(&gc->bgpio_lock);
 
        return 0;
 }
index c0aa387..0dc9161 100644 (file)
@@ -173,6 +173,11 @@ static int xgene_gpio_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               err = -EINVAL;
+               goto err;
+       }
+
        gpio->base = devm_ioremap_nocache(&pdev->dev, res->start,
                                                        resource_size(res));
        if (!gpio->base) {
index 0f734ee..ca77ec1 100644 (file)
@@ -1,10 +1,14 @@
-menu "ACP Configuration"
+menu "ACP (Audio CoProcessor) Configuration"
 
 config DRM_AMD_ACP
-       bool "Enable ACP IP support"
+       bool "Enable AMD Audio CoProcessor IP support"
        select MFD_CORE
        select PM_GENERIC_DOMAINS if PM
        help
        Choose this option to enable ACP IP support for AMD SOCs.
+       This adds the ACP (Audio CoProcessor) IP driver and wires
+       it up into the amdgpu driver.  The ACP block provides the DMA
+       engine for the i2s-based ALSA driver. It is required for audio
+       on APUs which utilize an i2s codec.
 
 endmenu
index d7ec9bd..9f4a45c 100644 (file)
@@ -48,7 +48,8 @@ struct amdgpu_mn {
        /* protected by adev->mn_lock */
        struct hlist_node       node;
 
-       /* objects protected by mm->mmap_sem */
+       /* objects protected by lock */
+       struct mutex            lock;
        struct rb_root          objects;
 };
 
@@ -72,7 +73,7 @@ static void amdgpu_mn_destroy(struct work_struct *work)
        struct amdgpu_bo *bo, *next_bo;
 
        mutex_lock(&adev->mn_lock);
-       down_write(&rmn->mm->mmap_sem);
+       mutex_lock(&rmn->lock);
        hash_del(&rmn->node);
        rbtree_postorder_for_each_entry_safe(node, next_node, &rmn->objects,
                                             it.rb) {
@@ -82,7 +83,7 @@ static void amdgpu_mn_destroy(struct work_struct *work)
                }
                kfree(node);
        }
-       up_write(&rmn->mm->mmap_sem);
+       mutex_unlock(&rmn->lock);
        mutex_unlock(&adev->mn_lock);
        mmu_notifier_unregister_no_release(&rmn->mn, rmn->mm);
        kfree(rmn);
@@ -104,6 +105,76 @@ static void amdgpu_mn_release(struct mmu_notifier *mn,
        schedule_work(&rmn->work);
 }
 
+/**
+ * amdgpu_mn_invalidate_node - unmap all BOs of a node
+ *
+ * @node: the node with the BOs to unmap
+ *
+ * We block for all BOs and unmap them by move them
+ * into system domain again.
+ */
+static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node,
+                                     unsigned long start,
+                                     unsigned long end)
+{
+       struct amdgpu_bo *bo;
+       long r;
+
+       list_for_each_entry(bo, &node->bos, mn_list) {
+
+               if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, start, end))
+                       continue;
+
+               r = amdgpu_bo_reserve(bo, true);
+               if (r) {
+                       DRM_ERROR("(%ld) failed to reserve user bo\n", r);
+                       continue;
+               }
+
+               r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
+                       true, false, MAX_SCHEDULE_TIMEOUT);
+               if (r <= 0)
+                       DRM_ERROR("(%ld) failed to wait for user bo\n", r);
+
+               amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_CPU);
+               r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+               if (r)
+                       DRM_ERROR("(%ld) failed to validate user bo\n", r);
+
+               amdgpu_bo_unreserve(bo);
+       }
+}
+
+/**
+ * amdgpu_mn_invalidate_page - callback to notify about mm change
+ *
+ * @mn: our notifier
+ * @mn: the mm this callback is about
+ * @address: address of invalidate page
+ *
+ * Invalidation of a single page. Blocks for all BOs mapping it
+ * and unmap them by move them into system domain again.
+ */
+static void amdgpu_mn_invalidate_page(struct mmu_notifier *mn,
+                                     struct mm_struct *mm,
+                                     unsigned long address)
+{
+       struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
+       struct interval_tree_node *it;
+
+       mutex_lock(&rmn->lock);
+
+       it = interval_tree_iter_first(&rmn->objects, address, address);
+       if (it) {
+               struct amdgpu_mn_node *node;
+
+               node = container_of(it, struct amdgpu_mn_node, it);
+               amdgpu_mn_invalidate_node(node, address, address);
+       }
+
+       mutex_unlock(&rmn->lock);
+}
+
 /**
  * amdgpu_mn_invalidate_range_start - callback to notify about mm change
  *
@@ -126,44 +197,24 @@ static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn,
        /* notification is exclusive, but interval is inclusive */
        end -= 1;
 
+       mutex_lock(&rmn->lock);
+
        it = interval_tree_iter_first(&rmn->objects, start, end);
        while (it) {
                struct amdgpu_mn_node *node;
-               struct amdgpu_bo *bo;
-               long r;
 
                node = container_of(it, struct amdgpu_mn_node, it);
                it = interval_tree_iter_next(it, start, end);
 
-               list_for_each_entry(bo, &node->bos, mn_list) {
-
-                       if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, start,
-                                                         end))
-                               continue;
-
-                       r = amdgpu_bo_reserve(bo, true);
-                       if (r) {
-                               DRM_ERROR("(%ld) failed to reserve user bo\n", r);
-                               continue;
-                       }
-
-                       r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
-                               true, false, MAX_SCHEDULE_TIMEOUT);
-                       if (r <= 0)
-                               DRM_ERROR("(%ld) failed to wait for user bo\n", r);
-
-                       amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_CPU);
-                       r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
-                       if (r)
-                               DRM_ERROR("(%ld) failed to validate user bo\n", r);
-
-                       amdgpu_bo_unreserve(bo);
-               }
+               amdgpu_mn_invalidate_node(node, start, end);
        }
+
+       mutex_unlock(&rmn->lock);
 }
 
 static const struct mmu_notifier_ops amdgpu_mn_ops = {
        .release = amdgpu_mn_release,
+       .invalidate_page = amdgpu_mn_invalidate_page,
        .invalidate_range_start = amdgpu_mn_invalidate_range_start,
 };
 
@@ -196,6 +247,7 @@ static struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev)
        rmn->adev = adev;
        rmn->mm = mm;
        rmn->mn.ops = &amdgpu_mn_ops;
+       mutex_init(&rmn->lock);
        rmn->objects = RB_ROOT;
 
        r = __mmu_notifier_register(&rmn->mn, mm);
@@ -242,7 +294,7 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
 
        INIT_LIST_HEAD(&bos);
 
-       down_write(&rmn->mm->mmap_sem);
+       mutex_lock(&rmn->lock);
 
        while ((it = interval_tree_iter_first(&rmn->objects, addr, end))) {
                kfree(node);
@@ -256,7 +308,7 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
        if (!node) {
                node = kmalloc(sizeof(struct amdgpu_mn_node), GFP_KERNEL);
                if (!node) {
-                       up_write(&rmn->mm->mmap_sem);
+                       mutex_unlock(&rmn->lock);
                        return -ENOMEM;
                }
        }
@@ -271,7 +323,7 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
 
        interval_tree_insert(&node->it, &rmn->objects);
 
-       up_write(&rmn->mm->mmap_sem);
+       mutex_unlock(&rmn->lock);
 
        return 0;
 }
@@ -297,7 +349,7 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo)
                return;
        }
 
-       down_write(&rmn->mm->mmap_sem);
+       mutex_lock(&rmn->lock);
 
        /* save the next list entry for later */
        head = bo->mn_list.next;
@@ -312,6 +364,6 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo)
                kfree(node);
        }
 
-       up_write(&rmn->mm->mmap_sem);
+       mutex_unlock(&rmn->lock);
        mutex_unlock(&adev->mn_lock);
 }
index 151a2d4..56d1458 100644 (file)
@@ -608,6 +608,10 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
        if ((offset + size) <= adev->mc.visible_vram_size)
                return 0;
 
+       /* Can't move a pinned BO to visible VRAM */
+       if (abo->pin_count > 0)
+               return -EINVAL;
+
        /* hurrah the memory is not visible ! */
        amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM);
        lpfn =  adev->mc.visible_vram_size >> PAGE_SHIFT;
index ab34190..f1a55d1 100644 (file)
@@ -384,9 +384,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo,
                        struct ttm_mem_reg *new_mem)
 {
        struct amdgpu_device *adev;
+       struct amdgpu_bo *abo;
        struct ttm_mem_reg *old_mem = &bo->mem;
        int r;
 
+       /* Can't move a pinned BO */
+       abo = container_of(bo, struct amdgpu_bo, tbo);
+       if (WARN_ON_ONCE(abo->pin_count > 0))
+               return -EINVAL;
+
        adev = amdgpu_get_adev(bo->bdev);
        if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
                amdgpu_move_null(bo, new_mem);
index e195bf5..043e6eb 100644 (file)
@@ -1,17 +1,17 @@
 
 subdir-ccflags-y += -Iinclude/drm  \
-               -Idrivers/gpu/drm/amd/powerplay/inc/  \
-               -Idrivers/gpu/drm/amd/include/asic_reg  \
-               -Idrivers/gpu/drm/amd/include  \
-               -Idrivers/gpu/drm/amd/powerplay/smumgr\
-               -Idrivers/gpu/drm/amd/powerplay/hwmgr \
-               -Idrivers/gpu/drm/amd/powerplay/eventmgr
+               -I$(FULL_AMD_PATH)/powerplay/inc/  \
+               -I$(FULL_AMD_PATH)/include/asic_reg  \
+               -I$(FULL_AMD_PATH)/include  \
+               -I$(FULL_AMD_PATH)/powerplay/smumgr\
+               -I$(FULL_AMD_PATH)/powerplay/hwmgr \
+               -I$(FULL_AMD_PATH)/powerplay/eventmgr
 
 AMD_PP_PATH = ../powerplay
 
 PP_LIBS = smumgr hwmgr eventmgr
 
-AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix drivers/gpu/drm/amd/powerplay/,$(PP_LIBS)))
+AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/powerplay/,$(PP_LIBS)))
 
 include $(AMD_POWERPLAY)
 
index 34f4bef..b156481 100644 (file)
@@ -512,8 +512,10 @@ static int get_cac_tdp_table(
 
        hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL);
 
-       if (NULL == hwmgr->dyn_state.cac_dtp_table)
+       if (NULL == hwmgr->dyn_state.cac_dtp_table) {
+               kfree(tdp_table);
                return -ENOMEM;
+       }
 
        memset(hwmgr->dyn_state.cac_dtp_table, 0x00, table_size);
 
index 1ffe9c3..d65dcae 100644 (file)
@@ -558,7 +558,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
        if (!state->base.crtc || !fb)
                return 0;
 
-       crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)];
+       crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
        mode = &crtc_state->adjusted_mode;
 
        state->src_x = s->src_x;
index a2596eb..8ee1db8 100644 (file)
@@ -380,7 +380,6 @@ EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
  * drm_atomic_replace_property_blob - replace a blob property
  * @blob: a pointer to the member blob to be replaced
  * @new_blob: the new blob to replace with
- * @expected_size: the expected size of the new blob
  * @replaced: whether the blob has been replaced
  *
  * RETURNS:
index 2bb90fa..4befe25 100644 (file)
@@ -67,7 +67,8 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
        struct drm_crtc_state *crtc_state;
 
        if (plane->state->crtc) {
-               crtc_state = state->crtc_states[drm_crtc_index(plane->state->crtc)];
+               crtc_state = drm_atomic_get_existing_crtc_state(state,
+                                                               plane->state->crtc);
 
                if (WARN_ON(!crtc_state))
                        return;
@@ -76,8 +77,8 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
        }
 
        if (plane_state->crtc) {
-               crtc_state =
-                       state->crtc_states[drm_crtc_index(plane_state->crtc)];
+               crtc_state = drm_atomic_get_existing_crtc_state(state,
+                                                               plane_state->crtc);
 
                if (WARN_ON(!crtc_state))
                        return;
@@ -374,8 +375,8 @@ mode_fixup(struct drm_atomic_state *state)
                if (!conn_state->crtc || !conn_state->best_encoder)
                        continue;
 
-               crtc_state =
-                       state->crtc_states[drm_crtc_index(conn_state->crtc)];
+               crtc_state = drm_atomic_get_existing_crtc_state(state,
+                                                               conn_state->crtc);
 
                /*
                 * Each encoder has at most one connector (since we always steal
@@ -679,7 +680,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
                if (!old_conn_state->crtc)
                        continue;
 
-               old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
+               old_crtc_state = drm_atomic_get_existing_crtc_state(old_state,
+                                                                   old_conn_state->crtc);
 
                if (!old_crtc_state->active ||
                    !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
index 7d58f59..df64ed1 100644 (file)
@@ -179,7 +179,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
 {
        struct drm_dp_aux_msg msg;
        unsigned int retry;
-       int err;
+       int err = 0;
 
        memset(&msg, 0, sizeof(msg));
        msg.address = offset;
@@ -187,6 +187,8 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
        msg.buffer = buffer;
        msg.size = size;
 
+       mutex_lock(&aux->hw_mutex);
+
        /*
         * The specification doesn't give any recommendation on how often to
         * retry native transactions. We used to retry 7 times like for
@@ -195,25 +197,24 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
         */
        for (retry = 0; retry < 32; retry++) {
 
-               mutex_lock(&aux->hw_mutex);
                err = aux->transfer(aux, &msg);
-               mutex_unlock(&aux->hw_mutex);
                if (err < 0) {
                        if (err == -EBUSY)
                                continue;
 
-                       return err;
+                       goto unlock;
                }
 
 
                switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) {
                case DP_AUX_NATIVE_REPLY_ACK:
                        if (err < size)
-                               return -EPROTO;
-                       return err;
+                               err = -EPROTO;
+                       goto unlock;
 
                case DP_AUX_NATIVE_REPLY_NACK:
-                       return -EIO;
+                       err = -EIO;
+                       goto unlock;
 
                case DP_AUX_NATIVE_REPLY_DEFER:
                        usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
@@ -222,7 +223,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
        }
 
        DRM_DEBUG_KMS("too many retries, giving up\n");
-       return -EIO;
+       err = -EIO;
+
+unlock:
+       mutex_unlock(&aux->hw_mutex);
+       return err;
 }
 
 /**
@@ -544,9 +549,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz));
 
        for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) {
-               mutex_lock(&aux->hw_mutex);
                ret = aux->transfer(aux, msg);
-               mutex_unlock(&aux->hw_mutex);
                if (ret < 0) {
                        if (ret == -EBUSY)
                                continue;
@@ -685,6 +688,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 
        memset(&msg, 0, sizeof(msg));
 
+       mutex_lock(&aux->hw_mutex);
+
        for (i = 0; i < num; i++) {
                msg.address = msgs[i].addr;
                drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
@@ -739,6 +744,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
        msg.size = 0;
        (void)drm_dp_i2c_do_msg(aux, &msg);
 
+       mutex_unlock(&aux->hw_mutex);
+
        return err;
 }
 
index 1f3eef6..0506016 100644 (file)
@@ -228,25 +228,20 @@ static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_dire
        return ret;
 }
 
-static void i915_gem_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction)
+static int i915_gem_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction)
 {
        struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
        struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       bool was_interruptible;
        int ret;
 
-       mutex_lock(&dev->struct_mutex);
-       was_interruptible = dev_priv->mm.interruptible;
-       dev_priv->mm.interruptible = false;
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
        ret = i915_gem_object_set_to_gtt_domain(obj, false);
-
-       dev_priv->mm.interruptible = was_interruptible;
        mutex_unlock(&dev->struct_mutex);
 
-       if (unlikely(ret))
-               DRM_ERROR("unable to flush buffer following CPU access; rendering may be corrupt\n");
+       return ret;
 }
 
 static const struct dma_buf_ops i915_dmabuf_ops =  {
index b04a646..65428cf 100644 (file)
@@ -196,7 +196,7 @@ void __exit msm_hdmi_phy_driver_unregister(void);
 int msm_hdmi_pll_8960_init(struct platform_device *pdev);
 int msm_hdmi_pll_8996_init(struct platform_device *pdev);
 #else
-static inline int msm_hdmi_pll_8960_init(struct platform_device *pdev);
+static inline int msm_hdmi_pll_8960_init(struct platform_device *pdev)
 {
        return -ENODEV;
 }
index d52910e..c03b967 100644 (file)
@@ -467,9 +467,6 @@ static void msm_preclose(struct drm_device *dev, struct drm_file *file)
        struct msm_file_private *ctx = file->driver_priv;
        struct msm_kms *kms = priv->kms;
 
-       if (kms)
-               kms->funcs->preclose(kms, file);
-
        mutex_lock(&dev->struct_mutex);
        if (ctx == priv->lastctx)
                priv->lastctx = NULL;
index 9bcabaa..e32222c 100644 (file)
@@ -55,7 +55,6 @@ struct msm_kms_funcs {
                        struct drm_encoder *slave_encoder,
                        bool is_cmd_mode);
        /* cleanup: */
-       void (*preclose)(struct msm_kms *kms, struct drm_file *file);
        void (*destroy)(struct msm_kms *kms);
 };
 
index 3cf8aab..af267c3 100644 (file)
@@ -97,11 +97,12 @@ static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer,
        return omap_gem_get_pages(obj, &pages, true);
 }
 
-static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer,
-               enum dma_data_direction dir)
+static int omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer,
+                                         enum dma_data_direction dir)
 {
        struct drm_gem_object *obj = buffer->priv;
        omap_gem_put_pages(obj);
+       return 0;
 }
 
 
index df7a171..43cffb5 100644 (file)
@@ -510,6 +510,7 @@ static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
 {
        struct radeon_encoder_mst *mst_enc;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_connector_atom_dig *dig_connector;
        int bpp = 24;
 
        mst_enc = radeon_encoder->enc_priv;
@@ -523,22 +524,11 @@ static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
 
 
        drm_mode_set_crtcinfo(adjusted_mode, 0);
-       {
-         struct radeon_connector_atom_dig *dig_connector;
-         int ret;
-
-         dig_connector = mst_enc->connector->con_priv;
-         ret = radeon_dp_get_dp_link_config(&mst_enc->connector->base,
-                                            dig_connector->dpcd, adjusted_mode->clock,
-                                            &dig_connector->dp_lane_count,
-                                            &dig_connector->dp_clock);
-         if (ret) {
-                 dig_connector->dp_lane_count = 0;
-                 dig_connector->dp_clock = 0;
-         }
-         DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
-                       dig_connector->dp_lane_count, dig_connector->dp_clock);
-       }
+       dig_connector = mst_enc->connector->con_priv;
+       dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
+       dig_connector->dp_clock = drm_dp_max_link_rate(dig_connector->dpcd);
+       DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
+                     dig_connector->dp_lane_count, dig_connector->dp_clock);
        return true;
 }
 
index dd46c38..2d901bf 100644 (file)
@@ -799,6 +799,10 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
        if ((offset + size) <= rdev->mc.visible_vram_size)
                return 0;
 
+       /* Can't move a pinned BO to visible VRAM */
+       if (rbo->pin_count > 0)
+               return -EINVAL;
+
        /* hurrah the memory is not visible ! */
        radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
        lpfn =  rdev->mc.visible_vram_size >> PAGE_SHIFT;
index 6d8c323..c008312 100644 (file)
@@ -397,9 +397,15 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,
                        struct ttm_mem_reg *new_mem)
 {
        struct radeon_device *rdev;
+       struct radeon_bo *rbo;
        struct ttm_mem_reg *old_mem = &bo->mem;
        int r;
 
+       /* Can't move a pinned BO */
+       rbo = container_of(bo, struct radeon_bo, tbo);
+       if (WARN_ON_ONCE(rbo->pin_count > 0))
+               return -EINVAL;
+
        rdev = radeon_get_rdev(bo->bdev);
        if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
                radeon_move_null(bo, new_mem);
index cb75ab7..af4df81 100644 (file)
@@ -2926,9 +2926,11 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = {
        /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */
        { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
+       { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0x2015, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 },
+       { PCI_VENDOR_ID_ATI, 0x6811, 0x148c, 0x2015, 0, 120000 },
        { 0, 0, 0, 0 },
 };
 
@@ -3008,6 +3010,10 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
                }
                ++p;
        }
+       /* limit mclk on all R7 370 parts for stability */
+       if (rdev->pdev->device == 0x6811 &&
+           rdev->pdev->revision == 0x81)
+               max_mclk = 120000;
 
        if (rps->vce_active) {
                rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
index 3d3cf2f..d5cfef7 100644 (file)
@@ -271,8 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
        if (!iores)
                return -ENXIO;
 
-       platform_set_drvdata(pdev, hdmi);
-
        encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
        /*
         * If we failed to find the CRTC(s) which this encoder is
@@ -293,7 +291,16 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
        drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
                         DRM_MODE_ENCODER_TMDS, NULL);
 
-       return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+       ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+
+       /*
+        * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
+        * which would have called the encoder cleanup.  Do it manually.
+        */
+       if (ret)
+               drm_encoder_cleanup(encoder);
+
+       return ret;
 }
 
 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
index 896da09..f556a8f 100644 (file)
@@ -251,6 +251,27 @@ static int rockchip_drm_unload(struct drm_device *drm_dev)
        return 0;
 }
 
+static void rockchip_drm_crtc_cancel_pending_vblank(struct drm_crtc *crtc,
+                                                   struct drm_file *file_priv)
+{
+       struct rockchip_drm_private *priv = crtc->dev->dev_private;
+       int pipe = drm_crtc_index(crtc);
+
+       if (pipe < ROCKCHIP_MAX_CRTC &&
+           priv->crtc_funcs[pipe] &&
+           priv->crtc_funcs[pipe]->cancel_pending_vblank)
+               priv->crtc_funcs[pipe]->cancel_pending_vblank(crtc, file_priv);
+}
+
+static void rockchip_drm_preclose(struct drm_device *dev,
+                                 struct drm_file *file_priv)
+{
+       struct drm_crtc *crtc;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               rockchip_drm_crtc_cancel_pending_vblank(crtc, file_priv);
+}
+
 void rockchip_drm_lastclose(struct drm_device *dev)
 {
        struct rockchip_drm_private *priv = dev->dev_private;
@@ -281,6 +302,7 @@ static struct drm_driver rockchip_drm_driver = {
                                  DRIVER_PRIME | DRIVER_ATOMIC,
        .load                   = rockchip_drm_load,
        .unload                 = rockchip_drm_unload,
+       .preclose               = rockchip_drm_preclose,
        .lastclose              = rockchip_drm_lastclose,
        .get_vblank_counter     = drm_vblank_no_hw_counter,
        .enable_vblank          = rockchip_drm_crtc_enable_vblank,
index 3529f69..00d17d7 100644 (file)
@@ -40,6 +40,7 @@ struct rockchip_crtc_funcs {
        int (*enable_vblank)(struct drm_crtc *crtc);
        void (*disable_vblank)(struct drm_crtc *crtc);
        void (*wait_for_update)(struct drm_crtc *crtc);
+       void (*cancel_pending_vblank)(struct drm_crtc *crtc, struct drm_file *file_priv);
 };
 
 struct rockchip_atomic_commit {
index fd37054..a619f12 100644 (file)
@@ -499,10 +499,25 @@ err_disable_hclk:
 static void vop_crtc_disable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
+       int i;
 
        if (!vop->is_enabled)
                return;
 
+       /*
+        * We need to make sure that all windows are disabled before we
+        * disable that crtc. Otherwise we might try to scan from a destroyed
+        * buffer later.
+        */
+       for (i = 0; i < vop->data->win_size; i++) {
+               struct vop_win *vop_win = &vop->win[i];
+               const struct vop_win_data *win = vop_win->data;
+
+               spin_lock(&vop->reg_lock);
+               VOP_WIN_SET(vop, win, enable, 0);
+               spin_unlock(&vop->reg_lock);
+       }
+
        drm_crtc_vblank_off(crtc);
 
        /*
@@ -549,6 +564,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
                           struct drm_plane_state *state)
 {
        struct drm_crtc *crtc = state->crtc;
+       struct drm_crtc_state *crtc_state;
        struct drm_framebuffer *fb = state->fb;
        struct vop_win *vop_win = to_vop_win(plane);
        struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
@@ -563,12 +579,13 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
        int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
                                        DRM_PLANE_HELPER_NO_SCALING;
 
-       crtc = crtc ? crtc : plane->state->crtc;
-       /*
-        * Both crtc or plane->state->crtc can be null.
-        */
        if (!crtc || !fb)
                goto out_disable;
+
+       crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
+       if (WARN_ON(!crtc_state))
+               return -EINVAL;
+
        src->x1 = state->src_x;
        src->y1 = state->src_y;
        src->x2 = state->src_x + state->src_w;
@@ -580,8 +597,8 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
 
        clip.x1 = 0;
        clip.y1 = 0;
-       clip.x2 = crtc->mode.hdisplay;
-       clip.y2 = crtc->mode.vdisplay;
+       clip.x2 = crtc_state->adjusted_mode.hdisplay;
+       clip.y2 = crtc_state->adjusted_mode.vdisplay;
 
        ret = drm_plane_helper_check_update(plane, crtc, state->fb,
                                            src, dest, &clip,
@@ -873,10 +890,30 @@ static void vop_crtc_wait_for_update(struct drm_crtc *crtc)
        WARN_ON(!wait_for_completion_timeout(&vop->wait_update_complete, 100));
 }
 
+static void vop_crtc_cancel_pending_vblank(struct drm_crtc *crtc,
+                                          struct drm_file *file_priv)
+{
+       struct drm_device *drm = crtc->dev;
+       struct vop *vop = to_vop(crtc);
+       struct drm_pending_vblank_event *e;
+       unsigned long flags;
+
+       spin_lock_irqsave(&drm->event_lock, flags);
+       e = vop->event;
+       if (e && e->base.file_priv == file_priv) {
+               vop->event = NULL;
+
+               e->base.destroy(&e->base);
+               file_priv->event_space += sizeof(e->event);
+       }
+       spin_unlock_irqrestore(&drm->event_lock, flags);
+}
+
 static const struct rockchip_crtc_funcs private_crtc_funcs = {
        .enable_vblank = vop_crtc_enable_vblank,
        .disable_vblank = vop_crtc_disable_vblank,
        .wait_for_update = vop_crtc_wait_for_update,
+       .cancel_pending_vblank = vop_crtc_cancel_pending_vblank,
 };
 
 static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -885,9 +922,6 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
 {
        struct vop *vop = to_vop(crtc);
 
-       if (adjusted_mode->htotal == 0 || adjusted_mode->vtotal == 0)
-               return false;
-
        adjusted_mode->clock =
                clk_round_rate(vop->dclk, mode->clock * 1000) / 1000;
 
@@ -1108,7 +1142,7 @@ static int vop_create_crtc(struct vop *vop)
        const struct vop_data *vop_data = vop->data;
        struct device *dev = vop->dev;
        struct drm_device *drm_dev = vop->drm_dev;
-       struct drm_plane *primary = NULL, *cursor = NULL, *plane;
+       struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp;
        struct drm_crtc *crtc = &vop->crtc;
        struct device_node *port;
        int ret;
@@ -1148,7 +1182,7 @@ static int vop_create_crtc(struct vop *vop)
        ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
                                        &vop_crtc_funcs, NULL);
        if (ret)
-               return ret;
+               goto err_cleanup_planes;
 
        drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs);
 
@@ -1181,6 +1215,7 @@ static int vop_create_crtc(struct vop *vop)
        if (!port) {
                DRM_ERROR("no port node found in %s\n",
                          dev->of_node->full_name);
+               ret = -ENOENT;
                goto err_cleanup_crtc;
        }
 
@@ -1194,7 +1229,8 @@ static int vop_create_crtc(struct vop *vop)
 err_cleanup_crtc:
        drm_crtc_cleanup(crtc);
 err_cleanup_planes:
-       list_for_each_entry(plane, &drm_dev->mode_config.plane_list, head)
+       list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list,
+                                head)
                drm_plane_cleanup(plane);
        return ret;
 }
@@ -1202,9 +1238,28 @@ err_cleanup_planes:
 static void vop_destroy_crtc(struct vop *vop)
 {
        struct drm_crtc *crtc = &vop->crtc;
+       struct drm_device *drm_dev = vop->drm_dev;
+       struct drm_plane *plane, *tmp;
 
        rockchip_unregister_crtc_funcs(crtc);
        of_node_put(crtc->port);
+
+       /*
+        * We need to cleanup the planes now.  Why?
+        *
+        * The planes are "&vop->win[i].base".  That means the memory is
+        * all part of the big "struct vop" chunk of memory.  That memory
+        * was devm allocated and associated with this component.  We need to
+        * free it ourselves before vop_unbind() finishes.
+        */
+       list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list,
+                                head)
+               vop_plane_destroy(plane);
+
+       /*
+        * Destroy CRTC after vop_plane_destroy() since vop_disable_plane()
+        * references the CRTC.
+        */
        drm_crtc_cleanup(crtc);
 }
 
index c427499..fd1eb9d 100644 (file)
@@ -423,8 +423,8 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
        }
 
        if (ufb->obj->base.import_attach) {
-               dma_buf_end_cpu_access(ufb->obj->base.import_attach->dmabuf,
-                                      DMA_FROM_DEVICE);
+               ret = dma_buf_end_cpu_access(ufb->obj->base.import_attach->dmabuf,
+                                            DMA_FROM_DEVICE);
        }
 
  unlock:
@@ -536,7 +536,7 @@ static int udlfb_create(struct drm_fb_helper *helper,
 out_destroy_fbi:
        drm_fb_helper_release_fbi(helper);
 out_gfree:
-       drm_gem_object_unreference(&ufbdev->ufb.obj->base);
+       drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base);
 out:
        return ret;
 }
index 2a0a784..d7528e0 100644 (file)
@@ -52,7 +52,7 @@ udl_gem_create(struct drm_file *file,
                return ret;
        }
 
-       drm_gem_object_unreference(&obj->base);
+       drm_gem_object_unreference_unlocked(&obj->base);
        *handle_p = handle;
        return 0;
 }
index 36544c4..303d0c9 100644 (file)
@@ -85,6 +85,9 @@ static struct max1111_data *the_max1111;
 
 int max1111_read_channel(int channel)
 {
+       if (!the_max1111 || !the_max1111->spi)
+               return -ENODEV;
+
        return max1111_read(&the_max1111->spi->dev, channel);
 }
 EXPORT_SYMBOL(max1111_read_channel);
@@ -258,6 +261,9 @@ static int max1111_remove(struct spi_device *spi)
 {
        struct max1111_data *data = spi_get_drvdata(spi);
 
+#ifdef CONFIG_SHARPSL_PM
+       the_max1111 = NULL;
+#endif
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
        sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
index 9f0a48e..80e933b 100644 (file)
@@ -451,7 +451,7 @@ err_free:
        return ret;
 }
 
-static const struct ide_port_info icside_v6_port_info __initconst = {
+static const struct ide_port_info icside_v6_port_info = {
        .init_dma               = icside_dma_off_init,
        .port_ops               = &icside_v6_no_dma_port_ops,
        .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO,
index 8012e43..46427ea 100644 (file)
@@ -325,6 +325,8 @@ static int __init palm_bk3710_probe(struct platform_device *pdev)
 
        clk_enable(clk);
        rate = clk_get_rate(clk);
+       if (!rate)
+               return -EINVAL;
 
        /* NOTE:  round *down* to meet minimum timings; we count in clocks */
        ideclk_period = 1000000000UL / rate;
index cd4510a..ba947df 100644 (file)
@@ -65,7 +65,7 @@
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
-#define INTEL_IDLE_VERSION "0.4"
+#define INTEL_IDLE_VERSION "0.4.1"
 #define PREFIX "intel_idle: "
 
 static struct cpuidle_driver intel_idle_driver = {
@@ -716,6 +716,26 @@ static struct cpuidle_state avn_cstates[] = {
        {
                .enter = NULL }
 };
+static struct cpuidle_state knl_cstates[] = {
+       {
+               .name = "C1-KNL",
+               .desc = "MWAIT 0x00",
+               .flags = MWAIT2flg(0x00),
+               .exit_latency = 1,
+               .target_residency = 2,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze },
+       {
+               .name = "C6-KNL",
+               .desc = "MWAIT 0x10",
+               .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 120,
+               .target_residency = 500,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze },
+       {
+               .enter = NULL }
+};
 
 /**
  * intel_idle
@@ -890,6 +910,10 @@ static const struct idle_cpu idle_cpu_avn = {
        .disable_promotion_to_c1e = true,
 };
 
+static const struct idle_cpu idle_cpu_knl = {
+       .state_table = knl_cstates,
+};
+
 #define ICPU(model, cpu) \
        { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
 
@@ -921,6 +945,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = {
        ICPU(0x56, idle_cpu_bdw),
        ICPU(0x4e, idle_cpu_skl),
        ICPU(0x5e, idle_cpu_skl),
+       ICPU(0x57, idle_cpu_knl),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
@@ -994,36 +1019,92 @@ static void intel_idle_cpuidle_devices_uninit(void)
 }
 
 /*
- * intel_idle_state_table_update()
+ * ivt_idle_state_table_update(void)
  *
- * Update the default state_table for this CPU-id
- *
- * Currently used to access tuned IVT multi-socket targets
+ * Tune IVT multi-socket targets
  * Assumption: num_sockets == (max_package_num + 1)
  */
-void intel_idle_state_table_update(void)
+static void ivt_idle_state_table_update(void)
 {
        /* IVT uses a different table for 1-2, 3-4, and > 4 sockets */
-       if (boot_cpu_data.x86_model == 0x3e) { /* IVT */
-               int cpu, package_num, num_sockets = 1;
-
-               for_each_online_cpu(cpu) {
-                       package_num = topology_physical_package_id(cpu);
-                       if (package_num + 1 > num_sockets) {
-                               num_sockets = package_num + 1;
-
-                               if (num_sockets > 4) {
-                                       cpuidle_state_table = ivt_cstates_8s;
-                                       return;
-                               }
+       int cpu, package_num, num_sockets = 1;
+
+       for_each_online_cpu(cpu) {
+               package_num = topology_physical_package_id(cpu);
+               if (package_num + 1 > num_sockets) {
+                       num_sockets = package_num + 1;
+
+                       if (num_sockets > 4) {
+                               cpuidle_state_table = ivt_cstates_8s;
+                               return;
                        }
                }
+       }
+
+       if (num_sockets > 2)
+               cpuidle_state_table = ivt_cstates_4s;
 
-               if (num_sockets > 2)
-                       cpuidle_state_table = ivt_cstates_4s;
-               /* else, 1 and 2 socket systems use default ivt_cstates */
+       /* else, 1 and 2 socket systems use default ivt_cstates */
+}
+/*
+ * sklh_idle_state_table_update(void)
+ *
+ * On SKL-H (model 0x5e) disable C8 and C9 if:
+ * C10 is enabled and SGX disabled
+ */
+static void sklh_idle_state_table_update(void)
+{
+       unsigned long long msr;
+       unsigned int eax, ebx, ecx, edx;
+
+
+       /* if PC10 disabled via cmdline intel_idle.max_cstate=7 or shallower */
+       if (max_cstate <= 7)
+               return;
+
+       /* if PC10 not present in CPUID.MWAIT.EDX */
+       if ((mwait_substates & (0xF << 28)) == 0)
+               return;
+
+       rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr);
+
+       /* PC10 is not enabled in PKG C-state limit */
+       if ((msr & 0xF) != 8)
+               return;
+
+       ecx = 0;
+       cpuid(7, &eax, &ebx, &ecx, &edx);
+
+       /* if SGX is present */
+       if (ebx & (1 << 2)) {
+
+               rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
+
+               /* if SGX is enabled */
+               if (msr & (1 << 18))
+                       return;
+       }
+
+       skl_cstates[5].disabled = 1;    /* C8-SKL */
+       skl_cstates[6].disabled = 1;    /* C9-SKL */
+}
+/*
+ * intel_idle_state_table_update()
+ *
+ * Update the default state_table for this CPU-id
+ */
+
+static void intel_idle_state_table_update(void)
+{
+       switch (boot_cpu_data.x86_model) {
+
+       case 0x3e: /* IVT */
+               ivt_idle_state_table_update();
+               break;
+       case 0x5e: /* SKL-H */
+               sklh_idle_state_table_update();
+               break;
        }
-       return;
 }
 
 /*
@@ -1063,6 +1144,14 @@ static int __init intel_idle_cpuidle_driver_init(void)
                if (num_substates == 0)
                        continue;
 
+               /* if state marked as disabled, skip it */
+               if (cpuidle_state_table[cstate].disabled != 0) {
+                       pr_debug(PREFIX "state %s is disabled",
+                               cpuidle_state_table[cstate].name);
+                       continue;
+               }
+
+
                if (((mwait_cstate + 1) > 2) &&
                        !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
                        mark_tsc_unstable("TSC halts in idle"
index 64ca711..d84d20b 100644 (file)
@@ -17,7 +17,7 @@
 int input_event_from_user(const char __user *buffer,
                          struct input_event *event)
 {
-       if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
+       if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
                struct input_event_compat compat_event;
 
                if (copy_from_user(&compat_event, buffer,
@@ -41,7 +41,7 @@ int input_event_from_user(const char __user *buffer,
 int input_event_to_user(char __user *buffer,
                        const struct input_event *event)
 {
-       if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
+       if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
                struct input_event_compat compat_event;
 
                compat_event.time.tv_sec = event->time.tv_sec;
@@ -65,7 +65,7 @@ int input_event_to_user(char __user *buffer,
 int input_ff_effect_from_user(const char __user *buffer, size_t size,
                              struct ff_effect *effect)
 {
-       if (INPUT_COMPAT_TEST) {
+       if (in_compat_syscall()) {
                struct ff_effect_compat *compat_effect;
 
                if (size != sizeof(struct ff_effect_compat))
index 0f25878..1563160 100644 (file)
@@ -17,8 +17,6 @@
 
 #ifdef CONFIG_COMPAT
 
-#define INPUT_COMPAT_TEST in_compat_syscall()
-
 struct input_event_compat {
        struct compat_timeval time;
        __u16 type;
@@ -57,7 +55,7 @@ struct ff_effect_compat {
 
 static inline size_t input_event_size(void)
 {
-       return (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) ?
+       return (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) ?
                sizeof(struct input_event_compat) : sizeof(struct input_event);
 }
 
index 8806059..b87ffbd 100644 (file)
@@ -1015,7 +1015,7 @@ static int input_bits_to_string(char *buf, int buf_size,
 {
        int len = 0;
 
-       if (INPUT_COMPAT_TEST) {
+       if (in_compat_syscall()) {
                u32 dword = bits >> 32;
                if (dword || !skip_empty)
                        len += snprintf(buf, buf_size, "%x ", dword);
index cfd58e8..1c5914c 100644 (file)
@@ -817,26 +817,49 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
 
        ar2->udev = udev;
 
+       /* Sanity check, first interface must have an endpoint */
+       if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
+               dev_err(&interface->dev,
+                       "%s(): interface 0 must have an endpoint\n", __func__);
+               r = -ENODEV;
+               goto fail1;
+       }
        ar2->intf[0] = interface;
        ar2->ep[0] = &alt->endpoint[0].desc;
 
+       /* Sanity check, the device must have two interfaces */
        ar2->intf[1] = usb_ifnum_to_if(udev, 1);
+       if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) {
+               dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n",
+                       __func__, udev->actconfig->desc.bNumInterfaces);
+               r = -ENODEV;
+               goto fail1;
+       }
+
        r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
        if (r)
                goto fail1;
+
+       /* Sanity check, second interface must have an endpoint */
        alt = ar2->intf[1]->cur_altsetting;
+       if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
+               dev_err(&interface->dev,
+                       "%s(): interface 1 must have an endpoint\n", __func__);
+               r = -ENODEV;
+               goto fail2;
+       }
        ar2->ep[1] = &alt->endpoint[0].desc;
 
        r = ati_remote2_urb_init(ar2);
        if (r)
-               goto fail2;
+               goto fail3;
 
        ar2->channel_mask = channel_mask;
        ar2->mode_mask = mode_mask;
 
        r = ati_remote2_setup(ar2, ar2->channel_mask);
        if (r)
-               goto fail2;
+               goto fail3;
 
        usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
        strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
@@ -845,11 +868,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
 
        r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);
        if (r)
-               goto fail2;
+               goto fail3;
 
        r = ati_remote2_input_init(ar2);
        if (r)
-               goto fail3;
+               goto fail4;
 
        usb_set_intfdata(interface, ar2);
 
@@ -857,10 +880,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
 
        return 0;
 
- fail3:
+ fail4:
        sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);
- fail2:
+ fail3:
        ati_remote2_urb_cleanup(ar2);
+ fail2:
        usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
  fail1:
        kfree(ar2);
index ac1fa5f..9c0ea36 100644 (file)
@@ -1663,6 +1663,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
 
        pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev,
                                         union_desc->bMasterInterface0);
+       if (!pcu->ctrl_intf)
+               return -EINVAL;
 
        alt = pcu->ctrl_intf->cur_altsetting;
        pcu->ep_ctrl = &alt->endpoint[0].desc;
@@ -1670,6 +1672,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
 
        pcu->data_intf = usb_ifnum_to_if(pcu->udev,
                                         union_desc->bSlaveInterface0);
+       if (!pcu->data_intf)
+               return -EINVAL;
 
        alt = pcu->data_intf->cur_altsetting;
        if (alt->desc.bNumEndpoints != 2) {
index 4eb9e4d..abe1a92 100644 (file)
@@ -664,7 +664,7 @@ struct uinput_ff_upload_compat {
 static int uinput_ff_upload_to_user(char __user *buffer,
                                    const struct uinput_ff_upload *ff_up)
 {
-       if (INPUT_COMPAT_TEST) {
+       if (in_compat_syscall()) {
                struct uinput_ff_upload_compat ff_up_compat;
 
                ff_up_compat.request_id = ff_up->request_id;
@@ -695,7 +695,7 @@ static int uinput_ff_upload_to_user(char __user *buffer,
 static int uinput_ff_upload_from_user(const char __user *buffer,
                                      struct uinput_ff_upload *ff_up)
 {
-       if (INPUT_COMPAT_TEST) {
+       if (in_compat_syscall()) {
                struct uinput_ff_upload_compat ff_up_compat;
 
                if (copy_from_user(&ff_up_compat, buffer,
index 9425e0f..fdc243c 100644 (file)
 #include <linux/input.h>
 #include <linux/libps2.h>
 #include <linux/serio.h>
+#include <linux/slab.h>
 
 #include "psmouse.h"
 #include "byd.h"
 
+/* PS2 Bits */
 #define PS2_Y_OVERFLOW BIT_MASK(7)
 #define PS2_X_OVERFLOW BIT_MASK(6)
 #define PS2_Y_SIGN     BIT_MASK(5)
 #define PS2_LEFT       BIT_MASK(0)
 
 /*
- * The touchpad reports gestures in the last byte of each packet. It can take
- * any of the following values:
+ * BYD pad constants
  */
 
-/* One-finger scrolling in one of the edge scroll zones. */
-#define BYD_SCROLLUP           0xCA
-#define BYD_SCROLLDOWN         0x36
-#define BYD_SCROLLLEFT         0xCB
-#define BYD_SCROLLRIGHT                0x35
-/* Two-finger scrolling. */
-#define BYD_2DOWN              0x2B
-#define BYD_2UP                        0xD5
-#define BYD_2LEFT              0xD6
-#define BYD_2RIGHT             0x2A
-/* Pinching in or out. */
-#define BYD_ZOOMOUT            0xD8
-#define BYD_ZOOMIN             0x28
-/* Three-finger swipe. */
-#define BYD_3UP                        0xD3
-#define BYD_3DOWN              0x2D
-#define BYD_3LEFT              0xD4
-#define BYD_3RIGHT             0x2C
-/* Four-finger swipe. */
-#define BYD_4UP                        0xCD
-#define BYD_4DOWN              0x33
+/*
+ * True device resolution is unknown, however experiments show the
+ * resolution is about 111 units/mm.
+ * Absolute coordinate packets are in the range 0-255 for both X and Y
+ * we pick ABS_X/ABS_Y dimensions which are multiples of 256 and in
+ * the right ballpark given the touchpad's physical dimensions and estimate
+ * resolution per spec sheet, device active area dimensions are
+ * 101.6 x 60.1 mm.
+ */
+#define BYD_PAD_WIDTH          11264
+#define BYD_PAD_HEIGHT         6656
+#define BYD_PAD_RESOLUTION     111
 
-int byd_detect(struct psmouse *psmouse, bool set_properties)
+/*
+ * Given the above dimensions, relative packets velocity is in multiples of
+ * 1 unit / 11 milliseconds.  We use this dt to estimate distance traveled
+ */
+#define BYD_DT                 11
+/* Time in jiffies used to timeout various touch events (64 ms) */
+#define BYD_TOUCH_TIMEOUT      msecs_to_jiffies(64)
+
+/* BYD commands reverse engineered from windows driver */
+
+/*
+ * Swipe gesture from off-pad to on-pad
+ *  0 : disable
+ *  1 : enable
+ */
+#define BYD_CMD_SET_OFFSCREEN_SWIPE            0x10cc
+/*
+ * Tap and drag delay time
+ *  0 : disable
+ *  1 - 8 : least to most delay
+ */
+#define BYD_CMD_SET_TAP_DRAG_DELAY_TIME                0x10cf
+/*
+ * Physical buttons function mapping
+ *  0 : enable
+ *  4 : normal
+ *  5 : left button custom command
+ *  6 : right button custom command
+ *  8 : disable
+ */
+#define BYD_CMD_SET_PHYSICAL_BUTTONS           0x10d0
+/*
+ * Absolute mode (1 byte X/Y resolution)
+ *  0 : disable
+ *  2 : enable
+ */
+#define BYD_CMD_SET_ABSOLUTE_MODE              0x10d1
+/*
+ * Two finger scrolling
+ *  1 : vertical
+ *  2 : horizontal
+ *  3 : vertical + horizontal
+ *  4 : disable
+ */
+#define BYD_CMD_SET_TWO_FINGER_SCROLL          0x10d2
+/*
+ * Handedness
+ *  1 : right handed
+ *  2 : left handed
+ */
+#define BYD_CMD_SET_HANDEDNESS                 0x10d3
+/*
+ * Tap to click
+ *  1 : enable
+ *  2 : disable
+ */
+#define BYD_CMD_SET_TAP                                0x10d4
+/*
+ * Tap and drag
+ *  1 : tap and hold to drag
+ *  2 : tap and hold to drag + lock
+ *  3 : disable
+ */
+#define BYD_CMD_SET_TAP_DRAG                   0x10d5
+/*
+ * Touch sensitivity
+ *  1 - 7 : least to most sensitive
+ */
+#define BYD_CMD_SET_TOUCH_SENSITIVITY          0x10d6
+/*
+ * One finger scrolling
+ *  1 : vertical
+ *  2 : horizontal
+ *  3 : vertical + horizontal
+ *  4 : disable
+ */
+#define BYD_CMD_SET_ONE_FINGER_SCROLL          0x10d7
+/*
+ * One finger scrolling function
+ *  1 : free scrolling
+ *  2 : edge motion
+ *  3 : free scrolling + edge motion
+ *  4 : disable
+ */
+#define BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC     0x10d8
+/*
+ * Sliding speed
+ *  1 - 5 : slowest to fastest
+ */
+#define BYD_CMD_SET_SLIDING_SPEED              0x10da
+/*
+ * Edge motion
+ *  1 : disable
+ *  2 : enable when dragging
+ *  3 : enable when dragging and pointing
+ */
+#define BYD_CMD_SET_EDGE_MOTION                        0x10db
+/*
+ * Left edge region size
+ *  0 - 7 : smallest to largest width
+ */
+#define BYD_CMD_SET_LEFT_EDGE_REGION           0x10dc
+/*
+ * Top edge region size
+ *  0 - 9 : smallest to largest height
+ */
+#define BYD_CMD_SET_TOP_EDGE_REGION            0x10dd
+/*
+ * Disregard palm press as clicks
+ *  1 - 6 : smallest to largest
+ */
+#define BYD_CMD_SET_PALM_CHECK                 0x10de
+/*
+ * Right edge region size
+ *  0 - 7 : smallest to largest width
+ */
+#define BYD_CMD_SET_RIGHT_EDGE_REGION          0x10df
+/*
+ * Bottom edge region size
+ *  0 - 9 : smallest to largest height
+ */
+#define BYD_CMD_SET_BOTTOM_EDGE_REGION         0x10e1
+/*
+ * Multitouch gestures
+ *  1 : enable
+ *  2 : disable
+ */
+#define BYD_CMD_SET_MULTITOUCH                 0x10e3
+/*
+ * Edge motion speed
+ *  0 : control with finger pressure
+ *  1 - 9 : slowest to fastest
+ */
+#define BYD_CMD_SET_EDGE_MOTION_SPEED          0x10e4
+/*
+ * Two finger scolling function
+ *  0 : free scrolling
+ *  1 : free scrolling (with momentum)
+ *  2 : edge motion
+ *  3 : free scrolling (with momentum) + edge motion
+ *  4 : disable
+ */
+#define BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC     0x10e5
+
+/*
+ * The touchpad generates a mixture of absolute and relative packets, indicated
+ * by the the last byte of each packet being set to one of the following:
+ */
+#define BYD_PACKET_ABSOLUTE                    0xf8
+#define BYD_PACKET_RELATIVE                    0x00
+/* Multitouch gesture packets */
+#define BYD_PACKET_PINCH_IN                    0xd8
+#define BYD_PACKET_PINCH_OUT                   0x28
+#define BYD_PACKET_ROTATE_CLOCKWISE            0x29
+#define BYD_PACKET_ROTATE_ANTICLOCKWISE                0xd7
+#define BYD_PACKET_TWO_FINGER_SCROLL_RIGHT     0x2a
+#define BYD_PACKET_TWO_FINGER_SCROLL_DOWN      0x2b
+#define BYD_PACKET_TWO_FINGER_SCROLL_UP                0xd5
+#define BYD_PACKET_TWO_FINGER_SCROLL_LEFT      0xd6
+#define BYD_PACKET_THREE_FINGER_SWIPE_RIGHT    0x2c
+#define BYD_PACKET_THREE_FINGER_SWIPE_DOWN     0x2d
+#define BYD_PACKET_THREE_FINGER_SWIPE_UP       0xd3
+#define BYD_PACKET_THREE_FINGER_SWIPE_LEFT     0xd4
+#define BYD_PACKET_FOUR_FINGER_DOWN            0x33
+#define BYD_PACKET_FOUR_FINGER_UP              0xcd
+#define BYD_PACKET_REGION_SCROLL_RIGHT         0x35
+#define BYD_PACKET_REGION_SCROLL_DOWN          0x36
+#define BYD_PACKET_REGION_SCROLL_UP            0xca
+#define BYD_PACKET_REGION_SCROLL_LEFT          0xcb
+#define BYD_PACKET_RIGHT_CORNER_CLICK          0xd2
+#define BYD_PACKET_LEFT_CORNER_CLICK           0x2e
+#define BYD_PACKET_LEFT_AND_RIGHT_CORNER_CLICK 0x2f
+#define BYD_PACKET_ONTO_PAD_SWIPE_RIGHT                0x37
+#define BYD_PACKET_ONTO_PAD_SWIPE_DOWN         0x30
+#define BYD_PACKET_ONTO_PAD_SWIPE_UP           0xd0
+#define BYD_PACKET_ONTO_PAD_SWIPE_LEFT         0xc9
+
+struct byd_data {
+       struct timer_list timer;
+       s32 abs_x;
+       s32 abs_y;
+       typeof(jiffies) last_touch_time;
+       bool btn_left;
+       bool btn_right;
+       bool touch;
+};
+
+static void byd_report_input(struct psmouse *psmouse)
 {
-       struct ps2dev *ps2dev = &psmouse->ps2dev;
-       unsigned char param[4];
+       struct byd_data *priv = psmouse->private;
+       struct input_dev *dev = psmouse->dev;
 
-       param[0] = 0x03;
-       param[1] = 0x00;
-       param[2] = 0x00;
-       param[3] = 0x00;
+       input_report_key(dev, BTN_TOUCH, priv->touch);
+       input_report_key(dev, BTN_TOOL_FINGER, priv->touch);
 
-       if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
-               return -1;
-       if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
-               return -1;
-       if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
-               return -1;
-       if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
-               return -1;
-       if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
-               return -1;
+       input_report_abs(dev, ABS_X, priv->abs_x);
+       input_report_abs(dev, ABS_Y, priv->abs_y);
+       input_report_key(dev, BTN_LEFT, priv->btn_left);
+       input_report_key(dev, BTN_RIGHT, priv->btn_right);
 
-       if (param[1] != 0x03 || param[2] != 0x64)
-               return -ENODEV;
+       input_sync(dev);
+}
 
-       psmouse_dbg(psmouse, "BYD touchpad detected\n");
+static void byd_clear_touch(unsigned long data)
+{
+       struct psmouse *psmouse = (struct psmouse *)data;
+       struct byd_data *priv = psmouse->private;
 
-       if (set_properties) {
-               psmouse->vendor = "BYD";
-               psmouse->name = "TouchPad";
-       }
+       serio_pause_rx(psmouse->ps2dev.serio);
+       priv->touch = false;
 
-       return 0;
+       byd_report_input(psmouse);
+
+       serio_continue_rx(psmouse->ps2dev.serio);
+
+       /*
+        * Move cursor back to center of pad when we lose touch - this
+        * specifically improves user experience when moving cursor with one
+        * finger, and pressing a button with another.
+        */
+       priv->abs_x = BYD_PAD_WIDTH / 2;
+       priv->abs_y = BYD_PAD_HEIGHT / 2;
 }
 
 static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
 {
-       struct input_dev *dev = psmouse->dev;
+       struct byd_data *priv = psmouse->private;
        u8 *pkt = psmouse->packet;
 
        if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) {
@@ -102,53 +284,34 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
 
        /* Otherwise, a full packet has been received */
        switch (pkt[3]) {
-       case 0: {
+       case BYD_PACKET_ABSOLUTE:
+               /* Only use absolute packets for the start of movement. */
+               if (!priv->touch) {
+                       /* needed to detect tap */
+                       typeof(jiffies) tap_time =
+                               priv->last_touch_time + BYD_TOUCH_TIMEOUT;
+                       priv->touch = time_after(jiffies, tap_time);
+
+                       /* init abs position */
+                       priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256);
+                       priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / 256);
+               }
+               break;
+       case BYD_PACKET_RELATIVE: {
                /* Standard packet */
                /* Sign-extend if a sign bit is set. */
-               unsigned int signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0;
-               unsigned int signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0;
-               int dx = signx | (int) pkt[1];
-               int dy = signy | (int) pkt[2];
+               u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0;
+               u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0;
+               s32 dx = signx | (int) pkt[1];
+               s32 dy = signy | (int) pkt[2];
 
-               input_report_rel(psmouse->dev, REL_X, dx);
-               input_report_rel(psmouse->dev, REL_Y, -dy);
+               /* Update position based on velocity */
+               priv->abs_x += dx * BYD_DT;
+               priv->abs_y -= dy * BYD_DT;
 
-               input_report_key(psmouse->dev, BTN_LEFT, pkt[0] & PS2_LEFT);
-               input_report_key(psmouse->dev, BTN_RIGHT, pkt[0] & PS2_RIGHT);
-               input_report_key(psmouse->dev, BTN_MIDDLE, pkt[0] & PS2_MIDDLE);
+               priv->touch = true;
                break;
        }
-
-       case BYD_SCROLLDOWN:
-       case BYD_2DOWN:
-               input_report_rel(dev, REL_WHEEL, -1);
-               break;
-
-       case BYD_SCROLLUP:
-       case BYD_2UP:
-               input_report_rel(dev, REL_WHEEL, 1);
-               break;
-
-       case BYD_SCROLLLEFT:
-       case BYD_2LEFT:
-               input_report_rel(dev, REL_HWHEEL, -1);
-               break;
-
-       case BYD_SCROLLRIGHT:
-       case BYD_2RIGHT:
-               input_report_rel(dev, REL_HWHEEL, 1);
-               break;
-
-       case BYD_ZOOMOUT:
-       case BYD_ZOOMIN:
-       case BYD_3UP:
-       case BYD_3DOWN:
-       case BYD_3LEFT:
-       case BYD_3RIGHT:
-       case BYD_4UP:
-       case BYD_4DOWN:
-               break;
-
        default:
                psmouse_warn(psmouse,
                             "Unrecognized Z: pkt = %02x %02x %02x %02x\n",
@@ -157,134 +320,76 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
                return PSMOUSE_BAD_DATA;
        }
 
-       input_sync(dev);
+       priv->btn_left = pkt[0] & PS2_LEFT;
+       priv->btn_right = pkt[0] & PS2_RIGHT;
 
-       return PSMOUSE_FULL_PACKET;
-}
+       byd_report_input(psmouse);
 
-/* Send a sequence of bytes, where each is ACKed before the next is sent. */
-static int byd_send_sequence(struct psmouse *psmouse, const u8 *seq, size_t len)
-{
-       unsigned int i;
-
-       for (i = 0; i < len; ++i) {
-               if (ps2_command(&psmouse->ps2dev, NULL, seq[i]))
-                       return -1;
+       /* Reset time since last touch. */
+       if (priv->touch) {
+               priv->last_touch_time = jiffies;
+               mod_timer(&priv->timer, jiffies + BYD_TOUCH_TIMEOUT);
        }
-       return 0;
-}
-
-/* Keep scrolling after fingers are removed. */
-#define SCROLL_INERTIAL                0x01
-#define SCROLL_NO_INERTIAL     0x02
-
-/* Clicking can be done by tapping or pressing. */
-#define CLICK_BOTH             0x01
-/* Clicking can only be done by pressing. */
-#define CLICK_PRESS_ONLY       0x02
 
-static int byd_enable(struct psmouse *psmouse)
-{
-       const u8 seq1[] = { 0xE2, 0x00, 0xE0, 0x02, 0xE0 };
-       const u8 seq2[] = {
-               0xD3, 0x01,
-               0xD0, 0x00,
-               0xD0, 0x04,
-               /* Whether clicking is done by tapping or pressing. */
-               0xD4, CLICK_PRESS_ONLY,
-               0xD5, 0x01,
-               0xD7, 0x03,
-               /* Vertical and horizontal one-finger scroll zone inertia. */
-               0xD8, SCROLL_INERTIAL,
-               0xDA, 0x05,
-               0xDB, 0x02,
-               0xE4, 0x05,
-               0xD6, 0x01,
-               0xDE, 0x04,
-               0xE3, 0x01,
-               0xCF, 0x00,
-               0xD2, 0x03,
-               /* Vertical and horizontal two-finger scrolling inertia. */
-               0xE5, SCROLL_INERTIAL,
-               0xD9, 0x02,
-               0xD9, 0x07,
-               0xDC, 0x03,
-               0xDD, 0x03,
-               0xDF, 0x03,
-               0xE1, 0x03,
-               0xD1, 0x00,
-               0xCE, 0x00,
-               0xCC, 0x00,
-               0xE0, 0x00,
-               0xE2, 0x01
-       };
-       u8 param[4];
-
-       if (byd_send_sequence(psmouse, seq1, ARRAY_SIZE(seq1)))
-               return -1;
-
-       /* Send a 0x01 command, which should return 4 bytes. */
-       if (ps2_command(&psmouse->ps2dev, param, 0x0401))
-               return -1;
-
-       if (byd_send_sequence(psmouse, seq2, ARRAY_SIZE(seq2)))
-               return -1;
-
-       return 0;
+       return PSMOUSE_FULL_PACKET;
 }
 
-/*
- * Send the set of PS/2 commands required to make it identify as an
- * intellimouse with 4-byte instead of 3-byte packets.
- */
-static int byd_send_intellimouse_sequence(struct psmouse *psmouse)
+static int byd_reset_touchpad(struct psmouse *psmouse)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        u8 param[4];
-       int i;
+       size_t i;
+
        const struct {
                u16 command;
                u8 arg;
        } seq[] = {
-               { PSMOUSE_CMD_RESET_BAT, 0 },
-               { PSMOUSE_CMD_RESET_BAT, 0 },
-               { PSMOUSE_CMD_GETID, 0 },
-               { PSMOUSE_CMD_SETSCALE11, 0 },
-               { PSMOUSE_CMD_SETSCALE11, 0 },
-               { PSMOUSE_CMD_SETSCALE11, 0 },
-               { PSMOUSE_CMD_GETINFO, 0 },
-               { PSMOUSE_CMD_SETRES, 0x03 },
+               /*
+                * Intellimouse initialization sequence, to get 4-byte instead
+                * of 3-byte packets.
+                */
                { PSMOUSE_CMD_SETRATE, 0xC8 },
                { PSMOUSE_CMD_SETRATE, 0x64 },
                { PSMOUSE_CMD_SETRATE, 0x50 },
                { PSMOUSE_CMD_GETID, 0 },
-               { PSMOUSE_CMD_SETRATE, 0xC8 },
-               { PSMOUSE_CMD_SETRATE, 0xC8 },
-               { PSMOUSE_CMD_SETRATE, 0x50 },
-               { PSMOUSE_CMD_GETID, 0 },
-               { PSMOUSE_CMD_SETRATE, 0x64 },
-               { PSMOUSE_CMD_SETRES, 0x03 },
-               { PSMOUSE_CMD_ENABLE, 0 }
+               { PSMOUSE_CMD_ENABLE, 0 },
+               /*
+                * BYD-specific initialization, which enables absolute mode and
+                * (if desired), the touchpad's built-in gesture detection.
+                */
+               { 0x10E2, 0x00 },
+               { 0x10E0, 0x02 },
+               /* The touchpad should reply with 4 seemingly-random bytes */
+               { 0x14E0, 0x01 },
+               /* Pairs of parameters and values. */
+               { BYD_CMD_SET_HANDEDNESS, 0x01 },
+               { BYD_CMD_SET_PHYSICAL_BUTTONS, 0x04 },
+               { BYD_CMD_SET_TAP, 0x02 },
+               { BYD_CMD_SET_ONE_FINGER_SCROLL, 0x04 },
+               { BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC, 0x04 },
+               { BYD_CMD_SET_EDGE_MOTION, 0x01 },
+               { BYD_CMD_SET_PALM_CHECK, 0x00 },
+               { BYD_CMD_SET_MULTITOUCH, 0x02 },
+               { BYD_CMD_SET_TWO_FINGER_SCROLL, 0x04 },
+               { BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC, 0x04 },
+               { BYD_CMD_SET_LEFT_EDGE_REGION, 0x00 },
+               { BYD_CMD_SET_TOP_EDGE_REGION, 0x00 },
+               { BYD_CMD_SET_RIGHT_EDGE_REGION, 0x00 },
+               { BYD_CMD_SET_BOTTOM_EDGE_REGION, 0x00 },
+               { BYD_CMD_SET_ABSOLUTE_MODE, 0x02 },
+               /* Finalize initialization. */
+               { 0x10E0, 0x00 },
+               { 0x10E2, 0x01 },
        };
 
-       memset(param, 0, sizeof(param));
        for (i = 0; i < ARRAY_SIZE(seq); ++i) {
+               memset(param, 0, sizeof(param));
                param[0] = seq[i].arg;
                if (ps2_command(ps2dev, param, seq[i].command))
-                       return -1;
+                       return -EIO;
        }
 
-       return 0;
-}
-
-static int byd_reset_touchpad(struct psmouse *psmouse)
-{
-       if (byd_send_intellimouse_sequence(psmouse))
-               return -EIO;
-
-       if (byd_enable(psmouse))
-               return -EIO;
-
+       psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
        return 0;
 }
 
@@ -314,9 +419,50 @@ static int byd_reconnect(struct psmouse *psmouse)
        return 0;
 }
 
+static void byd_disconnect(struct psmouse *psmouse)
+{
+       struct byd_data *priv = psmouse->private;
+
+       if (priv) {
+               del_timer(&priv->timer);
+               kfree(psmouse->private);
+               psmouse->private = NULL;
+       }
+}
+
+int byd_detect(struct psmouse *psmouse, bool set_properties)
+{
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       u8 param[4] = {0x03, 0x00, 0x00, 0x00};
+
+       if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+               return -1;
+       if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+               return -1;
+       if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+               return -1;
+       if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+               return -1;
+       if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+               return -1;
+
+       if (param[1] != 0x03 || param[2] != 0x64)
+               return -ENODEV;
+
+       psmouse_dbg(psmouse, "BYD touchpad detected\n");
+
+       if (set_properties) {
+               psmouse->vendor = "BYD";
+               psmouse->name = "TouchPad";
+       }
+
+       return 0;
+}
+
 int byd_init(struct psmouse *psmouse)
 {
        struct input_dev *dev = psmouse->dev;
+       struct byd_data *priv;
 
        if (psmouse_reset(psmouse))
                return -EIO;
@@ -324,14 +470,39 @@ int byd_init(struct psmouse *psmouse)
        if (byd_reset_touchpad(psmouse))
                return -EIO;
 
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       memset(priv, 0, sizeof(*priv));
+       setup_timer(&priv->timer, byd_clear_touch, (unsigned long) psmouse);
+
+       psmouse->private = priv;
+       psmouse->disconnect = byd_disconnect;
        psmouse->reconnect = byd_reconnect;
        psmouse->protocol_handler = byd_process_byte;
        psmouse->pktsize = 4;
        psmouse->resync_time = 0;
 
-       __set_bit(BTN_MIDDLE, dev->keybit);
-       __set_bit(REL_WHEEL, dev->relbit);
-       __set_bit(REL_HWHEEL, dev->relbit);
+       __set_bit(INPUT_PROP_POINTER, dev->propbit);
+       /* Touchpad */
+       __set_bit(BTN_TOUCH, dev->keybit);
+       __set_bit(BTN_TOOL_FINGER, dev->keybit);
+       /* Buttons */
+       __set_bit(BTN_LEFT, dev->keybit);
+       __set_bit(BTN_RIGHT, dev->keybit);
+       __clear_bit(BTN_MIDDLE, dev->keybit);
+
+       /* Absolute position */
+       __set_bit(EV_ABS, dev->evbit);
+       input_set_abs_params(dev, ABS_X, 0, BYD_PAD_WIDTH, 0, 0);
+       input_set_abs_params(dev, ABS_Y, 0, BYD_PAD_HEIGHT, 0, 0);
+       input_abs_set_res(dev, ABS_X, BYD_PAD_RESOLUTION);
+       input_abs_set_res(dev, ABS_Y, BYD_PAD_RESOLUTION);
+       /* No relative support */
+       __clear_bit(EV_REL, dev->evbit);
+       __clear_bit(REL_X, dev->relbit);
+       __clear_bit(REL_Y, dev->relbit);
 
        return 0;
 }
index 39d1bec..5784e20 100644 (file)
@@ -846,7 +846,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
 #ifdef CONFIG_MOUSE_PS2_BYD
        {
                .type           = PSMOUSE_BYD,
-               .name           = "BydPS/2",
+               .name           = "BYDPS/2",
                .alias          = "byd",
                .detect         = byd_detect,
                .init           = byd_init,
index 6025eb4..a41d832 100644 (file)
@@ -862,8 +862,9 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
        if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
                return;
 
-       /* Bug in FW 8.1, buttons are reported only when ExtBit is 1 */
-       if (SYN_ID_FULL(priv->identity) == 0x801 &&
+       /* Bug in FW 8.1 & 8.2, buttons are reported only when ExtBit is 1 */
+       if ((SYN_ID_FULL(priv->identity) == 0x801 ||
+            SYN_ID_FULL(priv->identity) == 0x802) &&
            !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
                return;
 
index da38f0a..faa295e 100644 (file)
@@ -126,7 +126,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
                return;
 
        fh = to_rmi_function_handler(fn->dev.driver);
-       if (fn->irq_mask && fh->attention) {
+       if (fh->attention) {
                bitmap_and(data->fn_irq_bits, data->irq_status, fn->irq_mask,
                                data->irq_count);
                if (!bitmap_empty(data->fn_irq_bits, data->irq_count))
@@ -172,8 +172,7 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
         * use irq_chip.
         */
        list_for_each_entry(entry, &data->function_list, node)
-               if (entry->irq_mask)
-                       process_one_interrupt(data, entry);
+               process_one_interrupt(data, entry);
 
        if (data->input)
                input_sync(data->input);
index 8927297..fb5fb91 100644 (file)
@@ -1310,8 +1310,34 @@ static ssize_t mip4_sysfs_read_fw_version(struct device *dev,
 
 static DEVICE_ATTR(fw_version, S_IRUGO, mip4_sysfs_read_fw_version, NULL);
 
+static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mip4_ts *ts = i2c_get_clientdata(client);
+       size_t count;
+
+       /* Take lock to prevent racing with firmware update */
+       mutex_lock(&ts->input->mutex);
+
+       /*
+        * product_name shows the name or version of the hardware
+        * paired with current firmware in the chip.
+        */
+       count = snprintf(buf, PAGE_SIZE, "%.*s\n",
+               (int)sizeof(ts->product_name), ts->product_name);
+
+       mutex_unlock(&ts->input->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL);
+
 static struct attribute *mip4_attrs[] = {
        &dev_attr_fw_version.attr,
+       &dev_attr_hw_version.attr,
        &dev_attr_update_fw.attr,
        NULL,
 };
@@ -1512,6 +1538,6 @@ static struct i2c_driver mip4_driver = {
 module_i2c_driver(mip4_driver);
 
 MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
-MODULE_VERSION("2016.03.03");
+MODULE_VERSION("2016.03.12");
 MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
 MODULE_LICENSE("GPL");
index b6c4d03..880c40b 100644 (file)
@@ -197,28 +197,34 @@ static int sur40_command(struct sur40_state *dev,
 static int sur40_init(struct sur40_state *dev)
 {
        int result;
-       u8 buffer[24];
+       u8 *buffer;
+
+       buffer = kmalloc(24, GFP_KERNEL);
+       if (!buffer) {
+               result = -ENOMEM;
+               goto error;
+       }
 
        /* stupidly replay the original MS driver init sequence */
        result = sur40_command(dev, SUR40_GET_VERSION, 0x00, buffer, 12);
        if (result < 0)
-               return result;
+               goto error;
 
        result = sur40_command(dev, SUR40_GET_VERSION, 0x01, buffer, 12);
        if (result < 0)
-               return result;
+               goto error;
 
        result = sur40_command(dev, SUR40_GET_VERSION, 0x02, buffer, 12);
        if (result < 0)
-               return result;
+               goto error;
 
        result = sur40_command(dev, SUR40_UNKNOWN2,    0x00, buffer, 24);
        if (result < 0)
-               return result;
+               goto error;
 
        result = sur40_command(dev, SUR40_UNKNOWN1,    0x00, buffer,  5);
        if (result < 0)
-               return result;
+               goto error;
 
        result = sur40_command(dev, SUR40_GET_VERSION, 0x03, buffer, 12);
 
@@ -226,7 +232,8 @@ static int sur40_init(struct sur40_state *dev)
         * Discard the result buffer - no known data inside except
         * some version strings, maybe extract these sometime...
         */
-
+error:
+       kfree(buffer);
        return result;
 }
 
index 0d1fb6b..0dc9a80 100644 (file)
@@ -464,8 +464,13 @@ static int nvm_core_init(struct nvm_dev *dev)
        dev->nr_luns = dev->luns_per_chnl * dev->nr_chnls;
 
        dev->total_secs = dev->nr_luns * dev->sec_per_lun;
+       dev->lun_map = kcalloc(BITS_TO_LONGS(dev->nr_luns),
+                                       sizeof(unsigned long), GFP_KERNEL);
+       if (!dev->lun_map)
+               return -ENOMEM;
        INIT_LIST_HEAD(&dev->online_targets);
        mutex_init(&dev->mlock);
+       spin_lock_init(&dev->lock);
 
        return 0;
 }
@@ -585,6 +590,7 @@ int nvm_register(struct request_queue *q, char *disk_name,
 
        return 0;
 err_init:
+       kfree(dev->lun_map);
        kfree(dev);
        return ret;
 }
@@ -607,6 +613,7 @@ void nvm_unregister(char *disk_name)
        up_write(&nvm_lock);
 
        nvm_exit(dev);
+       kfree(dev->lun_map);
        kfree(dev);
 }
 EXPORT_SYMBOL(nvm_unregister);
index d65ec36..72e124a 100644 (file)
 
 #include "gennvm.h"
 
+static int gennvm_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len)
+{
+       struct gen_nvm *gn = dev->mp;
+       struct gennvm_area *area, *prev, *next;
+       sector_t begin = 0;
+       sector_t max_sectors = (dev->sec_size * dev->total_secs) >> 9;
+
+       if (len > max_sectors)
+               return -EINVAL;
+
+       area = kmalloc(sizeof(struct gennvm_area), GFP_KERNEL);
+       if (!area)
+               return -ENOMEM;
+
+       prev = NULL;
+
+       spin_lock(&dev->lock);
+       list_for_each_entry(next, &gn->area_list, list) {
+               if (begin + len > next->begin) {
+                       begin = next->end;
+                       prev = next;
+                       continue;
+               }
+               break;
+       }
+
+       if ((begin + len) > max_sectors) {
+               spin_unlock(&dev->lock);
+               kfree(area);
+               return -EINVAL;
+       }
+
+       area->begin = *lba = begin;
+       area->end = begin + len;
+
+       if (prev) /* insert into sorted order */
+               list_add(&area->list, &prev->list);
+       else
+               list_add(&area->list, &gn->area_list);
+       spin_unlock(&dev->lock);
+
+       return 0;
+}
+
+static void gennvm_put_area(struct nvm_dev *dev, sector_t begin)
+{
+       struct gen_nvm *gn = dev->mp;
+       struct gennvm_area *area;
+
+       spin_lock(&dev->lock);
+       list_for_each_entry(area, &gn->area_list, list) {
+               if (area->begin != begin)
+                       continue;
+
+               list_del(&area->list);
+               spin_unlock(&dev->lock);
+               kfree(area);
+               return;
+       }
+       spin_unlock(&dev->lock);
+}
+
 static void gennvm_blocks_free(struct nvm_dev *dev)
 {
        struct gen_nvm *gn = dev->mp;
@@ -195,7 +257,7 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
                }
        }
 
-       if (dev->ops->get_l2p_tbl) {
+       if ((dev->identity.dom & NVM_RSP_L2P) && dev->ops->get_l2p_tbl) {
                ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs,
                                                        gennvm_block_map, dev);
                if (ret) {
@@ -229,6 +291,7 @@ static int gennvm_register(struct nvm_dev *dev)
 
        gn->dev = dev;
        gn->nr_luns = dev->nr_luns;
+       INIT_LIST_HEAD(&gn->area_list);
        dev->mp = gn;
 
        ret = gennvm_luns_init(dev, gn);
@@ -419,10 +482,23 @@ static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk,
        return nvm_erase_ppa(dev, &addr, 1);
 }
 
+static int gennvm_reserve_lun(struct nvm_dev *dev, int lunid)
+{
+       return test_and_set_bit(lunid, dev->lun_map);
+}
+
+static void gennvm_release_lun(struct nvm_dev *dev, int lunid)
+{
+       WARN_ON(!test_and_clear_bit(lunid, dev->lun_map));
+}
+
 static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
 {
        struct gen_nvm *gn = dev->mp;
 
+       if (unlikely(lunid >= dev->nr_luns))
+               return NULL;
+
        return &gn->luns[lunid].vlun;
 }
 
@@ -464,7 +540,13 @@ static struct nvmm_type gennvm = {
        .erase_blk              = gennvm_erase_blk,
 
        .get_lun                = gennvm_get_lun,
+       .reserve_lun            = gennvm_reserve_lun,
+       .release_lun            = gennvm_release_lun,
        .lun_info_print         = gennvm_lun_info_print,
+
+       .get_area               = gennvm_get_area,
+       .put_area               = gennvm_put_area,
+
 };
 
 static int __init gennvm_module_init(void)
index 9c24b5b..04d7c23 100644 (file)
@@ -39,8 +39,14 @@ struct gen_nvm {
 
        int nr_luns;
        struct gen_lun *luns;
+       struct list_head area_list;
 };
 
+struct gennvm_area {
+       struct list_head list;
+       sector_t begin;
+       sector_t end;   /* end is excluded */
+};
 #define gennvm_for_each_lun(bm, lun, i) \
                for ((i) = 0, lun = &(bm)->luns[0]; \
                        (i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)])
index 8234378..3ab6495 100644 (file)
@@ -965,25 +965,11 @@ static void rrpc_requeue(struct work_struct *work)
 
 static void rrpc_gc_free(struct rrpc *rrpc)
 {
-       struct rrpc_lun *rlun;
-       int i;
-
        if (rrpc->krqd_wq)
                destroy_workqueue(rrpc->krqd_wq);
 
        if (rrpc->kgc_wq)
                destroy_workqueue(rrpc->kgc_wq);
-
-       if (!rrpc->luns)
-               return;
-
-       for (i = 0; i < rrpc->nr_luns; i++) {
-               rlun = &rrpc->luns[i];
-
-               if (!rlun->blocks)
-                       break;
-               vfree(rlun->blocks);
-       }
 }
 
 static int rrpc_gc_init(struct rrpc *rrpc)
@@ -1053,8 +1039,11 @@ static int rrpc_map_init(struct rrpc *rrpc)
 {
        struct nvm_dev *dev = rrpc->dev;
        sector_t i;
+       u64 slba;
        int ret;
 
+       slba = rrpc->soffset >> (ilog2(dev->sec_size) - 9);
+
        rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects);
        if (!rrpc->trans_map)
                return -ENOMEM;
@@ -1076,7 +1065,7 @@ static int rrpc_map_init(struct rrpc *rrpc)
                return 0;
 
        /* Bring up the mapping table from device */
-       ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs, rrpc_l2p_update,
+       ret = dev->ops->get_l2p_tbl(dev, slba, rrpc->nr_sects, rrpc_l2p_update,
                                                                        rrpc);
        if (ret) {
                pr_err("nvm: rrpc: could not read L2P table.\n");
@@ -1086,7 +1075,6 @@ static int rrpc_map_init(struct rrpc *rrpc)
        return 0;
 }
 
-
 /* Minimum pages needed within a lun */
 #define PAGE_POOL_SIZE 16
 #define ADDR_POOL_SIZE 64
@@ -1141,6 +1129,23 @@ static void rrpc_core_free(struct rrpc *rrpc)
 
 static void rrpc_luns_free(struct rrpc *rrpc)
 {
+       struct nvm_dev *dev = rrpc->dev;
+       struct nvm_lun *lun;
+       struct rrpc_lun *rlun;
+       int i;
+
+       if (!rrpc->luns)
+               return;
+
+       for (i = 0; i < rrpc->nr_luns; i++) {
+               rlun = &rrpc->luns[i];
+               lun = rlun->parent;
+               if (!lun)
+                       break;
+               dev->mt->release_lun(dev, lun->id);
+               vfree(rlun->blocks);
+       }
+
        kfree(rrpc->luns);
 }
 
@@ -1148,7 +1153,7 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
 {
        struct nvm_dev *dev = rrpc->dev;
        struct rrpc_lun *rlun;
-       int i, j;
+       int i, j, ret = -EINVAL;
 
        if (dev->sec_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) {
                pr_err("rrpc: number of pages per block too high.");
@@ -1164,25 +1169,26 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
 
        /* 1:1 mapping */
        for (i = 0; i < rrpc->nr_luns; i++) {
-               struct nvm_lun *lun = dev->mt->get_lun(dev, lun_begin + i);
-
-               rlun = &rrpc->luns[i];
-               rlun->rrpc = rrpc;
-               rlun->parent = lun;
-               INIT_LIST_HEAD(&rlun->prio_list);
-               INIT_LIST_HEAD(&rlun->open_list);
-               INIT_LIST_HEAD(&rlun->closed_list);
+               int lunid = lun_begin + i;
+               struct nvm_lun *lun;
 
-               INIT_WORK(&rlun->ws_gc, rrpc_lun_gc);
-               spin_lock_init(&rlun->lock);
+               if (dev->mt->reserve_lun(dev, lunid)) {
+                       pr_err("rrpc: lun %u is already allocated\n", lunid);
+                       goto err;
+               }
 
-               rrpc->total_blocks += dev->blks_per_lun;
-               rrpc->nr_sects += dev->sec_per_lun;
+               lun = dev->mt->get_lun(dev, lunid);
+               if (!lun)
+                       goto err;
 
+               rlun = &rrpc->luns[i];
+               rlun->parent = lun;
                rlun->blocks = vzalloc(sizeof(struct rrpc_block) *
                                                rrpc->dev->blks_per_lun);
-               if (!rlun->blocks)
+               if (!rlun->blocks) {
+                       ret = -ENOMEM;
                        goto err;
+               }
 
                for (j = 0; j < rrpc->dev->blks_per_lun; j++) {
                        struct rrpc_block *rblk = &rlun->blocks[j];
@@ -1193,11 +1199,43 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
                        INIT_LIST_HEAD(&rblk->prio);
                        spin_lock_init(&rblk->lock);
                }
+
+               rlun->rrpc = rrpc;
+               INIT_LIST_HEAD(&rlun->prio_list);
+               INIT_LIST_HEAD(&rlun->open_list);
+               INIT_LIST_HEAD(&rlun->closed_list);
+
+               INIT_WORK(&rlun->ws_gc, rrpc_lun_gc);
+               spin_lock_init(&rlun->lock);
+
+               rrpc->total_blocks += dev->blks_per_lun;
+               rrpc->nr_sects += dev->sec_per_lun;
+
        }
 
        return 0;
 err:
-       return -ENOMEM;
+       return ret;
+}
+
+/* returns 0 on success and stores the beginning address in *begin */
+static int rrpc_area_init(struct rrpc *rrpc, sector_t *begin)
+{
+       struct nvm_dev *dev = rrpc->dev;
+       struct nvmm_type *mt = dev->mt;
+       sector_t size = rrpc->nr_sects * dev->sec_size;
+
+       size >>= 9;
+
+       return mt->get_area(dev, begin, size);
+}
+
+static void rrpc_area_free(struct rrpc *rrpc)
+{
+       struct nvm_dev *dev = rrpc->dev;
+       struct nvmm_type *mt = dev->mt;
+
+       mt->put_area(dev, rrpc->soffset);
 }
 
 static void rrpc_free(struct rrpc *rrpc)
@@ -1206,6 +1244,7 @@ static void rrpc_free(struct rrpc *rrpc)
        rrpc_map_free(rrpc);
        rrpc_core_free(rrpc);
        rrpc_luns_free(rrpc);
+       rrpc_area_free(rrpc);
 
        kfree(rrpc);
 }
@@ -1327,6 +1366,7 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
        struct request_queue *bqueue = dev->q;
        struct request_queue *tqueue = tdisk->queue;
        struct rrpc *rrpc;
+       sector_t soffset;
        int ret;
 
        if (!(dev->identity.dom & NVM_RSP_L2P)) {
@@ -1352,6 +1392,13 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
        /* simple round-robin strategy */
        atomic_set(&rrpc->next_lun, -1);
 
+       ret = rrpc_area_init(rrpc, &soffset);
+       if (ret < 0) {
+               pr_err("nvm: rrpc: could not initialize area\n");
+               return ERR_PTR(ret);
+       }
+       rrpc->soffset = soffset;
+
        ret = rrpc_luns_init(rrpc, lun_begin, lun_end);
        if (ret) {
                pr_err("nvm: rrpc: could not initialize luns\n");
index 855f4a5..2653484 100644 (file)
@@ -97,6 +97,7 @@ struct rrpc {
        struct nvm_dev *dev;
        struct gendisk *disk;
 
+       sector_t soffset; /* logical sector offset */
        u64 poffset; /* physical page offset */
        int lun_offset;
 
index acd1460..2a691da 100644 (file)
@@ -260,7 +260,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
 
        /* get the Controller level irq */
        fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
-       if (fsl_ifc_ctrl_dev->irq == NO_IRQ) {
+       if (fsl_ifc_ctrl_dev->irq == 0) {
                dev_err(&dev->dev, "failed to get irq resource "
                                                        "for IFC\n");
                ret = -ENODEV;
index ef09ba0..d5cfb50 100644 (file)
@@ -298,8 +298,7 @@ static int r592_transfer_fifo_dma(struct r592_device *dev)
        sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ?
                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
 
-       if (sg_count != 1 ||
-                       (sg_dma_len(&dev->req->sg) < dev->req->sg.length)) {
+       if (sg_count != 1 || sg_dma_len(&dev->req->sg) < R592_LFIFO_SIZE) {
                message("problem in dma_map_sg");
                return -EIO;
        }
index 42cc953..e83a279 100644 (file)
@@ -142,7 +142,7 @@ config MTD_AR7_PARTS
 
 config MTD_BCM63XX_PARTS
        tristate "BCM63XX CFE partitioning support"
-       depends on BCM63XX
+       depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
        select CRC32
        help
          This provides partions parsing for BCM63xx devices with CFE
index 8282f47..845dd27 100644 (file)
@@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
 {
        uint32_t buf;
        size_t bytes_read;
+       int err;
 
-       if (mtd_read(master, offset, sizeof(buf), &bytes_read,
-                    (uint8_t *)&buf) < 0) {
-               pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-                       offset);
+       err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
+                       (uint8_t *)&buf);
+       if (err && !mtd_is_bitflip(err)) {
+               pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+                       offset, err);
                goto out_default;
        }
 
@@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_info *master,
        int trx_part = -1;
        int last_trx_part = -1;
        int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
+       int err;
 
        /*
         * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
@@ -118,8 +121,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
        /* Parse block by block looking for magics */
        for (offset = 0; offset <= master->size - blocksize;
             offset += blocksize) {
-               /* Nothing more in higher memory */
-               if (offset >= 0x2000000)
+               /* Nothing more in higher memory on BCM47XX (MIPS) */
+               if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
                        break;
 
                if (curr_part >= BCM47XXPART_MAX_PARTS) {
@@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                }
 
                /* Read beginning of the block */
-               if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
-                            &bytes_read, (uint8_t *)buf) < 0) {
-                       pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-                              offset);
+               err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+                              &bytes_read, (uint8_t *)buf);
+               if (err && !mtd_is_bitflip(err)) {
+                       pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+                              offset, err);
                        continue;
                }
 
@@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                }
 
                /* Read middle of the block */
-               if (mtd_read(master, offset + 0x8000, 0x4,
-                            &bytes_read, (uint8_t *)buf) < 0) {
-                       pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-                              offset);
+               err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
+                              (uint8_t *)buf);
+               if (err && !mtd_is_bitflip(err)) {
+                       pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+                              offset, err);
                        continue;
                }
 
@@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                }
 
                offset = master->size - possible_nvram_sizes[i];
-               if (mtd_read(master, offset, 0x4, &bytes_read,
-                            (uint8_t *)buf) < 0) {
-                       pr_err("mtd_read error while reading at offset 0x%X!\n",
-                              offset);
+               err = mtd_read(master, offset, 0x4, &bytes_read,
+                              (uint8_t *)buf);
+               if (err && !mtd_is_bitflip(err)) {
+                       pr_err("mtd_read error while reading (offset 0x%X): %d\n",
+                              offset, err);
                        continue;
                }
 
index cec3188..41d1d31 100644 (file)
@@ -24,6 +24,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/bcm963xx_nvram.h>
 #include <linux/bcm963xx_tag.h>
 #include <linux/crc32.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/mach-bcm63xx/bcm63xx_nvram.h>
-#include <asm/mach-bcm63xx/board_bcm963xx.h>
+#define BCM963XX_CFE_BLOCK_SIZE                SZ_64K  /* always at least 64KiB */
 
-#define BCM63XX_CFE_BLOCK_SIZE SZ_64K          /* always at least 64KiB */
+#define BCM963XX_CFE_MAGIC_OFFSET      0x4e0
+#define BCM963XX_CFE_VERSION_OFFSET    0x570
+#define BCM963XX_NVRAM_OFFSET          0x580
 
-#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
+/* Ensure strings read from flash structs are null terminated */
+#define STR_NULL_TERMINATE(x) \
+       do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
 
 static int bcm63xx_detect_cfe(struct mtd_info *master)
 {
@@ -58,68 +62,130 @@ static int bcm63xx_detect_cfe(struct mtd_info *master)
                return 0;
 
        /* very old CFE's do not have the cfe-v string, so check for magic */
-       ret = mtd_read(master, BCM63XX_CFE_MAGIC_OFFSET, 8, &retlen,
+       ret = mtd_read(master, BCM963XX_CFE_MAGIC_OFFSET, 8, &retlen,
                       (void *)buf);
        buf[retlen] = 0;
 
        return strncmp("CFE1CFE1", buf, 8);
 }
 
-static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
-                                       const struct mtd_partition **pparts,
-                                       struct mtd_part_parser_data *data)
+static int bcm63xx_read_nvram(struct mtd_info *master,
+       struct bcm963xx_nvram *nvram)
+{
+       u32 actual_crc, expected_crc;
+       size_t retlen;
+       int ret;
+
+       /* extract nvram data */
+       ret = mtd_read(master, BCM963XX_NVRAM_OFFSET, BCM963XX_NVRAM_V5_SIZE,
+                       &retlen, (void *)nvram);
+       if (ret)
+               return ret;
+
+       ret = bcm963xx_nvram_checksum(nvram, &expected_crc, &actual_crc);
+       if (ret)
+               pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
+                       expected_crc, actual_crc);
+
+       if (!nvram->psi_size)
+               nvram->psi_size = BCM963XX_DEFAULT_PSI_SIZE;
+
+       return 0;
+}
+
+static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name,
+       loff_t tag_offset, struct bcm_tag *buf)
+{
+       int ret;
+       size_t retlen;
+       u32 computed_crc;
+
+       ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
+       if (ret)
+               return ret;
+
+       if (retlen != sizeof(*buf))
+               return -EIO;
+
+       computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
+                               offsetof(struct bcm_tag, header_crc));
+       if (computed_crc == buf->header_crc) {
+               STR_NULL_TERMINATE(buf->board_id);
+               STR_NULL_TERMINATE(buf->tag_version);
+
+               pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
+                       name, tag_offset, buf->tag_version, buf->board_id);
+
+               return 0;
+       }
+
+       pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
+               name, tag_offset, buf->header_crc, computed_crc);
+       return 1;
+}
+
+static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
+       const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)
 {
        /* CFE, NVRAM and global Linux are always present */
        int nrparts = 3, curpart = 0;
-       struct bcm_tag *buf;
+       struct bcm_tag *buf = NULL;
        struct mtd_partition *parts;
        int ret;
-       size_t retlen;
        unsigned int rootfsaddr, kerneladdr, spareaddr;
        unsigned int rootfslen, kernellen, sparelen, totallen;
        unsigned int cfelen, nvramlen;
        unsigned int cfe_erasesize;
        int i;
-       u32 computed_crc;
        bool rootfs_first = false;
 
-       if (bcm63xx_detect_cfe(master))
-               return -EINVAL;
-
        cfe_erasesize = max_t(uint32_t, master->erasesize,
-                             BCM63XX_CFE_BLOCK_SIZE);
+                             BCM963XX_CFE_BLOCK_SIZE);
 
        cfelen = cfe_erasesize;
-       nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
+       nvramlen = nvram->psi_size * SZ_1K;
        nvramlen = roundup(nvramlen, cfe_erasesize);
 
-       /* Allocate memory for buffer */
        buf = vmalloc(sizeof(struct bcm_tag));
        if (!buf)
                return -ENOMEM;
 
        /* Get the tag */
-       ret = mtd_read(master, cfelen, sizeof(struct bcm_tag), &retlen,
-                      (void *)buf);
-
-       if (retlen != sizeof(struct bcm_tag)) {
-               vfree(buf);
-               return -EIO;
-       }
+       ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf);
+       if (!ret) {
+               STR_NULL_TERMINATE(buf->flash_image_start);
+               if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
+                               rootfsaddr < BCM963XX_EXTENDED_SIZE) {
+                       pr_err("invalid rootfs address: %*ph\n",
+                               (int)sizeof(buf->flash_image_start),
+                               buf->flash_image_start);
+                       goto invalid_tag;
+               }
 
-       computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
-                               offsetof(struct bcm_tag, header_crc));
-       if (computed_crc == buf->header_crc) {
-               char *boardid = &(buf->board_id[0]);
-               char *tagversion = &(buf->tag_version[0]);
+               STR_NULL_TERMINATE(buf->kernel_address);
+               if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
+                               kerneladdr < BCM963XX_EXTENDED_SIZE) {
+                       pr_err("invalid kernel address: %*ph\n",
+                               (int)sizeof(buf->kernel_address),
+                               buf->kernel_address);
+                       goto invalid_tag;
+               }
 
-               sscanf(buf->flash_image_start, "%u", &rootfsaddr);
-               sscanf(buf->kernel_address, "%u", &kerneladdr);
-               sscanf(buf->kernel_length, "%u", &kernellen);
-               sscanf(buf->total_length, "%u", &totallen);
+               STR_NULL_TERMINATE(buf->kernel_length);
+               if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
+                       pr_err("invalid kernel length: %*ph\n",
+                               (int)sizeof(buf->kernel_length),
+                               buf->kernel_length);
+                       goto invalid_tag;
+               }
 
-               pr_info("CFE boot tag found with version %s and board type %s\n",
-                       tagversion, boardid);
+               STR_NULL_TERMINATE(buf->total_length);
+               if (kstrtouint(buf->total_length, 10, &totallen)) {
+                       pr_err("invalid total length: %*ph\n",
+                               (int)sizeof(buf->total_length),
+                               buf->total_length);
+                       goto invalid_tag;
+               }
 
                kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE;
                rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE;
@@ -134,13 +200,14 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                        rootfsaddr = kerneladdr + kernellen;
                        rootfslen = spareaddr - rootfsaddr;
                }
-       } else {
-               pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n",
-                       buf->header_crc, computed_crc);
+       } else if (ret > 0) {
+invalid_tag:
                kernellen = 0;
                rootfslen = 0;
                rootfsaddr = 0;
                spareaddr = cfelen;
+       } else {
+               goto out;
        }
        sparelen = master->size - spareaddr - nvramlen;
 
@@ -151,11 +218,10 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
        if (kernellen > 0)
                nrparts++;
 
-       /* Ask kernel for more memory */
        parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
        if (!parts) {
-               vfree(buf);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
        /* Start building partition list */
@@ -206,9 +272,43 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                sparelen);
 
        *pparts = parts;
+       ret = 0;
+
+out:
        vfree(buf);
 
+       if (ret)
+               return ret;
+
        return nrparts;
+}
+
+static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
+                                       const struct mtd_partition **pparts,
+                                       struct mtd_part_parser_data *data)
+{
+       struct bcm963xx_nvram *nvram = NULL;
+       int ret;
+
+       if (bcm63xx_detect_cfe(master))
+               return -EINVAL;
+
+       nvram = vzalloc(sizeof(*nvram));
+       if (!nvram)
+               return -ENOMEM;
+
+       ret = bcm63xx_read_nvram(master, nvram);
+       if (ret)
+               goto out;
+
+       if (!mtd_type_is_nand(master))
+               ret = bcm63xx_parse_cfe_nor_partitions(master, pparts, nvram);
+       else
+               ret = -EINVAL;
+
+out:
+       vfree(nvram);
+       return ret;
 };
 
 static struct mtd_part_parser bcm63xx_cfe_parser = {
index c3a2695..e7b2e43 100644 (file)
@@ -72,13 +72,11 @@ MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, "
  * @eccbytes: 8 bytes are used (1 for Hamming ECC, 7 for BCH ECC)
  * @eccpos: ecc positions (byte 7 is Hamming ECC, byte 8-14 are BCH ECC)
  * @oobfree: free pageinfo bytes (byte 0 until byte 6, byte 15
- * @oobavail: 8 available bytes remaining after ECC toll
  */
 static struct nand_ecclayout docg3_oobinfo = {
        .eccbytes = 8,
        .eccpos = {7, 8, 9, 10, 11, 12, 13, 14},
        .oobfree = {{0, 7}, {15, 1} },
-       .oobavail = 8,
 };
 
 static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
@@ -1438,7 +1436,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
                oobdelta = mtd->oobsize;
                break;
        case MTD_OPS_AUTO_OOB:
-               oobdelta = mtd->ecclayout->oobavail;
+               oobdelta = mtd->oobavail;
                break;
        default:
                return -EINVAL;
@@ -1860,6 +1858,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
        mtd->_write_oob = doc_write_oob;
        mtd->_block_isbad = doc_block_isbad;
        mtd->ecclayout = &docg3_oobinfo;
+       mtd->oobavail = 8;
        mtd->ecc_strength = DOC_ECC_BCH_T;
 
        return 0;
index 627a9bc..cbd8547 100644 (file)
@@ -19,6 +19,7 @@
 
 static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
 static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
+static unsigned long writebuf_size = 64;
 #define MTDRAM_TOTAL_SIZE (total_size * 1024)
 #define MTDRAM_ERASE_SIZE (erase_size * 1024)
 
@@ -27,6 +28,8 @@ module_param(total_size, ulong, 0);
 MODULE_PARM_DESC(total_size, "Total device size in KiB");
 module_param(erase_size, ulong, 0);
 MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
+module_param(writebuf_size, ulong, 0);
+MODULE_PARM_DESC(writebuf_size, "Device write buf size in Bytes (Default: 64)");
 #endif
 
 // We could store these in the mtd structure, but we only support 1 device..
@@ -123,7 +126,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
        mtd->flags = MTD_CAP_RAM;
        mtd->size = size;
        mtd->writesize = 1;
-       mtd->writebufsize = 64; /* Mimic CFI NOR flashes */
+       mtd->writebufsize = writebuf_size;
        mtd->erasesize = MTDRAM_ERASE_SIZE;
        mtd->priv = mapped_address;
 
index 10bf304..08de4b2 100644 (file)
@@ -126,10 +126,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
        if (ops->oobbuf) {
                size_t len, pages;
 
-               if (ops->mode == MTD_OPS_AUTO_OOB)
-                       len = mtd->oobavail;
-               else
-                       len = mtd->oobsize;
+               len = mtd_oobavail(mtd, ops);
                pages = mtd_div_by_ws(mtd->size, mtd);
                pages -= mtd_div_by_ws(from, mtd);
                if (ops->ooboffs + ops->ooblen > pages * len)
index fc8b3d1..cb06bdd 100644 (file)
@@ -346,7 +346,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
        if (mtd_can_have_bb(d->mtd) && mtd_block_isbad(d->mtd, offset))
                return MTDSWAP_SCANNED_BAD;
 
-       ops.ooblen = 2 * d->mtd->ecclayout->oobavail;
+       ops.ooblen = 2 * d->mtd->oobavail;
        ops.oobbuf = d->oob_buf;
        ops.ooboffs = 0;
        ops.datbuf = NULL;
@@ -359,7 +359,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
 
        data = (struct mtdswap_oobdata *)d->oob_buf;
        data2 = (struct mtdswap_oobdata *)
-               (d->oob_buf + d->mtd->ecclayout->oobavail);
+               (d->oob_buf + d->mtd->oobavail);
 
        if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) {
                eb->erase_count = le32_to_cpu(data->count);
@@ -933,7 +933,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
 
        ops.mode = MTD_OPS_AUTO_OOB;
        ops.len = mtd->writesize;
-       ops.ooblen = mtd->ecclayout->oobavail;
+       ops.ooblen = mtd->oobavail;
        ops.ooboffs = 0;
        ops.datbuf = d->page_buf;
        ops.oobbuf = d->oob_buf;
@@ -945,7 +945,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
                for (i = 0; i < mtd_pages; i++) {
                        patt = mtdswap_test_patt(test + i);
                        memset(d->page_buf, patt, mtd->writesize);
-                       memset(d->oob_buf, patt, mtd->ecclayout->oobavail);
+                       memset(d->oob_buf, patt, mtd->oobavail);
                        ret = mtd_write_oob(mtd, pos, &ops);
                        if (ret)
                                goto error;
@@ -964,7 +964,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
                                if (p1[j] != patt)
                                        goto error;
 
-                       for (j = 0; j < mtd->ecclayout->oobavail; j++)
+                       for (j = 0; j < mtd->oobavail; j++)
                                if (p2[j] != (unsigned char)patt)
                                        goto error;
 
@@ -1387,7 +1387,7 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks,
        if (!d->page_buf)
                goto page_buf_fail;
 
-       d->oob_buf = kmalloc(2 * mtd->ecclayout->oobavail, GFP_KERNEL);
+       d->oob_buf = kmalloc(2 * mtd->oobavail, GFP_KERNEL);
        if (!d->oob_buf)
                goto oob_buf_fail;
 
@@ -1417,7 +1417,6 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        unsigned long part;
        unsigned int eblocks, eavailable, bad_blocks, spare_cnt;
        uint64_t swap_size, use_size, size_limit;
-       struct nand_ecclayout *oinfo;
        int ret;
 
        parts = &partitions[0];
@@ -1447,17 +1446,10 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
                return;
        }
 
-       oinfo = mtd->ecclayout;
-       if (!oinfo) {
-               printk(KERN_ERR "%s: mtd%d does not have OOB\n",
-                       MTDSWAP_PREFIX, mtd->index);
-               return;
-       }
-
-       if (!mtd->oobsize || oinfo->oobavail < MTDSWAP_OOBSIZE) {
+       if (!mtd->oobsize || mtd->oobavail < MTDSWAP_OOBSIZE) {
                printk(KERN_ERR "%s: Not enough free bytes in OOB, "
                        "%d available, %zu needed.\n",
-                       MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE);
+                       MTDSWAP_PREFIX, mtd->oobavail, MTDSWAP_OOBSIZE);
                return;
        }
 
index 20f01b3..f05e0e9 100644 (file)
@@ -74,6 +74,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
 config MTD_NAND_GPIO
        tristate "GPIO assisted NAND Flash driver"
        depends on GPIOLIB || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          This enables a NAND flash driver where control signals are
          connected to GPIO pins, and commands and data are communicated
@@ -310,6 +311,7 @@ config MTD_NAND_CAFE
 config MTD_NAND_CS553X
        tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
        depends on X86_32
+       depends on !UML && HAS_IOMEM
        help
          The CS553x companion chips for the AMD Geode processor
          include NAND flash controllers with built-in hardware ECC
@@ -463,6 +465,7 @@ config MTD_NAND_MPC5121_NFC
 config MTD_NAND_VF610_NFC
        tristate "Support for Freescale NFC for VF610/MPC5125"
        depends on (SOC_VF610 || COMPILE_TEST)
+       depends on HAS_IOMEM
        help
          Enables support for NAND Flash Controller on some Freescale
          processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
@@ -553,4 +556,11 @@ config MTD_NAND_HISI504
        help
          Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+       tristate "Support for NAND on QCOM SoCs"
+       depends on ARCH_QCOM
+       help
+         Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+         controller. This controller is found on IPQ806x SoC.
+
 endif # MTD_NAND
index 9e36233..f553353 100644 (file)
@@ -56,5 +56,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)  += bcm47xxnflash/
 obj-$(CONFIG_MTD_NAND_SUNXI)           += sunxi_nand.o
 obj-$(CONFIG_MTD_NAND_HISI504)         += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)                += brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)            += qcom_nandc.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o
index bddcf83..20cbaab 100644 (file)
@@ -65,6 +65,11 @@ module_param(on_flash_bbt, int, 0);
 
 struct atmel_nand_caps {
        bool pmecc_correct_erase_page;
+       uint8_t pmecc_max_correction;
+};
+
+struct atmel_nand_nfc_caps {
+       uint32_t rb_mask;
 };
 
 /* oob layout for large page size
@@ -111,6 +116,7 @@ struct atmel_nfc {
        /* Point to the sram bank which include readed data via NFC */
        void                    *data_in_sram;
        bool                    will_write_sram;
+       const struct atmel_nand_nfc_caps *caps;
 };
 static struct atmel_nfc        nand_nfc;
 
@@ -140,6 +146,7 @@ struct atmel_nand_host {
        int                     pmecc_cw_len;   /* Length of codeword */
 
        void __iomem            *pmerrloc_base;
+       void __iomem            *pmerrloc_el_base;
        void __iomem            *pmecc_rom_base;
 
        /* lookup table for alpha_to and index_of */
@@ -468,6 +475,7 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
  *                8-bits                13-bytes                 14-bytes
  *               12-bits                20-bytes                 21-bytes
  *               24-bits                39-bytes                 42-bytes
+ *               32-bits                52-bytes                 56-bytes
  */
 static int pmecc_get_ecc_bytes(int cap, int sector_size)
 {
@@ -813,7 +821,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
        sector_size = host->pmecc_sector_size;
 
        while (err_nbr) {
-               tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1;
+               tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_el_base, i) - 1;
                byte_pos = tmp / 8;
                bit_pos  = tmp % 8;
 
@@ -825,7 +833,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
                        *(buf + byte_pos) ^= (1 << bit_pos);
 
                        pos = sector_num * host->pmecc_sector_size + byte_pos;
-                       dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+                       dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
                                pos, bit_pos, err_byte, *(buf + byte_pos));
                } else {
                        /* Bit flip in OOB area */
@@ -835,7 +843,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
                        ecc[tmp] ^= (1 << bit_pos);
 
                        pos = tmp + nand_chip->ecc.layout->eccpos[0];
-                       dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+                       dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
                                pos, bit_pos, err_byte, ecc[tmp]);
                }
 
@@ -1017,6 +1025,9 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
        case 24:
                val = PMECC_CFG_BCH_ERR24;
                break;
+       case 32:
+               val = PMECC_CFG_BCH_ERR32;
+               break;
        }
 
        if (host->pmecc_sector_size == 512)
@@ -1078,6 +1089,9 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
 
        /* If device tree doesn't specify, use NAND's minimum ECC parameters */
        if (host->pmecc_corr_cap == 0) {
+               if (*cap > host->caps->pmecc_max_correction)
+                       return -EINVAL;
+
                /* use the most fitable ecc bits (the near bigger one ) */
                if (*cap <= 2)
                        host->pmecc_corr_cap = 2;
@@ -1089,6 +1103,8 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
                        host->pmecc_corr_cap = 12;
                else if (*cap <= 24)
                        host->pmecc_corr_cap = 24;
+               else if (*cap <= 32)
+                       host->pmecc_corr_cap = 32;
                else
                        return -EINVAL;
        }
@@ -1205,6 +1221,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
                err_no = PTR_ERR(host->pmerrloc_base);
                goto err;
        }
+       host->pmerrloc_el_base = host->pmerrloc_base + ATMEL_PMERRLOC_SIGMAx +
+               (host->caps->pmecc_max_correction + 1) * 4;
 
        if (!host->has_no_lookup_table) {
                regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
@@ -1486,8 +1504,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
                ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
 }
 
-static const struct of_device_id atmel_nand_dt_ids[];
-
 static int atmel_of_init_port(struct atmel_nand_host *host,
                              struct device_node *np)
 {
@@ -1498,7 +1514,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
        enum of_gpio_flags flags = 0;
 
        host->caps = (struct atmel_nand_caps *)
-               of_match_device(atmel_nand_dt_ids, host->dev)->data;
+               of_device_get_match_data(host->dev);
 
        if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
                if (val >= 32) {
@@ -1547,10 +1563,16 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
         * them from NAND ONFI parameters.
         */
        if (of_property_read_u32(np, "atmel,pmecc-cap", &val) == 0) {
-               if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
-                               (val != 24)) {
+               if (val > host->caps->pmecc_max_correction) {
                        dev_err(host->dev,
-                               "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
+                               "Required ECC strength too high: %u max %u\n",
+                               val, host->caps->pmecc_max_correction);
+                       return -EINVAL;
+               }
+               if ((val != 2)  && (val != 4)  && (val != 8) &&
+                   (val != 12) && (val != 24) && (val != 32)) {
+                       dev_err(host->dev,
+                               "Required ECC strength not supported: %u\n",
                                val);
                        return -EINVAL;
                }
@@ -1560,7 +1582,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
        if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) == 0) {
                if ((val != 512) && (val != 1024)) {
                        dev_err(host->dev,
-                               "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
+                               "Required ECC sector size not supported: %u\n",
                                val);
                        return -EINVAL;
                }
@@ -1677,9 +1699,9 @@ static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
                nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
                ret = IRQ_HANDLED;
        }
-       if (pending & NFC_SR_RB_EDGE) {
+       if (pending & host->nfc->caps->rb_mask) {
                complete(&host->nfc->comp_ready);
-               nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
+               nfc_writel(host->nfc->hsmc_regs, IDR, host->nfc->caps->rb_mask);
                ret = IRQ_HANDLED;
        }
        if (pending & NFC_SR_CMD_DONE) {
@@ -1697,7 +1719,7 @@ static void nfc_prepare_interrupt(struct atmel_nand_host *host, u32 flag)
        if (flag & NFC_SR_XFR_DONE)
                init_completion(&host->nfc->comp_xfer_done);
 
-       if (flag & NFC_SR_RB_EDGE)
+       if (flag & host->nfc->caps->rb_mask)
                init_completion(&host->nfc->comp_ready);
 
        if (flag & NFC_SR_CMD_DONE)
@@ -1715,7 +1737,7 @@ static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
        if (flag & NFC_SR_XFR_DONE)
                comp[index++] = &host->nfc->comp_xfer_done;
 
-       if (flag & NFC_SR_RB_EDGE)
+       if (flag & host->nfc->caps->rb_mask)
                comp[index++] = &host->nfc->comp_ready;
 
        if (flag & NFC_SR_CMD_DONE)
@@ -1783,7 +1805,7 @@ static int nfc_device_ready(struct mtd_info *mtd)
                dev_err(host->dev, "Lost the interrupt flags: 0x%08x\n",
                                mask & status);
 
-       return status & NFC_SR_RB_EDGE;
+       return status & host->nfc->caps->rb_mask;
 }
 
 static void nfc_select_chip(struct mtd_info *mtd, int chip)
@@ -1956,8 +1978,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
                }
                /* fall through */
        default:
-               nfc_prepare_interrupt(host, NFC_SR_RB_EDGE);
-               nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
+               nfc_prepare_interrupt(host, host->nfc->caps->rb_mask);
+               nfc_wait_interrupt(host, host->nfc->caps->rb_mask);
        }
 }
 
@@ -2304,17 +2326,34 @@ static int atmel_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
+/*
+ * AT91RM9200 does not have PMECC or PMECC Errloc peripherals for
+ * BCH ECC. Combined with the "atmel,has-pmecc", it is used to describe
+ * devices from the SAM9 family that have those.
+ */
 static const struct atmel_nand_caps at91rm9200_caps = {
        .pmecc_correct_erase_page = false,
+       .pmecc_max_correction = 24,
 };
 
 static const struct atmel_nand_caps sama5d4_caps = {
        .pmecc_correct_erase_page = true,
+       .pmecc_max_correction = 24,
+};
+
+/*
+ * The PMECC Errloc controller starting in SAMA5D2 is not compatible,
+ * as the increased correction strength requires more registers.
+ */
+static const struct atmel_nand_caps sama5d2_caps = {
+       .pmecc_correct_erase_page = true,
+       .pmecc_max_correction = 32,
 };
 
 static const struct of_device_id atmel_nand_dt_ids[] = {
        { .compatible = "atmel,at91rm9200-nand", .data = &at91rm9200_caps },
        { .compatible = "atmel,sama5d4-nand", .data = &sama5d4_caps },
+       { .compatible = "atmel,sama5d2-nand", .data = &sama5d2_caps },
        { /* sentinel */ }
 };
 
@@ -2354,6 +2393,11 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
                }
        }
 
+       nfc->caps = (const struct atmel_nand_nfc_caps *)
+               of_device_get_match_data(&pdev->dev);
+       if (!nfc->caps)
+               return -ENODEV;
+
        nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff);
        nfc_readl(nfc->hsmc_regs, SR);  /* clear the NFC_SR */
 
@@ -2382,8 +2426,17 @@ static int atmel_nand_nfc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct atmel_nand_nfc_caps sama5d3_nfc_caps = {
+       .rb_mask = NFC_SR_RB_EDGE0,
+};
+
+static const struct atmel_nand_nfc_caps sama5d4_nfc_caps = {
+       .rb_mask = NFC_SR_RB_EDGE3,
+};
+
 static const struct of_device_id atmel_nand_nfc_match[] = {
-       { .compatible = "atmel,sama5d3-nfc" },
+       { .compatible = "atmel,sama5d3-nfc", .data = &sama5d3_nfc_caps },
+       { .compatible = "atmel,sama5d4-nfc", .data = &sama5d4_nfc_caps },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, atmel_nand_nfc_match);
index 668e735..834d694 100644 (file)
@@ -43,6 +43,7 @@
 #define                PMECC_CFG_BCH_ERR8              (2 << 0)
 #define                PMECC_CFG_BCH_ERR12             (3 << 0)
 #define                PMECC_CFG_BCH_ERR24             (4 << 0)
+#define                PMECC_CFG_BCH_ERR32             (5 << 0)
 
 #define                PMECC_CFG_SECTOR512             (0 << 4)
 #define                PMECC_CFG_SECTOR1024            (1 << 4)
 #define                PMERRLOC_ERR_NUM_MASK           (0x1f << 8)
 #define                PMERRLOC_CALC_DONE              (1 << 0)
 #define ATMEL_PMERRLOC_SIGMAx          0x028   /* Error location SIGMA x */
-#define ATMEL_PMERRLOC_ELx             0x08c   /* Error location x */
+
+/*
+ * The ATMEL_PMERRLOC_ELx register location depends from the number of
+ * bits corrected by the PMECC controller. Do not use it.
+ */
 
 /* Register access macros for PMECC */
 #define pmecc_readl_relaxed(addr, reg) \
        readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
 
 #define pmerrloc_readl_el_relaxed(addr, n) \
-       readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4))
+       readl_relaxed((addr) + ((n) * 4))
 
 /* Galois field dimension */
 #define PMECC_GF_DIMENSION_13                  13
index 4d5d262..0bbc1fa 100644 (file)
@@ -42,7 +42,8 @@
 #define                NFC_SR_UNDEF            (1 << 21)
 #define                NFC_SR_AWB              (1 << 22)
 #define                NFC_SR_ASE              (1 << 23)
-#define                NFC_SR_RB_EDGE          (1 << 24)
+#define                NFC_SR_RB_EDGE0         (1 << 24)
+#define                NFC_SR_RB_EDGE3         (1 << 27)
 
 #define ATMEL_HSMC_NFC_IER     0x0c
 #define ATMEL_HSMC_NFC_IDR     0x10
index 844fc07..e052839 100644 (file)
@@ -311,6 +311,36 @@ static const u16 brcmnand_regs_v60[] = {
        [BRCMNAND_FC_BASE]              = 0x400,
 };
 
+/* BRCMNAND v7.1 */
+static const u16 brcmnand_regs_v71[] = {
+       [BRCMNAND_CMD_START]            =  0x04,
+       [BRCMNAND_CMD_EXT_ADDRESS]      =  0x08,
+       [BRCMNAND_CMD_ADDRESS]          =  0x0c,
+       [BRCMNAND_INTFC_STATUS]         =  0x14,
+       [BRCMNAND_CS_SELECT]            =  0x18,
+       [BRCMNAND_CS_XOR]               =  0x1c,
+       [BRCMNAND_LL_OP]                =  0x20,
+       [BRCMNAND_CS0_BASE]             =  0x50,
+       [BRCMNAND_CS1_BASE]             =     0,
+       [BRCMNAND_CORR_THRESHOLD]       =  0xdc,
+       [BRCMNAND_CORR_THRESHOLD_EXT]   =  0xe0,
+       [BRCMNAND_UNCORR_COUNT]         =  0xfc,
+       [BRCMNAND_CORR_COUNT]           = 0x100,
+       [BRCMNAND_CORR_EXT_ADDR]        = 0x10c,
+       [BRCMNAND_CORR_ADDR]            = 0x110,
+       [BRCMNAND_UNCORR_EXT_ADDR]      = 0x114,
+       [BRCMNAND_UNCORR_ADDR]          = 0x118,
+       [BRCMNAND_SEMAPHORE]            = 0x150,
+       [BRCMNAND_ID]                   = 0x194,
+       [BRCMNAND_ID_EXT]               = 0x198,
+       [BRCMNAND_LL_RDATA]             = 0x19c,
+       [BRCMNAND_OOB_READ_BASE]        = 0x200,
+       [BRCMNAND_OOB_READ_10_BASE]     =     0,
+       [BRCMNAND_OOB_WRITE_BASE]       = 0x280,
+       [BRCMNAND_OOB_WRITE_10_BASE]    =     0,
+       [BRCMNAND_FC_BASE]              = 0x400,
+};
+
 enum brcmnand_cs_reg {
        BRCMNAND_CS_CFG_EXT = 0,
        BRCMNAND_CS_CFG,
@@ -406,7 +436,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
        }
 
        /* Register offsets */
-       if (ctrl->nand_version >= 0x0600)
+       if (ctrl->nand_version >= 0x0701)
+               ctrl->reg_offsets = brcmnand_regs_v71;
+       else if (ctrl->nand_version >= 0x0600)
                ctrl->reg_offsets = brcmnand_regs_v60;
        else if (ctrl->nand_version >= 0x0500)
                ctrl->reg_offsets = brcmnand_regs_v50;
@@ -796,7 +828,8 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
                                    idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
                                break;
                }
-               goto out;
+
+               return layout;
        }
 
        /*
@@ -847,10 +880,7 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
                                idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
                        break;
        }
-out:
-       /* Sum available OOB */
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE; i++)
-               layout->oobavail += layout->oobfree[i].length;
+
        return layout;
 }
 
index aa1a616..e553aff 100644 (file)
@@ -537,7 +537,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
        return 0;
 }
 
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
        return 0;
 }
index f170f3c..547c100 100644 (file)
@@ -794,7 +794,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
        }
 }
 
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
        /* This is our last resort if we couldn't find or create a BBT.  Just
           pretend all blocks are good. */
index df4165b..d86a60e 100644 (file)
@@ -225,7 +225,6 @@ struct docg4_priv {
 static struct nand_ecclayout docg4_oobinfo = {
        .eccbytes = 9,
        .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
-       .oobavail = 5,
        .oobfree = { {.offset = 2, .length = 5} }
 };
 
@@ -1121,7 +1120,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
        return ret;
 }
 
-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
 {
        /* only called when module_param ignore_badblocks is set */
        return 0;
index 235ddcb..8122c69 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Freescale GPMI NAND Flash Driver
  *
- * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
  * Copyright (C) 2008 Embedded Alley Solutions, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -136,7 +136,7 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
  *
  * We may have available oob space in this case.
  */
-static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
+static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
 {
        struct bch_geometry *geo = &this->bch_geometry;
        struct nand_chip *chip = &this->nand;
@@ -145,7 +145,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
        unsigned int block_mark_bit_offset;
 
        if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
-               return false;
+               return -EINVAL;
 
        switch (chip->ecc_step_ds) {
        case SZ_512:
@@ -158,19 +158,19 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
                dev_err(this->dev,
                        "unsupported nand chip. ecc bits : %d, ecc size : %d\n",
                        chip->ecc_strength_ds, chip->ecc_step_ds);
-               return false;
+               return -EINVAL;
        }
        geo->ecc_chunk_size = chip->ecc_step_ds;
        geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
        if (!gpmi_check_ecc(this))
-               return false;
+               return -EINVAL;
 
        /* Keep the C >= O */
        if (geo->ecc_chunk_size < mtd->oobsize) {
                dev_err(this->dev,
                        "unsupported nand chip. ecc size: %d, oob size : %d\n",
                        chip->ecc_step_ds, mtd->oobsize);
-               return false;
+               return -EINVAL;
        }
 
        /* The default value, see comment in the legacy_set_geometry(). */
@@ -242,7 +242,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
                                + ALIGN(geo->ecc_chunk_count, 4);
 
        if (!this->swap_block_mark)
-               return true;
+               return 0;
 
        /* For bit swap. */
        block_mark_bit_offset = mtd->writesize * 8 -
@@ -251,7 +251,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
 
        geo->block_mark_byte_offset = block_mark_bit_offset / 8;
        geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
-       return true;
+       return 0;
 }
 
 static int legacy_set_geometry(struct gpmi_nand_data *this)
@@ -285,7 +285,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
        geo->ecc_strength = get_ecc_strength(this);
        if (!gpmi_check_ecc(this)) {
                dev_err(this->dev,
-                       "required ecc strength of the NAND chip: %d is not supported by the GPMI controller (%d)\n",
+                       "ecc strength: %d cannot be supported by the controller (%d)\n"
+                       "try to use minimum ecc strength that NAND chip required\n",
                        geo->ecc_strength,
                        this->devdata->bch_max_ecc_strength);
                return -EINVAL;
@@ -366,10 +367,11 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
 
 int common_nfc_set_geometry(struct gpmi_nand_data *this)
 {
-       if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc")
-               && set_geometry_by_ecc_info(this))
-               return 0;
-       return legacy_set_geometry(this);
+       if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
+                               || legacy_set_geometry(this))
+               return set_geometry_by_ecc_info(this);
+
+       return 0;
 }
 
 struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
@@ -2033,9 +2035,54 @@ static int gpmi_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int gpmi_pm_suspend(struct device *dev)
+{
+       struct gpmi_nand_data *this = dev_get_drvdata(dev);
+
+       release_dma_channels(this);
+       return 0;
+}
+
+static int gpmi_pm_resume(struct device *dev)
+{
+       struct gpmi_nand_data *this = dev_get_drvdata(dev);
+       int ret;
+
+       ret = acquire_dma_channels(this);
+       if (ret < 0)
+               return ret;
+
+       /* re-init the GPMI registers */
+       this->flags &= ~GPMI_TIMING_INIT_OK;
+       ret = gpmi_init(this);
+       if (ret) {
+               dev_err(this->dev, "Error setting GPMI : %d\n", ret);
+               return ret;
+       }
+
+       /* re-init the BCH registers */
+       ret = bch_set_geometry(this);
+       if (ret) {
+               dev_err(this->dev, "Error setting BCH : %d\n", ret);
+               return ret;
+       }
+
+       /* re-init others */
+       gpmi_extra_init(this);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops gpmi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
+};
+
 static struct platform_driver gpmi_nand_driver = {
        .driver = {
                .name = "gpmi-nand",
+               .pm = &gpmi_pm_ops,
                .of_match_table = gpmi_nand_id_table,
        },
        .probe   = gpmi_nand_probe,
index f8d37f3..96502b6 100644 (file)
@@ -632,7 +632,6 @@ static void hisi_nfc_host_init(struct hinfc_host *host)
 }
 
 static struct nand_ecclayout nand_ecc_2K_16bits = {
-       .oobavail = 6,
        .oobfree = { {2, 6} },
 };
 
index b19d2a9..673ceb2 100644 (file)
@@ -427,9 +427,6 @@ static int jz_nand_probe(struct platform_device *pdev)
        chip->ecc.strength      = 4;
        chip->ecc.options       = NAND_ECC_GENERIC_ERASED_CHECK;
 
-       if (pdata)
-               chip->ecc.layout = pdata->ecc_layout;
-
        chip->chip_delay = 50;
        chip->cmd_ctrl = jz_nand_cmd_ctrl;
        chip->select_chip = jz_nand_select_chip;
index 9bc435d..d8c3e7a 100644 (file)
@@ -750,7 +750,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        nand_chip->ecc.mode = NAND_ECC_HW;
-       nand_chip->ecc.size = mtd->writesize;
+       nand_chip->ecc.size = 512;
        nand_chip->ecc.layout = &lpc32xx_nand_oob;
        host->mlcsubpages = mtd->writesize / 512;
 
index 6b93e89..5d7843f 100644 (file)
@@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 
 static int mpc5121_nfc_probe(struct platform_device *op)
 {
-       struct device_node *rootnode, *dn = op->dev.of_node;
+       struct device_node *dn = op->dev.of_node;
        struct clk *clk;
        struct device *dev = &op->dev;
        struct mpc5121_nfc_prv *prv;
@@ -712,18 +712,15 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        chip->ecc.mode = NAND_ECC_SOFT;
 
        /* Support external chip-select logic on ADS5121 board */
-       rootnode = of_find_node_by_path("/");
-       if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) {
+       if (of_machine_is_compatible("fsl,mpc5121ads")) {
                retval = ads5121_chipselect_init(mtd);
                if (retval) {
                        dev_err(dev, "Chipselect init error!\n");
-                       of_node_put(rootnode);
                        return retval;
                }
 
                chip->select_chip = ads5121_select_chip;
        }
-       of_node_put(rootnode);
 
        /* Enable NFC clock */
        clk = devm_clk_get(dev, "ipg");
index f2c8ff3..b6facac 100644 (file)
@@ -313,13 +313,12 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  * nand_block_bad - [DEFAULT] Read bad block marker from the chip
  * @mtd: MTD device structure
  * @ofs: offset from device start
- * @getchip: 0, if the chip is already selected
  *
  * Check, if the block is bad.
  */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
-       int page, chipnr, res = 0, i = 0;
+       int page, res = 0, i = 0;
        struct nand_chip *chip = mtd_to_nand(mtd);
        u16 bad;
 
@@ -328,15 +327,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 
        page = (int)(ofs >> chip->page_shift) & chip->pagemask;
 
-       if (getchip) {
-               chipnr = (int)(ofs >> chip->chip_shift);
-
-               nand_get_device(mtd, FL_READING);
-
-               /* Select the NAND device */
-               chip->select_chip(mtd, chipnr);
-       }
-
        do {
                if (chip->options & NAND_BUSWIDTH_16) {
                        chip->cmdfunc(mtd, NAND_CMD_READOOB,
@@ -361,11 +351,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
                i++;
        } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
-       if (getchip) {
-               chip->select_chip(mtd, -1);
-               nand_release_device(mtd);
-       }
-
        return res;
 }
 
@@ -503,19 +488,17 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
  * nand_block_checkbad - [GENERIC] Check if a block is marked bad
  * @mtd: MTD device structure
  * @ofs: offset from device start
- * @getchip: 0, if the chip is already selected
  * @allowbbt: 1, if its allowed to access the bbt area
  *
  * Check, if the block is bad. Either by reading the bad block table or
  * calling of the scan function.
  */
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
-                              int allowbbt)
+static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
 
        if (!chip->bbt)
-               return chip->block_bad(mtd, ofs, getchip);
+               return chip->block_bad(mtd, ofs);
 
        /* Return info from the table */
        return nand_isbad_bbt(mtd, ofs, allowbbt);
@@ -566,8 +549,8 @@ void nand_wait_ready(struct mtd_info *mtd)
                cond_resched();
        } while (time_before(jiffies, timeo));
 
-       pr_warn_ratelimited(
-               "timeout while waiting for chip to become ready\n");
+       if (!chip->dev_ready(mtd))
+               pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
 out:
        led_trigger_event(nand_led_trigger, LED_OFF);
 }
@@ -1723,8 +1706,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        int ret = 0;
        uint32_t readlen = ops->len;
        uint32_t oobreadlen = ops->ooblen;
-       uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
-               mtd->oobavail : mtd->oobsize;
+       uint32_t max_oobsize = mtd_oobavail(mtd, ops);
 
        uint8_t *bufpoi, *oob, *buf;
        int use_bufpoi;
@@ -2075,10 +2057,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 
        stats = mtd->ecc_stats;
 
-       if (ops->mode == MTD_OPS_AUTO_OOB)
-               len = chip->ecc.layout->oobavail;
-       else
-               len = mtd->oobsize;
+       len = mtd_oobavail(mtd, ops);
 
        if (unlikely(ops->ooboffs >= len)) {
                pr_debug("%s: attempt to start read outside oob\n",
@@ -2575,8 +2554,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        uint32_t writelen = ops->len;
 
        uint32_t oobwritelen = ops->ooblen;
-       uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
-                               mtd->oobavail : mtd->oobsize;
+       uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
 
        uint8_t *oob = ops->oobbuf;
        uint8_t *buf = ops->datbuf;
@@ -2766,10 +2744,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        pr_debug("%s: to = 0x%08x, len = %i\n",
                         __func__, (unsigned int)to, (int)ops->ooblen);
 
-       if (ops->mode == MTD_OPS_AUTO_OOB)
-               len = chip->ecc.layout->oobavail;
-       else
-               len = mtd->oobsize;
+       len = mtd_oobavail(mtd, ops);
 
        /* Do not allow write past end of page */
        if ((ops->ooboffs + ops->ooblen) > len) {
@@ -2957,7 +2932,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
        while (len) {
                /* Check if we have a bad block, we do not erase bad blocks! */
                if (nand_block_checkbad(mtd, ((loff_t) page) <<
-                                       chip->page_shift, 0, allowbbt)) {
+                                       chip->page_shift, allowbbt)) {
                        pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
                                    __func__, page);
                        instr->state = MTD_ERASE_FAILED;
@@ -3044,7 +3019,20 @@ static void nand_sync(struct mtd_info *mtd)
  */
 static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 {
-       return nand_block_checkbad(mtd, offs, 1, 0);
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       int chipnr = (int)(offs >> chip->chip_shift);
+       int ret;
+
+       /* Select the NAND device */
+       nand_get_device(mtd, FL_READING);
+       chip->select_chip(mtd, chipnr);
+
+       ret = nand_block_checkbad(mtd, offs, 0);
+
+       chip->select_chip(mtd, -1);
+       nand_release_device(mtd);
+
+       return ret;
 }
 
 /**
@@ -4287,10 +4275,8 @@ int nand_scan_tail(struct mtd_info *mtd)
                }
 
                /* See nand_bch_init() for details. */
-               ecc->bytes = DIV_ROUND_UP(
-                               ecc->strength * fls(8 * ecc->size), 8);
-               ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
-                                              &ecc->layout);
+               ecc->bytes = 0;
+               ecc->priv = nand_bch_init(mtd);
                if (!ecc->priv) {
                        pr_warn("BCH ECC initialization failed!\n");
                        BUG();
@@ -4325,11 +4311,11 @@ int nand_scan_tail(struct mtd_info *mtd)
         * The number of bytes available for a client to place data into
         * the out of band area.
         */
-       ecc->layout->oobavail = 0;
-       for (i = 0; ecc->layout->oobfree[i].length
-                       && i < ARRAY_SIZE(ecc->layout->oobfree); i++)
-               ecc->layout->oobavail += ecc->layout->oobfree[i].length;
-       mtd->oobavail = ecc->layout->oobavail;
+       mtd->oobavail = 0;
+       if (ecc->layout) {
+               for (i = 0; ecc->layout->oobfree[i].length; i++)
+                       mtd->oobavail += ecc->layout->oobfree[i].length;
+       }
 
        /* ECC sanity check: warn if it's too weak */
        if (!nand_ecc_strength_good(mtd))
index 4b6a708..2fbb523 100644 (file)
@@ -1373,5 +1373,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
 
        return ret;
 }
-
-EXPORT_SYMBOL(nand_scan_bbt);
index a87c1b6..b585bae 100644 (file)
@@ -107,9 +107,6 @@ EXPORT_SYMBOL(nand_bch_correct_data);
 /**
  * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
  * @mtd:       MTD block structure
- * @eccsize:   ecc block size in bytes
- * @eccbytes:  ecc length in bytes
- * @ecclayout: output default layout
  *
  * Returns:
  *  a pointer to a new NAND BCH control structure, or NULL upon failure
@@ -123,14 +120,21 @@ EXPORT_SYMBOL(nand_bch_correct_data);
  * @eccsize = 512  (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
  * @eccbytes = 7   (7 bytes are required to store m*t = 13*4 = 52 bits)
  */
-struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
-             struct nand_ecclayout **ecclayout)
+struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 {
+       struct nand_chip *nand = mtd_to_nand(mtd);
        unsigned int m, t, eccsteps, i;
-       struct nand_ecclayout *layout;
+       struct nand_ecclayout *layout = nand->ecc.layout;
        struct nand_bch_control *nbc = NULL;
        unsigned char *erased_page;
+       unsigned int eccsize = nand->ecc.size;
+       unsigned int eccbytes = nand->ecc.bytes;
+       unsigned int eccstrength = nand->ecc.strength;
+
+       if (!eccbytes && eccstrength) {
+               eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
+               nand->ecc.bytes = eccbytes;
+       }
 
        if (!eccsize || !eccbytes) {
                printk(KERN_WARNING "ecc parameters not supplied\n");
@@ -158,7 +162,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
        eccsteps = mtd->writesize/eccsize;
 
        /* if no ecc placement scheme was provided, build one */
-       if (!*ecclayout) {
+       if (!layout) {
 
                /* handle large page devices only */
                if (mtd->oobsize < 64) {
@@ -184,7 +188,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
                layout->oobfree[0].offset = 2;
                layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
 
-               *ecclayout = layout;
+               nand->ecc.layout = layout;
        }
 
        /* sanity checks */
@@ -192,7 +196,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
                printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
                goto fail;
        }
-       if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
+       if (layout->eccbytes != (eccsteps*eccbytes)) {
                printk(KERN_WARNING "invalid ecc layout\n");
                goto fail;
        }
@@ -216,6 +220,9 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
        for (i = 0; i < eccbytes; i++)
                nbc->eccmask[i] ^= 0xff;
 
+       if (!eccstrength)
+               nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
+
        return nbc;
 fail:
        nand_bch_free(nbc);
index a8804a3..ccc05f5 100644 (file)
@@ -50,8 +50,8 @@ struct nand_flash_dev nand_flash_ids[] = {
                  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
        {"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
                { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
-                 SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
-                 4 },
+                 SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
+                 NAND_ECC_INFO(40, SZ_1K), 4 },
 
        LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
        LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
index 220ddfc..dbc5b57 100644 (file)
@@ -113,7 +113,7 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
 {
        unsigned int val;
        spin_lock(&nand->lock);
-       val = __raw_readl(REG_SMISR);
+       val = __raw_readl(nand->reg + REG_SMISR);
        val &= READYBUSY;
        spin_unlock(&nand->lock);
 
index c553f78..0749ca1 100644 (file)
@@ -1807,13 +1807,19 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto return_error;
        }
 
+       /*
+        * Bail out earlier to let NAND_ECC_SOFT code create its own
+        * ecclayout instead of using ours.
+        */
+       if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
+               nand_chip->ecc.mode = NAND_ECC_SOFT;
+               goto scan_tail;
+       }
+
        /* populate MTD interface based on ECC scheme */
        ecclayout               = &info->oobinfo;
+       nand_chip->ecc.layout   = ecclayout;
        switch (info->ecc_opt) {
-       case OMAP_ECC_HAM1_CODE_SW:
-               nand_chip->ecc.mode = NAND_ECC_SOFT;
-               break;
-
        case OMAP_ECC_HAM1_CODE_HW:
                pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
                nand_chip->ecc.mode             = NAND_ECC_HW;
@@ -1861,10 +1867,7 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->oobfree->offset      = 1 +
                                ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* software bch library is used for locating errors */
-               nand_chip->ecc.priv             = nand_bch_init(mtd,
-                                                       nand_chip->ecc.size,
-                                                       nand_chip->ecc.bytes,
-                                                       &ecclayout);
+               nand_chip->ecc.priv             = nand_bch_init(mtd);
                if (!nand_chip->ecc.priv) {
                        dev_err(&info->pdev->dev, "unable to use BCH library\n");
                        err = -EINVAL;
@@ -1925,10 +1928,7 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->oobfree->offset      = 1 +
                                ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* software bch library is used for locating errors */
-               nand_chip->ecc.priv             = nand_bch_init(mtd,
-                                                       nand_chip->ecc.size,
-                                                       nand_chip->ecc.bytes,
-                                                       &ecclayout);
+               nand_chip->ecc.priv             = nand_bch_init(mtd);
                if (!nand_chip->ecc.priv) {
                        dev_err(&info->pdev->dev, "unable to use BCH library\n");
                        err = -EINVAL;
@@ -2002,9 +2002,6 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto return_error;
        }
 
-       if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW)
-               goto scan_tail;
-
        /* all OOB bytes from oobfree->offset till end off OOB are free */
        ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
        /* check if NAND device's OOB is enough to store ECC signatures */
@@ -2015,7 +2012,6 @@ static int omap_nand_probe(struct platform_device *pdev)
                err = -EINVAL;
                goto return_error;
        }
-       nand_chip->ecc.layout = ecclayout;
 
 scan_tail:
        /* second phase scan */
index a0e26de..e4e50da 100644 (file)
@@ -73,7 +73,6 @@ static int plat_nand_probe(struct platform_device *pdev)
        data->chip.bbt_options |= pdata->chip.bbt_options;
 
        data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
-       data->chip.ecc.layout = pdata->chip.ecclayout;
        data->chip.ecc.mode = NAND_ECC_SOFT;
 
        platform_set_drvdata(pdev, data);
index 86fc245..d650885 100644 (file)
 #define READ_ID_BYTES          7
 
 /* macros for registers read/write */
-#define nand_writel(info, off, val)    \
-       writel_relaxed((val), (info)->mmio_base + (off))
-
-#define nand_readl(info, off)          \
-       readl_relaxed((info)->mmio_base + (off))
+#define nand_writel(info, off, val)                                    \
+       do {                                                            \
+               dev_vdbg(&info->pdev->dev,                              \
+                        "%s():%d nand_writel(0x%x, 0x%04x)\n",         \
+                        __func__, __LINE__, (val), (off));             \
+               writel_relaxed((val), (info)->mmio_base + (off));       \
+       } while (0)
+
+#define nand_readl(info, off)                                          \
+       ({                                                              \
+               unsigned int _v;                                        \
+               _v = readl_relaxed((info)->mmio_base + (off));          \
+               dev_vdbg(&info->pdev->dev,                              \
+                        "%s():%d nand_readl(0x%04x) = 0x%x\n",         \
+                        __func__, __LINE__, (off), _v);                \
+               _v;                                                     \
+       })
 
 /* error code and state */
 enum {
@@ -199,7 +211,6 @@ struct pxa3xx_nand_info {
        struct dma_chan         *dma_chan;
        dma_cookie_t            dma_cookie;
        int                     drcmr_dat;
-       int                     drcmr_cmd;
 
        unsigned char           *data_buff;
        unsigned char           *oob_buff;
@@ -222,15 +233,44 @@ struct pxa3xx_nand_info {
        int                     use_spare;      /* use spare ? */
        int                     need_wait;
 
-       unsigned int            data_size;      /* data to be read from FIFO */
-       unsigned int            chunk_size;     /* split commands chunk size */
-       unsigned int            oob_size;
+       /* Amount of real data per full chunk */
+       unsigned int            chunk_size;
+
+       /* Amount of spare data per full chunk */
        unsigned int            spare_size;
+
+       /* Number of full chunks (i.e chunk_size + spare_size) */
+       unsigned int            nfullchunks;
+
+       /*
+        * Total number of chunks. If equal to nfullchunks, then there
+        * are only full chunks. Otherwise, there is one last chunk of
+        * size (last_chunk_size + last_spare_size)
+        */
+       unsigned int            ntotalchunks;
+
+       /* Amount of real data in the last chunk */
+       unsigned int            last_chunk_size;
+
+       /* Amount of spare data in the last chunk */
+       unsigned int            last_spare_size;
+
        unsigned int            ecc_size;
        unsigned int            ecc_err_cnt;
        unsigned int            max_bitflips;
        int                     retcode;
 
+       /*
+        * Variables only valid during command
+        * execution. step_chunk_size and step_spare_size is the
+        * amount of real data and spare data in the current
+        * chunk. cur_chunk is the current chunk being
+        * read/programmed.
+        */
+       unsigned int            step_chunk_size;
+       unsigned int            step_spare_size;
+       unsigned int            cur_chunk;
+
        /* cached register value */
        uint32_t                reg_ndcr;
        uint32_t                ndtr0cs0;
@@ -526,25 +566,6 @@ static int pxa3xx_nand_init(struct pxa3xx_nand_host *host)
        return 0;
 }
 
-/*
- * Set the data and OOB size, depending on the selected
- * spare and ECC configuration.
- * Only applicable to READ0, READOOB and PAGEPROG commands.
- */
-static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info,
-                               struct mtd_info *mtd)
-{
-       int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
-
-       info->data_size = mtd->writesize;
-       if (!oob_enable)
-               return;
-
-       info->oob_size = info->spare_size;
-       if (!info->use_ecc)
-               info->oob_size += info->ecc_size;
-}
-
 /**
  * NOTE: it is a must to set ND_RUN firstly, then write
  * command buffer, otherwise, it does not work.
@@ -660,28 +681,28 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
 
 static void handle_data_pio(struct pxa3xx_nand_info *info)
 {
-       unsigned int do_bytes = min(info->data_size, info->chunk_size);
-
        switch (info->state) {
        case STATE_PIO_WRITING:
-               writesl(info->mmio_base + NDDB,
-                       info->data_buff + info->data_buff_pos,
-                       DIV_ROUND_UP(do_bytes, 4));
+               if (info->step_chunk_size)
+                       writesl(info->mmio_base + NDDB,
+                               info->data_buff + info->data_buff_pos,
+                               DIV_ROUND_UP(info->step_chunk_size, 4));
 
-               if (info->oob_size > 0)
+               if (info->step_spare_size)
                        writesl(info->mmio_base + NDDB,
                                info->oob_buff + info->oob_buff_pos,
-                               DIV_ROUND_UP(info->oob_size, 4));
+                               DIV_ROUND_UP(info->step_spare_size, 4));
                break;
        case STATE_PIO_READING:
-               drain_fifo(info,
-                          info->data_buff + info->data_buff_pos,
-                          DIV_ROUND_UP(do_bytes, 4));
+               if (info->step_chunk_size)
+                       drain_fifo(info,
+                                  info->data_buff + info->data_buff_pos,
+                                  DIV_ROUND_UP(info->step_chunk_size, 4));
 
-               if (info->oob_size > 0)
+               if (info->step_spare_size)
                        drain_fifo(info,
                                   info->oob_buff + info->oob_buff_pos,
-                                  DIV_ROUND_UP(info->oob_size, 4));
+                                  DIV_ROUND_UP(info->step_spare_size, 4));
                break;
        default:
                dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
@@ -690,9 +711,8 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
        }
 
        /* Update buffer pointers for multi-page read/write */
-       info->data_buff_pos += do_bytes;
-       info->oob_buff_pos += info->oob_size;
-       info->data_size -= do_bytes;
+       info->data_buff_pos += info->step_chunk_size;
+       info->oob_buff_pos += info->step_spare_size;
 }
 
 static void pxa3xx_nand_data_dma_irq(void *data)
@@ -733,8 +753,9 @@ static void start_data_dma(struct pxa3xx_nand_info *info)
                                info->state);
                BUG();
        }
-       info->sg.length = info->data_size +
-               (info->oob_size ? info->spare_size + info->ecc_size : 0);
+       info->sg.length = info->chunk_size;
+       if (info->use_spare)
+               info->sg.length += info->spare_size + info->ecc_size;
        dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
 
        tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
@@ -895,9 +916,11 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
        /* reset data and oob column point to handle data */
        info->buf_start         = 0;
        info->buf_count         = 0;
-       info->oob_size          = 0;
        info->data_buff_pos     = 0;
        info->oob_buff_pos      = 0;
+       info->step_chunk_size   = 0;
+       info->step_spare_size   = 0;
+       info->cur_chunk         = 0;
        info->use_ecc           = 0;
        info->use_spare         = 1;
        info->retcode           = ERR_NONE;
@@ -909,8 +932,6 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
        case NAND_CMD_READ0:
        case NAND_CMD_PAGEPROG:
                info->use_ecc = 1;
-       case NAND_CMD_READOOB:
-               pxa3xx_set_datasize(info, mtd);
                break;
        case NAND_CMD_PARAM:
                info->use_spare = 0;
@@ -969,6 +990,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                if (command == NAND_CMD_READOOB)
                        info->buf_start += mtd->writesize;
 
+               if (info->cur_chunk < info->nfullchunks) {
+                       info->step_chunk_size = info->chunk_size;
+                       info->step_spare_size = info->spare_size;
+               } else {
+                       info->step_chunk_size = info->last_chunk_size;
+                       info->step_spare_size = info->last_spare_size;
+               }
+
                /*
                 * Multiple page read needs an 'extended command type' field,
                 * which is either naked-read or last-read according to the
@@ -980,8 +1009,8 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                        info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
                                        | NDCB0_LEN_OVRD
                                        | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-                       info->ndcb3 = info->chunk_size +
-                                     info->oob_size;
+                       info->ndcb3 = info->step_chunk_size +
+                               info->step_spare_size;
                }
 
                set_command_address(info, mtd->writesize, column, page_addr);
@@ -1001,8 +1030,6 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                                | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
                                | addr_cycle
                                | command;
-                       /* No data transfer in this case */
-                       info->data_size = 0;
                        exec_cmd = 1;
                }
                break;
@@ -1014,6 +1041,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                        break;
                }
 
+               if (info->cur_chunk < info->nfullchunks) {
+                       info->step_chunk_size = info->chunk_size;
+                       info->step_spare_size = info->spare_size;
+               } else {
+                       info->step_chunk_size = info->last_chunk_size;
+                       info->step_spare_size = info->last_spare_size;
+               }
+
                /* Second command setting for large pages */
                if (mtd->writesize > PAGE_CHUNK_SIZE) {
                        /*
@@ -1024,14 +1059,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                        info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
                                        | NDCB0_LEN_OVRD
                                        | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-                       info->ndcb3 = info->chunk_size +
-                                     info->oob_size;
+                       info->ndcb3 = info->step_chunk_size +
+                                     info->step_spare_size;
 
                        /*
                         * This is the command dispatch that completes a chunked
                         * page program operation.
                         */
-                       if (info->data_size == 0) {
+                       if (info->cur_chunk == info->ntotalchunks) {
                                info->ndcb0 = NDCB0_CMD_TYPE(0x1)
                                        | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
                                        | command;
@@ -1058,7 +1093,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                                | command;
                info->ndcb1 = (column & 0xFF);
                info->ndcb3 = INIT_BUFFER_SIZE;
-               info->data_size = INIT_BUFFER_SIZE;
+               info->step_chunk_size = INIT_BUFFER_SIZE;
                break;
 
        case NAND_CMD_READID:
@@ -1068,7 +1103,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                                | command;
                info->ndcb1 = (column & 0xFF);
 
-               info->data_size = 8;
+               info->step_chunk_size = 8;
                break;
        case NAND_CMD_STATUS:
                info->buf_count = 1;
@@ -1076,7 +1111,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                                | NDCB0_ADDR_CYC(1)
                                | command;
 
-               info->data_size = 8;
+               info->step_chunk_size = 8;
                break;
 
        case NAND_CMD_ERASE1:
@@ -1217,6 +1252,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
        init_completion(&info->dev_ready);
        do {
                info->state = STATE_PREPARED;
+
                exec_cmd = prepare_set_command(info, command, ext_cmd_type,
                                               column, page_addr);
                if (!exec_cmd) {
@@ -1236,22 +1272,30 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
                        break;
                }
 
+               /* Only a few commands need several steps */
+               if (command != NAND_CMD_PAGEPROG &&
+                   command != NAND_CMD_READ0    &&
+                   command != NAND_CMD_READOOB)
+                       break;
+
+               info->cur_chunk++;
+
                /* Check if the sequence is complete */
-               if (info->data_size == 0 && command != NAND_CMD_PAGEPROG)
+               if (info->cur_chunk == info->ntotalchunks && command != NAND_CMD_PAGEPROG)
                        break;
 
                /*
                 * After a splitted program command sequence has issued
                 * the command dispatch, the command sequence is complete.
                 */
-               if (info->data_size == 0 &&
+               if (info->cur_chunk == (info->ntotalchunks + 1) &&
                    command == NAND_CMD_PAGEPROG &&
                    ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
                        break;
 
                if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
                        /* Last read: issue a 'last naked read' */
-                       if (info->data_size == info->chunk_size)
+                       if (info->cur_chunk == info->ntotalchunks - 1)
                                ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
                        else
                                ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
@@ -1261,7 +1305,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
                 * the command dispatch must be issued to complete.
                 */
                } else if (command == NAND_CMD_PAGEPROG &&
-                          info->data_size == 0) {
+                          info->cur_chunk == info->ntotalchunks) {
                                ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
                }
        } while (1);
@@ -1506,6 +1550,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
                        int strength, int ecc_stepsize, int page_size)
 {
        if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
+               info->nfullchunks = 1;
+               info->ntotalchunks = 1;
                info->chunk_size = 2048;
                info->spare_size = 40;
                info->ecc_size = 24;
@@ -1514,6 +1560,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
                ecc->strength = 1;
 
        } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
+               info->nfullchunks = 1;
+               info->ntotalchunks = 1;
                info->chunk_size = 512;
                info->spare_size = 8;
                info->ecc_size = 8;
@@ -1527,6 +1575,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
         */
        } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
                info->ecc_bch = 1;
+               info->nfullchunks = 1;
+               info->ntotalchunks = 1;
                info->chunk_size = 2048;
                info->spare_size = 32;
                info->ecc_size = 32;
@@ -1537,6 +1587,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
 
        } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
                info->ecc_bch = 1;
+               info->nfullchunks = 2;
+               info->ntotalchunks = 2;
                info->chunk_size = 2048;
                info->spare_size = 32;
                info->ecc_size = 32;
@@ -1551,8 +1603,12 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
         */
        } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
                info->ecc_bch = 1;
+               info->nfullchunks = 4;
+               info->ntotalchunks = 5;
                info->chunk_size = 1024;
                info->spare_size = 0;
+               info->last_chunk_size = 0;
+               info->last_spare_size = 64;
                info->ecc_size = 32;
                ecc->mode = NAND_ECC_HW;
                ecc->size = info->chunk_size;
@@ -1738,7 +1794,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       if (use_dma) {
+       if (!np && use_dma) {
                r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
                if (r == NULL) {
                        dev_err(&pdev->dev,
@@ -1747,15 +1803,6 @@ static int alloc_nand_resource(struct platform_device *pdev)
                        goto fail_disable_clk;
                }
                info->drcmr_dat = r->start;
-
-               r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (r == NULL) {
-                       dev_err(&pdev->dev,
-                               "no resource defined for cmd DMA\n");
-                       ret = -ENXIO;
-                       goto fail_disable_clk;
-               }
-               info->drcmr_cmd = r->start;
        }
 
        irq = platform_get_irq(pdev, 0);
diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
new file mode 100644 (file)
index 0000000..f550a57
--- /dev/null
@@ -0,0 +1,2223 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
+#include <linux/delay.h>
+
+/* NANDc reg offsets */
+#define        NAND_FLASH_CMD                  0x00
+#define        NAND_ADDR0                      0x04
+#define        NAND_ADDR1                      0x08
+#define        NAND_FLASH_CHIP_SELECT          0x0c
+#define        NAND_EXEC_CMD                   0x10
+#define        NAND_FLASH_STATUS               0x14
+#define        NAND_BUFFER_STATUS              0x18
+#define        NAND_DEV0_CFG0                  0x20
+#define        NAND_DEV0_CFG1                  0x24
+#define        NAND_DEV0_ECC_CFG               0x28
+#define        NAND_DEV1_ECC_CFG               0x2c
+#define        NAND_DEV1_CFG0                  0x30
+#define        NAND_DEV1_CFG1                  0x34
+#define        NAND_READ_ID                    0x40
+#define        NAND_READ_STATUS                0x44
+#define        NAND_DEV_CMD0                   0xa0
+#define        NAND_DEV_CMD1                   0xa4
+#define        NAND_DEV_CMD2                   0xa8
+#define        NAND_DEV_CMD_VLD                0xac
+#define        SFLASHC_BURST_CFG               0xe0
+#define        NAND_ERASED_CW_DETECT_CFG       0xe8
+#define        NAND_ERASED_CW_DETECT_STATUS    0xec
+#define        NAND_EBI2_ECC_BUF_CFG           0xf0
+#define        FLASH_BUF_ACC                   0x100
+
+#define        NAND_CTRL                       0xf00
+#define        NAND_VERSION                    0xf08
+#define        NAND_READ_LOCATION_0            0xf20
+#define        NAND_READ_LOCATION_1            0xf24
+
+/* dummy register offsets, used by write_reg_dma */
+#define        NAND_DEV_CMD1_RESTORE           0xdead
+#define        NAND_DEV_CMD_VLD_RESTORE        0xbeef
+
+/* NAND_FLASH_CMD bits */
+#define        PAGE_ACC                        BIT(4)
+#define        LAST_PAGE                       BIT(5)
+
+/* NAND_FLASH_CHIP_SELECT bits */
+#define        NAND_DEV_SEL                    0
+#define        DM_EN                           BIT(2)
+
+/* NAND_FLASH_STATUS bits */
+#define        FS_OP_ERR                       BIT(4)
+#define        FS_READY_BSY_N                  BIT(5)
+#define        FS_MPU_ERR                      BIT(8)
+#define        FS_DEVICE_STS_ERR               BIT(16)
+#define        FS_DEVICE_WP                    BIT(23)
+
+/* NAND_BUFFER_STATUS bits */
+#define        BS_UNCORRECTABLE_BIT            BIT(8)
+#define        BS_CORRECTABLE_ERR_MSK          0x1f
+
+/* NAND_DEVn_CFG0 bits */
+#define        DISABLE_STATUS_AFTER_WRITE      4
+#define        CW_PER_PAGE                     6
+#define        UD_SIZE_BYTES                   9
+#define        ECC_PARITY_SIZE_BYTES_RS        19
+#define        SPARE_SIZE_BYTES                23
+#define        NUM_ADDR_CYCLES                 27
+#define        STATUS_BFR_READ                 30
+#define        SET_RD_MODE_AFTER_STATUS        31
+
+/* NAND_DEVn_CFG0 bits */
+#define        DEV0_CFG1_ECC_DISABLE           0
+#define        WIDE_FLASH                      1
+#define        NAND_RECOVERY_CYCLES            2
+#define        CS_ACTIVE_BSY                   5
+#define        BAD_BLOCK_BYTE_NUM              6
+#define        BAD_BLOCK_IN_SPARE_AREA         16
+#define        WR_RD_BSY_GAP                   17
+#define        ENABLE_BCH_ECC                  27
+
+/* NAND_DEV0_ECC_CFG bits */
+#define        ECC_CFG_ECC_DISABLE             0
+#define        ECC_SW_RESET                    1
+#define        ECC_MODE                        4
+#define        ECC_PARITY_SIZE_BYTES_BCH       8
+#define        ECC_NUM_DATA_BYTES              16
+#define        ECC_FORCE_CLK_OPEN              30
+
+/* NAND_DEV_CMD1 bits */
+#define        READ_ADDR                       0
+
+/* NAND_DEV_CMD_VLD bits */
+#define        READ_START_VLD                  0
+
+/* NAND_EBI2_ECC_BUF_CFG bits */
+#define        NUM_STEPS                       0
+
+/* NAND_ERASED_CW_DETECT_CFG bits */
+#define        ERASED_CW_ECC_MASK              1
+#define        AUTO_DETECT_RES                 0
+#define        MASK_ECC                        (1 << ERASED_CW_ECC_MASK)
+#define        RESET_ERASED_DET                (1 << AUTO_DETECT_RES)
+#define        ACTIVE_ERASED_DET               (0 << AUTO_DETECT_RES)
+#define        CLR_ERASED_PAGE_DET             (RESET_ERASED_DET | MASK_ECC)
+#define        SET_ERASED_PAGE_DET             (ACTIVE_ERASED_DET | MASK_ECC)
+
+/* NAND_ERASED_CW_DETECT_STATUS bits */
+#define        PAGE_ALL_ERASED                 BIT(7)
+#define        CODEWORD_ALL_ERASED             BIT(6)
+#define        PAGE_ERASED                     BIT(5)
+#define        CODEWORD_ERASED                 BIT(4)
+#define        ERASED_PAGE                     (PAGE_ALL_ERASED | PAGE_ERASED)
+#define        ERASED_CW                       (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+
+/* Version Mask */
+#define        NAND_VERSION_MAJOR_MASK         0xf0000000
+#define        NAND_VERSION_MAJOR_SHIFT        28
+#define        NAND_VERSION_MINOR_MASK         0x0fff0000
+#define        NAND_VERSION_MINOR_SHIFT        16
+
+/* NAND OP_CMDs */
+#define        PAGE_READ                       0x2
+#define        PAGE_READ_WITH_ECC              0x3
+#define        PAGE_READ_WITH_ECC_SPARE        0x4
+#define        PROGRAM_PAGE                    0x6
+#define        PAGE_PROGRAM_WITH_ECC           0x7
+#define        PROGRAM_PAGE_SPARE              0x9
+#define        BLOCK_ERASE                     0xa
+#define        FETCH_ID                        0xb
+#define        RESET_DEVICE                    0xd
+
+/*
+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+ * the driver calls the chunks 'step' or 'codeword' interchangeably
+ */
+#define        NANDC_STEP_SIZE                 512
+
+/*
+ * the largest page size we support is 8K, this will have 16 steps/codewords
+ * of 512 bytes each
+ */
+#define        MAX_NUM_STEPS                   (SZ_8K / NANDC_STEP_SIZE)
+
+/* we read at most 3 registers per codeword scan */
+#define        MAX_REG_RD                      (3 * MAX_NUM_STEPS)
+
+/* ECC modes supported by the controller */
+#define        ECC_NONE        BIT(0)
+#define        ECC_RS_4BIT     BIT(1)
+#define        ECC_BCH_4BIT    BIT(2)
+#define        ECC_BCH_8BIT    BIT(3)
+
+struct desc_info {
+       struct list_head node;
+
+       enum dma_data_direction dir;
+       struct scatterlist sgl;
+       struct dma_async_tx_descriptor *dma_desc;
+};
+
+/*
+ * holds the current register values that we want to write. acts as a contiguous
+ * chunk of memory which we use to write the controller registers through DMA.
+ */
+struct nandc_regs {
+       __le32 cmd;
+       __le32 addr0;
+       __le32 addr1;
+       __le32 chip_sel;
+       __le32 exec;
+
+       __le32 cfg0;
+       __le32 cfg1;
+       __le32 ecc_bch_cfg;
+
+       __le32 clrflashstatus;
+       __le32 clrreadstatus;
+
+       __le32 cmd1;
+       __le32 vld;
+
+       __le32 orig_cmd1;
+       __le32 orig_vld;
+
+       __le32 ecc_buf_cfg;
+};
+
+/*
+ * NAND controller data struct
+ *
+ * @controller:                        base controller structure
+ * @host_list:                 list containing all the chips attached to the
+ *                             controller
+ * @dev:                       parent device
+ * @base:                      MMIO base
+ * @base_dma:                  physical base address of controller registers
+ * @core_clk:                  controller clock
+ * @aon_clk:                   another controller clock
+ *
+ * @chan:                      dma channel
+ * @cmd_crci:                  ADM DMA CRCI for command flow control
+ * @data_crci:                 ADM DMA CRCI for data flow control
+ * @desc_list:                 DMA descriptor list (list of desc_infos)
+ *
+ * @data_buffer:               our local DMA buffer for page read/writes,
+ *                             used when we can't use the buffer provided
+ *                             by upper layers directly
+ * @buf_size/count/start:      markers for chip->read_buf/write_buf functions
+ * @reg_read_buf:              local buffer for reading back registers via DMA
+ * @reg_read_pos:              marker for data read in reg_read_buf
+ *
+ * @regs:                      a contiguous chunk of memory for DMA register
+ *                             writes. contains the register values to be
+ *                             written to controller
+ * @cmd1/vld:                  some fixed controller register values
+ * @ecc_modes:                 supported ECC modes by the current controller,
+ *                             initialized via DT match data
+ */
+struct qcom_nand_controller {
+       struct nand_hw_control controller;
+       struct list_head host_list;
+
+       struct device *dev;
+
+       void __iomem *base;
+       dma_addr_t base_dma;
+
+       struct clk *core_clk;
+       struct clk *aon_clk;
+
+       struct dma_chan *chan;
+       unsigned int cmd_crci;
+       unsigned int data_crci;
+       struct list_head desc_list;
+
+       u8              *data_buffer;
+       int             buf_size;
+       int             buf_count;
+       int             buf_start;
+
+       __le32 *reg_read_buf;
+       int reg_read_pos;
+
+       struct nandc_regs *regs;
+
+       u32 cmd1, vld;
+       u32 ecc_modes;
+};
+
+/*
+ * NAND chip structure
+ *
+ * @chip:                      base NAND chip structure
+ * @node:                      list node to add itself to host_list in
+ *                             qcom_nand_controller
+ *
+ * @cs:                                chip select value for this chip
+ * @cw_size:                   the number of bytes in a single step/codeword
+ *                             of a page, consisting of all data, ecc, spare
+ *                             and reserved bytes
+ * @cw_data:                   the number of bytes within a codeword protected
+ *                             by ECC
+ * @use_ecc:                   request the controller to use ECC for the
+ *                             upcoming read/write
+ * @bch_enabled:               flag to tell whether BCH ECC mode is used
+ * @ecc_bytes_hw:              ECC bytes used by controller hardware for this
+ *                             chip
+ * @status:                    value to be returned if NAND_CMD_STATUS command
+ *                             is executed
+ * @last_command:              keeps track of last command on this chip. used
+ *                             for reading correct status
+ *
+ * @cfg0, cfg1, cfg0_raw..:    NANDc register configurations needed for
+ *                             ecc/non-ecc mode for the current nand flash
+ *                             device
+ */
+struct qcom_nand_host {
+       struct nand_chip chip;
+       struct list_head node;
+
+       int cs;
+       int cw_size;
+       int cw_data;
+       bool use_ecc;
+       bool bch_enabled;
+       int ecc_bytes_hw;
+       int spare_bytes;
+       int bbm_size;
+       u8 status;
+       int last_command;
+
+       u32 cfg0, cfg1;
+       u32 cfg0_raw, cfg1_raw;
+       u32 ecc_buf_cfg;
+       u32 ecc_bch_cfg;
+       u32 clrflashstatus;
+       u32 clrreadstatus;
+};
+
+static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
+{
+       return container_of(chip, struct qcom_nand_host, chip);
+}
+
+static inline struct qcom_nand_controller *
+get_qcom_nand_controller(struct nand_chip *chip)
+{
+       return container_of(chip->controller, struct qcom_nand_controller,
+                           controller);
+}
+
+static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
+{
+       return ioread32(nandc->base + offset);
+}
+
+static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
+                              u32 val)
+{
+       iowrite32(val, nandc->base + offset);
+}
+
+static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
+{
+       switch (offset) {
+       case NAND_FLASH_CMD:
+               return &regs->cmd;
+       case NAND_ADDR0:
+               return &regs->addr0;
+       case NAND_ADDR1:
+               return &regs->addr1;
+       case NAND_FLASH_CHIP_SELECT:
+               return &regs->chip_sel;
+       case NAND_EXEC_CMD:
+               return &regs->exec;
+       case NAND_FLASH_STATUS:
+               return &regs->clrflashstatus;
+       case NAND_DEV0_CFG0:
+               return &regs->cfg0;
+       case NAND_DEV0_CFG1:
+               return &regs->cfg1;
+       case NAND_DEV0_ECC_CFG:
+               return &regs->ecc_bch_cfg;
+       case NAND_READ_STATUS:
+               return &regs->clrreadstatus;
+       case NAND_DEV_CMD1:
+               return &regs->cmd1;
+       case NAND_DEV_CMD1_RESTORE:
+               return &regs->orig_cmd1;
+       case NAND_DEV_CMD_VLD:
+               return &regs->vld;
+       case NAND_DEV_CMD_VLD_RESTORE:
+               return &regs->orig_vld;
+       case NAND_EBI2_ECC_BUF_CFG:
+               return &regs->ecc_buf_cfg;
+       default:
+               return NULL;
+       }
+}
+
+static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset,
+                         u32 val)
+{
+       struct nandc_regs *regs = nandc->regs;
+       __le32 *reg;
+
+       reg = offset_to_nandc_reg(regs, offset);
+
+       if (reg)
+               *reg = cpu_to_le32(val);
+}
+
+/* helper to configure address register values */
+static void set_address(struct qcom_nand_host *host, u16 column, int page)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+       if (chip->options & NAND_BUSWIDTH_16)
+               column >>= 1;
+
+       nandc_set_reg(nandc, NAND_ADDR0, page << 16 | column);
+       nandc_set_reg(nandc, NAND_ADDR1, page >> 16 & 0xff);
+}
+
+/*
+ * update_rw_regs:     set up read/write register values, these will be
+ *                     written to the NAND controller registers via DMA
+ *
+ * @num_cw:            number of steps for the read/write operation
+ * @read:              read or write operation
+ */
+static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       u32 cmd, cfg0, cfg1, ecc_bch_cfg;
+
+       if (read) {
+               if (host->use_ecc)
+                       cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
+               else
+                       cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
+       } else {
+                       cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
+       }
+
+       if (host->use_ecc) {
+               cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
+                               (num_cw - 1) << CW_PER_PAGE;
+
+               cfg1 = host->cfg1;
+               ecc_bch_cfg = host->ecc_bch_cfg;
+       } else {
+               cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
+                               (num_cw - 1) << CW_PER_PAGE;
+
+               cfg1 = host->cfg1_raw;
+               ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
+       }
+
+       nandc_set_reg(nandc, NAND_FLASH_CMD, cmd);
+       nandc_set_reg(nandc, NAND_DEV0_CFG0, cfg0);
+       nandc_set_reg(nandc, NAND_DEV0_CFG1, cfg1);
+       nandc_set_reg(nandc, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
+       nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
+       nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
+       nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
+       nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+}
+
+static int prep_dma_desc(struct qcom_nand_controller *nandc, bool read,
+                        int reg_off, const void *vaddr, int size,
+                        bool flow_control)
+{
+       struct desc_info *desc;
+       struct dma_async_tx_descriptor *dma_desc;
+       struct scatterlist *sgl;
+       struct dma_slave_config slave_conf;
+       enum dma_transfer_direction dir_eng;
+       int ret;
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+
+       sgl = &desc->sgl;
+
+       sg_init_one(sgl, vaddr, size);
+
+       if (read) {
+               dir_eng = DMA_DEV_TO_MEM;
+               desc->dir = DMA_FROM_DEVICE;
+       } else {
+               dir_eng = DMA_MEM_TO_DEV;
+               desc->dir = DMA_TO_DEVICE;
+       }
+
+       ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
+       if (ret == 0) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       memset(&slave_conf, 0x00, sizeof(slave_conf));
+
+       slave_conf.device_fc = flow_control;
+       if (read) {
+               slave_conf.src_maxburst = 16;
+               slave_conf.src_addr = nandc->base_dma + reg_off;
+               slave_conf.slave_id = nandc->data_crci;
+       } else {
+               slave_conf.dst_maxburst = 16;
+               slave_conf.dst_addr = nandc->base_dma + reg_off;
+               slave_conf.slave_id = nandc->cmd_crci;
+       }
+
+       ret = dmaengine_slave_config(nandc->chan, &slave_conf);
+       if (ret) {
+               dev_err(nandc->dev, "failed to configure dma channel\n");
+               goto err;
+       }
+
+       dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
+       if (!dma_desc) {
+               dev_err(nandc->dev, "failed to prepare desc\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       desc->dma_desc = dma_desc;
+
+       list_add_tail(&desc->node, &nandc->desc_list);
+
+       return 0;
+err:
+       kfree(desc);
+
+       return ret;
+}
+
+/*
+ * read_reg_dma:       prepares a descriptor to read a given number of
+ *                     contiguous registers to the reg_read_buf pointer
+ *
+ * @first:             offset of the first register in the contiguous block
+ * @num_regs:          number of registers to read
+ */
+static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
+                       int num_regs)
+{
+       bool flow_control = false;
+       void *vaddr;
+       int size;
+
+       if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
+               flow_control = true;
+
+       size = num_regs * sizeof(u32);
+       vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
+       nandc->reg_read_pos += num_regs;
+
+       return prep_dma_desc(nandc, true, first, vaddr, size, flow_control);
+}
+
+/*
+ * write_reg_dma:      prepares a descriptor to write a given number of
+ *                     contiguous registers
+ *
+ * @first:             offset of the first register in the contiguous block
+ * @num_regs:          number of registers to write
+ */
+static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
+                        int num_regs)
+{
+       bool flow_control = false;
+       struct nandc_regs *regs = nandc->regs;
+       void *vaddr;
+       int size;
+
+       vaddr = offset_to_nandc_reg(regs, first);
+
+       if (first == NAND_FLASH_CMD)
+               flow_control = true;
+
+       if (first == NAND_DEV_CMD1_RESTORE)
+               first = NAND_DEV_CMD1;
+
+       if (first == NAND_DEV_CMD_VLD_RESTORE)
+               first = NAND_DEV_CMD_VLD;
+
+       size = num_regs * sizeof(u32);
+
+       return prep_dma_desc(nandc, false, first, vaddr, size, flow_control);
+}
+
+/*
+ * read_data_dma:      prepares a DMA descriptor to transfer data from the
+ *                     controller's internal buffer to the buffer 'vaddr'
+ *
+ * @reg_off:           offset within the controller's data buffer
+ * @vaddr:             virtual address of the buffer we want to write to
+ * @size:              DMA transaction size in bytes
+ */
+static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+                        const u8 *vaddr, int size)
+{
+       return prep_dma_desc(nandc, true, reg_off, vaddr, size, false);
+}
+
+/*
+ * write_data_dma:     prepares a DMA descriptor to transfer data from
+ *                     'vaddr' to the controller's internal buffer
+ *
+ * @reg_off:           offset within the controller's data buffer
+ * @vaddr:             virtual address of the buffer we want to read from
+ * @size:              DMA transaction size in bytes
+ */
+static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+                         const u8 *vaddr, int size)
+{
+       return prep_dma_desc(nandc, false, reg_off, vaddr, size, false);
+}
+
+/*
+ * helper to prepare dma descriptors to configure registers needed for reading a
+ * codeword/step in a page
+ */
+static void config_cw_read(struct qcom_nand_controller *nandc)
+{
+       write_reg_dma(nandc, NAND_FLASH_CMD, 3);
+       write_reg_dma(nandc, NAND_DEV0_CFG0, 3);
+       write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1);
+
+       write_reg_dma(nandc, NAND_EXEC_CMD, 1);
+
+       read_reg_dma(nandc, NAND_FLASH_STATUS, 2);
+       read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1);
+}
+
+/*
+ * helpers to prepare dma descriptors used to configure registers needed for
+ * writing a codeword/step in a page
+ */
+static void config_cw_write_pre(struct qcom_nand_controller *nandc)
+{
+       write_reg_dma(nandc, NAND_FLASH_CMD, 3);
+       write_reg_dma(nandc, NAND_DEV0_CFG0, 3);
+       write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1);
+}
+
+static void config_cw_write_post(struct qcom_nand_controller *nandc)
+{
+       write_reg_dma(nandc, NAND_EXEC_CMD, 1);
+
+       read_reg_dma(nandc, NAND_FLASH_STATUS, 1);
+
+       write_reg_dma(nandc, NAND_FLASH_STATUS, 1);
+       write_reg_dma(nandc, NAND_READ_STATUS, 1);
+}
+
+/*
+ * the following functions are used within chip->cmdfunc() to perform different
+ * NAND_CMD_* commands
+ */
+
+/* sets up descriptors for NAND_CMD_PARAM */
+static int nandc_param(struct qcom_nand_host *host)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+       /*
+        * NAND_CMD_PARAM is called before we know much about the FLASH chip
+        * in use. we configure the controller to perform a raw read of 512
+        * bytes to read onfi params
+        */
+       nandc_set_reg(nandc, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE);
+       nandc_set_reg(nandc, NAND_ADDR0, 0);
+       nandc_set_reg(nandc, NAND_ADDR1, 0);
+       nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
+                                       | 512 << UD_SIZE_BYTES
+                                       | 5 << NUM_ADDR_CYCLES
+                                       | 0 << SPARE_SIZE_BYTES);
+       nandc_set_reg(nandc, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
+                                       | 0 << CS_ACTIVE_BSY
+                                       | 17 << BAD_BLOCK_BYTE_NUM
+                                       | 1 << BAD_BLOCK_IN_SPARE_AREA
+                                       | 2 << WR_RD_BSY_GAP
+                                       | 0 << WIDE_FLASH
+                                       | 1 << DEV0_CFG1_ECC_DISABLE);
+       nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
+
+       /* configure CMD1 and VLD for ONFI param probing */
+       nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
+                     (nandc->vld & ~(1 << READ_START_VLD))
+                     | 0 << READ_START_VLD);
+       nandc_set_reg(nandc, NAND_DEV_CMD1,
+                     (nandc->cmd1 & ~(0xFF << READ_ADDR))
+                     | NAND_CMD_PARAM << READ_ADDR);
+
+       nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+
+       nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
+       nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
+
+       write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1);
+       write_reg_dma(nandc, NAND_DEV_CMD1, 1);
+
+       nandc->buf_count = 512;
+       memset(nandc->data_buffer, 0xff, nandc->buf_count);
+
+       config_cw_read(nandc);
+
+       read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
+                     nandc->buf_count);
+
+       /* restore CMD1 and VLD regs */
+       write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1);
+       write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1);
+
+       return 0;
+}
+
+/* sets up descriptors for NAND_CMD_ERASE1 */
+static int erase_block(struct qcom_nand_host *host, int page_addr)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+       nandc_set_reg(nandc, NAND_FLASH_CMD,
+                     BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
+       nandc_set_reg(nandc, NAND_ADDR0, page_addr);
+       nandc_set_reg(nandc, NAND_ADDR1, 0);
+       nandc_set_reg(nandc, NAND_DEV0_CFG0,
+                     host->cfg0_raw & ~(7 << CW_PER_PAGE));
+       nandc_set_reg(nandc, NAND_DEV0_CFG1, host->cfg1_raw);
+       nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+       nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
+       nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
+
+       write_reg_dma(nandc, NAND_FLASH_CMD, 3);
+       write_reg_dma(nandc, NAND_DEV0_CFG0, 2);
+       write_reg_dma(nandc, NAND_EXEC_CMD, 1);
+
+       read_reg_dma(nandc, NAND_FLASH_STATUS, 1);
+
+       write_reg_dma(nandc, NAND_FLASH_STATUS, 1);
+       write_reg_dma(nandc, NAND_READ_STATUS, 1);
+
+       return 0;
+}
+
+/* sets up descriptors for NAND_CMD_READID */
+static int read_id(struct qcom_nand_host *host, int column)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+       if (column == -1)
+               return 0;
+
+       nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID);
+       nandc_set_reg(nandc, NAND_ADDR0, column);
+       nandc_set_reg(nandc, NAND_ADDR1, 0);
+       nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
+       nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+
+       write_reg_dma(nandc, NAND_FLASH_CMD, 4);
+       write_reg_dma(nandc, NAND_EXEC_CMD, 1);
+
+       read_reg_dma(nandc, NAND_READ_ID, 1);
+
+       return 0;
+}
+
+/* sets up descriptors for NAND_CMD_RESET */
+static int reset(struct qcom_nand_host *host)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+       nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE);
+       nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+
+       write_reg_dma(nandc, NAND_FLASH_CMD, 1);
+       write_reg_dma(nandc, NAND_EXEC_CMD, 1);
+
+       read_reg_dma(nandc, NAND_FLASH_STATUS, 1);
+
+       return 0;
+}
+
+/* helpers to submit/free our list of dma descriptors */
+static int submit_descs(struct qcom_nand_controller *nandc)
+{
+       struct desc_info *desc;
+       dma_cookie_t cookie = 0;
+
+       list_for_each_entry(desc, &nandc->desc_list, node)
+               cookie = dmaengine_submit(desc->dma_desc);
+
+       if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static void free_descs(struct qcom_nand_controller *nandc)
+{
+       struct desc_info *desc, *n;
+
+       list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
+               list_del(&desc->node);
+               dma_unmap_sg(nandc->dev, &desc->sgl, 1, desc->dir);
+               kfree(desc);
+       }
+}
+
+/* reset the register read buffer for next NAND operation */
+static void clear_read_regs(struct qcom_nand_controller *nandc)
+{
+       nandc->reg_read_pos = 0;
+       memset(nandc->reg_read_buf, 0,
+              MAX_REG_RD * sizeof(*nandc->reg_read_buf));
+}
+
+static void pre_command(struct qcom_nand_host *host, int command)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+       nandc->buf_count = 0;
+       nandc->buf_start = 0;
+       host->use_ecc = false;
+       host->last_command = command;
+
+       clear_read_regs(nandc);
+}
+
+/*
+ * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
+ * privately maintained status byte, this status byte can be read after
+ * NAND_CMD_STATUS is called
+ */
+static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int num_cw;
+       int i;
+
+       num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
+
+       for (i = 0; i < num_cw; i++) {
+               u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
+
+               if (flash_status & FS_MPU_ERR)
+                       host->status &= ~NAND_STATUS_WP;
+
+               if (flash_status & FS_OP_ERR || (i == (num_cw - 1) &&
+                                                (flash_status &
+                                                 FS_DEVICE_STS_ERR)))
+                       host->status |= NAND_STATUS_FAIL;
+       }
+}
+
+static void post_command(struct qcom_nand_host *host, int command)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+       switch (command) {
+       case NAND_CMD_READID:
+               memcpy(nandc->data_buffer, nandc->reg_read_buf,
+                      nandc->buf_count);
+               break;
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+               parse_erase_write_errors(host, command);
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * Implements chip->cmdfunc. It's  only used for a limited set of commands.
+ * The rest of the commands wouldn't be called by upper layers. For example,
+ * NAND_CMD_READOOB would never be called because we have our own versions
+ * of read_oob ops for nand_ecc_ctrl.
+ */
+static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
+                              int column, int page_addr)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       bool wait = false;
+       int ret = 0;
+
+       pre_command(host, command);
+
+       switch (command) {
+       case NAND_CMD_RESET:
+               ret = reset(host);
+               wait = true;
+               break;
+
+       case NAND_CMD_READID:
+               nandc->buf_count = 4;
+               ret = read_id(host, column);
+               wait = true;
+               break;
+
+       case NAND_CMD_PARAM:
+               ret = nandc_param(host);
+               wait = true;
+               break;
+
+       case NAND_CMD_ERASE1:
+               ret = erase_block(host, page_addr);
+               wait = true;
+               break;
+
+       case NAND_CMD_READ0:
+               /* we read the entire page for now */
+               WARN_ON(column != 0);
+
+               host->use_ecc = true;
+               set_address(host, 0, page_addr);
+               update_rw_regs(host, ecc->steps, true);
+               break;
+
+       case NAND_CMD_SEQIN:
+               WARN_ON(column != 0);
+               set_address(host, 0, page_addr);
+               break;
+
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_NONE:
+       default:
+               break;
+       }
+
+       if (ret) {
+               dev_err(nandc->dev, "failure executing command %d\n",
+                       command);
+               free_descs(nandc);
+               return;
+       }
+
+       if (wait) {
+               ret = submit_descs(nandc);
+               if (ret)
+                       dev_err(nandc->dev,
+                               "failure submitting descs for command %d\n",
+                               command);
+       }
+
+       free_descs(nandc);
+
+       post_command(host, command);
+}
+
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff.
+ */
+static bool erased_chunk_check_and_fixup(u8 *data_buf, int data_len)
+{
+       u8 empty1, empty2;
+
+       /*
+        * an erased page flags an error in NAND_FLASH_STATUS, check if the page
+        * is erased by looking for 0x54s at offsets 3 and 175 from the
+        * beginning of each codeword
+        */
+
+       empty1 = data_buf[3];
+       empty2 = data_buf[175];
+
+       /*
+        * if the erased codework markers, if they exist override them with
+        * 0xffs
+        */
+       if ((empty1 == 0x54 && empty2 == 0xff) ||
+           (empty1 == 0xff && empty2 == 0x54)) {
+               data_buf[3] = 0xff;
+               data_buf[175] = 0xff;
+       }
+
+       /*
+        * check if the entire chunk contains 0xffs or not. if it doesn't, then
+        * restore the original values at the special offsets
+        */
+       if (memchr_inv(data_buf, 0xff, data_len)) {
+               data_buf[3] = empty1;
+               data_buf[175] = empty2;
+
+               return false;
+       }
+
+       return true;
+}
+
+struct read_stats {
+       __le32 flash;
+       __le32 buffer;
+       __le32 erased_cw;
+};
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+                            u8 *oob_buf)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       unsigned int max_bitflips = 0;
+       struct read_stats *buf;
+       int i;
+
+       buf = (struct read_stats *)nandc->reg_read_buf;
+
+       for (i = 0; i < ecc->steps; i++, buf++) {
+               u32 flash, buffer, erased_cw;
+               int data_len, oob_len;
+
+               if (i == (ecc->steps - 1)) {
+                       data_len = ecc->size - ((ecc->steps - 1) << 2);
+                       oob_len = ecc->steps << 2;
+               } else {
+                       data_len = host->cw_data;
+                       oob_len = 0;
+               }
+
+               flash = le32_to_cpu(buf->flash);
+               buffer = le32_to_cpu(buf->buffer);
+               erased_cw = le32_to_cpu(buf->erased_cw);
+
+               if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+                       bool erased;
+
+                       /* ignore erased codeword errors */
+                       if (host->bch_enabled) {
+                               erased = (erased_cw & ERASED_CW) == ERASED_CW ?
+                                        true : false;
+                       } else {
+                               erased = erased_chunk_check_and_fixup(data_buf,
+                                                                     data_len);
+                       }
+
+                       if (erased) {
+                               data_buf += data_len;
+                               if (oob_buf)
+                                       oob_buf += oob_len + ecc->bytes;
+                               continue;
+                       }
+
+                       if (buffer & BS_UNCORRECTABLE_BIT) {
+                               int ret, ecclen, extraooblen;
+                               void *eccbuf;
+
+                               eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+                               ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+                               extraooblen = oob_buf ? oob_len : 0;
+
+                               /*
+                                * make sure it isn't an erased page reported
+                                * as not-erased by HW because of a few bitflips
+                                */
+                               ret = nand_check_erased_ecc_chunk(data_buf,
+                                       data_len, eccbuf, ecclen, oob_buf,
+                                       extraooblen, ecc->strength);
+                               if (ret < 0) {
+                                       mtd->ecc_stats.failed++;
+                               } else {
+                                       mtd->ecc_stats.corrected += ret;
+                                       max_bitflips =
+                                               max_t(unsigned int, max_bitflips, ret);
+                               }
+                       }
+               } else {
+                       unsigned int stat;
+
+                       stat = buffer & BS_CORRECTABLE_ERR_MSK;
+                       mtd->ecc_stats.corrected += stat;
+                       max_bitflips = max(max_bitflips, stat);
+               }
+
+               data_buf += data_len;
+               if (oob_buf)
+                       oob_buf += oob_len + ecc->bytes;
+       }
+
+       return max_bitflips;
+}
+
+/*
+ * helper to perform the actual page read operation, used by ecc->read_page(),
+ * ecc->read_oob()
+ */
+static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
+                        u8 *oob_buf)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int i, ret;
+
+       /* queue cmd descs for each codeword */
+       for (i = 0; i < ecc->steps; i++) {
+               int data_size, oob_size;
+
+               if (i == (ecc->steps - 1)) {
+                       data_size = ecc->size - ((ecc->steps - 1) << 2);
+                       oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
+                                  host->spare_bytes;
+               } else {
+                       data_size = host->cw_data;
+                       oob_size = host->ecc_bytes_hw + host->spare_bytes;
+               }
+
+               config_cw_read(nandc);
+
+               if (data_buf)
+                       read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
+                                     data_size);
+
+               /*
+                * when ecc is enabled, the controller doesn't read the real
+                * or dummy bad block markers in each chunk. To maintain a
+                * consistent layout across RAW and ECC reads, we just
+                * leave the real/dummy BBM offsets empty (i.e, filled with
+                * 0xffs)
+                */
+               if (oob_buf) {
+                       int j;
+
+                       for (j = 0; j < host->bbm_size; j++)
+                               *oob_buf++ = 0xff;
+
+                       read_data_dma(nandc, FLASH_BUF_ACC + data_size,
+                                     oob_buf, oob_size);
+               }
+
+               if (data_buf)
+                       data_buf += data_size;
+               if (oob_buf)
+                       oob_buf += oob_size;
+       }
+
+       ret = submit_descs(nandc);
+       if (ret)
+               dev_err(nandc->dev, "failure to read page/oob\n");
+
+       free_descs(nandc);
+
+       return ret;
+}
+
+/*
+ * a helper that copies the last step/codeword of a page (containing free oob)
+ * into our local buffer
+ */
+static int copy_last_cw(struct qcom_nand_host *host, int page)
+{
+       struct nand_chip *chip = &host->chip;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int size;
+       int ret;
+
+       clear_read_regs(nandc);
+
+       size = host->use_ecc ? host->cw_data : host->cw_size;
+
+       /* prepare a clean read buffer */
+       memset(nandc->data_buffer, 0xff, size);
+
+       set_address(host, host->cw_size * (ecc->steps - 1), page);
+       update_rw_regs(host, 1, true);
+
+       config_cw_read(nandc);
+
+       read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size);
+
+       ret = submit_descs(nandc);
+       if (ret)
+               dev_err(nandc->dev, "failed to copy last codeword\n");
+
+       free_descs(nandc);
+
+       return ret;
+}
+
+/* implements ecc->read_page() */
+static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                               uint8_t *buf, int oob_required, int page)
+{
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       u8 *data_buf, *oob_buf = NULL;
+       int ret;
+
+       data_buf = buf;
+       oob_buf = oob_required ? chip->oob_poi : NULL;
+
+       ret = read_page_ecc(host, data_buf, oob_buf);
+       if (ret) {
+               dev_err(nandc->dev, "failure to read page\n");
+               return ret;
+       }
+
+       return parse_read_errors(host, data_buf, oob_buf);
+}
+
+/* implements ecc->read_page_raw() */
+static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
+                                   struct nand_chip *chip, uint8_t *buf,
+                                   int oob_required, int page)
+{
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       u8 *data_buf, *oob_buf;
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int i, ret;
+
+       data_buf = buf;
+       oob_buf = chip->oob_poi;
+
+       host->use_ecc = false;
+       update_rw_regs(host, ecc->steps, true);
+
+       for (i = 0; i < ecc->steps; i++) {
+               int data_size1, data_size2, oob_size1, oob_size2;
+               int reg_off = FLASH_BUF_ACC;
+
+               data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
+               oob_size1 = host->bbm_size;
+
+               if (i == (ecc->steps - 1)) {
+                       data_size2 = ecc->size - data_size1 -
+                                    ((ecc->steps - 1) << 2);
+                       oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
+                                   host->spare_bytes;
+               } else {
+                       data_size2 = host->cw_data - data_size1;
+                       oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+               }
+
+               config_cw_read(nandc);
+
+               read_data_dma(nandc, reg_off, data_buf, data_size1);
+               reg_off += data_size1;
+               data_buf += data_size1;
+
+               read_data_dma(nandc, reg_off, oob_buf, oob_size1);
+               reg_off += oob_size1;
+               oob_buf += oob_size1;
+
+               read_data_dma(nandc, reg_off, data_buf, data_size2);
+               reg_off += data_size2;
+               data_buf += data_size2;
+
+               read_data_dma(nandc, reg_off, oob_buf, oob_size2);
+               oob_buf += oob_size2;
+       }
+
+       ret = submit_descs(nandc);
+       if (ret)
+               dev_err(nandc->dev, "failure to read raw page\n");
+
+       free_descs(nandc);
+
+       return 0;
+}
+
+/* implements ecc->read_oob() */
+static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                              int page)
+{
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int ret;
+
+       clear_read_regs(nandc);
+
+       host->use_ecc = true;
+       set_address(host, 0, page);
+       update_rw_regs(host, ecc->steps, true);
+
+       ret = read_page_ecc(host, NULL, chip->oob_poi);
+       if (ret)
+               dev_err(nandc->dev, "failure to read oob\n");
+
+       return ret;
+}
+
+/* implements ecc->write_page() */
+static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                                const uint8_t *buf, int oob_required, int page)
+{
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       u8 *data_buf, *oob_buf;
+       int i, ret;
+
+       clear_read_regs(nandc);
+
+       data_buf = (u8 *)buf;
+       oob_buf = chip->oob_poi;
+
+       host->use_ecc = true;
+       update_rw_regs(host, ecc->steps, false);
+
+       for (i = 0; i < ecc->steps; i++) {
+               int data_size, oob_size;
+
+               if (i == (ecc->steps - 1)) {
+                       data_size = ecc->size - ((ecc->steps - 1) << 2);
+                       oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
+                                  host->spare_bytes;
+               } else {
+                       data_size = host->cw_data;
+                       oob_size = ecc->bytes;
+               }
+
+               config_cw_write_pre(nandc);
+
+               write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size);
+
+               /*
+                * when ECC is enabled, we don't really need to write anything
+                * to oob for the first n - 1 codewords since these oob regions
+                * just contain ECC bytes that's written by the controller
+                * itself. For the last codeword, we skip the bbm positions and
+                * write to the free oob area.
+                */
+               if (i == (ecc->steps - 1)) {
+                       oob_buf += host->bbm_size;
+
+                       write_data_dma(nandc, FLASH_BUF_ACC + data_size,
+                                      oob_buf, oob_size);
+               }
+
+               config_cw_write_post(nandc);
+
+               data_buf += data_size;
+               oob_buf += oob_size;
+       }
+
+       ret = submit_descs(nandc);
+       if (ret)
+               dev_err(nandc->dev, "failure to write page\n");
+
+       free_descs(nandc);
+
+       return ret;
+}
+
+/* implements ecc->write_page_raw() */
+static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
+                                    struct nand_chip *chip, const uint8_t *buf,
+                                    int oob_required, int page)
+{
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       u8 *data_buf, *oob_buf;
+       int i, ret;
+
+       clear_read_regs(nandc);
+
+       data_buf = (u8 *)buf;
+       oob_buf = chip->oob_poi;
+
+       host->use_ecc = false;
+       update_rw_regs(host, ecc->steps, false);
+
+       for (i = 0; i < ecc->steps; i++) {
+               int data_size1, data_size2, oob_size1, oob_size2;
+               int reg_off = FLASH_BUF_ACC;
+
+               data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
+               oob_size1 = host->bbm_size;
+
+               if (i == (ecc->steps - 1)) {
+                       data_size2 = ecc->size - data_size1 -
+                                    ((ecc->steps - 1) << 2);
+                       oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
+                                   host->spare_bytes;
+               } else {
+                       data_size2 = host->cw_data - data_size1;
+                       oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+               }
+
+               config_cw_write_pre(nandc);
+
+               write_data_dma(nandc, reg_off, data_buf, data_size1);
+               reg_off += data_size1;
+               data_buf += data_size1;
+
+               write_data_dma(nandc, reg_off, oob_buf, oob_size1);
+               reg_off += oob_size1;
+               oob_buf += oob_size1;
+
+               write_data_dma(nandc, reg_off, data_buf, data_size2);
+               reg_off += data_size2;
+               data_buf += data_size2;
+
+               write_data_dma(nandc, reg_off, oob_buf, oob_size2);
+               oob_buf += oob_size2;
+
+               config_cw_write_post(nandc);
+       }
+
+       ret = submit_descs(nandc);
+       if (ret)
+               dev_err(nandc->dev, "failure to write raw page\n");
+
+       free_descs(nandc);
+
+       return ret;
+}
+
+/*
+ * implements ecc->write_oob()
+ *
+ * the NAND controller cannot write only data or only oob within a codeword,
+ * since ecc is calculated for the combined codeword. we first copy the
+ * entire contents for the last codeword(data + oob), replace the old oob
+ * with the new one in chip->oob_poi, and then write the entire codeword.
+ * this read-copy-write operation results in a slight performance loss.
+ */
+static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                               int page)
+{
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       u8 *oob = chip->oob_poi;
+       int free_boff;
+       int data_size, oob_size;
+       int ret, status = 0;
+
+       host->use_ecc = true;
+
+       ret = copy_last_cw(host, page);
+       if (ret)
+               return ret;
+
+       clear_read_regs(nandc);
+
+       /* calculate the data and oob size for the last codeword/step */
+       data_size = ecc->size - ((ecc->steps - 1) << 2);
+       oob_size = ecc->steps << 2;
+
+       free_boff = ecc->layout->oobfree[0].offset;
+
+       /* override new oob content to last codeword */
+       memcpy(nandc->data_buffer + data_size, oob + free_boff, oob_size);
+
+       set_address(host, host->cw_size * (ecc->steps - 1), page);
+       update_rw_regs(host, 1, false);
+
+       config_cw_write_pre(nandc);
+       write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
+                      data_size + oob_size);
+       config_cw_write_post(nandc);
+
+       ret = submit_descs(nandc);
+
+       free_descs(nandc);
+
+       if (ret) {
+               dev_err(nandc->dev, "failure to write oob\n");
+               return -EIO;
+       }
+
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+       status = chip->waitfunc(mtd, chip);
+
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int page, ret, bbpos, bad = 0;
+       u32 flash_status;
+
+       page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
+       /*
+        * configure registers for a raw sub page read, the address is set to
+        * the beginning of the last codeword, we don't care about reading ecc
+        * portion of oob. we just want the first few bytes from this codeword
+        * that contains the BBM
+        */
+       host->use_ecc = false;
+
+       ret = copy_last_cw(host, page);
+       if (ret)
+               goto err;
+
+       flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
+
+       if (flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
+               dev_warn(nandc->dev, "error when trying to read BBM\n");
+               goto err;
+       }
+
+       bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
+
+       bad = nandc->data_buffer[bbpos] != 0xff;
+
+       if (chip->options & NAND_BUSWIDTH_16)
+               bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
+err:
+       return bad;
+}
+
+static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int page, ret, status = 0;
+
+       clear_read_regs(nandc);
+
+       /*
+        * to mark the BBM as bad, we flash the entire last codeword with 0s.
+        * we don't care about the rest of the content in the codeword since
+        * we aren't going to use this block again
+        */
+       memset(nandc->data_buffer, 0x00, host->cw_size);
+
+       page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
+       /* prepare write */
+       host->use_ecc = false;
+       set_address(host, host->cw_size * (ecc->steps - 1), page);
+       update_rw_regs(host, 1, false);
+
+       config_cw_write_pre(nandc);
+       write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, host->cw_size);
+       config_cw_write_post(nandc);
+
+       ret = submit_descs(nandc);
+
+       free_descs(nandc);
+
+       if (ret) {
+               dev_err(nandc->dev, "failure to update BBM\n");
+               return -EIO;
+       }
+
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+       status = chip->waitfunc(mtd, chip);
+
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/*
+ * the three functions below implement chip->read_byte(), chip->read_buf()
+ * and chip->write_buf() respectively. these aren't used for
+ * reading/writing page data, they are used for smaller data like reading
+ * id, status etc
+ */
+static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct qcom_nand_host *host = to_qcom_nand_host(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       u8 *buf = nandc->data_buffer;
+       u8 ret = 0x0;
+
+       if (host->last_command == NAND_CMD_STATUS) {
+               ret = host->status;
+
+               host->status = NAND_STATUS_READY | NAND_STATUS_WP;
+
+               return ret;
+       }
+
+       if (nandc->buf_start < nandc->buf_count)
+               ret = buf[nandc->buf_start++];
+
+       return ret;
+}
+
+static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
+
+       memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
+       nandc->buf_start += real_len;
+}
+
+static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+                                int len)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
+
+       memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
+
+       nandc->buf_start += real_len;
+}
+
+/* we support only one external chip for now */
+static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+       if (chipnr <= 0)
+               return;
+
+       dev_warn(nandc->dev, "invalid chip select\n");
+}
+
+/*
+ * NAND controller page layout info
+ *
+ * Layout with ECC enabled:
+ *
+ * |----------------------|  |---------------------------------|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
+ * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |----------------------|  |---------------------------------|
+ *     codeword 1,2..n-1                  codeword n
+ *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Reserved byte(s)
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes
+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * When we access a page with ECC enabled, the reserved bytes(s) are not
+ * accessible at all. When reading, we fill up these unreadable positions
+ * with 0xffs. When writing, the controller skips writing the inaccessible
+ * bytes.
+ *
+ * Layout with ECC disabled:
+ *
+ * |------------------------------|  |---------------------------------------|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
+ * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |------------------------------|  |---------------------------------------|
+ *         codeword 1,2..n-1                        codeword n
+ *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Dummy Bad Bock byte(s)
+ * b = Real Bad Block byte(s)
+ * size1/size2 = function of codeword size and 'n'
+ *
+ * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
+ * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
+ * Block Markers. In the last codeword, this position contains the real BBM
+ *
+ * In order to have a consistent layout between RAW and ECC modes, we assume
+ * the following OOB layout arrangement:
+ *
+ * |-----------|  |--------------------|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx.......|  |bb*********xx.......|
+ * |-----------|  |--------------------|
+ *  first n - 1       nth OOB region
+ *  OOB regions
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = FREE OOB bytes
+ * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
+ * x = Unused byte(s)
+ * b = Real bad block byte(s) (inaccessible when ECC enabled)
+ *
+ * This layout is read as is when ECC is disabled. When ECC is enabled, the
+ * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
+ * and assumed as 0xffs when we read a page/oob. The ECC, unused and
+ * dummy/real bad block bytes are grouped as ecc bytes in nand_ecclayout (i.e,
+ * ecc->bytes is the sum of the three).
+ */
+
+static struct nand_ecclayout *
+qcom_nand_create_layout(struct qcom_nand_host *host)
+{
+       struct nand_chip *chip = &host->chip;
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       struct nand_ecclayout *layout;
+       int i, j, steps, pos = 0, shift = 0;
+
+       layout = devm_kzalloc(nandc->dev, sizeof(*layout), GFP_KERNEL);
+       if (!layout)
+               return NULL;
+
+       steps = mtd->writesize / ecc->size;
+       layout->eccbytes = steps * ecc->bytes;
+
+       layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
+       layout->oobfree[0].length = steps << 2;
+
+       /*
+        * the oob bytes in the first n - 1 codewords are all grouped together
+        * in the format:
+        * DUMMY_BBM + UNUSED + ECC
+        */
+       for (i = 0; i < steps - 1; i++) {
+               for (j = 0; j < ecc->bytes; j++)
+                       layout->eccpos[pos++] = i * ecc->bytes + j;
+       }
+
+       /*
+        * the oob bytes in the last codeword are grouped in the format:
+        * BBM + FREE OOB + UNUSED + ECC
+        */
+
+       /* fill up the bbm positions */
+       for (j = 0; j < host->bbm_size; j++)
+               layout->eccpos[pos++] = i * ecc->bytes + j;
+
+       /*
+        * fill up the ecc and reserved positions, their indices are offseted
+        * by the free oob region
+        */
+       shift = layout->oobfree[0].length + host->bbm_size;
+
+       for (j = 0; j < (host->ecc_bytes_hw + host->spare_bytes); j++)
+               layout->eccpos[pos++] = i * ecc->bytes + shift + j;
+
+       return layout;
+}
+
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+       struct nand_chip *chip = &host->chip;
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       int cwperpage, bad_block_byte;
+       bool wide_bus;
+       int ecc_mode = 1;
+
+       /*
+        * the controller requires each step consists of 512 bytes of data.
+        * bail out if DT has populated a wrong step size.
+        */
+       if (ecc->size != NANDC_STEP_SIZE) {
+               dev_err(nandc->dev, "invalid ecc size\n");
+               return -EINVAL;
+       }
+
+       wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+       if (ecc->strength >= 8) {
+               /* 8 bit ECC defaults to BCH ECC on all platforms */
+               host->bch_enabled = true;
+               ecc_mode = 1;
+
+               if (wide_bus) {
+                       host->ecc_bytes_hw = 14;
+                       host->spare_bytes = 0;
+                       host->bbm_size = 2;
+               } else {
+                       host->ecc_bytes_hw = 13;
+                       host->spare_bytes = 2;
+                       host->bbm_size = 1;
+               }
+       } else {
+               /*
+                * if the controller supports BCH for 4 bit ECC, the controller
+                * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+                * always 10 bytes
+                */
+               if (nandc->ecc_modes & ECC_BCH_4BIT) {
+                       /* BCH */
+                       host->bch_enabled = true;
+                       ecc_mode = 0;
+
+                       if (wide_bus) {
+                               host->ecc_bytes_hw = 8;
+                               host->spare_bytes = 2;
+                               host->bbm_size = 2;
+                       } else {
+                               host->ecc_bytes_hw = 7;
+                               host->spare_bytes = 4;
+                               host->bbm_size = 1;
+                       }
+               } else {
+                       /* RS */
+                       host->ecc_bytes_hw = 10;
+
+                       if (wide_bus) {
+                               host->spare_bytes = 0;
+                               host->bbm_size = 2;
+                       } else {
+                               host->spare_bytes = 1;
+                               host->bbm_size = 1;
+                       }
+               }
+       }
+
+       /*
+        * we consider ecc->bytes as the sum of all the non-data content in a
+        * step. It gives us a clean representation of the oob area (even if
+        * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
+        * ECC and 12 bytes for 4 bit ECC
+        */
+       ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
+
+       ecc->read_page          = qcom_nandc_read_page;
+       ecc->read_page_raw      = qcom_nandc_read_page_raw;
+       ecc->read_oob           = qcom_nandc_read_oob;
+       ecc->write_page         = qcom_nandc_write_page;
+       ecc->write_page_raw     = qcom_nandc_write_page_raw;
+       ecc->write_oob          = qcom_nandc_write_oob;
+
+       ecc->mode = NAND_ECC_HW;
+
+       ecc->layout = qcom_nand_create_layout(host);
+       if (!ecc->layout)
+               return -ENOMEM;
+
+       cwperpage = mtd->writesize / ecc->size;
+
+       /*
+        * DATA_UD_BYTES varies based on whether the read/write command protects
+        * spare data with ECC too. We protect spare data by default, so we set
+        * it to main + spare data, which are 512 and 4 bytes respectively.
+        */
+       host->cw_data = 516;
+
+       /*
+        * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
+        * for 8 bit ECC
+        */
+       host->cw_size = host->cw_data + ecc->bytes;
+
+       if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
+               dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
+               return -EINVAL;
+       }
+
+       bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
+
+       host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+                               | host->cw_data << UD_SIZE_BYTES
+                               | 0 << DISABLE_STATUS_AFTER_WRITE
+                               | 5 << NUM_ADDR_CYCLES
+                               | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
+                               | 0 << STATUS_BFR_READ
+                               | 1 << SET_RD_MODE_AFTER_STATUS
+                               | host->spare_bytes << SPARE_SIZE_BYTES;
+
+       host->cfg1 = 7 << NAND_RECOVERY_CYCLES
+                               | 0 <<  CS_ACTIVE_BSY
+                               | bad_block_byte << BAD_BLOCK_BYTE_NUM
+                               | 0 << BAD_BLOCK_IN_SPARE_AREA
+                               | 2 << WR_RD_BSY_GAP
+                               | wide_bus << WIDE_FLASH
+                               | host->bch_enabled << ENABLE_BCH_ECC;
+
+       host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+                               | host->cw_size << UD_SIZE_BYTES
+                               | 5 << NUM_ADDR_CYCLES
+                               | 0 << SPARE_SIZE_BYTES;
+
+       host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+                               | 0 << CS_ACTIVE_BSY
+                               | 17 << BAD_BLOCK_BYTE_NUM
+                               | 1 << BAD_BLOCK_IN_SPARE_AREA
+                               | 2 << WR_RD_BSY_GAP
+                               | wide_bus << WIDE_FLASH
+                               | 1 << DEV0_CFG1_ECC_DISABLE;
+
+       host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
+                               | 0 << ECC_SW_RESET
+                               | host->cw_data << ECC_NUM_DATA_BYTES
+                               | 1 << ECC_FORCE_CLK_OPEN
+                               | ecc_mode << ECC_MODE
+                               | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
+
+       host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+
+       host->clrflashstatus = FS_READY_BSY_N;
+       host->clrreadstatus = 0xc0;
+
+       dev_dbg(nandc->dev,
+               "cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
+               host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
+               host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
+               cwperpage);
+
+       return 0;
+}
+
+static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
+{
+       int ret;
+
+       ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(nandc->dev, "failed to set DMA mask\n");
+               return ret;
+       }
+
+       /*
+        * we use the internal buffer for reading ONFI params, reading small
+        * data like ID and status, and preforming read-copy-write operations
+        * when writing to a codeword partially. 532 is the maximum possible
+        * size of a codeword for our nand controller
+        */
+       nandc->buf_size = 532;
+
+       nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size,
+                                       GFP_KERNEL);
+       if (!nandc->data_buffer)
+               return -ENOMEM;
+
+       nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs),
+                                       GFP_KERNEL);
+       if (!nandc->regs)
+               return -ENOMEM;
+
+       nandc->reg_read_buf = devm_kzalloc(nandc->dev,
+                               MAX_REG_RD * sizeof(*nandc->reg_read_buf),
+                               GFP_KERNEL);
+       if (!nandc->reg_read_buf)
+               return -ENOMEM;
+
+       nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
+       if (!nandc->chan) {
+               dev_err(nandc->dev, "failed to request slave channel\n");
+               return -ENODEV;
+       }
+
+       INIT_LIST_HEAD(&nandc->desc_list);
+       INIT_LIST_HEAD(&nandc->host_list);
+
+       spin_lock_init(&nandc->controller.lock);
+       init_waitqueue_head(&nandc->controller.wq);
+
+       return 0;
+}
+
+static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
+{
+       dma_release_channel(nandc->chan);
+}
+
+/* one time setup of a few nand controller registers */
+static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
+{
+       /* kill onenand */
+       nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+
+       /* enable ADM DMA */
+       nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
+
+       /* save the original values of these registers */
+       nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1);
+       nandc->vld = nandc_read(nandc, NAND_DEV_CMD_VLD);
+
+       return 0;
+}
+
+static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
+                              struct qcom_nand_host *host,
+                              struct device_node *dn)
+{
+       struct nand_chip *chip = &host->chip;
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct device *dev = nandc->dev;
+       int ret;
+
+       ret = of_property_read_u32(dn, "reg", &host->cs);
+       if (ret) {
+               dev_err(dev, "can't get chip-select\n");
+               return -ENXIO;
+       }
+
+       nand_set_flash_node(chip, dn);
+       mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
+       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = dev;
+
+       chip->cmdfunc           = qcom_nandc_command;
+       chip->select_chip       = qcom_nandc_select_chip;
+       chip->read_byte         = qcom_nandc_read_byte;
+       chip->read_buf          = qcom_nandc_read_buf;
+       chip->write_buf         = qcom_nandc_write_buf;
+
+       /*
+        * the bad block marker is readable only when we read the last codeword
+        * of a page with ECC disabled. currently, the nand_base and nand_bbt
+        * helpers don't allow us to read BB from a nand chip with ECC
+        * disabled (MTD_OPS_PLACE_OOB is set by default). use the block_bad
+        * and block_markbad helpers until we permanently switch to using
+        * MTD_OPS_RAW for all drivers (with the help of badblockbits)
+        */
+       chip->block_bad         = qcom_nandc_block_bad;
+       chip->block_markbad     = qcom_nandc_block_markbad;
+
+       chip->controller = &nandc->controller;
+       chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
+                        NAND_SKIP_BBTSCAN;
+
+       /* set up initial status value */
+       host->status = NAND_STATUS_READY | NAND_STATUS_WP;
+
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret)
+               return ret;
+
+       ret = qcom_nand_host_setup(host);
+       if (ret)
+               return ret;
+
+       ret = nand_scan_tail(mtd);
+       if (ret)
+               return ret;
+
+       return mtd_device_register(mtd, NULL, 0);
+}
+
+/* parse custom DT properties here */
+static int qcom_nandc_parse_dt(struct platform_device *pdev)
+{
+       struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
+       struct device_node *np = nandc->dev->of_node;
+       int ret;
+
+       ret = of_property_read_u32(np, "qcom,cmd-crci", &nandc->cmd_crci);
+       if (ret) {
+               dev_err(nandc->dev, "command CRCI unspecified\n");
+               return ret;
+       }
+
+       ret = of_property_read_u32(np, "qcom,data-crci", &nandc->data_crci);
+       if (ret) {
+               dev_err(nandc->dev, "data CRCI unspecified\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int qcom_nandc_probe(struct platform_device *pdev)
+{
+       struct qcom_nand_controller *nandc;
+       struct qcom_nand_host *host;
+       const void *dev_data;
+       struct device *dev = &pdev->dev;
+       struct device_node *dn = dev->of_node, *child;
+       struct resource *res;
+       int ret;
+
+       nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
+       if (!nandc)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, nandc);
+       nandc->dev = dev;
+
+       dev_data = of_device_get_match_data(dev);
+       if (!dev_data) {
+               dev_err(&pdev->dev, "failed to get device data\n");
+               return -ENODEV;
+       }
+
+       nandc->ecc_modes = (unsigned long)dev_data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       nandc->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(nandc->base))
+               return PTR_ERR(nandc->base);
+
+       nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
+
+       nandc->core_clk = devm_clk_get(dev, "core");
+       if (IS_ERR(nandc->core_clk))
+               return PTR_ERR(nandc->core_clk);
+
+       nandc->aon_clk = devm_clk_get(dev, "aon");
+       if (IS_ERR(nandc->aon_clk))
+               return PTR_ERR(nandc->aon_clk);
+
+       ret = qcom_nandc_parse_dt(pdev);
+       if (ret)
+               return ret;
+
+       ret = qcom_nandc_alloc(nandc);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(nandc->core_clk);
+       if (ret)
+               goto err_core_clk;
+
+       ret = clk_prepare_enable(nandc->aon_clk);
+       if (ret)
+               goto err_aon_clk;
+
+       ret = qcom_nandc_setup(nandc);
+       if (ret)
+               goto err_setup;
+
+       for_each_available_child_of_node(dn, child) {
+               if (of_device_is_compatible(child, "qcom,nandcs")) {
+                       host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+                       if (!host) {
+                               of_node_put(child);
+                               ret = -ENOMEM;
+                               goto err_cs_init;
+                       }
+
+                       ret = qcom_nand_host_init(nandc, host, child);
+                       if (ret) {
+                               devm_kfree(dev, host);
+                               continue;
+                       }
+
+                       list_add_tail(&host->node, &nandc->host_list);
+               }
+       }
+
+       if (list_empty(&nandc->host_list)) {
+               ret = -ENODEV;
+               goto err_cs_init;
+       }
+
+       return 0;
+
+err_cs_init:
+       list_for_each_entry(host, &nandc->host_list, node)
+               nand_release(nand_to_mtd(&host->chip));
+err_setup:
+       clk_disable_unprepare(nandc->aon_clk);
+err_aon_clk:
+       clk_disable_unprepare(nandc->core_clk);
+err_core_clk:
+       qcom_nandc_unalloc(nandc);
+
+       return ret;
+}
+
+static int qcom_nandc_remove(struct platform_device *pdev)
+{
+       struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
+       struct qcom_nand_host *host;
+
+       list_for_each_entry(host, &nandc->host_list, node)
+               nand_release(nand_to_mtd(&host->chip));
+
+       qcom_nandc_unalloc(nandc);
+
+       clk_disable_unprepare(nandc->aon_clk);
+       clk_disable_unprepare(nandc->core_clk);
+
+       return 0;
+}
+
+#define EBI2_NANDC_ECC_MODES   (ECC_RS_4BIT | ECC_BCH_8BIT)
+
+/*
+ * data will hold a struct pointer containing more differences once we support
+ * more controller variants
+ */
+static const struct of_device_id qcom_nandc_of_match[] = {
+       {       .compatible = "qcom,ipq806x-nand",
+               .data = (void *)EBI2_NANDC_ECC_MODES,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
+
+static struct platform_driver qcom_nandc_driver = {
+       .driver = {
+               .name = "qcom-nandc",
+               .of_match_table = qcom_nandc_of_match,
+       },
+       .probe   = qcom_nandc_probe,
+       .remove  = qcom_nandc_remove,
+};
+module_platform_driver(qcom_nandc_driver);
+
+MODULE_AUTHOR("Archit Taneja <architt@codeaurora.org>");
+MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
+MODULE_LICENSE("GPL v2");
index 01ac74f..9c9397b 100644 (file)
@@ -861,9 +861,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        chip->ecc.mode      = NAND_ECC_SOFT;
 #endif
 
-       if (set->ecc_layout != NULL)
-               chip->ecc.layout = set->ecc_layout;
-
        if (set->disable_ecc)
                chip->ecc.mode  = NAND_ECC_NONE;
 
index 51e10a3..1c03eee 100644 (file)
@@ -60,6 +60,7 @@
 #define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3)
 #define NFC_REG_USER_DATA(x)   (0x0050 + ((x) * 4))
 #define NFC_REG_SPARE_AREA     0x00A0
+#define NFC_REG_PAT_ID         0x00A4
 #define NFC_RAM0_BASE          0x0400
 #define NFC_RAM1_BASE          0x0800
 
@@ -538,6 +539,174 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
        sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
 }
 
+/* These seed values have been extracted from Allwinner's BSP */
+static const u16 sunxi_nfc_randomizer_page_seeds[] = {
+       0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
+       0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
+       0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
+       0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
+       0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
+       0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
+       0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
+       0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
+       0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
+       0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
+       0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
+       0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
+       0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
+       0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
+       0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
+       0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
+};
+
+/*
+ * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
+ * have been generated using
+ * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
+ * the randomizer engine does internally before de/scrambling OOB data.
+ *
+ * Those tables are statically defined to avoid calculating randomizer state
+ * at runtime.
+ */
+static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
+       0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
+       0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
+       0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
+       0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
+       0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
+       0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
+       0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
+       0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
+       0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
+       0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
+       0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
+       0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
+       0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
+       0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
+       0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
+       0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
+};
+
+static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
+       0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
+       0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
+       0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
+       0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
+       0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
+       0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
+       0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
+       0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
+       0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
+       0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
+       0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
+       0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
+       0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
+       0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
+       0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
+       0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
+};
+
+static u16 sunxi_nfc_randomizer_step(u16 state, int count)
+{
+       state &= 0x7fff;
+
+       /*
+        * This loop is just a simple implementation of a Fibonacci LFSR using
+        * the x16 + x15 + 1 polynomial.
+        */
+       while (count--)
+               state = ((state >> 1) |
+                        (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
+
+       return state;
+}
+
+static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
+{
+       const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
+       int mod = mtd_div_by_ws(mtd->erasesize, mtd);
+
+       if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
+               mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
+
+       if (ecc) {
+               if (mtd->ecc_step_size == 512)
+                       seeds = sunxi_nfc_randomizer_ecc512_seeds;
+               else
+                       seeds = sunxi_nfc_randomizer_ecc1024_seeds;
+       }
+
+       return seeds[page % mod];
+}
+
+static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
+                                       int page, bool ecc)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+       u16 state;
+
+       if (!(nand->options & NAND_NEED_SCRAMBLING))
+               return;
+
+       ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+       state = sunxi_nfc_randomizer_state(mtd, page, ecc);
+       ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
+       writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+       if (!(nand->options & NAND_NEED_SCRAMBLING))
+               return;
+
+       writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
+              nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+       if (!(nand->options & NAND_NEED_SCRAMBLING))
+               return;
+
+       writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+              nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
+{
+       u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
+
+       bbm[0] ^= state;
+       bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
+}
+
+static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
+                                          const uint8_t *buf, int len,
+                                          bool ecc, int page)
+{
+       sunxi_nfc_randomizer_config(mtd, page, ecc);
+       sunxi_nfc_randomizer_enable(mtd);
+       sunxi_nfc_write_buf(mtd, buf, len);
+       sunxi_nfc_randomizer_disable(mtd);
+}
+
+static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
+                                         int len, bool ecc, int page)
+{
+       sunxi_nfc_randomizer_config(mtd, page, ecc);
+       sunxi_nfc_randomizer_enable(mtd);
+       sunxi_nfc_read_buf(mtd, buf, len);
+       sunxi_nfc_randomizer_disable(mtd);
+}
+
 static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
@@ -574,18 +743,20 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
                                       u8 *data, int data_off,
                                       u8 *oob, int oob_off,
                                       int *cur_off,
-                                      unsigned int *max_bitflips)
+                                      unsigned int *max_bitflips,
+                                      bool bbm, int page)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
+       int raw_mode = 0;
        u32 status;
        int ret;
 
        if (*cur_off != data_off)
                nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
 
-       sunxi_nfc_read_buf(mtd, NULL, ecc->size);
+       sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
 
        if (data_off + ecc->size != oob_off)
                nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
@@ -594,25 +765,54 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
        if (ret)
                return ret;
 
+       sunxi_nfc_randomizer_enable(mtd);
        writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
               nfc->regs + NFC_REG_CMD);
 
        ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+       sunxi_nfc_randomizer_disable(mtd);
        if (ret)
                return ret;
 
+       *cur_off = oob_off + ecc->bytes + 4;
+
        status = readl(nfc->regs + NFC_REG_ECC_ST);
+       if (status & NFC_ECC_PAT_FOUND(0)) {
+               u8 pattern = 0xff;
+
+               if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1)))
+                       pattern = 0x0;
+
+               memset(data, pattern, ecc->size);
+               memset(oob, pattern, ecc->bytes + 4);
+
+               return 1;
+       }
+
        ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0)));
 
        memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
 
        nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
-       sunxi_nfc_read_buf(mtd, oob, ecc->bytes + 4);
+       sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page);
 
        if (status & NFC_ECC_ERR(0)) {
+               /*
+                * Re-read the data with the randomizer disabled to identify
+                * bitflips in erased pages.
+                */
+               if (nand->options & NAND_NEED_SCRAMBLING) {
+                       nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
+                       nand->read_buf(mtd, data, ecc->size);
+                       nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+                       nand->read_buf(mtd, oob, ecc->bytes + 4);
+               }
+
                ret = nand_check_erased_ecc_chunk(data, ecc->size,
                                                  oob, ecc->bytes + 4,
                                                  NULL, 0, ecc->strength);
+               if (ret >= 0)
+                       raw_mode = 1;
        } else {
                /*
                 * The engine protects 4 bytes of OOB data per chunk.
@@ -620,6 +820,10 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
                 */
                sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(0)),
                                           oob);
+
+               /* De-randomize the Bad Block Marker. */
+               if (bbm && nand->options & NAND_NEED_SCRAMBLING)
+                       sunxi_nfc_randomize_bbm(mtd, page, oob);
        }
 
        if (ret < 0) {
@@ -629,13 +833,12 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
                *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
        }
 
-       *cur_off = oob_off + ecc->bytes + 4;
-
-       return 0;
+       return raw_mode;
 }
 
 static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
-                                           u8 *oob, int *cur_off)
+                                           u8 *oob, int *cur_off,
+                                           bool randomize, int page)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
@@ -649,7 +852,11 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
                nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
                              offset + mtd->writesize, -1);
 
-       sunxi_nfc_read_buf(mtd, oob + offset, len);
+       if (!randomize)
+               sunxi_nfc_read_buf(mtd, oob + offset, len);
+       else
+               sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
+                                             false, page);
 
        *cur_off = mtd->oobsize + mtd->writesize;
 }
@@ -662,7 +869,8 @@ static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
 static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
                                        const u8 *data, int data_off,
                                        const u8 *oob, int oob_off,
-                                       int *cur_off)
+                                       int *cur_off, bool bbm,
+                                       int page)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
@@ -672,11 +880,20 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
        if (data_off != *cur_off)
                nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1);
 
-       sunxi_nfc_write_buf(mtd, data, ecc->size);
+       sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
 
        /* Fill OOB data in */
-       writel(sunxi_nfc_buf_to_user_data(oob),
-              nfc->regs + NFC_REG_USER_DATA(0));
+       if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) {
+               u8 user_data[4];
+
+               memcpy(user_data, oob, 4);
+               sunxi_nfc_randomize_bbm(mtd, page, user_data);
+               writel(sunxi_nfc_buf_to_user_data(user_data),
+                      nfc->regs + NFC_REG_USER_DATA(0));
+       } else {
+               writel(sunxi_nfc_buf_to_user_data(oob),
+                      nfc->regs + NFC_REG_USER_DATA(0));
+       }
 
        if (data_off + ecc->size != oob_off)
                nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1);
@@ -685,11 +902,13 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
        if (ret)
                return ret;
 
+       sunxi_nfc_randomizer_enable(mtd);
        writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
               NFC_ACCESS_DIR | NFC_ECC_OP,
               nfc->regs + NFC_REG_CMD);
 
        ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+       sunxi_nfc_randomizer_disable(mtd);
        if (ret)
                return ret;
 
@@ -699,7 +918,8 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
 }
 
 static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
-                                            u8 *oob, int *cur_off)
+                                            u8 *oob, int *cur_off,
+                                            int page)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
@@ -713,7 +933,7 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
                nand->cmdfunc(mtd, NAND_CMD_RNDIN,
                              offset + mtd->writesize, -1);
 
-       sunxi_nfc_write_buf(mtd, oob + offset, len);
+       sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
 
        *cur_off = mtd->oobsize + mtd->writesize;
 }
@@ -725,6 +945,7 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        unsigned int max_bitflips = 0;
        int ret, i, cur_off = 0;
+       bool raw_mode = false;
 
        sunxi_nfc_hw_ecc_enable(mtd);
 
@@ -736,13 +957,17 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
 
                ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
                                                  oob_off + mtd->writesize,
-                                                 &cur_off, &max_bitflips);
-               if (ret)
+                                                 &cur_off, &max_bitflips,
+                                                 !i, page);
+               if (ret < 0)
                        return ret;
+               else if (ret)
+                       raw_mode = true;
        }
 
        if (oob_required)
-               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off);
+               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+                                               !raw_mode, page);
 
        sunxi_nfc_hw_ecc_disable(mtd);
 
@@ -767,13 +992,14 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
 
                ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
                                                   oob_off + mtd->writesize,
-                                                  &cur_off);
+                                                  &cur_off, !i, page);
                if (ret)
                        return ret;
        }
 
-       if (oob_required)
-               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off);
+       if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+                                                &cur_off, page);
 
        sunxi_nfc_hw_ecc_disable(mtd);
 
@@ -788,6 +1014,7 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        unsigned int max_bitflips = 0;
        int ret, i, cur_off = 0;
+       bool raw_mode = false;
 
        sunxi_nfc_hw_ecc_enable(mtd);
 
@@ -799,13 +1026,16 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
 
                ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
                                                  oob_off, &cur_off,
-                                                 &max_bitflips);
-               if (ret)
+                                                 &max_bitflips, !i, page);
+               if (ret < 0)
                        return ret;
+               else if (ret)
+                       raw_mode = true;
        }
 
        if (oob_required)
-               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off);
+               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+                                               !raw_mode, page);
 
        sunxi_nfc_hw_ecc_disable(mtd);
 
@@ -829,13 +1059,15 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
                const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
 
                ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
-                                                  oob, oob_off, &cur_off);
+                                                  oob, oob_off, &cur_off,
+                                                  false, page);
                if (ret)
                        return ret;
        }
 
-       if (oob_required)
-               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off);
+       if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+                                                &cur_off, page);
 
        sunxi_nfc_hw_ecc_disable(mtd);
 
@@ -1345,6 +1577,9 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
        if (nand->bbt_options & NAND_BBT_USE_FLASH)
                nand->bbt_options |= NAND_BBT_NO_OOB;
 
+       if (nand->options & NAND_NEED_SCRAMBLING)
+               nand->options |= NAND_NO_SUBPAGE_WRITE;
+
        ret = sunxi_nand_chip_init_timings(chip, np);
        if (ret) {
                dev_err(dev, "could not configure chip timings: %d\n", ret);
index 034420f..293feb1 100644 (file)
@@ -795,8 +795,6 @@ static int vf610_nfc_probe(struct platform_device *pdev)
                        goto error;
                }
 
-               /* propagate ecc.layout to mtd_info */
-               mtd->ecclayout = chip->ecc.layout;
                chip->ecc.read_page = vf610_nfc_read_page;
                chip->ecc.write_page = vf610_nfc_write_page;
 
index 43b3392..af28bb3 100644 (file)
@@ -1124,11 +1124,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
        pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
                        (int)len);
 
-       if (ops->mode == MTD_OPS_AUTO_OOB)
-               oobsize = this->ecclayout->oobavail;
-       else
-               oobsize = mtd->oobsize;
-
+       oobsize = mtd_oobavail(mtd, ops);
        oobcolumn = from & (mtd->oobsize - 1);
 
        /* Do not allow reads past end of device */
@@ -1229,11 +1225,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
        pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
                        (int)len);
 
-       if (ops->mode == MTD_OPS_AUTO_OOB)
-               oobsize = this->ecclayout->oobavail;
-       else
-               oobsize = mtd->oobsize;
-
+       oobsize = mtd_oobavail(mtd, ops);
        oobcolumn = from & (mtd->oobsize - 1);
 
        /* Do not allow reads past end of device */
@@ -1365,7 +1357,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
        ops->oobretlen = 0;
 
        if (mode == MTD_OPS_AUTO_OOB)
-               oobsize = this->ecclayout->oobavail;
+               oobsize = mtd->oobavail;
        else
                oobsize = mtd->oobsize;
 
@@ -1885,12 +1877,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
        /* Check zero length */
        if (!len)
                return 0;
-
-       if (ops->mode == MTD_OPS_AUTO_OOB)
-               oobsize = this->ecclayout->oobavail;
-       else
-               oobsize = mtd->oobsize;
-
+       oobsize = mtd_oobavail(mtd, ops);
        oobcolumn = to & (mtd->oobsize - 1);
 
        column = to & (mtd->writesize - 1);
@@ -2063,7 +2050,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
        ops->oobretlen = 0;
 
        if (mode == MTD_OPS_AUTO_OOB)
-               oobsize = this->ecclayout->oobavail;
+               oobsize = mtd->oobavail;
        else
                oobsize = mtd->oobsize;
 
@@ -2599,6 +2586,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
  */
 static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
+       struct onenand_chip *this = mtd->priv;
        int ret;
 
        ret = onenand_block_isbad(mtd, ofs);
@@ -2610,7 +2598,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
        }
 
        onenand_get_device(mtd, FL_WRITING);
-       ret = mtd_block_markbad(mtd, ofs);
+       ret = this->block_markbad(mtd, ofs);
        onenand_release_device(mtd);
        return ret;
 }
@@ -4049,12 +4037,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
         * The number of bytes available for a client to place data into
         * the out of band area
         */
-       this->ecclayout->oobavail = 0;
+       mtd->oobavail = 0;
        for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
            this->ecclayout->oobfree[i].length; i++)
-               this->ecclayout->oobavail +=
-                       this->ecclayout->oobfree[i].length;
-       mtd->oobavail = this->ecclayout->oobavail;
+               mtd->oobavail += this->ecclayout->oobfree[i].length;
 
        mtd->ecclayout = this->ecclayout;
        mtd->ecc_strength = 1;
index 08d0085..680188a 100644 (file)
@@ -179,7 +179,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
  * by the onenand_release function.
  *
  */
-int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
        struct onenand_chip *this = mtd->priv;
        struct bbm_info *bbm = this->bbm;
@@ -247,6 +247,3 @@ int onenand_default_bbt(struct mtd_info *mtd)
 
        return onenand_scan_bbt(mtd, bbm->badblock_pattern);
 }
-
-EXPORT_SYMBOL(onenand_scan_bbt);
-EXPORT_SYMBOL(onenand_default_bbt);
index 0dc9275..d42c98e 100644 (file)
@@ -9,6 +9,7 @@ if MTD_SPI_NOR
 
 config MTD_MT81xx_NOR
        tristate "Mediatek MT81xx SPI NOR flash controller"
+       depends on HAS_IOMEM
        help
          This enables access to SPI NOR flash, using MT81xx SPI NOR flash
          controller. This controller does not support generic SPI BUS, it only
@@ -30,7 +31,7 @@ config MTD_SPI_NOR_USE_4K_SECTORS
 
 config SPI_FSL_QUADSPI
        tristate "Freescale Quad SPI controller"
-       depends on ARCH_MXC || COMPILE_TEST
+       depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
        depends on HAS_IOMEM
        help
          This enables support for the Quad SPI controller in master mode.
index 54640f1..9ab2b51 100644 (file)
@@ -213,6 +213,7 @@ enum fsl_qspi_devtype {
        FSL_QUADSPI_IMX6SX,
        FSL_QUADSPI_IMX7D,
        FSL_QUADSPI_IMX6UL,
+       FSL_QUADSPI_LS1021A,
 };
 
 struct fsl_qspi_devtype_data {
@@ -258,6 +259,14 @@ static struct fsl_qspi_devtype_data imx6ul_data = {
                       | QUADSPI_QUIRK_4X_INT_CLK,
 };
 
+static struct fsl_qspi_devtype_data ls1021a_data = {
+       .devtype = FSL_QUADSPI_LS1021A,
+       .rxfifo = 128,
+       .txfifo = 64,
+       .ahb_buf_size = 1024,
+       .driver_data = 0,
+};
+
 #define FSL_QSPI_MAX_CHIP      4
 struct fsl_qspi {
        struct spi_nor nor[FSL_QSPI_MAX_CHIP];
@@ -275,6 +284,7 @@ struct fsl_qspi {
        u32 clk_rate;
        unsigned int chip_base_addr; /* We may support two chips. */
        bool has_second_chip;
+       bool big_endian;
        struct mutex lock;
        struct pm_qos_request pm_qos_req;
 };
@@ -299,6 +309,28 @@ static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
        return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
 }
 
+/*
+ * R/W functions for big- or little-endian registers:
+ * The qSPI controller's endian is independent of the CPU core's endian.
+ * So far, although the CPU core is little-endian but the qSPI have two
+ * versions for big-endian and little-endian.
+ */
+static void qspi_writel(struct fsl_qspi *q, u32 val, void __iomem *addr)
+{
+       if (q->big_endian)
+               iowrite32be(val, addr);
+       else
+               iowrite32(val, addr);
+}
+
+static u32 qspi_readl(struct fsl_qspi *q, void __iomem *addr)
+{
+       if (q->big_endian)
+               return ioread32be(addr);
+       else
+               return ioread32(addr);
+}
+
 /*
  * An IC bug makes us to re-arrange the 32-bit data.
  * The following chips, such as IMX6SLX, have fixed this bug.
@@ -310,14 +342,14 @@ static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a)
 
 static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q)
 {
-       writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
-       writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
+       qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+       qspi_writel(q, QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
 }
 
 static inline void fsl_qspi_lock_lut(struct fsl_qspi *q)
 {
-       writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
-       writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
+       qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+       qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
 }
 
 static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id)
@@ -326,8 +358,8 @@ static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id)
        u32 reg;
 
        /* clear interrupt */
-       reg = readl(q->iobase + QUADSPI_FR);
-       writel(reg, q->iobase + QUADSPI_FR);
+       reg = qspi_readl(q, q->iobase + QUADSPI_FR);
+       qspi_writel(q, reg, q->iobase + QUADSPI_FR);
 
        if (reg & QUADSPI_FR_TFF_MASK)
                complete(&q->c);
@@ -348,7 +380,7 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
 
        /* Clear all the LUT table */
        for (i = 0; i < QUADSPI_LUT_NUM; i++)
-               writel(0, base + QUADSPI_LUT_BASE + i * 4);
+               qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
 
        /* Quad Read */
        lut_base = SEQID_QUAD_READ * 4;
@@ -364,14 +396,15 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
                dummy = 8;
        }
 
-       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+       qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
                        base + QUADSPI_LUT(lut_base));
-       writel(LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
+       qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
                        base + QUADSPI_LUT(lut_base + 1));
 
        /* Write enable */
        lut_base = SEQID_WREN * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_WREN), base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN),
+                       base + QUADSPI_LUT(lut_base));
 
        /* Page Program */
        lut_base = SEQID_PP * 4;
@@ -385,13 +418,15 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
                addrlen = ADDR32BIT;
        }
 
-       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+       qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
                        base + QUADSPI_LUT(lut_base));
-       writel(LUT0(FSL_WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
+       qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
+                       base + QUADSPI_LUT(lut_base + 1));
 
        /* Read Status */
        lut_base = SEQID_RDSR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(FSL_READ, PAD1, 0x1),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDSR) |
+                       LUT1(FSL_READ, PAD1, 0x1),
                        base + QUADSPI_LUT(lut_base));
 
        /* Erase a sector */
@@ -400,40 +435,46 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
        cmd = q->nor[0].erase_opcode;
        addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
 
-       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+       qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
                        base + QUADSPI_LUT(lut_base));
 
        /* Erase the whole chip */
        lut_base = SEQID_CHIP_ERASE * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
                        base + QUADSPI_LUT(lut_base));
 
        /* READ ID */
        lut_base = SEQID_RDID * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(FSL_READ, PAD1, 0x8),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDID) |
+                       LUT1(FSL_READ, PAD1, 0x8),
                        base + QUADSPI_LUT(lut_base));
 
        /* Write Register */
        lut_base = SEQID_WRSR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(FSL_WRITE, PAD1, 0x2),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRSR) |
+                       LUT1(FSL_WRITE, PAD1, 0x2),
                        base + QUADSPI_LUT(lut_base));
 
        /* Read Configuration Register */
        lut_base = SEQID_RDCR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(FSL_READ, PAD1, 0x1),
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDCR) |
+                       LUT1(FSL_READ, PAD1, 0x1),
                        base + QUADSPI_LUT(lut_base));
 
        /* Write disable */
        lut_base = SEQID_WRDI * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_WRDI), base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRDI),
+                       base + QUADSPI_LUT(lut_base));
 
        /* Enter 4 Byte Mode (Micron) */
        lut_base = SEQID_EN4B * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_EN4B), base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_EN4B),
+                       base + QUADSPI_LUT(lut_base));
 
        /* Enter 4 Byte Mode (Spansion) */
        lut_base = SEQID_BRWR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_BRWR), base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
+                       base + QUADSPI_LUT(lut_base));
 
        fsl_qspi_lock_lut(q);
 }
@@ -488,15 +529,16 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
                        q->chip_base_addr, addr, len, cmd);
 
        /* save the reg */
-       reg = readl(base + QUADSPI_MCR);
+       reg = qspi_readl(q, base + QUADSPI_MCR);
 
-       writel(q->memmap_phy + q->chip_base_addr + addr, base + QUADSPI_SFAR);
-       writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
+       qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
+                       base + QUADSPI_SFAR);
+       qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
                        base + QUADSPI_RBCT);
-       writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
+       qspi_writel(q, reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
 
        do {
-               reg2 = readl(base + QUADSPI_SR);
+               reg2 = qspi_readl(q, base + QUADSPI_SR);
                if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) {
                        udelay(1);
                        dev_dbg(q->dev, "The controller is busy, 0x%x\n", reg2);
@@ -507,21 +549,22 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
 
        /* trigger the LUT now */
        seqid = fsl_qspi_get_seqid(q, cmd);
-       writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);
+       qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len,
+                       base + QUADSPI_IPCR);
 
        /* Wait for the interrupt. */
        if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) {
                dev_err(q->dev,
                        "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n",
-                       cmd, addr, readl(base + QUADSPI_FR),
-                       readl(base + QUADSPI_SR));
+                       cmd, addr, qspi_readl(q, base + QUADSPI_FR),
+                       qspi_readl(q, base + QUADSPI_SR));
                err = -ETIMEDOUT;
        } else {
                err = 0;
        }
 
        /* restore the MCR */
-       writel(reg, base + QUADSPI_MCR);
+       qspi_writel(q, reg, base + QUADSPI_MCR);
 
        return err;
 }
@@ -533,7 +576,7 @@ static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf)
        int i = 0;
 
        while (len > 0) {
-               tmp = readl(q->iobase + QUADSPI_RBDR + i * 4);
+               tmp = qspi_readl(q, q->iobase + QUADSPI_RBDR + i * 4);
                tmp = fsl_qspi_endian_xchg(q, tmp);
                dev_dbg(q->dev, "chip addr:0x%.8x, rcv:0x%.8x\n",
                                q->chip_base_addr, tmp);
@@ -561,9 +604,9 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q)
 {
        u32 reg;
 
-       reg = readl(q->iobase + QUADSPI_MCR);
+       reg = qspi_readl(q, q->iobase + QUADSPI_MCR);
        reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK;
-       writel(reg, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
 
        /*
         * The minimum delay : 1 AHB + 2 SFCK clocks.
@@ -572,7 +615,7 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q)
        udelay(1);
 
        reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK);
-       writel(reg, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
 }
 
 static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
@@ -586,20 +629,20 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
                q->chip_base_addr, to, count);
 
        /* clear the TX FIFO. */
-       tmp = readl(q->iobase + QUADSPI_MCR);
-       writel(tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
+       tmp = qspi_readl(q, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
 
        /* fill the TX data to the FIFO */
        for (j = 0, i = ((count + 3) / 4); j < i; j++) {
                tmp = fsl_qspi_endian_xchg(q, *txbuf);
-               writel(tmp, q->iobase + QUADSPI_TBDR);
+               qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR);
                txbuf++;
        }
 
        /* fill the TXFIFO upto 16 bytes for i.MX7d */
        if (needs_fill_txfifo(q))
                for (; i < 4; i++)
-                       writel(tmp, q->iobase + QUADSPI_TBDR);
+                       qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR);
 
        /* Trigger it */
        ret = fsl_qspi_runcmd(q, opcode, to, count);
@@ -615,10 +658,10 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
        int nor_size = q->nor_size;
        void __iomem *base = q->iobase;
 
-       writel(nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
-       writel(nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
-       writel(nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
-       writel(nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
+       qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
+       qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
+       qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
+       qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
 }
 
 /*
@@ -640,24 +683,26 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
        int seqid;
 
        /* AHB configuration for access buffer 0/1/2 .*/
-       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
-       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
-       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
        /*
         * Set ADATSZ with the maximum AHB buffer size to improve the
         * read performance.
         */
-       writel(QUADSPI_BUF3CR_ALLMST_MASK | ((q->devtype_data->ahb_buf_size / 8)
-                       << QUADSPI_BUF3CR_ADATSZ_SHIFT), base + QUADSPI_BUF3CR);
+       qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
+                       ((q->devtype_data->ahb_buf_size / 8)
+                       << QUADSPI_BUF3CR_ADATSZ_SHIFT),
+                       base + QUADSPI_BUF3CR);
 
        /* We only use the buffer3 */
-       writel(0, base + QUADSPI_BUF0IND);
-       writel(0, base + QUADSPI_BUF1IND);
-       writel(0, base + QUADSPI_BUF2IND);
+       qspi_writel(q, 0, base + QUADSPI_BUF0IND);
+       qspi_writel(q, 0, base + QUADSPI_BUF1IND);
+       qspi_writel(q, 0, base + QUADSPI_BUF2IND);
 
        /* Set the default lut sequence for AHB Read. */
        seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
-       writel(seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
+       qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
                q->iobase + QUADSPI_BFGENCR);
 }
 
@@ -713,7 +758,7 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
                return ret;
 
        /* Reset the module */
-       writel(QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
+       qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
                base + QUADSPI_MCR);
        udelay(1);
 
@@ -721,24 +766,24 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
        fsl_qspi_init_lut(q);
 
        /* Disable the module */
-       writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
+       qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
                        base + QUADSPI_MCR);
 
-       reg = readl(base + QUADSPI_SMPR);
-       writel(reg & ~(QUADSPI_SMPR_FSDLY_MASK
+       reg = qspi_readl(q, base + QUADSPI_SMPR);
+       qspi_writel(q, reg & ~(QUADSPI_SMPR_FSDLY_MASK
                        | QUADSPI_SMPR_FSPHS_MASK
                        | QUADSPI_SMPR_HSENA_MASK
                        | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR);
 
        /* Enable the module */
-       writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
+       qspi_writel(q, QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
                        base + QUADSPI_MCR);
 
        /* clear all interrupt status */
-       writel(0xffffffff, q->iobase + QUADSPI_FR);
+       qspi_writel(q, 0xffffffff, q->iobase + QUADSPI_FR);
 
        /* enable the interrupt */
-       writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
+       qspi_writel(q, QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
 
        return 0;
 }
@@ -776,6 +821,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = {
        { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, },
        { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
        { .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
+       { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
@@ -954,6 +1000,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
        if (IS_ERR(q->iobase))
                return PTR_ERR(q->iobase);
 
+       q->big_endian = of_property_read_bool(np, "big-endian");
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                        "QuadSPI-memory");
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
@@ -1101,8 +1148,8 @@ static int fsl_qspi_remove(struct platform_device *pdev)
        }
 
        /* disable the hardware */
-       writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
-       writel(0x0, q->iobase + QUADSPI_RSER);
+       qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER);
 
        mutex_destroy(&q->lock);
 
index d5f850d..8bed1a4 100644 (file)
@@ -371,8 +371,8 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
        return ret;
 }
 
-static int __init mtk_nor_init(struct mt8173_nor *mt8173_nor,
-                              struct device_node *flash_node)
+static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
+                       struct device_node *flash_node)
 {
        int ret;
        struct spi_nor *nor;
index ed0c19c..157841d 100644 (file)
@@ -61,14 +61,20 @@ struct flash_info {
        u16             addr_width;
 
        u16             flags;
-#define        SECT_4K                 0x01    /* SPINOR_OP_BE_4K works uniformly */
-#define        SPI_NOR_NO_ERASE        0x02    /* No erase command needed */
-#define        SST_WRITE               0x04    /* use SST byte programming */
-#define        SPI_NOR_NO_FR           0x08    /* Can't do fastread */
-#define        SECT_4K_PMC             0x10    /* SPINOR_OP_BE_4K_PMC works uniformly */
-#define        SPI_NOR_DUAL_READ       0x20    /* Flash supports Dual Read */
-#define        SPI_NOR_QUAD_READ       0x40    /* Flash supports Quad Read */
-#define        USE_FSR                 0x80    /* use flag status register */
+#define SECT_4K                        BIT(0)  /* SPINOR_OP_BE_4K works uniformly */
+#define SPI_NOR_NO_ERASE       BIT(1)  /* No erase command needed */
+#define SST_WRITE              BIT(2)  /* use SST byte programming */
+#define SPI_NOR_NO_FR          BIT(3)  /* Can't do fastread */
+#define SECT_4K_PMC            BIT(4)  /* SPINOR_OP_BE_4K_PMC works uniformly */
+#define SPI_NOR_DUAL_READ      BIT(5)  /* Flash supports Dual Read */
+#define SPI_NOR_QUAD_READ      BIT(6)  /* Flash supports Quad Read */
+#define USE_FSR                        BIT(7)  /* use flag status register */
+#define SPI_NOR_HAS_LOCK       BIT(8)  /* Flash supports lock/unlock via SR */
+#define SPI_NOR_HAS_TB         BIT(9)  /*
+                                        * Flash SR has Top/Bottom (TB) protect
+                                        * bit. Must be used with
+                                        * SPI_NOR_HAS_LOCK.
+                                        */
 };
 
 #define JEDEC_MFR(info)        ((info)->id[0])
@@ -434,32 +440,58 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
        } else {
                pow = ((sr & mask) ^ mask) >> shift;
                *len = mtd->size >> pow;
-               *ofs = mtd->size - *len;
+               if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
+                       *ofs = 0;
+               else
+                       *ofs = mtd->size - *len;
        }
 }
 
 /*
- * Return 1 if the entire region is locked, 0 otherwise
+ * Return 1 if the entire region is locked (if @locked is true) or unlocked (if
+ * @locked is false); 0 otherwise
  */
-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-                           u8 sr)
+static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+                                   u8 sr, bool locked)
 {
        loff_t lock_offs;
        uint64_t lock_len;
 
+       if (!len)
+               return 1;
+
        stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
 
-       return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+       if (locked)
+               /* Requested range is a sub-range of locked range */
+               return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+       else
+               /* Requested range does not overlap with locked range */
+               return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
+}
+
+static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+                           u8 sr)
+{
+       return stm_check_lock_status_sr(nor, ofs, len, sr, true);
+}
+
+static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+                             u8 sr)
+{
+       return stm_check_lock_status_sr(nor, ofs, len, sr, false);
 }
 
 /*
  * Lock a region of the flash. Compatible with ST Micro and similar flash.
- * Supports only the block protection bits BP{0,1,2} in the status register
+ * Supports the block protection bits BP{0,1,2} in the status register
  * (SR). Does not support these features found in newer SR bitfields:
- *   - TB: top/bottom protect - only handle TB=0 (top protect)
  *   - SEC: sector/block protect - only handle SEC=0 (block protect)
  *   - CMP: complement protect - only support CMP=0 (range is not complemented)
  *
+ * Support for the following is provided conditionally for some flash:
+ *   - TB: top/bottom protect
+ *
  * Sample table portion for 8MB flash (Winbond w25q64fw):
  *
  *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
@@ -472,6 +504,13 @@ static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
  *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
  *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
  *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
+ *  ------|-------|-------|-------|-------|---------------|-------------------
+ *    0   |   1   |   0   |   0   |   1   |  128 KB       | Lower 1/64
+ *    0   |   1   |   0   |   1   |   0   |  256 KB       | Lower 1/32
+ *    0   |   1   |   0   |   1   |   1   |  512 KB       | Lower 1/16
+ *    0   |   1   |   1   |   0   |   0   |  1 MB         | Lower 1/8
+ *    0   |   1   |   1   |   0   |   1   |  2 MB         | Lower 1/4
+ *    0   |   1   |   1   |   1   |   0   |  4 MB         | Lower 1/2
  *
  * Returns negative on errors, 0 on success.
  */
@@ -481,20 +520,39 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
        int status_old, status_new;
        u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
        u8 shift = ffs(mask) - 1, pow, val;
+       loff_t lock_len;
+       bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
+       bool use_top;
        int ret;
 
        status_old = read_sr(nor);
        if (status_old < 0)
                return status_old;
 
-       /* SPI NOR always locks to the end */
-       if (ofs + len != mtd->size) {
-               /* Does combined region extend to end? */
-               if (!stm_is_locked_sr(nor, ofs + len, mtd->size - ofs - len,
-                                     status_old))
-                       return -EINVAL;
-               len = mtd->size - ofs;
-       }
+       /* If nothing in our range is unlocked, we don't need to do anything */
+       if (stm_is_locked_sr(nor, ofs, len, status_old))
+               return 0;
+
+       /* If anything below us is unlocked, we can't use 'bottom' protection */
+       if (!stm_is_locked_sr(nor, 0, ofs, status_old))
+               can_be_bottom = false;
+
+       /* If anything above us is unlocked, we can't use 'top' protection */
+       if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
+                               status_old))
+               can_be_top = false;
+
+       if (!can_be_bottom && !can_be_top)
+               return -EINVAL;
+
+       /* Prefer top, if both are valid */
+       use_top = can_be_top;
+
+       /* lock_len: length of region that should end up locked */
+       if (use_top)
+               lock_len = mtd->size - ofs;
+       else
+               lock_len = ofs + len;
 
        /*
         * Need smallest pow such that:
@@ -505,7 +563,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
         *
         *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
         */
-       pow = ilog2(mtd->size) - ilog2(len);
+       pow = ilog2(mtd->size) - ilog2(lock_len);
        val = mask - (pow << shift);
        if (val & ~mask)
                return -EINVAL;
@@ -513,10 +571,20 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
        if (!(val & mask))
                return -EINVAL;
 
-       status_new = (status_old & ~mask) | val;
+       status_new = (status_old & ~mask & ~SR_TB) | val;
+
+       /* Disallow further writes if WP pin is asserted */
+       status_new |= SR_SRWD;
+
+       if (!use_top)
+               status_new |= SR_TB;
+
+       /* Don't bother if they're the same */
+       if (status_new == status_old)
+               return 0;
 
        /* Only modify protection if it will not unlock other areas */
-       if ((status_new & mask) <= (status_old & mask))
+       if ((status_new & mask) < (status_old & mask))
                return -EINVAL;
 
        write_enable(nor);
@@ -537,17 +605,40 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
        int status_old, status_new;
        u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
        u8 shift = ffs(mask) - 1, pow, val;
+       loff_t lock_len;
+       bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
+       bool use_top;
        int ret;
 
        status_old = read_sr(nor);
        if (status_old < 0)
                return status_old;
 
-       /* Cannot unlock; would unlock larger region than requested */
-       if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
-                            status_old))
+       /* If nothing in our range is locked, we don't need to do anything */
+       if (stm_is_unlocked_sr(nor, ofs, len, status_old))
+               return 0;
+
+       /* If anything below us is locked, we can't use 'top' protection */
+       if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
+               can_be_top = false;
+
+       /* If anything above us is locked, we can't use 'bottom' protection */
+       if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
+                               status_old))
+               can_be_bottom = false;
+
+       if (!can_be_bottom && !can_be_top)
                return -EINVAL;
 
+       /* Prefer top, if both are valid */
+       use_top = can_be_top;
+
+       /* lock_len: length of region that should remain locked */
+       if (use_top)
+               lock_len = mtd->size - (ofs + len);
+       else
+               lock_len = ofs;
+
        /*
         * Need largest pow such that:
         *
@@ -557,8 +648,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
         *
         *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
         */
-       pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len));
-       if (ofs + len == mtd->size) {
+       pow = ilog2(mtd->size) - order_base_2(lock_len);
+       if (lock_len == 0) {
                val = 0; /* fully unlocked */
        } else {
                val = mask - (pow << shift);
@@ -567,10 +658,21 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
                        return -EINVAL;
        }
 
-       status_new = (status_old & ~mask) | val;
+       status_new = (status_old & ~mask & ~SR_TB) | val;
+
+       /* Don't protect status register if we're fully unlocked */
+       if (lock_len == mtd->size)
+               status_new &= ~SR_SRWD;
+
+       if (!use_top)
+               status_new |= SR_TB;
+
+       /* Don't bother if they're the same */
+       if (status_new == status_old)
+               return 0;
 
        /* Only modify protection if it will not lock other areas */
-       if ((status_new & mask) >= (status_old & mask))
+       if ((status_new & mask) > (status_old & mask))
                return -EINVAL;
 
        write_enable(nor);
@@ -762,8 +864,8 @@ static const struct flash_info spi_nor_ids[] = {
        { "n25q032a",    INFO(0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
        { "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q064a",    INFO(0x20bb17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
-       { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ) },
-       { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ) },
+       { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
+       { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
        { "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
@@ -797,6 +899,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
+       { "s25fl116k",  INFO(0x014015,      0,  64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, SECT_4K) },
        { "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
        { "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ) },
@@ -860,11 +963,23 @@ static const struct flash_info spi_nor_ids[] = {
        { "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
        { "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
        { "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
-       { "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       {
+               "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
        { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
-       { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-       { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       {
+               "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
+       {
+               "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
@@ -1100,45 +1215,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
        return 0;
 }
 
-static int micron_quad_enable(struct spi_nor *nor)
-{
-       int ret;
-       u8 val;
-
-       ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
-       if (ret < 0) {
-               dev_err(nor->dev, "error %d reading EVCR\n", ret);
-               return ret;
-       }
-
-       write_enable(nor);
-
-       /* set EVCR, enable quad I/O */
-       nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
-       ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
-       if (ret < 0) {
-               dev_err(nor->dev, "error while writing EVCR register\n");
-               return ret;
-       }
-
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret)
-               return ret;
-
-       /* read EVCR and check it */
-       ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
-       if (ret < 0) {
-               dev_err(nor->dev, "error %d reading EVCR\n", ret);
-               return ret;
-       }
-       if (val & EVCR_QUAD_EN_MICRON) {
-               dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 {
        int status;
@@ -1152,12 +1228,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
                }
                return status;
        case SNOR_MFR_MICRON:
-               status = micron_quad_enable(nor);
-               if (status) {
-                       dev_err(nor->dev, "Micron quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
+               return 0;
        default:
                status = spansion_quad_enable(nor);
                if (status) {
@@ -1233,9 +1304,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
        if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
            JEDEC_MFR(info) == SNOR_MFR_INTEL ||
-           JEDEC_MFR(info) == SNOR_MFR_SST) {
+           JEDEC_MFR(info) == SNOR_MFR_SST ||
+           info->flags & SPI_NOR_HAS_LOCK) {
                write_enable(nor);
                write_sr(nor, 0);
+               spi_nor_wait_till_ready(nor);
        }
 
        if (!mtd->name)
@@ -1249,7 +1322,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        mtd->_read = spi_nor_read;
 
        /* NOR protection support for STmicro/Micron chips and similar */
-       if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
+       if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
+                       info->flags & SPI_NOR_HAS_LOCK) {
                nor->flash_lock = stm_lock;
                nor->flash_unlock = stm_unlock;
                nor->flash_is_locked = stm_is_locked;
@@ -1269,6 +1343,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
        if (info->flags & USE_FSR)
                nor->flags |= SNOR_F_USE_FSR;
+       if (info->flags & SPI_NOR_HAS_TB)
+               nor->flags |= SNOR_F_HAS_SR_TB;
 
 #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
        /* prefer "small sector" erase if possible */
index 3176212..1cb3f77 100644 (file)
@@ -215,19 +215,19 @@ static int verify_eraseblock(int ebnum)
                        pr_info("ignoring error as within bitflip_limit\n");
                }
 
-               if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
+               if (use_offset != 0 || use_len < mtd->oobavail) {
                        int k;
 
                        ops.mode      = MTD_OPS_AUTO_OOB;
                        ops.len       = 0;
                        ops.retlen    = 0;
-                       ops.ooblen    = mtd->ecclayout->oobavail;
+                       ops.ooblen    = mtd->oobavail;
                        ops.oobretlen = 0;
                        ops.ooboffs   = 0;
                        ops.datbuf    = NULL;
                        ops.oobbuf    = readbuf;
                        err = mtd_read_oob(mtd, addr, &ops);
-                       if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
+                       if (err || ops.oobretlen != mtd->oobavail) {
                                pr_err("error: readoob failed at %#llx\n",
                                                (long long)addr);
                                errcnt += 1;
@@ -244,7 +244,7 @@ static int verify_eraseblock(int ebnum)
                        /* verify post-(use_offset + use_len) area for 0xff */
                        k = use_offset + use_len;
                        bitflips += memffshow(addr, k, readbuf + k,
-                                             mtd->ecclayout->oobavail - k);
+                                             mtd->oobavail - k);
 
                        if (bitflips > bitflip_limit) {
                                pr_err("error: verify failed at %#llx\n",
@@ -269,8 +269,8 @@ static int verify_eraseblock_in_one_go(int ebnum)
        struct mtd_oob_ops ops;
        int err = 0;
        loff_t addr = (loff_t)ebnum * mtd->erasesize;
-       size_t len = mtd->ecclayout->oobavail * pgcnt;
-       size_t oobavail = mtd->ecclayout->oobavail;
+       size_t len = mtd->oobavail * pgcnt;
+       size_t oobavail = mtd->oobavail;
        size_t bitflips;
        int i;
 
@@ -394,8 +394,8 @@ static int __init mtd_oobtest_init(void)
                goto out;
 
        use_offset = 0;
-       use_len = mtd->ecclayout->oobavail;
-       use_len_max = mtd->ecclayout->oobavail;
+       use_len = mtd->oobavail;
+       use_len_max = mtd->oobavail;
        vary_offset = 0;
 
        /* First test: write all OOB, read it back and verify */
@@ -460,8 +460,8 @@ static int __init mtd_oobtest_init(void)
 
        /* Write all eraseblocks */
        use_offset = 0;
-       use_len = mtd->ecclayout->oobavail;
-       use_len_max = mtd->ecclayout->oobavail;
+       use_len = mtd->oobavail;
+       use_len_max = mtd->oobavail;
        vary_offset = 1;
        prandom_seed_state(&rnd_state, 5);
 
@@ -471,8 +471,8 @@ static int __init mtd_oobtest_init(void)
 
        /* Check all eraseblocks */
        use_offset = 0;
-       use_len = mtd->ecclayout->oobavail;
-       use_len_max = mtd->ecclayout->oobavail;
+       use_len = mtd->oobavail;
+       use_len_max = mtd->oobavail;
        vary_offset = 1;
        prandom_seed_state(&rnd_state, 5);
        err = verify_all_eraseblocks();
@@ -480,8 +480,8 @@ static int __init mtd_oobtest_init(void)
                goto out;
 
        use_offset = 0;
-       use_len = mtd->ecclayout->oobavail;
-       use_len_max = mtd->ecclayout->oobavail;
+       use_len = mtd->oobavail;
+       use_len_max = mtd->oobavail;
        vary_offset = 0;
 
        /* Fourth test: try to write off end of device */
@@ -501,7 +501,7 @@ static int __init mtd_oobtest_init(void)
        ops.retlen    = 0;
        ops.ooblen    = 1;
        ops.oobretlen = 0;
-       ops.ooboffs   = mtd->ecclayout->oobavail;
+       ops.ooboffs   = mtd->oobavail;
        ops.datbuf    = NULL;
        ops.oobbuf    = writebuf;
        pr_info("attempting to start write past end of OOB\n");
@@ -521,7 +521,7 @@ static int __init mtd_oobtest_init(void)
        ops.retlen    = 0;
        ops.ooblen    = 1;
        ops.oobretlen = 0;
-       ops.ooboffs   = mtd->ecclayout->oobavail;
+       ops.ooboffs   = mtd->oobavail;
        ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
        pr_info("attempting to start read past end of OOB\n");
@@ -543,7 +543,7 @@ static int __init mtd_oobtest_init(void)
                ops.mode      = MTD_OPS_AUTO_OOB;
                ops.len       = 0;
                ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail + 1;
+               ops.ooblen    = mtd->oobavail + 1;
                ops.oobretlen = 0;
                ops.ooboffs   = 0;
                ops.datbuf    = NULL;
@@ -563,7 +563,7 @@ static int __init mtd_oobtest_init(void)
                ops.mode      = MTD_OPS_AUTO_OOB;
                ops.len       = 0;
                ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail + 1;
+               ops.ooblen    = mtd->oobavail + 1;
                ops.oobretlen = 0;
                ops.ooboffs   = 0;
                ops.datbuf    = NULL;
@@ -587,7 +587,7 @@ static int __init mtd_oobtest_init(void)
                ops.mode      = MTD_OPS_AUTO_OOB;
                ops.len       = 0;
                ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail;
+               ops.ooblen    = mtd->oobavail;
                ops.oobretlen = 0;
                ops.ooboffs   = 1;
                ops.datbuf    = NULL;
@@ -607,7 +607,7 @@ static int __init mtd_oobtest_init(void)
                ops.mode      = MTD_OPS_AUTO_OOB;
                ops.len       = 0;
                ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail;
+               ops.ooblen    = mtd->oobavail;
                ops.oobretlen = 0;
                ops.ooboffs   = 1;
                ops.datbuf    = NULL;
@@ -638,7 +638,7 @@ static int __init mtd_oobtest_init(void)
        for (i = 0; i < ebcnt - 1; ++i) {
                int cnt = 2;
                int pg;
-               size_t sz = mtd->ecclayout->oobavail;
+               size_t sz = mtd->oobavail;
                if (bbt[i] || bbt[i + 1])
                        continue;
                addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
@@ -673,13 +673,12 @@ static int __init mtd_oobtest_init(void)
        for (i = 0; i < ebcnt - 1; ++i) {
                if (bbt[i] || bbt[i + 1])
                        continue;
-               prandom_bytes_state(&rnd_state, writebuf,
-                                       mtd->ecclayout->oobavail * 2);
+               prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2);
                addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
                ops.mode      = MTD_OPS_AUTO_OOB;
                ops.len       = 0;
                ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail * 2;
+               ops.ooblen    = mtd->oobavail * 2;
                ops.oobretlen = 0;
                ops.ooboffs   = 0;
                ops.datbuf    = NULL;
@@ -688,7 +687,7 @@ static int __init mtd_oobtest_init(void)
                if (err)
                        goto out;
                if (memcmpshow(addr, readbuf, writebuf,
-                              mtd->ecclayout->oobavail * 2)) {
+                              mtd->oobavail * 2)) {
                        pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
index 2a45ac2..989036c 100644 (file)
@@ -153,3 +153,52 @@ int ubi_check_pattern(const void *buf, uint8_t patt, int size)
                        return 0;
        return 1;
 }
+
+/* Normal UBI messages */
+void ubi_msg(const struct ubi_device *ubi, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       pr_notice(UBI_NAME_STR "%d: %pV\n", ubi->ubi_num, &vaf);
+
+       va_end(args);
+}
+
+/* UBI warning messages */
+void ubi_warn(const struct ubi_device *ubi, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       pr_warn(UBI_NAME_STR "%d warning: %ps: %pV\n",
+               ubi->ubi_num, __builtin_return_address(0), &vaf);
+
+       va_end(args);
+}
+
+/* UBI error messages */
+void ubi_err(const struct ubi_device *ubi, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       pr_err(UBI_NAME_STR "%d error: %ps: %pV\n",
+              ubi->ubi_num, __builtin_return_address(0), &vaf);
+       va_end(args);
+}
index 2974b67..dadc6a9 100644 (file)
 /* UBI name used for character devices, sysfs, etc */
 #define UBI_NAME_STR "ubi"
 
+struct ubi_device;
+
 /* Normal UBI messages */
-#define ubi_msg(ubi, fmt, ...) pr_notice(UBI_NAME_STR "%d: " fmt "\n", \
-                                        ubi->ubi_num, ##__VA_ARGS__)
+__printf(2, 3)
+void ubi_msg(const struct ubi_device *ubi, const char *fmt, ...);
+
 /* UBI warning messages */
-#define ubi_warn(ubi, fmt, ...) pr_warn(UBI_NAME_STR "%d warning: %s: " fmt "\n", \
-                                       ubi->ubi_num, __func__, ##__VA_ARGS__)
+__printf(2, 3)
+void ubi_warn(const struct ubi_device *ubi, const char *fmt, ...);
+
 /* UBI error messages */
-#define ubi_err(ubi, fmt, ...) pr_err(UBI_NAME_STR "%d error: %s: " fmt "\n", \
-                                     ubi->ubi_num, __func__, ##__VA_ARGS__)
+__printf(2, 3)
+void ubi_err(const struct ubi_device *ubi, const char *fmt, ...);
 
 /* Background thread name pattern */
 #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
index 802d554..fd90f37 100644 (file)
@@ -7,7 +7,7 @@
  * (at your option) any later version.
  */
 
-#include <asm-generic/io-64-nonatomic-hi-lo.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/of_mdio.h>
 #include "hns_dsaf_main.h"
 #include "hns_dsaf_mac.h"
index ab264e1..75683fb 100644 (file)
@@ -45,7 +45,7 @@
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/pci.h>
-#include <asm-generic/io-64-nonatomic-hi-lo.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 
 #include "nfp_net_ctrl.h"
 
index 588803a..6ccba0d 100644 (file)
@@ -357,20 +357,6 @@ static int amd_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
        return 0;
 }
 
-static int amd_ntb_peer_db_addr(struct ntb_dev *ntb,
-                               phys_addr_t *db_addr,
-                               resource_size_t *db_size)
-{
-       struct amd_ntb_dev *ndev = ntb_ndev(ntb);
-
-       if (db_addr)
-               *db_addr = (phys_addr_t)(ndev->peer_mmio + AMD_DBREQ_OFFSET);
-       if (db_size)
-               *db_size = sizeof(u32);
-
-       return 0;
-}
-
 static int amd_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
 {
        struct amd_ntb_dev *ndev = ntb_ndev(ntb);
@@ -415,20 +401,6 @@ static int amd_ntb_spad_write(struct ntb_dev *ntb,
        return 0;
 }
 
-static int amd_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
-                                 phys_addr_t *spad_addr)
-{
-       struct amd_ntb_dev *ndev = ntb_ndev(ntb);
-
-       if (idx < 0 || idx >= ndev->spad_count)
-               return -EINVAL;
-
-       if (spad_addr)
-               *spad_addr = (phys_addr_t)(ndev->self_mmio + AMD_SPAD_OFFSET +
-                                          ndev->peer_spad + (idx << 2));
-       return 0;
-}
-
 static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
 {
        struct amd_ntb_dev *ndev = ntb_ndev(ntb);
@@ -472,12 +444,10 @@ static const struct ntb_dev_ops amd_ntb_ops = {
        .db_clear               = amd_ntb_db_clear,
        .db_set_mask            = amd_ntb_db_set_mask,
        .db_clear_mask          = amd_ntb_db_clear_mask,
-       .peer_db_addr           = amd_ntb_peer_db_addr,
        .peer_db_set            = amd_ntb_peer_db_set,
        .spad_count             = amd_ntb_spad_count,
        .spad_read              = amd_ntb_spad_read,
        .spad_write             = amd_ntb_spad_write,
-       .peer_spad_addr         = amd_ntb_peer_spad_addr,
        .peer_spad_read         = amd_ntb_peer_spad_read,
        .peer_spad_write        = amd_ntb_peer_spad_write,
 };
index ec4775f..2ef9d91 100644 (file)
@@ -124,6 +124,7 @@ struct ntb_transport_qp {
 
        bool client_ready;
        bool link_is_up;
+       bool active;
 
        u8 qp_num;      /* Only 64 QP's are allowed.  0-63 */
        u64 qp_bit;
@@ -719,6 +720,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
 static void ntb_qp_link_down_reset(struct ntb_transport_qp *qp)
 {
        qp->link_is_up = false;
+       qp->active = false;
 
        qp->tx_index = 0;
        qp->rx_index = 0;
@@ -827,7 +829,7 @@ static void ntb_transport_link_work(struct work_struct *work)
        struct pci_dev *pdev = ndev->pdev;
        resource_size_t size;
        u32 val;
-       int rc, i, spad;
+       int rc = 0, i, spad;
 
        /* send the local info, in the opposite order of the way we read it */
        for (i = 0; i < nt->mw_count; i++) {
@@ -897,6 +899,13 @@ static void ntb_transport_link_work(struct work_struct *work)
 out1:
        for (i = 0; i < nt->mw_count; i++)
                ntb_free_mw(nt, i);
+
+       /* if there's an actual failure, we should just bail */
+       if (rc < 0) {
+               ntb_link_disable(ndev);
+               return;
+       }
+
 out:
        if (ntb_link_is_up(ndev, NULL, NULL) == 1)
                schedule_delayed_work(&nt->link_work,
@@ -926,11 +935,13 @@ static void ntb_qp_link_work(struct work_struct *work)
        if (val & BIT(qp->qp_num)) {
                dev_info(&pdev->dev, "qp %d: Link Up\n", qp->qp_num);
                qp->link_is_up = true;
+               qp->active = true;
 
                if (qp->event_handler)
                        qp->event_handler(qp->cb_data, qp->link_is_up);
 
-               tasklet_schedule(&qp->rxc_db_work);
+               if (qp->active)
+                       tasklet_schedule(&qp->rxc_db_work);
        } else if (nt->link_is_up)
                schedule_delayed_work(&qp->link_work,
                                      msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
@@ -1411,7 +1422,8 @@ static void ntb_transport_rxc_db(unsigned long data)
 
        if (i == qp->rx_max_entry) {
                /* there is more work to do */
-               tasklet_schedule(&qp->rxc_db_work);
+               if (qp->active)
+                       tasklet_schedule(&qp->rxc_db_work);
        } else if (ntb_db_read(qp->ndev) & BIT_ULL(qp->qp_num)) {
                /* the doorbell bit is set: clear it */
                ntb_db_clear(qp->ndev, BIT_ULL(qp->qp_num));
@@ -1422,7 +1434,8 @@ static void ntb_transport_rxc_db(unsigned long data)
                 * ntb_process_rxc and clearing the doorbell bit:
                 * there might be some more work to do.
                 */
-               tasklet_schedule(&qp->rxc_db_work);
+               if (qp->active)
+                       tasklet_schedule(&qp->rxc_db_work);
        }
 }
 
@@ -1760,6 +1773,8 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 
        pdev = qp->ndev->pdev;
 
+       qp->active = false;
+
        if (qp->tx_dma_chan) {
                struct dma_chan *chan = qp->tx_dma_chan;
                /* Putting the dma_chan to NULL will force any new traffic to be
@@ -1793,7 +1808,7 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
        qp_bit = BIT_ULL(qp->qp_num);
 
        ntb_db_set_mask(qp->ndev, qp_bit);
-       tasklet_disable(&qp->rxc_db_work);
+       tasklet_kill(&qp->rxc_db_work);
 
        cancel_delayed_work_sync(&qp->link_work);
 
@@ -1886,7 +1901,8 @@ int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
 
        ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_pend_q);
 
-       tasklet_schedule(&qp->rxc_db_work);
+       if (qp->active)
+               tasklet_schedule(&qp->rxc_db_work);
 
        return 0;
 }
@@ -2069,7 +2085,8 @@ static void ntb_transport_doorbell_callback(void *data, int vector)
                qp_num = __ffs(db_bits);
                qp = &nt->qp_vec[qp_num];
 
-               tasklet_schedule(&qp->rxc_db_work);
+               if (qp->active)
+                       tasklet_schedule(&qp->rxc_db_work);
 
                db_bits &= ~BIT_ULL(qp_num);
        }
index c8a37ba..8dfce9c 100644 (file)
@@ -178,7 +178,7 @@ static void perf_copy_callback(void *data)
        atomic_dec(&pctx->dma_sync);
 }
 
-static ssize_t perf_copy(struct pthr_ctx *pctx, char *dst,
+static ssize_t perf_copy(struct pthr_ctx *pctx, char __iomem *dst,
                         char *src, size_t size)
 {
        struct perf_ctx *perf = pctx->perf;
@@ -189,7 +189,8 @@ static ssize_t perf_copy(struct pthr_ctx *pctx, char *dst,
        dma_cookie_t cookie;
        size_t src_off, dst_off;
        struct perf_mw *mw = &perf->mw;
-       u64 vbase, dst_vaddr;
+       void __iomem *vbase;
+       void __iomem *dst_vaddr;
        dma_addr_t dst_phys;
        int retries = 0;
 
@@ -204,14 +205,14 @@ static ssize_t perf_copy(struct pthr_ctx *pctx, char *dst,
        }
 
        device = chan->device;
-       src_off = (size_t)src & ~PAGE_MASK;
-       dst_off = (size_t)dst & ~PAGE_MASK;
+       src_off = (uintptr_t)src & ~PAGE_MASK;
+       dst_off = (uintptr_t __force)dst & ~PAGE_MASK;
 
        if (!is_dma_copy_aligned(device, src_off, dst_off, size))
                return -ENODEV;
 
-       vbase = (u64)(u64 *)mw->vbase;
-       dst_vaddr = (u64)(u64 *)dst;
+       vbase = mw->vbase;
+       dst_vaddr = dst;
        dst_phys = mw->phys_addr + (dst_vaddr - vbase);
 
        unmap = dmaengine_get_unmap_data(device->dev, 1, GFP_NOWAIT);
@@ -261,13 +262,13 @@ err_get_unmap:
        return 0;
 }
 
-static int perf_move_data(struct pthr_ctx *pctx, char *dst, char *src,
+static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src,
                          u64 buf_size, u64 win_size, u64 total)
 {
        int chunks, total_chunks, i;
        int copied_chunks = 0;
        u64 copied = 0, result;
-       char *tmp = dst;
+       char __iomem *tmp = dst;
        u64 perf, diff_us;
        ktime_t kstart, kstop, kdiff;
 
@@ -324,7 +325,7 @@ static int ntb_perf_thread(void *data)
        struct perf_ctx *perf = pctx->perf;
        struct pci_dev *pdev = perf->ntb->pdev;
        struct perf_mw *mw = &perf->mw;
-       char *dst;
+       char __iomem *dst;
        u64 win_size, buf_size, total;
        void *src;
        int rc, node, i;
@@ -364,7 +365,7 @@ static int ntb_perf_thread(void *data)
        if (buf_size > MAX_TEST_SIZE)
                buf_size = MAX_TEST_SIZE;
 
-       dst = (char *)mw->vbase;
+       dst = (char __iomem *)mw->vbase;
 
        atomic_inc(&perf->tsync);
        while (atomic_read(&perf->tsync) != perf->perf_threads)
@@ -424,6 +425,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
 {
        struct perf_mw *mw = &perf->mw;
        size_t xlat_size, buf_size;
+       int rc;
 
        if (!size)
                return -EINVAL;
@@ -447,6 +449,13 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
                mw->buf_size = 0;
        }
 
+       rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
+       if (rc) {
+               dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
+               perf_free_mw(perf);
+               return -EIO;
+       }
+
        return 0;
 }
 
@@ -541,6 +550,8 @@ static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf,
                return 0;
 
        buf = kmalloc(64, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
        out_offset = snprintf(buf, 64, "%d\n", perf->run);
        ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
        kfree(buf);
@@ -548,6 +559,21 @@ static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf,
        return ret;
 }
 
+static void threads_cleanup(struct perf_ctx *perf)
+{
+       struct pthr_ctx *pctx;
+       int i;
+
+       perf->run = false;
+       for (i = 0; i < MAX_THREADS; i++) {
+               pctx = &perf->pthr_ctx[i];
+               if (pctx->thread) {
+                       kthread_stop(pctx->thread);
+                       pctx->thread = NULL;
+               }
+       }
+}
+
 static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf,
                                 size_t count, loff_t *offp)
 {
@@ -563,17 +589,9 @@ static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf,
        if (atomic_read(&perf->tsync) == 0)
                perf->run = false;
 
-       if (perf->run) {
-               /* lets stop the threads */
-               perf->run = false;
-               for (i = 0; i < MAX_THREADS; i++) {
-                       if (perf->pthr_ctx[i].thread) {
-                               kthread_stop(perf->pthr_ctx[i].thread);
-                               perf->pthr_ctx[i].thread = NULL;
-                       } else
-                               break;
-               }
-       } else {
+       if (perf->run)
+               threads_cleanup(perf);
+       else {
                perf->run = true;
 
                if (perf->perf_threads > MAX_THREADS) {
@@ -604,17 +622,11 @@ static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf,
                                kthread_create_on_node(ntb_perf_thread,
                                                       (void *)pctx,
                                                       node, "ntb_perf %d", i);
-                       if (pctx->thread)
+                       if (IS_ERR(pctx->thread)) {
+                               pctx->thread = NULL;
+                               goto err;
+                       } else
                                wake_up_process(pctx->thread);
-                       else {
-                               perf->run = false;
-                               for (i = 0; i < MAX_THREADS; i++) {
-                                       if (pctx->thread) {
-                                               kthread_stop(pctx->thread);
-                                               pctx->thread = NULL;
-                                       }
-                               }
-                       }
 
                        if (perf->run == false)
                                return -ENXIO;
@@ -623,6 +635,10 @@ static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf,
        }
 
        return count;
+
+err:
+       threads_cleanup(perf);
+       return -ENXIO;
 }
 
 static const struct file_operations ntb_perf_debugfs_run = {
index ca5721c..cc31c6f 100644 (file)
@@ -99,7 +99,7 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
                if (unlikely(bad_pmem))
                        rc = -EIO;
                else {
-                       memcpy_from_pmem(mem + off, pmem_addr, len);
+                       rc = memcpy_from_pmem(mem + off, pmem_addr, len);
                        flush_dcache_page(page);
                }
        } else {
@@ -295,7 +295,7 @@ static int pmem_rw_bytes(struct nd_namespace_common *ndns,
 
                if (unlikely(is_bad_pmem(&pmem->bb, offset / 512, sz_align)))
                        return -EIO;
-               memcpy_from_pmem(buf, pmem->virt_addr + offset, size);
+               return memcpy_from_pmem(buf, pmem->virt_addr + offset, size);
        } else {
                memcpy_to_pmem(pmem->virt_addr + offset, buf, size);
                wmb_pmem();
index 42a01a9..9461dd6 100644 (file)
@@ -146,6 +146,14 @@ struct nvme_nvm_command {
        };
 };
 
+struct nvme_nvm_completion {
+       __le64  result;         /* Used by LightNVM to return ppa completions */
+       __le16  sq_head;        /* how much of this queue may be reclaimed */
+       __le16  sq_id;          /* submission queue that generated this entry */
+       __u16   command_id;     /* of the command which completed */
+       __le16  status;         /* did the command fail, and if so, why? */
+};
+
 #define NVME_NVM_LP_MLC_PAIRS 886
 struct nvme_nvm_lp_mlc {
        __u16                   num_pairs;
@@ -507,6 +515,10 @@ static inline void nvme_nvm_rqtocmd(struct request *rq, struct nvm_rq *rqd,
 static void nvme_nvm_end_io(struct request *rq, int error)
 {
        struct nvm_rq *rqd = rq->end_io_data;
+       struct nvme_nvm_completion *cqe = rq->special;
+
+       if (cqe)
+               rqd->ppa_status = le64_to_cpu(cqe->result);
 
        nvm_end_io(rqd, error);
 
@@ -526,7 +538,8 @@ static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
        if (IS_ERR(rq))
                return -ENOMEM;
 
-       cmd = kzalloc(sizeof(struct nvme_nvm_command), GFP_KERNEL);
+       cmd = kzalloc(sizeof(struct nvme_nvm_command) +
+                               sizeof(struct nvme_nvm_completion), GFP_KERNEL);
        if (!cmd) {
                blk_mq_free_request(rq);
                return -ENOMEM;
@@ -545,7 +558,7 @@ static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
 
        rq->cmd = (unsigned char *)cmd;
        rq->cmd_len = sizeof(struct nvme_nvm_command);
-       rq->special = (void *)0;
+       rq->special = cmd + 1;
 
        rq->end_io_data = rqd;
 
index f8db70a..24ccda3 100644 (file)
@@ -723,6 +723,13 @@ static void nvme_complete_rq(struct request *req)
        blk_mq_end_request(req, error);
 }
 
+/* We read the CQE phase first to check if the rest of the entry is valid */
+static inline bool nvme_cqe_valid(struct nvme_queue *nvmeq, u16 head,
+               u16 phase)
+{
+       return (le16_to_cpu(nvmeq->cqes[head].status) & 1) == phase;
+}
+
 static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag)
 {
        u16 head, phase;
@@ -730,13 +737,10 @@ static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag)
        head = nvmeq->cq_head;
        phase = nvmeq->cq_phase;
 
-       for (;;) {
+       while (nvme_cqe_valid(nvmeq, head, phase)) {
                struct nvme_completion cqe = nvmeq->cqes[head];
-               u16 status = le16_to_cpu(cqe.status);
                struct request *req;
 
-               if ((status & 1) != phase)
-                       break;
                if (++head == nvmeq->q_depth) {
                        head = 0;
                        phase = !phase;
@@ -767,7 +771,7 @@ static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag)
                req = blk_mq_tag_to_rq(*nvmeq->tags, cqe.command_id);
                if (req->cmd_type == REQ_TYPE_DRV_PRIV && req->special)
                        memcpy(req->special, &cqe, sizeof(cqe));
-               blk_mq_complete_request(req, status >> 1);
+               blk_mq_complete_request(req, le16_to_cpu(cqe.status) >> 1);
 
        }
 
@@ -808,18 +812,16 @@ static irqreturn_t nvme_irq(int irq, void *data)
 static irqreturn_t nvme_irq_check(int irq, void *data)
 {
        struct nvme_queue *nvmeq = data;
-       struct nvme_completion cqe = nvmeq->cqes[nvmeq->cq_head];
-       if ((le16_to_cpu(cqe.status) & 1) != nvmeq->cq_phase)
-               return IRQ_NONE;
-       return IRQ_WAKE_THREAD;
+       if (nvme_cqe_valid(nvmeq, nvmeq->cq_head, nvmeq->cq_phase))
+               return IRQ_WAKE_THREAD;
+       return IRQ_NONE;
 }
 
 static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
 {
        struct nvme_queue *nvmeq = hctx->driver_data;
 
-       if ((le16_to_cpu(nvmeq->cqes[nvmeq->cq_head].status) & 1) ==
-           nvmeq->cq_phase) {
+       if (nvme_cqe_valid(nvmeq, nvmeq->cq_head, nvmeq->cq_phase)) {
                spin_lock_irq(&nvmeq->q_lock);
                __nvme_process_cq(nvmeq, &tag);
                spin_unlock_irq(&nvmeq->q_lock);
index 8099456..8986382 100644 (file)
 #define RK3368_SOC_CON15_FLASH0                BIT(14)
 #define RK3368_SOC_FLASH_SUPPLY_NUM    2
 
+#define RK3399_PMUGRF_CON0             0x180
+#define RK3399_PMUGRF_CON0_VSEL                BIT(8)
+#define RK3399_PMUGRF_VSEL_SUPPLY_NUM  9
+
 struct rockchip_iodomain;
 
 /**
@@ -181,6 +185,25 @@ static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
                dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
 }
 
+static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
+{
+       int ret;
+       u32 val;
+
+       /* if no pmu io supply we should leave things alone */
+       if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
+               return;
+
+       /*
+        * set pmu io iodomain to also use this framework
+        * instead of a special gpio.
+        */
+       val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
+       ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
+       if (ret < 0)
+               dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
+}
+
 /*
  * On the rk3188 the io-domains are handled by a shared register with the
  * lower 8 bits being still being continuing drive-strength settings.
@@ -252,6 +275,33 @@ static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
        },
 };
 
+static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
+       .grf_offset = 0xe640,
+       .supply_names = {
+               "bt656",                /* APIO2_VDD */
+               "audio",                /* APIO5_VDD */
+               "sdmmc",                /* SDMMC0_VDD */
+               "gpio1830",             /* APIO4_VDD */
+       },
+};
+
+static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
+       .grf_offset = 0x180,
+       .supply_names = {
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               "pmu1830",              /* PMUIO2_VDD */
+       },
+       .init = rk3399_pmu_iodomain_init,
+};
+
 static const struct of_device_id rockchip_iodomain_match[] = {
        {
                .compatible = "rockchip,rk3188-io-voltage-domain",
@@ -269,6 +319,14 @@ static const struct of_device_id rockchip_iodomain_match[] = {
                .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
                .data = (void *)&soc_data_rk3368_pmu
        },
+       {
+               .compatible = "rockchip,rk3399-io-voltage-domain",
+               .data = (void *)&soc_data_rk3399
+       },
+       {
+               .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
+               .data = (void *)&soc_data_rk3399_pmu
+       },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
index 544bd34..3e84315 100644 (file)
@@ -589,7 +589,7 @@ config RTC_DRV_RV3029_HWMON
        default y
        help
          Say Y here if you want to expose temperature sensor data on
-         rtc-rv3029c2.
+         rtc-rv3029.
 
 config RTC_DRV_RV8803
        tristate "Micro Crystal RV8803"
index d41bbcd..ba0d619 100644 (file)
 
 #define ABX8XX_REG_CD_TIMER_CTL        0x18
 
+#define ABX8XX_REG_OSC         0x1c
+#define ABX8XX_OSC_FOS         BIT(3)
+#define ABX8XX_OSC_BOS         BIT(4)
+#define ABX8XX_OSC_ACAL_512    BIT(5)
+#define ABX8XX_OSC_ACAL_1024   BIT(6)
+
+#define ABX8XX_OSC_OSEL                BIT(7)
+
+#define ABX8XX_REG_OSS         0x1d
+#define ABX8XX_OSS_OF          BIT(1)
+#define ABX8XX_OSS_OMODE       BIT(4)
+
 #define ABX8XX_REG_CFG_KEY     0x1f
+#define ABX8XX_CFG_KEY_OSC     0xa1
 #define ABX8XX_CFG_KEY_MISC    0x9d
 
 #define ABX8XX_REG_ID0         0x28
@@ -81,6 +94,20 @@ static struct abx80x_cap abx80x_caps[] = {
        [ABX80X] = {.pn = 0}
 };
 
+static int abx80x_is_rc_mode(struct i2c_client *client)
+{
+       int flags = 0;
+
+       flags =  i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
+       if (flags < 0) {
+               dev_err(&client->dev,
+                       "Failed to read autocalibration attribute\n");
+               return flags;
+       }
+
+       return (flags & ABX8XX_OSS_OMODE) ? 1 : 0;
+}
+
 static int abx80x_enable_trickle_charger(struct i2c_client *client,
                                         u8 trickle_cfg)
 {
@@ -112,7 +139,23 @@ static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct i2c_client *client = to_i2c_client(dev);
        unsigned char buf[8];
-       int err;
+       int err, flags, rc_mode = 0;
+
+       /* Read the Oscillator Failure only in XT mode */
+       rc_mode = abx80x_is_rc_mode(client);
+       if (rc_mode < 0)
+               return rc_mode;
+
+       if (!rc_mode) {
+               flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
+               if (flags < 0)
+                       return flags;
+
+               if (flags & ABX8XX_OSS_OF) {
+                       dev_err(dev, "Oscillator failure, data is invalid.\n");
+                       return -EINVAL;
+               }
+       }
 
        err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH,
                                            sizeof(buf), buf);
@@ -140,7 +183,7 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct i2c_client *client = to_i2c_client(dev);
        unsigned char buf[8];
-       int err;
+       int err, flags;
 
        if (tm->tm_year < 100)
                return -EINVAL;
@@ -161,6 +204,18 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
                return -EIO;
        }
 
+       /* Clear the OF bit of Oscillator Status Register */
+       flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
+       if (flags < 0)
+               return flags;
+
+       err = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSS,
+                                       flags & ~ABX8XX_OSS_OF);
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to write oscillator status register\n");
+               return err;
+       }
+
        return 0;
 }
 
@@ -248,6 +303,174 @@ static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        return 0;
 }
 
+static int abx80x_rtc_set_autocalibration(struct device *dev,
+                                         int autocalibration)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int retval, flags = 0;
+
+       if ((autocalibration != 0) && (autocalibration != 1024) &&
+           (autocalibration != 512)) {
+               dev_err(dev, "autocalibration value outside permitted range\n");
+               return -EINVAL;
+       }
+
+       flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
+       if (flags < 0)
+               return flags;
+
+       if (autocalibration == 0) {
+               flags &= ~(ABX8XX_OSC_ACAL_512 | ABX8XX_OSC_ACAL_1024);
+       } else if (autocalibration == 1024) {
+               /* 1024 autocalibration is 0x10 */
+               flags |= ABX8XX_OSC_ACAL_1024;
+               flags &= ~(ABX8XX_OSC_ACAL_512);
+       } else {
+               /* 512 autocalibration is 0x11 */
+               flags |= (ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512);
+       }
+
+       /* Unlock write access to Oscillator Control Register */
+       retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY,
+                                          ABX8XX_CFG_KEY_OSC);
+       if (retval < 0) {
+               dev_err(dev, "Failed to write CONFIG_KEY register\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags);
+
+       return retval;
+}
+
+static int abx80x_rtc_get_autocalibration(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int flags = 0, autocalibration;
+
+       flags =  i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
+       if (flags < 0)
+               return flags;
+
+       if (flags & ABX8XX_OSC_ACAL_512)
+               autocalibration = 512;
+       else if (flags & ABX8XX_OSC_ACAL_1024)
+               autocalibration = 1024;
+       else
+               autocalibration = 0;
+
+       return autocalibration;
+}
+
+static ssize_t autocalibration_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       int retval;
+       unsigned long autocalibration = 0;
+
+       retval = kstrtoul(buf, 10, &autocalibration);
+       if (retval < 0) {
+               dev_err(dev, "Failed to store RTC autocalibration attribute\n");
+               return -EINVAL;
+       }
+
+       retval = abx80x_rtc_set_autocalibration(dev, autocalibration);
+
+       return retval ? retval : count;
+}
+
+static ssize_t autocalibration_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       int autocalibration = 0;
+
+       autocalibration = abx80x_rtc_get_autocalibration(dev);
+       if (autocalibration < 0) {
+               dev_err(dev, "Failed to read RTC autocalibration\n");
+               sprintf(buf, "0\n");
+               return autocalibration;
+       }
+
+       return sprintf(buf, "%d\n", autocalibration);
+}
+
+static DEVICE_ATTR_RW(autocalibration);
+
+static ssize_t oscillator_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int retval, flags, rc_mode = 0;
+
+       if (strncmp(buf, "rc", 2) == 0) {
+               rc_mode = 1;
+       } else if (strncmp(buf, "xtal", 4) == 0) {
+               rc_mode = 0;
+       } else {
+               dev_err(dev, "Oscillator selection value outside permitted ones\n");
+               return -EINVAL;
+       }
+
+       flags =  i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
+       if (flags < 0)
+               return flags;
+
+       if (rc_mode == 0)
+               flags &= ~(ABX8XX_OSC_OSEL);
+       else
+               flags |= (ABX8XX_OSC_OSEL);
+
+       /* Unlock write access on Oscillator Control register */
+       retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY,
+                                          ABX8XX_CFG_KEY_OSC);
+       if (retval < 0) {
+               dev_err(dev, "Failed to write CONFIG_KEY register\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags);
+       if (retval < 0) {
+               dev_err(dev, "Failed to write Oscillator Control register\n");
+               return retval;
+       }
+
+       return retval ? retval : count;
+}
+
+static ssize_t oscillator_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       int rc_mode = 0;
+       struct i2c_client *client = to_i2c_client(dev);
+
+       rc_mode = abx80x_is_rc_mode(client);
+
+       if (rc_mode < 0) {
+               dev_err(dev, "Failed to read RTC oscillator selection\n");
+               sprintf(buf, "\n");
+               return rc_mode;
+       }
+
+       if (rc_mode)
+               return sprintf(buf, "rc\n");
+       else
+               return sprintf(buf, "xtal\n");
+}
+
+static DEVICE_ATTR_RW(oscillator);
+
+static struct attribute *rtc_calib_attrs[] = {
+       &dev_attr_autocalibration.attr,
+       &dev_attr_oscillator.attr,
+       NULL,
+};
+
+static const struct attribute_group rtc_calib_attr_group = {
+       .attrs          = rtc_calib_attrs,
+};
+
 static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -303,6 +526,13 @@ static int abx80x_dt_trickle_cfg(struct device_node *np)
        return (trickle_cfg | i);
 }
 
+static void rtc_calib_remove_sysfs_group(void *_dev)
+{
+       struct device *dev = _dev;
+
+       sysfs_remove_group(&dev->kobj, &rtc_calib_attr_group);
+}
+
 static int abx80x_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -405,6 +635,24 @@ static int abx80x_probe(struct i2c_client *client,
                }
        }
 
+       /* Export sysfs entries */
+       err = sysfs_create_group(&(&client->dev)->kobj, &rtc_calib_attr_group);
+       if (err) {
+               dev_err(&client->dev, "Failed to create sysfs group: %d\n",
+                       err);
+               return err;
+       }
+
+       err = devm_add_action(&client->dev, rtc_calib_remove_sysfs_group,
+                             &client->dev);
+       if (err) {
+               rtc_calib_remove_sysfs_group(&client->dev);
+               dev_err(&client->dev,
+                       "Failed to add sysfs cleanup action: %d\n",
+                       err);
+               return err;
+       }
+
        return 0;
 }
 
index 14e08c4..355fdb9 100644 (file)
@@ -255,7 +255,7 @@ static const struct rtc_class_ops asm9260_rtc_ops = {
        .alarm_irq_enable       = asm9260_alarm_irq_enable,
 };
 
-static int __init asm9260_rtc_probe(struct platform_device *pdev)
+static int asm9260_rtc_probe(struct platform_device *pdev)
 {
        struct asm9260_rtc_priv *priv;
        struct device *dev = &pdev->dev;
@@ -323,7 +323,7 @@ err_return:
        return ret;
 }
 
-static int __exit asm9260_rtc_remove(struct platform_device *pdev)
+static int asm9260_rtc_remove(struct platform_device *pdev)
 {
        struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev);
 
index a82937e..d107a8e 100644 (file)
@@ -176,7 +176,13 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
                bin2bcd(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f);
        buf[M41T80_REG_MON] =
                bin2bcd(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f);
+
        /* assume 20YY not 19YY */
+       if (tm->tm_year < 100 || tm->tm_year > 199) {
+               dev_err(&client->dev, "Year must be between 2000 and 2099. It's %d.\n",
+                       tm->tm_year + 1900);
+               return -EINVAL;
+       }
        buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year % 100);
 
        if (i2c_transfer(client->adapter, msgs, 1) != 1) {
index 1c91ce8..025bb33 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/printk.h>
 #include <linux/spi/spi.h>
 #include <linux/rtc.h>
+#include <linux/of.h>
 
 /* MCP795 Instructions, see datasheet table 3-1 */
 #define MCP795_EEREAD  0x03
@@ -183,9 +184,18 @@ static int mcp795_probe(struct spi_device *spi)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id mcp795_of_match[] = {
+       { .compatible = "maxim,mcp795" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mcp795_of_match);
+#endif
+
 static struct spi_driver mcp795_driver = {
                .driver = {
                                .name = "rtc-mcp795",
+                               .of_match_table = of_match_ptr(mcp795_of_match),
                },
                .probe = mcp795_probe,
 };
index 8d9f35c..f623038 100644 (file)
@@ -61,11 +61,14 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
        struct i2c_client *client = dev_id;
        struct rv8803_data *rv8803 = i2c_get_clientdata(client);
        unsigned long events = 0;
-       int flags;
+       int flags, try = 0;
 
        mutex_lock(&rv8803->flags_lock);
 
-       flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+       do {
+               flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+               try++;
+       } while ((flags == -ENXIO) && (try < 3));
        if (flags <= 0) {
                mutex_unlock(&rv8803->flags_lock);
                return IRQ_NONE;
@@ -424,7 +427,7 @@ static int rv8803_probe(struct i2c_client *client,
 {
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
        struct rv8803_data *rv8803;
-       int err, flags;
+       int err, flags, try = 0;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                                     I2C_FUNC_SMBUS_I2C_BLOCK)) {
@@ -441,7 +444,16 @@ static int rv8803_probe(struct i2c_client *client,
        rv8803->client = client;
        i2c_set_clientdata(client, rv8803);
 
-       flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+       /*
+        * There is a 60µs window where the RTC may not reply on the i2c bus in
+        * that case, the transfer is not ACKed. In that case, ensure there are
+        * multiple attempts.
+        */
+       do {
+               flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+               try++;
+       } while ((flags == -ENXIO) && (try < 3));
+
        if (flags < 0)
                return flags;
 
@@ -476,8 +488,12 @@ static int rv8803_probe(struct i2c_client *client,
                return PTR_ERR(rv8803->rtc);
        }
 
-       err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
-                                       RV8803_EXT_WADA);
+       try = 0;
+       do {
+               err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
+                                               RV8803_EXT_WADA);
+               try++;
+       } while ((err == -ENXIO) && (try < 3));
        if (err)
                return err;
 
index ffb860d..d01ad7e 100644 (file)
@@ -501,18 +501,27 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 
        info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
        if (IS_ERR(info->rtc_clk)) {
-               dev_err(&pdev->dev, "failed to find rtc clock\n");
-               return PTR_ERR(info->rtc_clk);
+               ret = PTR_ERR(info->rtc_clk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to find rtc clock\n");
+               else
+                       dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
+               return ret;
        }
        clk_prepare_enable(info->rtc_clk);
 
        if (info->data->needs_src_clk) {
                info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
                if (IS_ERR(info->rtc_src_clk)) {
-                       dev_err(&pdev->dev,
-                               "failed to find rtc source clock\n");
+                       ret = PTR_ERR(info->rtc_src_clk);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(&pdev->dev,
+                                       "failed to find rtc source clock\n");
+                       else
+                               dev_dbg(&pdev->dev,
+                                       "probe deferred due to missing rtc src clk\n");
                        clk_disable_unprepare(info->rtc_clk);
-                       return PTR_ERR(info->rtc_src_clk);
+                       return ret;
                }
                clk_prepare_enable(info->rtc_src_clk);
        }
index 17ad574..1e56018 100644 (file)
@@ -317,17 +317,17 @@ static int _add_device_to_lcu(struct alias_lcu *lcu,
        struct alias_pav_group *group;
        struct dasd_uid uid;
 
+       spin_lock(get_ccwdev_lock(device->cdev));
        private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type;
        private->uid.base_unit_addr =
                lcu->uac->unit[private->uid.real_unit_addr].base_ua;
        uid = private->uid;
-
+       spin_unlock(get_ccwdev_lock(device->cdev));
        /* if we have no PAV anyway, we don't need to bother with PAV groups */
        if (lcu->pav == NO_PAV) {
                list_move(&device->alias_list, &lcu->active_devices);
                return 0;
        }
-
        group = _find_group(lcu, &uid);
        if (!group) {
                group = kzalloc(sizeof(*group), GFP_ATOMIC);
@@ -397,130 +397,6 @@ suborder_not_supported(struct dasd_ccw_req *cqr)
        return 0;
 }
 
-/*
- * This function tries to lock all devices on an lcu via trylock
- * return NULL on success otherwise return first failed device
- */
-static struct dasd_device *_trylock_all_devices_on_lcu(struct alias_lcu *lcu,
-                                                     struct dasd_device *pos)
-
-{
-       struct alias_pav_group *pavgroup;
-       struct dasd_device *device;
-
-       list_for_each_entry(device, &lcu->active_devices, alias_list) {
-               if (device == pos)
-                       continue;
-               if (!spin_trylock(get_ccwdev_lock(device->cdev)))
-                       return device;
-       }
-       list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
-               if (device == pos)
-                       continue;
-               if (!spin_trylock(get_ccwdev_lock(device->cdev)))
-                       return device;
-       }
-       list_for_each_entry(pavgroup, &lcu->grouplist, group) {
-               list_for_each_entry(device, &pavgroup->baselist, alias_list) {
-                       if (device == pos)
-                               continue;
-                       if (!spin_trylock(get_ccwdev_lock(device->cdev)))
-                               return device;
-               }
-               list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
-                       if (device == pos)
-                               continue;
-                       if (!spin_trylock(get_ccwdev_lock(device->cdev)))
-                               return device;
-               }
-       }
-       return NULL;
-}
-
-/*
- * unlock all devices except the one that is specified as pos
- * stop if enddev is specified and reached
- */
-static void _unlock_all_devices_on_lcu(struct alias_lcu *lcu,
-                                      struct dasd_device *pos,
-                                      struct dasd_device *enddev)
-
-{
-       struct alias_pav_group *pavgroup;
-       struct dasd_device *device;
-
-       list_for_each_entry(device, &lcu->active_devices, alias_list) {
-               if (device == pos)
-                       continue;
-               if (device == enddev)
-                       return;
-               spin_unlock(get_ccwdev_lock(device->cdev));
-       }
-       list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
-               if (device == pos)
-                       continue;
-               if (device == enddev)
-                       return;
-               spin_unlock(get_ccwdev_lock(device->cdev));
-       }
-       list_for_each_entry(pavgroup, &lcu->grouplist, group) {
-               list_for_each_entry(device, &pavgroup->baselist, alias_list) {
-                       if (device == pos)
-                               continue;
-                       if (device == enddev)
-                               return;
-                       spin_unlock(get_ccwdev_lock(device->cdev));
-               }
-               list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
-                       if (device == pos)
-                               continue;
-                       if (device == enddev)
-                               return;
-                       spin_unlock(get_ccwdev_lock(device->cdev));
-               }
-       }
-}
-
-/*
- *  this function is needed because the locking order
- *  device lock -> lcu lock
- *  needs to be assured when iterating over devices in an LCU
- *
- *  if a device is specified in pos then the device lock is already hold
- */
-static void _trylock_and_lock_lcu_irqsave(struct alias_lcu *lcu,
-                                         struct dasd_device *pos,
-                                         unsigned long *flags)
-{
-       struct dasd_device *failed;
-
-       do {
-               spin_lock_irqsave(&lcu->lock, *flags);
-               failed = _trylock_all_devices_on_lcu(lcu, pos);
-               if (failed) {
-                       _unlock_all_devices_on_lcu(lcu, pos, failed);
-                       spin_unlock_irqrestore(&lcu->lock, *flags);
-                       cpu_relax();
-               }
-       } while (failed);
-}
-
-static void _trylock_and_lock_lcu(struct alias_lcu *lcu,
-                                 struct dasd_device *pos)
-{
-       struct dasd_device *failed;
-
-       do {
-               spin_lock(&lcu->lock);
-               failed = _trylock_all_devices_on_lcu(lcu, pos);
-               if (failed) {
-                       _unlock_all_devices_on_lcu(lcu, pos, failed);
-                       spin_unlock(&lcu->lock);
-                       cpu_relax();
-               }
-       } while (failed);
-}
-
 static int read_unit_address_configuration(struct dasd_device *device,
                                           struct alias_lcu *lcu)
 {
@@ -615,7 +491,7 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
        if (rc)
                return rc;
 
-       _trylock_and_lock_lcu_irqsave(lcu, NULL, &flags);
+       spin_lock_irqsave(&lcu->lock, flags);
        lcu->pav = NO_PAV;
        for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {
                switch (lcu->uac->unit[i].ua_type) {
@@ -634,7 +510,6 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
                                 alias_list) {
                _add_device_to_lcu(lcu, device, refdev);
        }
-       _unlock_all_devices_on_lcu(lcu, NULL, NULL);
        spin_unlock_irqrestore(&lcu->lock, flags);
        return 0;
 }
@@ -722,8 +597,7 @@ int dasd_alias_add_device(struct dasd_device *device)
 
        lcu = private->lcu;
        rc = 0;
-       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-       spin_lock(&lcu->lock);
+       spin_lock_irqsave(&lcu->lock, flags);
        if (!(lcu->flags & UPDATE_PENDING)) {
                rc = _add_device_to_lcu(lcu, device, device);
                if (rc)
@@ -733,8 +607,7 @@ int dasd_alias_add_device(struct dasd_device *device)
                list_move(&device->alias_list, &lcu->active_devices);
                _schedule_lcu_update(lcu, device);
        }
-       spin_unlock(&lcu->lock);
-       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       spin_unlock_irqrestore(&lcu->lock, flags);
        return rc;
 }
 
@@ -933,15 +806,27 @@ static void _stop_all_devices_on_lcu(struct alias_lcu *lcu)
        struct alias_pav_group *pavgroup;
        struct dasd_device *device;
 
-       list_for_each_entry(device, &lcu->active_devices, alias_list)
+       list_for_each_entry(device, &lcu->active_devices, alias_list) {
+               spin_lock(get_ccwdev_lock(device->cdev));
                dasd_device_set_stop_bits(device, DASD_STOPPED_SU);
-       list_for_each_entry(device, &lcu->inactive_devices, alias_list)
+               spin_unlock(get_ccwdev_lock(device->cdev));
+       }
+       list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+               spin_lock(get_ccwdev_lock(device->cdev));
                dasd_device_set_stop_bits(device, DASD_STOPPED_SU);
+               spin_unlock(get_ccwdev_lock(device->cdev));
+       }
        list_for_each_entry(pavgroup, &lcu->grouplist, group) {
-               list_for_each_entry(device, &pavgroup->baselist, alias_list)
+               list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+                       spin_lock(get_ccwdev_lock(device->cdev));
                        dasd_device_set_stop_bits(device, DASD_STOPPED_SU);
-               list_for_each_entry(device, &pavgroup->aliaslist, alias_list)
+                       spin_unlock(get_ccwdev_lock(device->cdev));
+               }
+               list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
+                       spin_lock(get_ccwdev_lock(device->cdev));
                        dasd_device_set_stop_bits(device, DASD_STOPPED_SU);
+                       spin_unlock(get_ccwdev_lock(device->cdev));
+               }
        }
 }
 
@@ -950,15 +835,27 @@ static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)
        struct alias_pav_group *pavgroup;
        struct dasd_device *device;
 
-       list_for_each_entry(device, &lcu->active_devices, alias_list)
+       list_for_each_entry(device, &lcu->active_devices, alias_list) {
+               spin_lock(get_ccwdev_lock(device->cdev));
                dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
-       list_for_each_entry(device, &lcu->inactive_devices, alias_list)
+               spin_unlock(get_ccwdev_lock(device->cdev));
+       }
+       list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+               spin_lock(get_ccwdev_lock(device->cdev));
                dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
+               spin_unlock(get_ccwdev_lock(device->cdev));
+       }
        list_for_each_entry(pavgroup, &lcu->grouplist, group) {
-               list_for_each_entry(device, &pavgroup->baselist, alias_list)
+               list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+                       spin_lock(get_ccwdev_lock(device->cdev));
                        dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
-               list_for_each_entry(device, &pavgroup->aliaslist, alias_list)
+                       spin_unlock(get_ccwdev_lock(device->cdev));
+               }
+               list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
+                       spin_lock(get_ccwdev_lock(device->cdev));
                        dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
+                       spin_unlock(get_ccwdev_lock(device->cdev));
+               }
        }
 }
 
@@ -984,48 +881,32 @@ static void summary_unit_check_handling_work(struct work_struct *work)
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
        reset_summary_unit_check(lcu, device, suc_data->reason);
 
-       _trylock_and_lock_lcu_irqsave(lcu, NULL, &flags);
+       spin_lock_irqsave(&lcu->lock, flags);
        _unstop_all_devices_on_lcu(lcu);
        _restart_all_base_devices_on_lcu(lcu);
        /* 3. read new alias configuration */
        _schedule_lcu_update(lcu, device);
        lcu->suc_data.device = NULL;
        dasd_put_device(device);
-       _unlock_all_devices_on_lcu(lcu, NULL, NULL);
        spin_unlock_irqrestore(&lcu->lock, flags);
 }
 
-/*
- * note: this will be called from int handler context (cdev locked)
- */
-void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
-                                         struct irb *irb)
+void dasd_alias_handle_summary_unit_check(struct work_struct *work)
 {
+       struct dasd_device *device = container_of(work, struct dasd_device,
+                                                 suc_work);
        struct dasd_eckd_private *private = device->private;
        struct alias_lcu *lcu;
-       char reason;
-       char *sense;
-
-       sense = dasd_get_sense(irb);
-       if (sense) {
-               reason = sense[8];
-               DBF_DEV_EVENT(DBF_NOTICE, device, "%s %x",
-                           "eckd handle summary unit check: reason", reason);
-       } else {
-               DBF_DEV_EVENT(DBF_WARNING, device, "%s",
-                           "eckd handle summary unit check:"
-                           " no reason code available");
-               return;
-       }
+       unsigned long flags;
 
        lcu = private->lcu;
        if (!lcu) {
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
                            "device not ready to handle summary"
                            " unit check (no lcu structure)");
-               return;
+               goto out;
        }
-       _trylock_and_lock_lcu(lcu, device);
+       spin_lock_irqsave(&lcu->lock, flags);
        /* If this device is about to be removed just return and wait for
         * the next interrupt on a different device
         */
@@ -1033,27 +914,26 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
                            "device is in offline processing,"
                            " don't do summary unit check handling");
-               _unlock_all_devices_on_lcu(lcu, device, NULL);
-               spin_unlock(&lcu->lock);
-               return;
+               goto out_unlock;
        }
        if (lcu->suc_data.device) {
                /* already scheduled or running */
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
                            "previous instance of summary unit check worker"
                            " still pending");
-               _unlock_all_devices_on_lcu(lcu, device, NULL);
-               spin_unlock(&lcu->lock);
-               return ;
+               goto out_unlock;
        }
        _stop_all_devices_on_lcu(lcu);
        /* prepare for lcu_update */
-       private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
-       lcu->suc_data.reason = reason;
+       lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
+       lcu->suc_data.reason = private->suc_reason;
        lcu->suc_data.device = device;
        dasd_get_device(device);
-       _unlock_all_devices_on_lcu(lcu, device, NULL);
-       spin_unlock(&lcu->lock);
        if (!schedule_work(&lcu->suc_data.worker))
                dasd_put_device(device);
+out_unlock:
+       spin_unlock_irqrestore(&lcu->lock, flags);
+out:
+       clear_bit(DASD_FLAG_SUC, &device->flags);
+       dasd_put_device(device);
 };
index 75c032d..c1b4ae5 100644 (file)
@@ -1682,6 +1682,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 
        /* setup work queue for validate server*/
        INIT_WORK(&device->kick_validate, dasd_eckd_do_validate_server);
+       /* setup work queue for summary unit check */
+       INIT_WORK(&device->suc_work, dasd_alias_handle_summary_unit_check);
 
        if (!ccw_device_is_pathgroup(device->cdev)) {
                dev_warn(&device->cdev->dev,
@@ -2549,14 +2551,6 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
                    device->state == DASD_STATE_ONLINE &&
                    !test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
                    !test_bit(DASD_FLAG_SUSPENDED, &device->flags)) {
-                       /*
-                        * the state change could be caused by an alias
-                        * reassignment remove device from alias handling
-                        * to prevent new requests from being scheduled on
-                        * the wrong alias device
-                        */
-                       dasd_alias_remove_device(device);
-
                        /* schedule worker to reload device */
                        dasd_reload_device(device);
                }
@@ -2571,7 +2565,27 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
        /* summary unit check */
        if ((sense[27] & DASD_SENSE_BIT_0) && (sense[7] == 0x0D) &&
            (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
-               dasd_alias_handle_summary_unit_check(device, irb);
+               if (test_and_set_bit(DASD_FLAG_SUC, &device->flags)) {
+                       DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+                                     "eckd suc: device already notified");
+                       return;
+               }
+               sense = dasd_get_sense(irb);
+               if (!sense) {
+                       DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+                                     "eckd suc: no reason code available");
+                       clear_bit(DASD_FLAG_SUC, &device->flags);
+                       return;
+
+               }
+               private->suc_reason = sense[8];
+               DBF_DEV_EVENT(DBF_NOTICE, device, "%s %x",
+                             "eckd handle summary unit check: reason",
+                             private->suc_reason);
+               dasd_get_device(device);
+               if (!schedule_work(&device->suc_work))
+                       dasd_put_device(device);
+
                return;
        }
 
@@ -4495,6 +4509,12 @@ static int dasd_eckd_reload_device(struct dasd_device *device)
        struct dasd_uid uid;
        unsigned long flags;
 
+       /*
+        * remove device from alias handling to prevent new requests
+        * from being scheduled on the wrong alias device
+        */
+       dasd_alias_remove_device(device);
+
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
        old_base = private->uid.base_unit_addr;
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
index f8f91ee..6d9a6d3 100644 (file)
@@ -525,6 +525,7 @@ struct dasd_eckd_private {
        int count;
 
        u32 fcx_max_data;
+       char suc_reason;
 };
 
 
@@ -534,7 +535,7 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *);
 int dasd_alias_add_device(struct dasd_device *);
 int dasd_alias_remove_device(struct dasd_device *);
 struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
-void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
+void dasd_alias_handle_summary_unit_check(struct work_struct *);
 void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
 void dasd_alias_lcu_setup_complete(struct dasd_device *);
 void dasd_alias_wait_for_lcu_setup(struct dasd_device *);
index 8de29be..0f0add9 100644 (file)
@@ -470,6 +470,7 @@ struct dasd_device {
        struct work_struct restore_device;
        struct work_struct reload_device;
        struct work_struct kick_validate;
+       struct work_struct suc_work;
        struct timer_list timer;
 
        debug_info_t *debug_area;
@@ -542,6 +543,7 @@ struct dasd_attention_data {
 #define DASD_FLAG_SAFE_OFFLINE_RUNNING 11      /* safe offline running */
 #define DASD_FLAG_ABORTALL     12      /* Abort all noretry requests */
 #define DASD_FLAG_PATH_VERIFY  13      /* Path verification worker running */
+#define DASD_FLAG_SUC          14      /* unhandled summary unit check */
 
 #define DASD_SLEEPON_START_TAG ((void *) 1)
 #define DASD_SLEEPON_END_TAG   ((void *) 2)
index 5bcdf8d..a404a41 100644 (file)
@@ -332,7 +332,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
 {
        int rel_port = -1, group_id;
        struct alua_port_group *pg, *old_pg = NULL;
-       bool pg_updated;
+       bool pg_updated = false;
        unsigned long flags;
 
        group_id = scsi_vpd_tpg_id(sdev, &rel_port);
index 266b909..f3032ca 100644 (file)
@@ -958,23 +958,22 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic,
        case FCPIO_INVALID_PARAM:    /* some parameter in request invalid */
        case FCPIO_REQ_NOT_SUPPORTED:/* request type is not supported */
        default:
-               shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n",
-                            fnic_fcpio_status_to_str(hdr_status));
                sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status;
                break;
        }
 
-       if (hdr_status != FCPIO_SUCCESS) {
-               atomic64_inc(&fnic_stats->io_stats.io_failures);
-               shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n",
-                            fnic_fcpio_status_to_str(hdr_status));
-       }
        /* Break link with the SCSI command */
        CMD_SP(sc) = NULL;
        CMD_FLAGS(sc) |= FNIC_IO_DONE;
 
        spin_unlock_irqrestore(io_lock, flags);
 
+       if (hdr_status != FCPIO_SUCCESS) {
+               atomic64_inc(&fnic_stats->io_stats.io_failures);
+               shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n",
+                            fnic_fcpio_status_to_str(hdr_status));
+       }
+
        fnic_release_ioreq_buf(fnic, io_req, sc);
 
        mempool_free(io_req, fnic->io_req_pool);
index a544366..f57d02c 100644 (file)
@@ -2860,7 +2860,7 @@ lpfc_online(struct lpfc_hba *phba)
        }
 
        vports = lpfc_create_vport_work_array(phba);
-       if (vports != NULL)
+       if (vports != NULL) {
                for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        struct Scsi_Host *shost;
                        shost = lpfc_shost_from_vport(vports[i]);
@@ -2877,7 +2877,8 @@ lpfc_online(struct lpfc_hba *phba)
                        }
                        spin_unlock_irq(shost->host_lock);
                }
-               lpfc_destroy_vport_work_array(phba, vports);
+       }
+       lpfc_destroy_vport_work_array(phba, vports);
 
        lpfc_unblock_mgmt_io(phba);
        return 0;
index 4484e63..fce414a 100644 (file)
@@ -2097,7 +2097,7 @@ struct megasas_instance {
        u8 UnevenSpanSupport;
 
        u8 supportmax256vd;
-       u8 allow_fw_scan;
+       u8 pd_list_not_supported;
        u16 fw_supported_vd_count;
        u16 fw_supported_pd_count;
 
index 5c08568..e6ebc7a 100644 (file)
@@ -1838,7 +1838,7 @@ static int megasas_slave_configure(struct scsi_device *sdev)
        struct megasas_instance *instance;
 
        instance = megasas_lookup_instance(sdev->host->host_no);
-       if (instance->allow_fw_scan) {
+       if (instance->pd_list_not_supported) {
                if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
                        sdev->type == TYPE_DISK) {
                        pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
@@ -1874,7 +1874,8 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
                pd_index =
                        (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
                        sdev->id;
-               if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState ==
+               if ((instance->pd_list_not_supported ||
+                       instance->pd_list[pd_index].driveState ==
                        MR_PD_STATE_SYSTEM)) {
                        goto scan_target;
                }
@@ -4087,7 +4088,13 @@ megasas_get_pd_list(struct megasas_instance *instance)
 
        switch (ret) {
        case DCMD_FAILED:
-               megaraid_sas_kill_hba(instance);
+               dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
+                       "failed/not supported by firmware\n");
+
+               if (instance->ctrl_context)
+                       megaraid_sas_kill_hba(instance);
+               else
+                       instance->pd_list_not_supported = 1;
                break;
        case DCMD_TIMEOUT:
 
@@ -5034,7 +5041,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
        case PCI_DEVICE_ID_DELL_PERC5:
        default:
                instance->instancet = &megasas_instance_template_xscale;
-               instance->allow_fw_scan = 1;
                break;
        }
 
@@ -6650,12 +6656,13 @@ out:
        }
 
        for (i = 0; i < ioc->sge_count; i++) {
-               if (kbuff_arr[i])
+               if (kbuff_arr[i]) {
                        dma_free_coherent(&instance->pdev->dev,
                                          le32_to_cpu(kern_sge32[i].length),
                                          kbuff_arr[i],
                                          le32_to_cpu(kern_sge32[i].phys_addr));
                        kbuff_arr[i] = NULL;
+               }
        }
 
        megasas_return_cmd(instance, cmd);
index 9852319..8a44d15 100644 (file)
@@ -1881,15 +1881,17 @@ static int qlt_check_reserve_free_req(struct scsi_qla_host *vha,
                else
                        vha->req->cnt = vha->req->length -
                            (vha->req->ring_index - cnt);
-       }
 
-       if (unlikely(vha->req->cnt < (req_cnt + 2))) {
-               ql_dbg(ql_dbg_io, vha, 0x305a,
-                   "qla_target(%d): There is no room in the request ring: vha->req->ring_index=%d, vha->req->cnt=%d, req_cnt=%d Req-out=%d Req-in=%d Req-Length=%d\n",
-                   vha->vp_idx, vha->req->ring_index,
-                   vha->req->cnt, req_cnt, cnt, cnt_in, vha->req->length);
-               return -EAGAIN;
+               if (unlikely(vha->req->cnt < (req_cnt + 2))) {
+                       ql_dbg(ql_dbg_io, vha, 0x305a,
+                           "qla_target(%d): There is no room in the request ring: vha->req->ring_index=%d, vha->req->cnt=%d, req_cnt=%d Req-out=%d Req-in=%d Req-Length=%d\n",
+                           vha->vp_idx, vha->req->ring_index,
+                           vha->req->cnt, req_cnt, cnt, cnt_in,
+                           vha->req->length);
+                       return -EAGAIN;
+               }
        }
+
        vha->req->cnt -= req_cnt;
 
        return 0;
index c126966..ce79de8 100644 (file)
@@ -278,8 +278,16 @@ int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
                ucp[3] = 0;
                put_unaligned_be64(info, &ucp[4]);
        } else if ((buf[0] & 0x7f) == 0x70) {
-               buf[0] |= 0x80;
-               put_unaligned_be64(info, &buf[3]);
+               /*
+                * Only set the 'VALID' bit if we can represent the value
+                * correctly; otherwise just fill out the lower bytes and
+                * clear the 'VALID' flag.
+                */
+               if (info <= 0xffffffffUL)
+                       buf[0] |= 0x80;
+               else
+                       buf[0] &= 0x7f;
+               put_unaligned_be32((u32)info, &buf[3]);
        }
 
        return 0;
index 6266a5d..e659912 100644 (file)
@@ -4,7 +4,7 @@
 #define SAS_HOST_ATTRS         0
 #define SAS_PHY_ATTRS          17
 #define SAS_PORT_ATTRS         1
-#define SAS_RPORT_ATTRS                7
+#define SAS_RPORT_ATTRS                8
 #define SAS_END_DEV_ATTRS      5
 #define SAS_EXPANDER_ATTRS     7
 
index d164419..92ffd24 100644 (file)
@@ -1105,7 +1105,7 @@ static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj,
        if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80)
                return 0;
 
-       if (attr == &dev_attr_vpd_pg83 && sdev->vpd_pg83)
+       if (attr == &dev_attr_vpd_pg83 && !sdev->vpd_pg83)
                return 0;
 
        return S_IRUGO;
index 80520e2..b6f9581 100644 (file)
@@ -1286,6 +1286,7 @@ sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
 sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
                unsigned long long);
 sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
+sas_rphy_simple_attr(scsi_target_id, scsi_target_id, "%d\n", u32);
 
 /* only need 8 bytes of data plus header (4 or 8) */
 #define BUF_SIZE 64
@@ -1886,6 +1887,7 @@ sas_attach_transport(struct sas_function_template *ft)
        SETUP_RPORT_ATTRIBUTE(rphy_device_type);
        SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
        SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
+       SETUP_RPORT_ATTRIBUTE(rphy_scsi_target_id);
        SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,
                                       get_enclosure_identifier);
        SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,
index 5f45307..097894a 100644 (file)
@@ -37,6 +37,7 @@ config SCSI_UFSHCD
        depends on SCSI && SCSI_DMA
        select PM_DEVFREQ
        select DEVFREQ_GOV_SIMPLE_ONDEMAND
+       select NLS
        ---help---
        This selects the support for UFS devices in Linux, say Y and make
          sure that you know the name of your UFS host adapter (the card
index 4f38d00..3aedf73 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,8 +16,8 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
-
 #include <linux/phy/phy-qcom-ufs.h>
+
 #include "ufshcd.h"
 #include "ufshcd-pltfrm.h"
 #include "unipro.h"
@@ -58,6 +58,12 @@ static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len,
                        len * 4, false);
 }
 
+static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len,
+               char *prefix, void *priv)
+{
+       ufs_qcom_dump_regs(hba, offset, len, prefix);
+}
+
 static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
 {
        int err = 0;
@@ -106,9 +112,11 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
        if (!host->is_lane_clks_enabled)
                return;
 
-       clk_disable_unprepare(host->tx_l1_sync_clk);
+       if (host->hba->lanes_per_direction > 1)
+               clk_disable_unprepare(host->tx_l1_sync_clk);
        clk_disable_unprepare(host->tx_l0_sync_clk);
-       clk_disable_unprepare(host->rx_l1_sync_clk);
+       if (host->hba->lanes_per_direction > 1)
+               clk_disable_unprepare(host->rx_l1_sync_clk);
        clk_disable_unprepare(host->rx_l0_sync_clk);
 
        host->is_lane_clks_enabled = false;
@@ -132,21 +140,24 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
        if (err)
                goto disable_rx_l0;
 
-       err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
-               host->rx_l1_sync_clk);
-       if (err)
-               goto disable_tx_l0;
+       if (host->hba->lanes_per_direction > 1) {
+               err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
+                       host->rx_l1_sync_clk);
+               if (err)
+                       goto disable_tx_l0;
 
-       err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
-               host->tx_l1_sync_clk);
-       if (err)
-               goto disable_rx_l1;
+               err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+                       host->tx_l1_sync_clk);
+               if (err)
+                       goto disable_rx_l1;
+       }
 
        host->is_lane_clks_enabled = true;
        goto out;
 
 disable_rx_l1:
-       clk_disable_unprepare(host->rx_l1_sync_clk);
+       if (host->hba->lanes_per_direction > 1)
+               clk_disable_unprepare(host->rx_l1_sync_clk);
 disable_tx_l0:
        clk_disable_unprepare(host->tx_l0_sync_clk);
 disable_rx_l0:
@@ -170,14 +181,16 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
        if (err)
                goto out;
 
-       err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
-               &host->rx_l1_sync_clk);
-       if (err)
-               goto out;
-
-       err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
-               &host->tx_l1_sync_clk);
+       /* In case of single lane per direction, don't read lane1 clocks */
+       if (host->hba->lanes_per_direction > 1) {
+               err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
+                       &host->rx_l1_sync_clk);
+               if (err)
+                       goto out;
 
+               err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
+                       &host->tx_l1_sync_clk);
+       }
 out:
        return err;
 }
@@ -267,9 +280,8 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
        ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B);
 
        if (ret) {
-               dev_err(hba->dev,
-               "%s: ufs_qcom_phy_calibrate_phy()failed, ret = %d\n",
-               __func__, ret);
+               dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n",
+                       __func__, ret);
                goto out;
        }
 
@@ -519,6 +531,18 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
                        err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba,
                                                                          150);
 
+               /*
+                * Some UFS devices (and may be host) have issues if LCC is
+                * enabled. So we are setting PA_Local_TX_LCC_Enable to 0
+                * before link startup which will make sure that both host
+                * and device TX LCC are disabled once link startup is
+                * completed.
+                */
+               if (ufshcd_get_local_unipro_ver(hba) != UFS_UNIPRO_VER_1_41)
+                       err = ufshcd_dme_set(hba,
+                                       UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE),
+                                       0);
+
                break;
        case POST_CHANGE:
                ufs_qcom_link_startup_post_change(hba);
@@ -962,6 +986,10 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
                        goto out;
                }
 
+               /* enable the device ref clock before changing to HS mode */
+               if (!ufshcd_is_hs_mode(&hba->pwr_info) &&
+                       ufshcd_is_hs_mode(dev_req_params))
+                       ufs_qcom_dev_ref_clk_ctrl(host, true);
                break;
        case POST_CHANGE:
                if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
@@ -989,6 +1017,11 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
                memcpy(&host->dev_req_params,
                                dev_req_params, sizeof(*dev_req_params));
                ufs_qcom_update_bus_bw_vote(host);
+
+               /* disable the device ref clock if entered PWM mode */
+               if (ufshcd_is_hs_mode(&hba->pwr_info) &&
+                       !ufshcd_is_hs_mode(dev_req_params))
+                       ufs_qcom_dev_ref_clk_ctrl(host, false);
                break;
        default:
                ret = -EINVAL;
@@ -1090,6 +1123,9 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
                        ufs_qcom_phy_disable_iface_clk(host->generic_phy);
                        goto out;
                }
+               /* enable the device ref clock for HS mode*/
+               if (ufshcd_is_hs_mode(&hba->pwr_info))
+                       ufs_qcom_dev_ref_clk_ctrl(host, true);
                vote = host->bus_vote.saved_vote;
                if (vote == host->bus_vote.min_bw_vote)
                        ufs_qcom_update_bus_bw_vote(host);
@@ -1367,6 +1403,74 @@ out:
        return err;
 }
 
+static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba,
+               void *priv, void (*print_fn)(struct ufs_hba *hba,
+               int offset, int num_regs, char *str, void *priv))
+{
+       u32 reg;
+       struct ufs_qcom_host *host;
+
+       if (unlikely(!hba)) {
+               pr_err("%s: hba is NULL\n", __func__);
+               return;
+       }
+       if (unlikely(!print_fn)) {
+               dev_err(hba->dev, "%s: print_fn is NULL\n", __func__);
+               return;
+       }
+
+       host = ufshcd_get_variant(hba);
+       if (!(host->dbg_print_en & UFS_QCOM_DBG_PRINT_REGS_EN))
+               return;
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_REG_OCSC);
+       print_fn(hba, reg, 44, "UFS_UFS_DBG_RD_REG_OCSC ", priv);
+
+       reg = ufshcd_readl(hba, REG_UFS_CFG1);
+       reg |= UFS_BIT(17);
+       ufshcd_writel(hba, reg, REG_UFS_CFG1);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_EDTL_RAM);
+       print_fn(hba, reg, 32, "UFS_UFS_DBG_RD_EDTL_RAM ", priv);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_DESC_RAM);
+       print_fn(hba, reg, 128, "UFS_UFS_DBG_RD_DESC_RAM ", priv);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM);
+       print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv);
+
+       ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM);
+       print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UARM);
+       print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UARM ", priv);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TXUC);
+       print_fn(hba, reg, 48, "UFS_DBG_RD_REG_TXUC ", priv);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_RXUC);
+       print_fn(hba, reg, 27, "UFS_DBG_RD_REG_RXUC ", priv);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_DFC);
+       print_fn(hba, reg, 19, "UFS_DBG_RD_REG_DFC ", priv);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TRLUT);
+       print_fn(hba, reg, 34, "UFS_DBG_RD_REG_TRLUT ", priv);
+
+       reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TMRLUT);
+       print_fn(hba, reg, 9, "UFS_DBG_RD_REG_TMRLUT ", priv);
+}
+
+static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
+{
+       if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+               ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
+       else
+               ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+}
+
 static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
 {
        /* provide a legal default configuration */
@@ -1475,6 +1579,7 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
        ufshcd_rmwl(host->hba, mask,
                    (u32)host->testbus.select_minor << offset,
                    reg);
+       ufs_qcom_enable_test_bus(host);
        ufshcd_release(host->hba);
        pm_runtime_put_sync(host->hba->dev);
 
@@ -1491,8 +1596,10 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
        ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
                        "HCI Vendor Specific Registers ");
 
+       ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
        ufs_qcom_testbus_read(hba);
 }
+
 /**
  * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
  *
@@ -1537,7 +1644,7 @@ static int ufs_qcom_probe(struct platform_device *pdev)
  * ufs_qcom_remove - set driver_data of the device to NULL
  * @pdev: pointer to platform device handle
  *
- * Always return 0
+ * Always returns 0
  */
 static int ufs_qcom_remove(struct platform_device *pdev)
 {
index 36249b3..a19307a 100644 (file)
@@ -241,6 +241,15 @@ struct ufs_qcom_host {
        struct ufs_qcom_testbus testbus;
 };
 
+static inline u32
+ufs_qcom_get_debug_reg_offset(struct ufs_qcom_host *host, u32 reg)
+{
+       if (host->hw_ver.major <= 0x02)
+               return UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(reg);
+
+       return UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(reg);
+};
+
 #define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
 #define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
 #define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
index 54a16ce..b291fa6 100644 (file)
@@ -43,6 +43,7 @@
 #define GENERAL_UPIU_REQUEST_SIZE 32
 #define QUERY_DESC_MAX_SIZE       255
 #define QUERY_DESC_MIN_SIZE       2
+#define QUERY_DESC_HDR_SIZE       2
 #define QUERY_OSF_SIZE            (GENERAL_UPIU_REQUEST_SIZE - \
                                        (sizeof(struct utp_upiu_header)))
 
@@ -195,6 +196,37 @@ enum unit_desc_param {
        UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1      = 0x22,
 };
 
+/* Device descriptor parameters offsets in bytes*/
+enum device_desc_param {
+       DEVICE_DESC_PARAM_LEN                   = 0x0,
+       DEVICE_DESC_PARAM_TYPE                  = 0x1,
+       DEVICE_DESC_PARAM_DEVICE_TYPE           = 0x2,
+       DEVICE_DESC_PARAM_DEVICE_CLASS          = 0x3,
+       DEVICE_DESC_PARAM_DEVICE_SUB_CLASS      = 0x4,
+       DEVICE_DESC_PARAM_PRTCL                 = 0x5,
+       DEVICE_DESC_PARAM_NUM_LU                = 0x6,
+       DEVICE_DESC_PARAM_NUM_WLU               = 0x7,
+       DEVICE_DESC_PARAM_BOOT_ENBL             = 0x8,
+       DEVICE_DESC_PARAM_DESC_ACCSS_ENBL       = 0x9,
+       DEVICE_DESC_PARAM_INIT_PWR_MODE         = 0xA,
+       DEVICE_DESC_PARAM_HIGH_PR_LUN           = 0xB,
+       DEVICE_DESC_PARAM_SEC_RMV_TYPE          = 0xC,
+       DEVICE_DESC_PARAM_SEC_LU                = 0xD,
+       DEVICE_DESC_PARAM_BKOP_TERM_LT          = 0xE,
+       DEVICE_DESC_PARAM_ACTVE_ICC_LVL         = 0xF,
+       DEVICE_DESC_PARAM_SPEC_VER              = 0x10,
+       DEVICE_DESC_PARAM_MANF_DATE             = 0x12,
+       DEVICE_DESC_PARAM_MANF_NAME             = 0x14,
+       DEVICE_DESC_PARAM_PRDCT_NAME            = 0x15,
+       DEVICE_DESC_PARAM_SN                    = 0x16,
+       DEVICE_DESC_PARAM_OEM_ID                = 0x17,
+       DEVICE_DESC_PARAM_MANF_ID               = 0x18,
+       DEVICE_DESC_PARAM_UD_OFFSET             = 0x1A,
+       DEVICE_DESC_PARAM_UD_LEN                = 0x1B,
+       DEVICE_DESC_PARAM_RTT_CAP               = 0x1C,
+       DEVICE_DESC_PARAM_FRQ_RTC               = 0x1D,
+};
+
 /*
  * Logical Unit Write Protect
  * 00h: LU not write protected
@@ -469,6 +501,7 @@ struct ufs_vreg {
        struct regulator *reg;
        const char *name;
        bool enabled;
+       bool unused;
        int min_uV;
        int max_uV;
        int min_uA;
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
new file mode 100644 (file)
index 0000000..ee4ab85
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _UFS_QUIRKS_H_
+#define _UFS_QUIRKS_H_
+
+/* return true if s1 is a prefix of s2 */
+#define STR_PRFX_EQUAL(s1, s2) !strncmp(s1, s2, strlen(s1))
+
+#define UFS_ANY_VENDOR 0xFFFF
+#define UFS_ANY_MODEL  "ANY_MODEL"
+
+#define MAX_MODEL_LEN 16
+
+#define UFS_VENDOR_TOSHIBA     0x198
+#define UFS_VENDOR_SAMSUNG     0x1CE
+
+/**
+ * ufs_device_info - ufs device details
+ * @wmanufacturerid: card details
+ * @model: card model
+ */
+struct ufs_device_info {
+       u16 wmanufacturerid;
+       char model[MAX_MODEL_LEN + 1];
+};
+
+/**
+ * ufs_dev_fix - ufs device quirk info
+ * @card: ufs card details
+ * @quirk: device quirk
+ */
+struct ufs_dev_fix {
+       struct ufs_device_info card;
+       unsigned int quirk;
+};
+
+#define END_FIX { { 0 }, 0 }
+
+/* add specific device quirk */
+#define UFS_FIX(_vendor, _model, _quirk) \
+               {                                         \
+                       .card.wmanufacturerid = (_vendor),\
+                       .card.model = (_model),           \
+                       .quirk = (_quirk),                \
+               }
+
+/*
+ * If UFS device is having issue in processing LCC (Line Control
+ * Command) coming from UFS host controller then enable this quirk.
+ * When this quirk is enabled, host controller driver should disable
+ * the LCC transmission on UFS host controller (by clearing
+ * TX_LCC_ENABLE attribute of host to 0).
+ */
+#define UFS_DEVICE_QUIRK_BROKEN_LCC (1 << 0)
+
+/*
+ * Some UFS devices don't need VCCQ rail for device operations. Enabling this
+ * quirk for such devices will make sure that VCCQ rail is not voted.
+ */
+#define UFS_DEVICE_NO_VCCQ (1 << 1)
+
+/*
+ * Some vendor's UFS device sends back to back NACs for the DL data frames
+ * causing the host controller to raise the DFES error status. Sometimes
+ * such UFS devices send back to back NAC without waiting for new
+ * retransmitted DL frame from the host and in such cases it might be possible
+ * the Host UniPro goes into bad state without raising the DFES error
+ * interrupt. If this happens then all the pending commands would timeout
+ * only after respective SW command (which is generally too large).
+ *
+ * We can workaround such device behaviour like this:
+ * - As soon as SW sees the DL NAC error, it should schedule the error handler
+ * - Error handler would sleep for 50ms to see if there are any fatal errors
+ *   raised by UFS controller.
+ *    - If there are fatal errors then SW does normal error recovery.
+ *    - If there are no fatal errors then SW sends the NOP command to device
+ *      to check if link is alive.
+ *        - If NOP command times out, SW does normal error recovery
+ *        - If NOP command succeed, skip the error handling.
+ *
+ * If DL NAC error is seen multiple times with some vendor's UFS devices then
+ * enable this quirk to initiate quick error recovery and also silence related
+ * error logs to reduce spamming of kernel logs.
+ */
+#define UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS (1 << 2)
+
+/*
+ * Some UFS devices may not work properly after resume if the link was kept
+ * in off state during suspend. Enabling this quirk will not allow the
+ * link to be kept in off state during suspend.
+ */
+#define UFS_DEVICE_QUIRK_NO_LINK_OFF   (1 << 3)
+
+/*
+ * Few Toshiba UFS device models advertise RX_MIN_ACTIVATETIME_CAPABILITY as
+ * 600us which may not be enough for reliable hibern8 exit hardware sequence
+ * from UFS device.
+ * To workaround this issue, host should set its PA_TACTIVATE time to 1ms even
+ * if device advertises RX_MIN_ACTIVATETIME_CAPABILITY less than 1ms.
+ */
+#define UFS_DEVICE_QUIRK_PA_TACTIVATE  (1 << 4)
+
+/*
+ * Some UFS memory devices may have really low read/write throughput in
+ * FAST AUTO mode, enable this quirk to make sure that FAST AUTO mode is
+ * never enabled for such devices.
+ */
+#define UFS_DEVICE_NO_FASTAUTO         (1 << 5)
+
+/*
+ * It seems some UFS devices may keep drawing more than sleep current
+ * (atleast for 500us) from UFS rails (especially from VCCQ rail).
+ * To avoid this situation, add 2ms delay before putting these UFS
+ * rails in LPM mode.
+ */
+#define UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM      (1 << 6)
+
+struct ufs_hba;
+void ufs_advertise_fixup_device(struct ufs_hba *hba);
+
+static struct ufs_dev_fix ufs_fixups[] = {
+       /* UFS cards deviations table */
+       UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
+               UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
+       UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
+       UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
+               UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
+       UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
+               UFS_DEVICE_NO_FASTAUTO),
+       UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL,
+               UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
+       UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
+               UFS_DEVICE_QUIRK_PA_TACTIVATE),
+       UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG",
+               UFS_DEVICE_QUIRK_PA_TACTIVATE),
+
+       END_FIX
+};
+#endif /* UFS_QUIRKS_H_ */
index d2a7b12..718f12e 100644 (file)
@@ -40,6 +40,8 @@
 #include "ufshcd.h"
 #include "ufshcd-pltfrm.h"
 
+#define UFSHCD_DEFAULT_LANES_PER_DIRECTION             2
+
 static int ufshcd_parse_clock_info(struct ufs_hba *hba)
 {
        int ret = 0;
@@ -277,6 +279,21 @@ void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(ufshcd_pltfrm_shutdown);
 
+static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
+{
+       struct device *dev = hba->dev;
+       int ret;
+
+       ret = of_property_read_u32(dev->of_node, "lanes-per-direction",
+               &hba->lanes_per_direction);
+       if (ret) {
+               dev_dbg(hba->dev,
+                       "%s: failed to read lanes-per-direction, ret=%d\n",
+                       __func__, ret);
+               hba->lanes_per_direction = UFSHCD_DEFAULT_LANES_PER_DIRECTION;
+       }
+}
+
 /**
  * ufshcd_pltfrm_init - probe routine of the driver
  * @pdev: pointer to Platform device handle
@@ -331,6 +348,8 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
+       ufshcd_init_lanes_per_dir(hba);
+
        err = ufshcd_init(hba, mmio_base, irq);
        if (err) {
                dev_err(dev, "Initialization failed\n");
index 9c1b94b..f8fa72c 100644 (file)
 
 #include <linux/async.h>
 #include <linux/devfreq.h>
-
+#include <linux/nls.h>
+#include <linux/of.h>
 #include "ufshcd.h"
+#include "ufs_quirks.h"
 #include "unipro.h"
 
 #define UFSHCD_ENABLE_INTRS    (UTP_TRANSFER_REQ_COMPL |\
@@ -131,9 +133,11 @@ enum {
 /* UFSHCD UIC layer error flags */
 enum {
        UFSHCD_UIC_DL_PA_INIT_ERROR = (1 << 0), /* Data link layer error */
-       UFSHCD_UIC_NL_ERROR = (1 << 1), /* Network layer error */
-       UFSHCD_UIC_TL_ERROR = (1 << 2), /* Transport Layer error */
-       UFSHCD_UIC_DME_ERROR = (1 << 3), /* DME error */
+       UFSHCD_UIC_DL_NAC_RECEIVED_ERROR = (1 << 1), /* Data link layer error */
+       UFSHCD_UIC_DL_TCx_REPLAY_ERROR = (1 << 2), /* Data link layer error */
+       UFSHCD_UIC_NL_ERROR = (1 << 3), /* Network layer error */
+       UFSHCD_UIC_TL_ERROR = (1 << 4), /* Transport Layer error */
+       UFSHCD_UIC_DME_ERROR = (1 << 5), /* DME error */
 };
 
 /* Interrupt configuration options */
@@ -193,6 +197,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba);
 static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
                                 bool skip_ref_clk);
 static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
+static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused);
 static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
 static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
 static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
@@ -231,6 +236,16 @@ static inline void ufshcd_disable_irq(struct ufs_hba *hba)
        }
 }
 
+/* replace non-printable or non-ASCII characters with spaces */
+static inline void ufshcd_remove_non_printable(char *val)
+{
+       if (!val)
+               return;
+
+       if (*val < 0x20 || *val > 0x7e)
+               *val = ' ';
+}
+
 /*
  * ufshcd_wait_for_register - wait for register value to change
  * @hba - per-adapter interface
@@ -239,11 +254,13 @@ static inline void ufshcd_disable_irq(struct ufs_hba *hba)
  * @val - wait condition
  * @interval_us - polling interval in microsecs
  * @timeout_ms - timeout in millisecs
+ * @can_sleep - perform sleep or just spin
  *
  * Returns -ETIMEDOUT on error, zero on success
  */
-static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
-               u32 val, unsigned long interval_us, unsigned long timeout_ms)
+int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+                               u32 val, unsigned long interval_us,
+                               unsigned long timeout_ms, bool can_sleep)
 {
        int err = 0;
        unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
@@ -252,9 +269,10 @@ static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
        val = val & mask;
 
        while ((ufshcd_readl(hba, reg) & mask) != val) {
-               /* wakeup within 50us of expiry */
-               usleep_range(interval_us, interval_us + 50);
-
+               if (can_sleep)
+                       usleep_range(interval_us, interval_us + 50);
+               else
+                       udelay(interval_us);
                if (time_after(jiffies, timeout)) {
                        if ((ufshcd_readl(hba, reg) & mask) != val)
                                err = -ETIMEDOUT;
@@ -552,6 +570,34 @@ static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
        return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
 }
 
+u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)
+{
+       /* HCI version 1.0 and 1.1 supports UniPro 1.41 */
+       if ((hba->ufs_version == UFSHCI_VERSION_10) ||
+           (hba->ufs_version == UFSHCI_VERSION_11))
+               return UFS_UNIPRO_VER_1_41;
+       else
+               return UFS_UNIPRO_VER_1_6;
+}
+EXPORT_SYMBOL(ufshcd_get_local_unipro_ver);
+
+static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
+{
+       /*
+        * If both host and device support UniPro ver1.6 or later, PA layer
+        * parameters tuning happens during link startup itself.
+        *
+        * We can manually tune PA layer parameters if either host or device
+        * doesn't support UniPro ver 1.6 or later. But to keep manual tuning
+        * logic simple, we will only do manual tuning if local unipro version
+        * doesn't support ver1.6 or later.
+        */
+       if (ufshcd_get_local_unipro_ver(hba) < UFS_UNIPRO_VER_1_6)
+               return true;
+       else
+               return false;
+}
+
 static void ufshcd_ungate_work(struct work_struct *work)
 {
        int ret;
@@ -1458,7 +1504,7 @@ ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
         */
        err = ufshcd_wait_for_register(hba,
                        REG_UTP_TRANSFER_REQ_DOOR_BELL,
-                       mask, ~mask, 1000, 1000);
+                       mask, ~mask, 1000, 1000, true);
 
        return err;
 }
@@ -1857,21 +1903,7 @@ static int ufshcd_query_attr_retry(struct ufs_hba *hba,
        return ret;
 }
 
-/**
- * ufshcd_query_descriptor - API function for sending descriptor requests
- * hba: per-adapter instance
- * opcode: attribute opcode
- * idn: attribute idn to access
- * index: index field
- * selector: selector field
- * desc_buf: the buffer that contains the descriptor
- * buf_len: length parameter passed to the device
- *
- * Returns 0 for success, non-zero in case of failure.
- * The buf_len parameter will contain, on return, the length parameter
- * received on the response.
- */
-static int ufshcd_query_descriptor(struct ufs_hba *hba,
+static int __ufshcd_query_descriptor(struct ufs_hba *hba,
                        enum query_opcode opcode, enum desc_idn idn, u8 index,
                        u8 selector, u8 *desc_buf, int *buf_len)
 {
@@ -1935,6 +1967,39 @@ out:
        return err;
 }
 
+/**
+ * ufshcd_query_descriptor_retry - API function for sending descriptor
+ * requests
+ * hba: per-adapter instance
+ * opcode: attribute opcode
+ * idn: attribute idn to access
+ * index: index field
+ * selector: selector field
+ * desc_buf: the buffer that contains the descriptor
+ * buf_len: length parameter passed to the device
+ *
+ * Returns 0 for success, non-zero in case of failure.
+ * The buf_len parameter will contain, on return, the length parameter
+ * received on the response.
+ */
+int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
+                       enum query_opcode opcode, enum desc_idn idn, u8 index,
+                       u8 selector, u8 *desc_buf, int *buf_len)
+{
+       int err;
+       int retries;
+
+       for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+               err = __ufshcd_query_descriptor(hba, opcode, idn, index,
+                                               selector, desc_buf, buf_len);
+               if (!err || err == -EINVAL)
+                       break;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(ufshcd_query_descriptor_retry);
+
 /**
  * ufshcd_read_desc_param - read the specified descriptor parameter
  * @hba: Pointer to adapter instance
@@ -1977,9 +2042,9 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
                        return -ENOMEM;
        }
 
-       ret = ufshcd_query_descriptor(hba, UPIU_QUERY_OPCODE_READ_DESC,
-                                     desc_id, desc_index, 0, desc_buf,
-                                     &buff_len);
+       ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
+                                       desc_id, desc_index, 0, desc_buf,
+                                       &buff_len);
 
        if (ret || (buff_len < ufs_query_desc_max_size[desc_id]) ||
            (desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
@@ -2017,6 +2082,82 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba,
        return ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size);
 }
 
+int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
+{
+       return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size);
+}
+EXPORT_SYMBOL(ufshcd_read_device_desc);
+
+/**
+ * ufshcd_read_string_desc - read string descriptor
+ * @hba: pointer to adapter instance
+ * @desc_index: descriptor index
+ * @buf: pointer to buffer where descriptor would be read
+ * @size: size of buf
+ * @ascii: if true convert from unicode to ascii characters
+ *
+ * Return 0 in case of success, non-zero otherwise
+ */
+int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
+                               u32 size, bool ascii)
+{
+       int err = 0;
+
+       err = ufshcd_read_desc(hba,
+                               QUERY_DESC_IDN_STRING, desc_index, buf, size);
+
+       if (err) {
+               dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n",
+                       __func__, QUERY_REQ_RETRIES, err);
+               goto out;
+       }
+
+       if (ascii) {
+               int desc_len;
+               int ascii_len;
+               int i;
+               char *buff_ascii;
+
+               desc_len = buf[0];
+               /* remove header and divide by 2 to move from UTF16 to UTF8 */
+               ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1;
+               if (size < ascii_len + QUERY_DESC_HDR_SIZE) {
+                       dev_err(hba->dev, "%s: buffer allocated size is too small\n",
+                                       __func__);
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
+               if (!buff_ascii) {
+                       err = -ENOMEM;
+                       goto out_free_buff;
+               }
+
+               /*
+                * the descriptor contains string in UTF16 format
+                * we need to convert to utf-8 so it can be displayed
+                */
+               utf16s_to_utf8s((wchar_t *)&buf[QUERY_DESC_HDR_SIZE],
+                               desc_len - QUERY_DESC_HDR_SIZE,
+                               UTF16_BIG_ENDIAN, buff_ascii, ascii_len);
+
+               /* replace non-printable or non-ASCII characters with spaces */
+               for (i = 0; i < ascii_len; i++)
+                       ufshcd_remove_non_printable(&buff_ascii[i]);
+
+               memset(buf + QUERY_DESC_HDR_SIZE, 0,
+                               size - QUERY_DESC_HDR_SIZE);
+               memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len);
+               buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE;
+out_free_buff:
+               kfree(buff_ascii);
+       }
+out:
+       return err;
+}
+EXPORT_SYMBOL(ufshcd_read_string_desc);
+
 /**
  * ufshcd_read_unit_desc_param - read the specified unit descriptor parameter
  * @hba: Pointer to adapter instance
@@ -2813,6 +2954,23 @@ out:
        return err;
 }
 
+/**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ * @can_sleep: perform sleep or just spin
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep)
+{
+       int err;
+
+       ufshcd_writel(hba, CONTROLLER_DISABLE,  REG_CONTROLLER_ENABLE);
+       err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE,
+                                       CONTROLLER_ENABLE, CONTROLLER_DISABLE,
+                                       10, 1, can_sleep);
+       if (err)
+               dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
+}
+
 /**
  * ufshcd_hba_enable - initialize the controller
  * @hba: per adapter instance
@@ -2833,18 +2991,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
         * development and testing of this driver. msleep can be changed to
         * mdelay and retry count can be reduced based on the controller.
         */
-       if (!ufshcd_is_hba_active(hba)) {
-
+       if (!ufshcd_is_hba_active(hba))
                /* change controller state to "reset state" */
-               ufshcd_hba_stop(hba);
-
-               /*
-                * This delay is based on the testing done with UFS host
-                * controller FPGA. The delay can be changed based on the
-                * host controller used.
-                */
-               msleep(5);
-       }
+               ufshcd_hba_stop(hba, true);
 
        /* UniPro link is disabled at this point */
        ufshcd_set_link_off(hba);
@@ -3365,31 +3514,18 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 }
 
 /**
- * ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * __ufshcd_transfer_req_compl - handle SCSI and query command completion
  * @hba: per adapter instance
+ * @completed_reqs: requests to complete
  */
-static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
+                                       unsigned long completed_reqs)
 {
        struct ufshcd_lrb *lrbp;
        struct scsi_cmnd *cmd;
-       unsigned long completed_reqs;
-       u32 tr_doorbell;
        int result;
        int index;
 
-       /* Resetting interrupt aggregation counters first and reading the
-        * DOOR_BELL afterward allows us to handle all the completed requests.
-        * In order to prevent other interrupts starvation the DB is read once
-        * after reset. The down side of this solution is the possibility of
-        * false interrupt if device completes another request after resetting
-        * aggregation and before reading the DB.
-        */
-       if (ufshcd_is_intr_aggr_allowed(hba))
-               ufshcd_reset_intr_aggr(hba);
-
-       tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
-       completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
-
        for_each_set_bit(index, &completed_reqs, hba->nutrs) {
                lrbp = &hba->lrb[index];
                cmd = lrbp->cmd;
@@ -3418,6 +3554,31 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
        wake_up(&hba->dev_cmd.tag_wq);
 }
 
+/**
+ * ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * @hba: per adapter instance
+ */
+static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+{
+       unsigned long completed_reqs;
+       u32 tr_doorbell;
+
+       /* Resetting interrupt aggregation counters first and reading the
+        * DOOR_BELL afterward allows us to handle all the completed requests.
+        * In order to prevent other interrupts starvation the DB is read once
+        * after reset. The down side of this solution is the possibility of
+        * false interrupt if device completes another request after resetting
+        * aggregation and before reading the DB.
+        */
+       if (ufshcd_is_intr_aggr_allowed(hba))
+               ufshcd_reset_intr_aggr(hba);
+
+       tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+       completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
+
+       __ufshcd_transfer_req_compl(hba, completed_reqs);
+}
+
 /**
  * ufshcd_disable_ee - disable exception event
  * @hba: per-adapter instance
@@ -3630,7 +3791,7 @@ out:
  */
 static int ufshcd_urgent_bkops(struct ufs_hba *hba)
 {
-       return ufshcd_bkops_ctrl(hba, BKOPS_STATUS_PERF_IMPACT);
+       return ufshcd_bkops_ctrl(hba, hba->urgent_bkops_lvl);
 }
 
 static inline int ufshcd_get_ee_status(struct ufs_hba *hba, u32 *status)
@@ -3639,6 +3800,43 @@ static inline int ufshcd_get_ee_status(struct ufs_hba *hba, u32 *status)
                        QUERY_ATTR_IDN_EE_STATUS, 0, 0, status);
 }
 
+static void ufshcd_bkops_exception_event_handler(struct ufs_hba *hba)
+{
+       int err;
+       u32 curr_status = 0;
+
+       if (hba->is_urgent_bkops_lvl_checked)
+               goto enable_auto_bkops;
+
+       err = ufshcd_get_bkops_status(hba, &curr_status);
+       if (err) {
+               dev_err(hba->dev, "%s: failed to get BKOPS status %d\n",
+                               __func__, err);
+               goto out;
+       }
+
+       /*
+        * We are seeing that some devices are raising the urgent bkops
+        * exception events even when BKOPS status doesn't indicate performace
+        * impacted or critical. Handle these device by determining their urgent
+        * bkops status at runtime.
+        */
+       if (curr_status < BKOPS_STATUS_PERF_IMPACT) {
+               dev_err(hba->dev, "%s: device raised urgent BKOPS exception for bkops status %d\n",
+                               __func__, curr_status);
+               /* update the current status as the urgent bkops level */
+               hba->urgent_bkops_lvl = curr_status;
+               hba->is_urgent_bkops_lvl_checked = true;
+       }
+
+enable_auto_bkops:
+       err = ufshcd_enable_auto_bkops(hba);
+out:
+       if (err < 0)
+               dev_err(hba->dev, "%s: failed to handle urgent bkops %d\n",
+                               __func__, err);
+}
+
 /**
  * ufshcd_exception_event_handler - handle exceptions raised by device
  * @work: pointer to work data
@@ -3662,17 +3860,95 @@ static void ufshcd_exception_event_handler(struct work_struct *work)
        }
 
        status &= hba->ee_ctrl_mask;
-       if (status & MASK_EE_URGENT_BKOPS) {
-               err = ufshcd_urgent_bkops(hba);
-               if (err < 0)
-                       dev_err(hba->dev, "%s: failed to handle urgent bkops %d\n",
-                                       __func__, err);
-       }
+
+       if (status & MASK_EE_URGENT_BKOPS)
+               ufshcd_bkops_exception_event_handler(hba);
+
 out:
        pm_runtime_put_sync(hba->dev);
        return;
 }
 
+/* Complete requests that have door-bell cleared */
+static void ufshcd_complete_requests(struct ufs_hba *hba)
+{
+       ufshcd_transfer_req_compl(hba);
+       ufshcd_tmc_handler(hba);
+}
+
+/**
+ * ufshcd_quirk_dl_nac_errors - This function checks if error handling is
+ *                             to recover from the DL NAC errors or not.
+ * @hba: per-adapter instance
+ *
+ * Returns true if error handling is required, false otherwise
+ */
+static bool ufshcd_quirk_dl_nac_errors(struct ufs_hba *hba)
+{
+       unsigned long flags;
+       bool err_handling = true;
+
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       /*
+        * UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS only workaround the
+        * device fatal error and/or DL NAC & REPLAY timeout errors.
+        */
+       if (hba->saved_err & (CONTROLLER_FATAL_ERROR | SYSTEM_BUS_FATAL_ERROR))
+               goto out;
+
+       if ((hba->saved_err & DEVICE_FATAL_ERROR) ||
+           ((hba->saved_err & UIC_ERROR) &&
+            (hba->saved_uic_err & UFSHCD_UIC_DL_TCx_REPLAY_ERROR)))
+               goto out;
+
+       if ((hba->saved_err & UIC_ERROR) &&
+           (hba->saved_uic_err & UFSHCD_UIC_DL_NAC_RECEIVED_ERROR)) {
+               int err;
+               /*
+                * wait for 50ms to see if we can get any other errors or not.
+                */
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
+               msleep(50);
+               spin_lock_irqsave(hba->host->host_lock, flags);
+
+               /*
+                * now check if we have got any other severe errors other than
+                * DL NAC error?
+                */
+               if ((hba->saved_err & INT_FATAL_ERRORS) ||
+                   ((hba->saved_err & UIC_ERROR) &&
+                   (hba->saved_uic_err & ~UFSHCD_UIC_DL_NAC_RECEIVED_ERROR)))
+                       goto out;
+
+               /*
+                * As DL NAC is the only error received so far, send out NOP
+                * command to confirm if link is still active or not.
+                *   - If we don't get any response then do error recovery.
+                *   - If we get response then clear the DL NAC error bit.
+                */
+
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
+               err = ufshcd_verify_dev_init(hba);
+               spin_lock_irqsave(hba->host->host_lock, flags);
+
+               if (err)
+                       goto out;
+
+               /* Link seems to be alive hence ignore the DL NAC errors */
+               if (hba->saved_uic_err == UFSHCD_UIC_DL_NAC_RECEIVED_ERROR)
+                       hba->saved_err &= ~UIC_ERROR;
+               /* clear NAC error */
+               hba->saved_uic_err &= ~UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
+               if (!hba->saved_uic_err) {
+                       err_handling = false;
+                       goto out;
+               }
+       }
+out:
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+       return err_handling;
+}
+
 /**
  * ufshcd_err_handler - handle UFS errors that require s/w attention
  * @work: pointer to work structure
@@ -3685,6 +3961,7 @@ static void ufshcd_err_handler(struct work_struct *work)
        u32 err_tm = 0;
        int err = 0;
        int tag;
+       bool needs_reset = false;
 
        hba = container_of(work, struct ufs_hba, eh_work);
 
@@ -3692,40 +3969,86 @@ static void ufshcd_err_handler(struct work_struct *work)
        ufshcd_hold(hba, false);
 
        spin_lock_irqsave(hba->host->host_lock, flags);
-       if (hba->ufshcd_state == UFSHCD_STATE_RESET) {
-               spin_unlock_irqrestore(hba->host->host_lock, flags);
+       if (hba->ufshcd_state == UFSHCD_STATE_RESET)
                goto out;
-       }
 
        hba->ufshcd_state = UFSHCD_STATE_RESET;
        ufshcd_set_eh_in_progress(hba);
 
        /* Complete requests that have door-bell cleared by h/w */
-       ufshcd_transfer_req_compl(hba);
-       ufshcd_tmc_handler(hba);
-       spin_unlock_irqrestore(hba->host->host_lock, flags);
+       ufshcd_complete_requests(hba);
+
+       if (hba->dev_quirks & UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
+               bool ret;
 
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
+               /* release the lock as ufshcd_quirk_dl_nac_errors() may sleep */
+               ret = ufshcd_quirk_dl_nac_errors(hba);
+               spin_lock_irqsave(hba->host->host_lock, flags);
+               if (!ret)
+                       goto skip_err_handling;
+       }
+       if ((hba->saved_err & INT_FATAL_ERRORS) ||
+           ((hba->saved_err & UIC_ERROR) &&
+           (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
+                                  UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
+                                  UFSHCD_UIC_DL_TCx_REPLAY_ERROR))))
+               needs_reset = true;
+
+       /*
+        * if host reset is required then skip clearing the pending
+        * transfers forcefully because they will automatically get
+        * cleared after link startup.
+        */
+       if (needs_reset)
+               goto skip_pending_xfer_clear;
+
+       /* release lock as clear command might sleep */
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
        /* Clear pending transfer requests */
-       for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs)
-               if (ufshcd_clear_cmd(hba, tag))
-                       err_xfer |= 1 << tag;
+       for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs) {
+               if (ufshcd_clear_cmd(hba, tag)) {
+                       err_xfer = true;
+                       goto lock_skip_pending_xfer_clear;
+               }
+       }
 
        /* Clear pending task management requests */
-       for_each_set_bit(tag, &hba->outstanding_tasks, hba->nutmrs)
-               if (ufshcd_clear_tm_cmd(hba, tag))
-                       err_tm |= 1 << tag;
+       for_each_set_bit(tag, &hba->outstanding_tasks, hba->nutmrs) {
+               if (ufshcd_clear_tm_cmd(hba, tag)) {
+                       err_tm = true;
+                       goto lock_skip_pending_xfer_clear;
+               }
+       }
 
-       /* Complete the requests that are cleared by s/w */
+lock_skip_pending_xfer_clear:
        spin_lock_irqsave(hba->host->host_lock, flags);
-       ufshcd_transfer_req_compl(hba);
-       ufshcd_tmc_handler(hba);
-       spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+       /* Complete the requests that are cleared by s/w */
+       ufshcd_complete_requests(hba);
+
+       if (err_xfer || err_tm)
+               needs_reset = true;
+
+skip_pending_xfer_clear:
        /* Fatal errors need reset */
-       if (err_xfer || err_tm || (hba->saved_err & INT_FATAL_ERRORS) ||
-                       ((hba->saved_err & UIC_ERROR) &&
-                        (hba->saved_uic_err & UFSHCD_UIC_DL_PA_INIT_ERROR))) {
+       if (needs_reset) {
+               unsigned long max_doorbells = (1UL << hba->nutrs) - 1;
+
+               /*
+                * ufshcd_reset_and_restore() does the link reinitialization
+                * which will need atleast one empty doorbell slot to send the
+                * device management commands (NOP and query commands).
+                * If there is no slot empty at this moment then free up last
+                * slot forcefully.
+                */
+               if (hba->outstanding_reqs == max_doorbells)
+                       __ufshcd_transfer_req_compl(hba,
+                                                   (1UL << (hba->nutrs - 1)));
+
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
                err = ufshcd_reset_and_restore(hba);
+               spin_lock_irqsave(hba->host->host_lock, flags);
                if (err) {
                        dev_err(hba->dev, "%s: reset and restore failed\n",
                                        __func__);
@@ -3739,9 +4062,19 @@ static void ufshcd_err_handler(struct work_struct *work)
                hba->saved_err = 0;
                hba->saved_uic_err = 0;
        }
+
+skip_err_handling:
+       if (!needs_reset) {
+               hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
+               if (hba->saved_err || hba->saved_uic_err)
+                       dev_err_ratelimited(hba->dev, "%s: exit: saved_err 0x%x saved_uic_err 0x%x",
+                           __func__, hba->saved_err, hba->saved_uic_err);
+       }
+
        ufshcd_clear_eh_in_progress(hba);
 
 out:
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
        scsi_unblock_requests(hba->host);
        ufshcd_release(hba);
        pm_runtime_put_sync(hba->dev);
@@ -3759,6 +4092,14 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
        if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
                hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
+       else if (hba->dev_quirks &
+                  UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
+               if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED)
+                       hba->uic_error |=
+                               UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
+               else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT)
+                       hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR;
+       }
 
        /* UIC NL/TL/DME errors needs software retry */
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER);
@@ -3796,15 +4137,18 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
        }
 
        if (queue_eh_work) {
+               /*
+                * update the transfer error masks to sticky bits, let's do this
+                * irrespective of current ufshcd_state.
+                */
+               hba->saved_err |= hba->errors;
+               hba->saved_uic_err |= hba->uic_error;
+
                /* handle fatal errors only when link is functional */
                if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
                        /* block commands from scsi mid-layer */
                        scsi_block_requests(hba->host);
 
-                       /* transfer error masks to sticky bits */
-                       hba->saved_err |= hba->errors;
-                       hba->saved_uic_err |= hba->uic_error;
-
                        hba->ufshcd_state = UFSHCD_STATE_ERROR;
                        schedule_work(&hba->eh_work);
                }
@@ -3897,7 +4241,7 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag)
        /* poll for max. 1 sec to clear door bell register by h/w */
        err = ufshcd_wait_for_register(hba,
                        REG_UTP_TASK_REQ_DOOR_BELL,
-                       mask, 0, 1000, 1000);
+                       mask, 0, 1000, 1000, true);
 out:
        return err;
 }
@@ -4179,7 +4523,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
 
        /* Reset the host controller */
        spin_lock_irqsave(hba->host->host_lock, flags);
-       ufshcd_hba_stop(hba);
+       ufshcd_hba_stop(hba, false);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
        err = ufshcd_hba_enable(hba);
@@ -4466,6 +4810,164 @@ out:
        return ret;
 }
 
+static int ufs_get_device_info(struct ufs_hba *hba,
+                               struct ufs_device_info *card_data)
+{
+       int err;
+       u8 model_index;
+       u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1] = {0};
+       u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
+
+       err = ufshcd_read_device_desc(hba, desc_buf,
+                                       QUERY_DESC_DEVICE_MAX_SIZE);
+       if (err) {
+               dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n",
+                       __func__, err);
+               goto out;
+       }
+
+       /*
+        * getting vendor (manufacturerID) and Bank Index in big endian
+        * format
+        */
+       card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
+                                    desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
+
+       model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
+
+       err = ufshcd_read_string_desc(hba, model_index, str_desc_buf,
+                                       QUERY_DESC_STRING_MAX_SIZE, ASCII_STD);
+       if (err) {
+               dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n",
+                       __func__, err);
+               goto out;
+       }
+
+       str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
+       strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
+               min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
+                     MAX_MODEL_LEN));
+
+       /* Null terminate the model string */
+       card_data->model[MAX_MODEL_LEN] = '\0';
+
+out:
+       return err;
+}
+
+void ufs_advertise_fixup_device(struct ufs_hba *hba)
+{
+       int err;
+       struct ufs_dev_fix *f;
+       struct ufs_device_info card_data;
+
+       card_data.wmanufacturerid = 0;
+
+       err = ufs_get_device_info(hba, &card_data);
+       if (err) {
+               dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
+                       __func__, err);
+               return;
+       }
+
+       for (f = ufs_fixups; f->quirk; f++) {
+               if (((f->card.wmanufacturerid == card_data.wmanufacturerid) ||
+                   (f->card.wmanufacturerid == UFS_ANY_VENDOR)) &&
+                   (STR_PRFX_EQUAL(f->card.model, card_data.model) ||
+                    !strcmp(f->card.model, UFS_ANY_MODEL)))
+                       hba->dev_quirks |= f->quirk;
+       }
+}
+
+/**
+ * ufshcd_tune_pa_tactivate - Tunes PA_TActivate of local UniPro
+ * @hba: per-adapter instance
+ *
+ * PA_TActivate parameter can be tuned manually if UniPro version is less than
+ * 1.61. PA_TActivate needs to be greater than or equal to peerM-PHY's
+ * RX_MIN_ACTIVATETIME_CAPABILITY attribute. This optimal value can help reduce
+ * the hibern8 exit latency.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_tune_pa_tactivate(struct ufs_hba *hba)
+{
+       int ret = 0;
+       u32 peer_rx_min_activatetime = 0, tuned_pa_tactivate;
+
+       ret = ufshcd_dme_peer_get(hba,
+                                 UIC_ARG_MIB_SEL(
+                                       RX_MIN_ACTIVATETIME_CAPABILITY,
+                                       UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+                                 &peer_rx_min_activatetime);
+       if (ret)
+               goto out;
+
+       /* make sure proper unit conversion is applied */
+       tuned_pa_tactivate =
+               ((peer_rx_min_activatetime * RX_MIN_ACTIVATETIME_UNIT_US)
+                / PA_TACTIVATE_TIME_UNIT_US);
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE),
+                            tuned_pa_tactivate);
+
+out:
+       return ret;
+}
+
+/**
+ * ufshcd_tune_pa_hibern8time - Tunes PA_Hibern8Time of local UniPro
+ * @hba: per-adapter instance
+ *
+ * PA_Hibern8Time parameter can be tuned manually if UniPro version is less than
+ * 1.61. PA_Hibern8Time needs to be maximum of local M-PHY's
+ * TX_HIBERN8TIME_CAPABILITY & peer M-PHY's RX_HIBERN8TIME_CAPABILITY.
+ * This optimal value can help reduce the hibern8 exit latency.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_tune_pa_hibern8time(struct ufs_hba *hba)
+{
+       int ret = 0;
+       u32 local_tx_hibern8_time_cap = 0, peer_rx_hibern8_time_cap = 0;
+       u32 max_hibern8_time, tuned_pa_hibern8time;
+
+       ret = ufshcd_dme_get(hba,
+                            UIC_ARG_MIB_SEL(TX_HIBERN8TIME_CAPABILITY,
+                                       UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+                                 &local_tx_hibern8_time_cap);
+       if (ret)
+               goto out;
+
+       ret = ufshcd_dme_peer_get(hba,
+                                 UIC_ARG_MIB_SEL(RX_HIBERN8TIME_CAPABILITY,
+                                       UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+                                 &peer_rx_hibern8_time_cap);
+       if (ret)
+               goto out;
+
+       max_hibern8_time = max(local_tx_hibern8_time_cap,
+                              peer_rx_hibern8_time_cap);
+       /* make sure proper unit conversion is applied */
+       tuned_pa_hibern8time = ((max_hibern8_time * HIBERN8TIME_UNIT_US)
+                               / PA_HIBERN8_TIME_UNIT_US);
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME),
+                            tuned_pa_hibern8time);
+out:
+       return ret;
+}
+
+static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
+{
+       if (ufshcd_is_unipro_pa_params_tuning_req(hba)) {
+               ufshcd_tune_pa_tactivate(hba);
+               ufshcd_tune_pa_hibern8time(hba);
+       }
+
+       if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TACTIVATE)
+               /* set 1ms timeout for PA_TACTIVATE */
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 10);
+}
+
 /**
  * ufshcd_probe_hba - probe hba to detect device and initialize
  * @hba: per-adapter instance
@@ -4482,6 +4984,10 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
 
        ufshcd_init_pwr_info(hba);
 
+       /* set the default level for urgent bkops */
+       hba->urgent_bkops_lvl = BKOPS_STATUS_PERF_IMPACT;
+       hba->is_urgent_bkops_lvl_checked = false;
+
        /* UniPro link is active now */
        ufshcd_set_link_active(hba);
 
@@ -4493,6 +4999,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
        if (ret)
                goto out;
 
+       ufs_advertise_fixup_device(hba);
+       ufshcd_tune_unipro_params(hba);
+
+       ret = ufshcd_set_vccq_rail_unused(hba,
+               (hba->dev_quirks & UFS_DEVICE_NO_VCCQ) ? true : false);
+       if (ret)
+               goto out;
+
        /* UFS device is also active now */
        ufshcd_set_ufs_dev_active(hba);
        ufshcd_force_reset_auto_bkops(hba);
@@ -4567,6 +5081,41 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
        ufshcd_probe_hba(hba);
 }
 
+static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd)
+{
+       unsigned long flags;
+       struct Scsi_Host *host;
+       struct ufs_hba *hba;
+       int index;
+       bool found = false;
+
+       if (!scmd || !scmd->device || !scmd->device->host)
+               return BLK_EH_NOT_HANDLED;
+
+       host = scmd->device->host;
+       hba = shost_priv(host);
+       if (!hba)
+               return BLK_EH_NOT_HANDLED;
+
+       spin_lock_irqsave(host->host_lock, flags);
+
+       for_each_set_bit(index, &hba->outstanding_reqs, hba->nutrs) {
+               if (hba->lrb[index].cmd == scmd) {
+                       found = true;
+                       break;
+               }
+       }
+
+       spin_unlock_irqrestore(host->host_lock, flags);
+
+       /*
+        * Bypass SCSI error handling and reset the block layer timer if this
+        * SCSI command was not actually dispatched to UFS driver, otherwise
+        * let SCSI layer handle the error as usual.
+        */
+       return found ? BLK_EH_NOT_HANDLED : BLK_EH_RESET_TIMER;
+}
+
 static struct scsi_host_template ufshcd_driver_template = {
        .module                 = THIS_MODULE,
        .name                   = UFSHCD,
@@ -4579,6 +5128,7 @@ static struct scsi_host_template ufshcd_driver_template = {
        .eh_abort_handler       = ufshcd_abort,
        .eh_device_reset_handler = ufshcd_eh_device_reset_handler,
        .eh_host_reset_handler   = ufshcd_eh_host_reset_handler,
+       .eh_timed_out           = ufshcd_eh_timed_out,
        .this_id                = -1,
        .sg_tablesize           = SG_ALL,
        .cmd_per_lun            = UFSHCD_CMD_PER_LUN,
@@ -4607,13 +5157,24 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
 static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
                                         struct ufs_vreg *vreg)
 {
-       return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA);
+       if (!vreg)
+               return 0;
+       else if (vreg->unused)
+               return 0;
+       else
+               return ufshcd_config_vreg_load(hba->dev, vreg,
+                                              UFS_VREG_LPM_LOAD_UA);
 }
 
 static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
                                         struct ufs_vreg *vreg)
 {
-       return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
+       if (!vreg)
+               return 0;
+       else if (vreg->unused)
+               return 0;
+       else
+               return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
 }
 
 static int ufshcd_config_vreg(struct device *dev,
@@ -4648,7 +5209,9 @@ static int ufshcd_enable_vreg(struct device *dev, struct ufs_vreg *vreg)
 {
        int ret = 0;
 
-       if (!vreg || vreg->enabled)
+       if (!vreg)
+               goto out;
+       else if (vreg->enabled || vreg->unused)
                goto out;
 
        ret = ufshcd_config_vreg(dev, vreg, true);
@@ -4668,7 +5231,9 @@ static int ufshcd_disable_vreg(struct device *dev, struct ufs_vreg *vreg)
 {
        int ret = 0;
 
-       if (!vreg || !vreg->enabled)
+       if (!vreg)
+               goto out;
+       else if (!vreg->enabled || vreg->unused)
                goto out;
 
        ret = regulator_disable(vreg->reg);
@@ -4774,6 +5339,36 @@ static int ufshcd_init_hba_vreg(struct ufs_hba *hba)
        return 0;
 }
 
+static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused)
+{
+       int ret = 0;
+       struct ufs_vreg_info *info = &hba->vreg_info;
+
+       if (!info)
+               goto out;
+       else if (!info->vccq)
+               goto out;
+
+       if (unused) {
+               /* shut off the rail here */
+               ret = ufshcd_toggle_vreg(hba->dev, info->vccq, false);
+               /*
+                * Mark this rail as no longer used, so it doesn't get enabled
+                * later by mistake
+                */
+               if (!ret)
+                       info->vccq->unused = true;
+       } else {
+               /*
+                * rail should have been already enabled hence just make sure
+                * that unused flag is cleared.
+                */
+               info->vccq->unused = false;
+       }
+out:
+       return ret;
+}
+
 static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
                                        bool skip_ref_clk)
 {
@@ -5092,11 +5687,21 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba,
        else if ((req_link_state == UIC_LINK_OFF_STATE) &&
                   (!check_for_bkops || (check_for_bkops &&
                    !hba->auto_bkops_enabled))) {
+               /*
+                * Let's make sure that link is in low power mode, we are doing
+                * this currently by putting the link in Hibern8. Otherway to
+                * put the link in low power mode is to send the DME end point
+                * to device and then send the DME reset command to local
+                * unipro. But putting the link in hibern8 is much faster.
+                */
+               ret = ufshcd_uic_hibern8_enter(hba);
+               if (ret)
+                       goto out;
                /*
                 * Change controller state to "reset state" which
                 * should also put the link in off/reset state
                 */
-               ufshcd_hba_stop(hba);
+               ufshcd_hba_stop(hba, true);
                /*
                 * TODO: Check if we need any delay to make sure that
                 * controller is reset
@@ -5110,6 +5715,16 @@ out:
 
 static void ufshcd_vreg_set_lpm(struct ufs_hba *hba)
 {
+       /*
+        * It seems some UFS devices may keep drawing more than sleep current
+        * (atleast for 500us) from UFS rails (especially from VCCQ rail).
+        * To avoid this situation, add 2ms delay before putting these UFS
+        * rails in LPM mode.
+        */
+       if (!ufshcd_is_link_active(hba) &&
+           hba->dev_quirks & UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM)
+               usleep_range(2000, 2100);
+
        /*
         * If UFS device is either in UFS_Sleep turn off VCC rail to save some
         * power.
@@ -5572,7 +6187,7 @@ void ufshcd_remove(struct ufs_hba *hba)
        scsi_remove_host(hba->host);
        /* disable interrupts */
        ufshcd_disable_intr(hba, hba->intr_mask);
-       ufshcd_hba_stop(hba);
+       ufshcd_hba_stop(hba, true);
 
        scsi_host_put(hba->host);
 
@@ -5836,6 +6451,21 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        init_waitqueue_head(&hba->dev_cmd.tag_wq);
 
        ufshcd_init_clk_gating(hba);
+
+       /*
+        * In order to avoid any spurious interrupt immediately after
+        * registering UFS controller interrupt handler, clear any pending UFS
+        * interrupt status and disable all the UFS interrupts.
+        */
+       ufshcd_writel(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS),
+                     REG_INTERRUPT_STATUS);
+       ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE);
+       /*
+        * Make sure that UFS interrupts are disabled and any pending interrupt
+        * status is cleared before registering UFS interrupt handler.
+        */
+       mb();
+
        /* IRQ registration */
        err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
        if (err) {
index e3931d0..4bb6566 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/regulator/consumer.h>
+#include "unipro.h"
 
 #include <asm/irq.h>
 #include <asm/byteorder.h>
@@ -383,6 +384,9 @@ struct ufs_init_prefetch {
  * @clk_list_head: UFS host controller clocks list node head
  * @pwr_info: holds current power mode
  * @max_pwr_info: keeps the device max valid pwm
+ * @urgent_bkops_lvl: keeps track of urgent bkops level for device
+ * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for
+ *  device is known or not.
  */
 struct ufs_hba {
        void __iomem *mmio_base;
@@ -470,6 +474,9 @@ struct ufs_hba {
 
        unsigned int quirks;    /* Deviations from standard UFSHCI spec. */
 
+       /* Device deviations from standard UFS device spec. */
+       unsigned int dev_quirks;
+
        wait_queue_head_t tm_wq;
        wait_queue_head_t tm_tag_wq;
        unsigned long tm_condition;
@@ -509,6 +516,8 @@ struct ufs_hba {
 
        bool wlun_dev_clr_ua;
 
+       /* Number of lanes available (1 or 2) for Rx/Tx */
+       u32 lanes_per_direction;
        struct ufs_pa_layer_attr pwr_info;
        struct ufs_pwr_mode_info max_pwr_info;
 
@@ -533,6 +542,9 @@ struct ufs_hba {
        struct devfreq *devfreq;
        struct ufs_clk_scaling clk_scaling;
        bool is_sys_suspended;
+
+       enum bkops_status urgent_bkops_lvl;
+       bool is_urgent_bkops_lvl_checked;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
@@ -588,15 +600,9 @@ int ufshcd_alloc_host(struct device *, struct ufs_hba **);
 void ufshcd_dealloc_host(struct ufs_hba *);
 int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
 void ufshcd_remove(struct ufs_hba *);
-
-/**
- * ufshcd_hba_stop - Send controller to reset state
- * @hba: per adapter instance
- */
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
-{
-       ufshcd_writel(hba, CONTROLLER_DISABLE,  REG_CONTROLLER_ENABLE);
-}
+int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+                               u32 val, unsigned long interval_us,
+                               unsigned long timeout_ms, bool can_sleep);
 
 static inline void check_upiu_size(void)
 {
@@ -682,11 +688,27 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
        return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
 }
 
+int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size);
+
+static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info)
+{
+       return (pwr_info->pwr_rx == FAST_MODE ||
+               pwr_info->pwr_rx == FASTAUTO_MODE) &&
+               (pwr_info->pwr_tx == FAST_MODE ||
+               pwr_info->pwr_tx == FASTAUTO_MODE);
+}
+
+#define ASCII_STD true
+
+int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
+                               u32 size, bool ascii);
+
 /* Expose Query-Request API */
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
        enum flag_idn idn, bool *flag_res);
 int ufshcd_hold(struct ufs_hba *hba, bool async);
 void ufshcd_release(struct ufs_hba *hba);
+u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba);
 
 /* Wrapper functions for safely calling variant operations */
 static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
index 0ae0967..4cb1cc6 100644 (file)
@@ -92,6 +92,7 @@ enum {
        UFSHCI_VERSION_10 = 0x00010000, /* 1.0 */
        UFSHCI_VERSION_11 = 0x00010100, /* 1.1 */
        UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */
+       UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */
 };
 
 /*
@@ -170,6 +171,8 @@ enum {
 #define UIC_DATA_LINK_LAYER_ERROR              UFS_BIT(31)
 #define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK    0x7FFF
 #define UIC_DATA_LINK_LAYER_ERROR_PA_INIT      0x2000
+#define UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED 0x0001
+#define UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT 0x0002
 
 /* UECN - Host UIC Error Code Network Layer 40h */
 #define UIC_NETWORK_LAYER_ERROR                        UFS_BIT(31)
@@ -209,6 +212,7 @@ enum {
 
 /* GenSelectorIndex calculation macros for M-PHY attributes */
 #define UIC_ARG_MPHY_TX_GEN_SEL_INDEX(lane) (lane)
+#define UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane) (PA_MAXDATALANES + (lane))
 
 #define UIC_ARG_MIB_SEL(attr, sel)     ((((attr) & 0xFFFF) << 16) |\
                                         ((sel) & 0xFFFF))
index 816a8a4..e2854e4 100644 (file)
@@ -15,6 +15,7 @@
 /*
  * M-TX Configuration Attributes
  */
+#define TX_HIBERN8TIME_CAPABILITY              0x000F
 #define TX_MODE                                        0x0021
 #define TX_HSRATE_SERIES                       0x0022
 #define TX_HSGEAR                              0x0023
 #define RX_ENTER_HIBERN8                       0x00A7
 #define RX_BYPASS_8B10B_ENABLE                 0x00A8
 #define RX_TERMINATION_FORCE_ENABLE            0x0089
+#define RX_MIN_ACTIVATETIME_CAPABILITY         0x008F
+#define RX_HIBERN8TIME_CAPABILITY              0x0092
 
 #define is_mphy_tx_attr(attr)                  (attr < RX_MODE)
+#define RX_MIN_ACTIVATETIME_UNIT_US            100
+#define HIBERN8TIME_UNIT_US                    100
 /*
  * PHY Adpater attributes
  */
@@ -70,6 +75,7 @@
 #define PA_MAXRXSPEEDFAST      0x1541
 #define PA_MAXRXSPEEDSLOW      0x1542
 #define PA_TXLINKSTARTUPHS     0x1544
+#define PA_LOCAL_TX_LCC_ENABLE 0x155E
 #define PA_TXSPEEDFAST         0x1565
 #define PA_TXSPEEDSLOW         0x1566
 #define PA_REMOTEVERINFO       0x15A0
 #define PA_STALLNOCONFIGTIME   0x15A3
 #define PA_SAVECONFIGTIME      0x15A4
 
+#define PA_TACTIVATE_TIME_UNIT_US      10
+#define PA_HIBERN8_TIME_UNIT_US                100
+
+/* PHY Adapter Protocol Constants */
+#define PA_MAXDATALANES        4
+
 /* PA power modes */
 enum {
        FAST_MODE       = 1,
@@ -143,6 +155,16 @@ enum ufs_hs_gear_tag {
        UFS_HS_G3,              /* HS Gear 3 */
 };
 
+enum ufs_unipro_ver {
+       UFS_UNIPRO_VER_RESERVED = 0,
+       UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */
+       UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */
+       UFS_UNIPRO_VER_1_6 = 3,  /* UniPro version 1.6 */
+       UFS_UNIPRO_VER_MAX = 4,  /* UniPro unsupported version */
+       /* UniPro version field mask in PA_LOCALVERINFO */
+       UFS_UNIPRO_VER_MASK = 0xF,
+};
+
 /*
  * Data Link Layer Attributes
  */
index bceb813..8536567 100644 (file)
@@ -1141,14 +1141,16 @@ static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
        return PTR_ERR_OR_ZERO(vaddr);
 }
 
-static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
-                                      enum dma_data_direction direction)
+static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
+                                     enum dma_data_direction direction)
 {
        struct ion_buffer *buffer = dmabuf->priv;
 
        mutex_lock(&buffer->lock);
        ion_buffer_kmap_put(buffer);
        mutex_unlock(&buffer->lock);
+
+       return 0;
 }
 
 static struct dma_buf_ops dma_buf_ops = {
index 9d47c5d..163f21a 100644 (file)
@@ -49,7 +49,6 @@ static struct nand_ecclayout spinand_oob_64 = {
                17, 18, 19, 20, 21, 22,
                33, 34, 35, 36, 37, 38,
                49, 50, 51, 52, 53, 54, },
-       .oobavail = 32,
        .oobfree = {
                {.offset = 8,
                        .length = 8},
index ae62975..457dc7f 100644 (file)
@@ -78,7 +78,6 @@
 #define BL_ALL_UNLOCKED    0
 
 struct spinand_info {
-       struct nand_ecclayout *ecclayout;
        struct spi_device *spi;
        void *priv;
 };
index 9d75767..6725f59 100644 (file)
@@ -209,6 +209,7 @@ menuconfig MISC_FILESYSTEMS
 
 if MISC_FILESYSTEMS
 
+source "fs/orangefs/Kconfig"
 source "fs/adfs/Kconfig"
 source "fs/affs/Kconfig"
 source "fs/ecryptfs/Kconfig"
index 252c968..85b6e13 100644 (file)
@@ -106,6 +106,7 @@ obj-$(CONFIG_AUTOFS4_FS)    += autofs4/
 obj-$(CONFIG_ADFS_FS)          += adfs/
 obj-$(CONFIG_FUSE_FS)          += fuse/
 obj-$(CONFIG_OVERLAY_FS)       += overlayfs/
+obj-$(CONFIG_ORANGEFS_FS)       += orangefs/
 obj-$(CONFIG_UDF_FS)           += udf/
 obj-$(CONFIG_SUN_OPENPROMFS)   += openpromfs/
 obj-$(CONFIG_OMFS_FS)          += omfs/
index 4b02591..d01f89d 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/buffer_head.h>
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
-#include <linux/freezer.h>
 #include <linux/slab.h>
 #include <linux/migrate.h>
 #include <linux/ratelimit.h>
@@ -303,7 +302,7 @@ static int csum_tree_block(struct btrfs_fs_info *fs_info,
                err = map_private_extent_buffer(buf, offset, 32,
                                        &kaddr, &map_start, &map_len);
                if (err)
-                       return 1;
+                       return err;
                cur_len = min(len, map_len - (offset - map_start));
                crc = btrfs_csum_data(kaddr + offset - map_start,
                                      crc, cur_len);
@@ -313,7 +312,7 @@ static int csum_tree_block(struct btrfs_fs_info *fs_info,
        if (csum_size > sizeof(inline_result)) {
                result = kzalloc(csum_size, GFP_NOFS);
                if (!result)
-                       return 1;
+                       return -ENOMEM;
        } else {
                result = (char *)&inline_result;
        }
@@ -334,7 +333,7 @@ static int csum_tree_block(struct btrfs_fs_info *fs_info,
                                val, found, btrfs_header_level(buf));
                        if (result != (char *)&inline_result)
                                kfree(result);
-                       return 1;
+                       return -EUCLEAN;
                }
        } else {
                write_extent_buffer(buf, result, 0, csum_size);
@@ -513,11 +512,21 @@ static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct page *page)
        eb = (struct extent_buffer *)page->private;
        if (page != eb->pages[0])
                return 0;
+
        found_start = btrfs_header_bytenr(eb);
-       if (WARN_ON(found_start != start || !PageUptodate(page)))
-               return 0;
-       csum_tree_block(fs_info, eb, 0);
-       return 0;
+       /*
+        * Please do not consolidate these warnings into a single if.
+        * It is useful to know what went wrong.
+        */
+       if (WARN_ON(found_start != start))
+               return -EUCLEAN;
+       if (WARN_ON(!PageUptodate(page)))
+               return -EUCLEAN;
+
+       ASSERT(memcmp_extent_buffer(eb, fs_info->fsid,
+                       btrfs_header_fsid(), BTRFS_FSID_SIZE) == 0);
+
+       return csum_tree_block(fs_info, eb, 0);
 }
 
 static int check_tree_block_fsid(struct btrfs_fs_info *fs_info,
@@ -661,10 +670,8 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
                                       eb, found_level);
 
        ret = csum_tree_block(fs_info, eb, 1);
-       if (ret) {
-               ret = -EIO;
+       if (ret)
                goto err;
-       }
 
        /*
         * If this is a leaf block and it is corrupt, set the corrupt bit so
@@ -1831,7 +1838,7 @@ static int cleaner_kthread(void *arg)
                 */
                btrfs_delete_unused_bgs(root->fs_info);
 sleep:
-               if (!try_to_freeze() && !again) {
+               if (!again) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        if (!kthread_should_stop())
                                schedule();
@@ -1921,14 +1928,12 @@ sleep:
                if (unlikely(test_bit(BTRFS_FS_STATE_ERROR,
                                      &root->fs_info->fs_state)))
                        btrfs_cleanup_transaction(root);
-               if (!try_to_freeze()) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (!kthread_should_stop() &&
-                           (!btrfs_transaction_blocked(root->fs_info) ||
-                            cannot_commit))
-                               schedule_timeout(delay);
-                       __set_current_state(TASK_RUNNING);
-               }
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!kthread_should_stop() &&
+                               (!btrfs_transaction_blocked(root->fs_info) ||
+                                cannot_commit))
+                       schedule_timeout(delay);
+               __set_current_state(TASK_RUNNING);
        } while (!kthread_should_stop());
        return 0;
 }
index 19adeb0..fc5cae2 100644 (file)
@@ -175,8 +175,8 @@ static void ceph_invalidatepage(struct page *page, unsigned int offset,
 
 static int ceph_releasepage(struct page *page, gfp_t g)
 {
-       struct inode *inode = page->mapping ? page->mapping->host : NULL;
-       dout("%p releasepage %p idx %lu\n", inode, page, page->index);
+       dout("%p releasepage %p idx %lu\n", page->mapping->host,
+            page, page->index);
        WARN_ON(PageDirty(page));
 
        /* Can we release the page from the cache? */
@@ -276,7 +276,7 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg)
        for (i = 0; i < num_pages; i++) {
                struct page *page = osd_data->pages[i];
 
-               if (rc < 0 && rc != ENOENT)
+               if (rc < 0 && rc != -ENOENT)
                        goto unlock;
                if (bytes < (int)PAGE_CACHE_SIZE) {
                        /* zero (remainder of) page */
@@ -606,71 +606,71 @@ static void writepages_finish(struct ceph_osd_request *req,
        struct inode *inode = req->r_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_osd_data *osd_data;
-       unsigned wrote;
        struct page *page;
-       int num_pages;
-       int i;
+       int num_pages, total_pages = 0;
+       int i, j;
+       int rc = req->r_result;
        struct ceph_snap_context *snapc = req->r_snapc;
        struct address_space *mapping = inode->i_mapping;
-       int rc = req->r_result;
-       u64 bytes = req->r_ops[0].extent.length;
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
-       long writeback_stat;
-       unsigned issued = ceph_caps_issued(ci);
+       bool remove_page;
 
-       osd_data = osd_req_op_extent_osd_data(req, 0);
-       BUG_ON(osd_data->type != CEPH_OSD_DATA_TYPE_PAGES);
-       num_pages = calc_pages_for((u64)osd_data->alignment,
-                                       (u64)osd_data->length);
-       if (rc >= 0) {
-               /*
-                * Assume we wrote the pages we originally sent.  The
-                * osd might reply with fewer pages if our writeback
-                * raced with a truncation and was adjusted at the osd,
-                * so don't believe the reply.
-                */
-               wrote = num_pages;
-       } else {
-               wrote = 0;
+
+       dout("writepages_finish %p rc %d\n", inode, rc);
+       if (rc < 0)
                mapping_set_error(mapping, rc);
-       }
-       dout("writepages_finish %p rc %d bytes %llu wrote %d (pages)\n",
-            inode, rc, bytes, wrote);
 
-       /* clean all pages */
-       for (i = 0; i < num_pages; i++) {
-               page = osd_data->pages[i];
-               BUG_ON(!page);
-               WARN_ON(!PageUptodate(page));
+       /*
+        * We lost the cache cap, need to truncate the page before
+        * it is unlocked, otherwise we'd truncate it later in the
+        * page truncation thread, possibly losing some data that
+        * raced its way in
+        */
+       remove_page = !(ceph_caps_issued(ci) &
+                       (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO));
 
-               writeback_stat =
-                       atomic_long_dec_return(&fsc->writeback_count);
-               if (writeback_stat <
-                   CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb))
-                       clear_bdi_congested(&fsc->backing_dev_info,
-                                           BLK_RW_ASYNC);
+       /* clean all pages */
+       for (i = 0; i < req->r_num_ops; i++) {
+               if (req->r_ops[i].op != CEPH_OSD_OP_WRITE)
+                       break;
 
-               ceph_put_snap_context(page_snap_context(page));
-               page->private = 0;
-               ClearPagePrivate(page);
-               dout("unlocking %d %p\n", i, page);
-               end_page_writeback(page);
+               osd_data = osd_req_op_extent_osd_data(req, i);
+               BUG_ON(osd_data->type != CEPH_OSD_DATA_TYPE_PAGES);
+               num_pages = calc_pages_for((u64)osd_data->alignment,
+                                          (u64)osd_data->length);
+               total_pages += num_pages;
+               for (j = 0; j < num_pages; j++) {
+                       page = osd_data->pages[j];
+                       BUG_ON(!page);
+                       WARN_ON(!PageUptodate(page));
+
+                       if (atomic_long_dec_return(&fsc->writeback_count) <
+                            CONGESTION_OFF_THRESH(
+                                       fsc->mount_options->congestion_kb))
+                               clear_bdi_congested(&fsc->backing_dev_info,
+                                                   BLK_RW_ASYNC);
+
+                       ceph_put_snap_context(page_snap_context(page));
+                       page->private = 0;
+                       ClearPagePrivate(page);
+                       dout("unlocking %p\n", page);
+                       end_page_writeback(page);
+
+                       if (remove_page)
+                               generic_error_remove_page(inode->i_mapping,
+                                                         page);
 
-               /*
-                * We lost the cache cap, need to truncate the page before
-                * it is unlocked, otherwise we'd truncate it later in the
-                * page truncation thread, possibly losing some data that
-                * raced its way in
-                */
-               if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0)
-                       generic_error_remove_page(inode->i_mapping, page);
+                       unlock_page(page);
+               }
+               dout("writepages_finish %p wrote %llu bytes cleaned %d pages\n",
+                    inode, osd_data->length, rc >= 0 ? num_pages : 0);
 
-               unlock_page(page);
+               ceph_release_pages(osd_data->pages, num_pages);
        }
-       dout("%p wrote+cleaned %d pages\n", inode, wrote);
-       ceph_put_wrbuffer_cap_refs(ci, num_pages, snapc);
 
-       ceph_release_pages(osd_data->pages, num_pages);
+       ceph_put_wrbuffer_cap_refs(ci, total_pages, snapc);
+
+       osd_data = osd_req_op_extent_osd_data(req, 0);
        if (osd_data->pages_from_pool)
                mempool_free(osd_data->pages,
                             ceph_sb_to_client(inode->i_sb)->wb_pagevec_pool);
@@ -778,17 +778,15 @@ retry:
        while (!done && index <= end) {
                unsigned i;
                int first;
-               pgoff_t next;
-               int pvec_pages, locked_pages;
-               struct page **pages = NULL;
+               pgoff_t strip_unit_end = 0;
+               int num_ops = 0, op_idx;
+               int pvec_pages, locked_pages = 0;
+               struct page **pages = NULL, **data_pages;
                mempool_t *pool = NULL; /* Becomes non-null if mempool used */
                struct page *page;
                int want;
-               u64 offset, len;
-               long writeback_stat;
+               u64 offset = 0, len = 0;
 
-               next = 0;
-               locked_pages = 0;
                max_pages = max_pages_ever;
 
 get_more_pages:
@@ -824,8 +822,8 @@ get_more_pages:
                                unlock_page(page);
                                break;
                        }
-                       if (next && (page->index != next)) {
-                               dout("not consecutive %p\n", page);
+                       if (strip_unit_end && (page->index > strip_unit_end)) {
+                               dout("end of strip unit %p\n", page);
                                unlock_page(page);
                                break;
                        }
@@ -867,36 +865,31 @@ get_more_pages:
                        /*
                         * We have something to write.  If this is
                         * the first locked page this time through,
-                        * allocate an osd request and a page array
-                        * that it will use.
+                        * calculate max possinle write size and
+                        * allocate a page array
                         */
                        if (locked_pages == 0) {
-                               BUG_ON(pages);
+                               u64 objnum;
+                               u64 objoff;
+
                                /* prepare async write request */
                                offset = (u64)page_offset(page);
                                len = wsize;
-                               req = ceph_osdc_new_request(&fsc->client->osdc,
-                                                       &ci->i_layout, vino,
-                                                       offset, &len, 0,
-                                                       do_sync ? 2 : 1,
-                                                       CEPH_OSD_OP_WRITE,
-                                                       CEPH_OSD_FLAG_WRITE |
-                                                       CEPH_OSD_FLAG_ONDISK,
-                                                       snapc, truncate_seq,
-                                                       truncate_size, true);
-                               if (IS_ERR(req)) {
-                                       rc = PTR_ERR(req);
+
+                               rc = ceph_calc_file_object_mapping(&ci->i_layout,
+                                                               offset, len,
+                                                               &objnum, &objoff,
+                                                               &len);
+                               if (rc < 0) {
                                        unlock_page(page);
                                        break;
                                }
 
-                               if (do_sync)
-                                       osd_req_op_init(req, 1,
-                                                       CEPH_OSD_OP_STARTSYNC, 0);
-
-                               req->r_callback = writepages_finish;
-                               req->r_inode = inode;
+                               num_ops = 1 + do_sync;
+                               strip_unit_end = page->index +
+                                       ((len - 1) >> PAGE_CACHE_SHIFT);
 
+                               BUG_ON(pages);
                                max_pages = calc_pages_for(0, (u64)len);
                                pages = kmalloc(max_pages * sizeof (*pages),
                                                GFP_NOFS);
@@ -905,6 +898,20 @@ get_more_pages:
                                        pages = mempool_alloc(pool, GFP_NOFS);
                                        BUG_ON(!pages);
                                }
+
+                               len = 0;
+                       } else if (page->index !=
+                                  (offset + len) >> PAGE_CACHE_SHIFT) {
+                               if (num_ops >= (pool ?  CEPH_OSD_SLAB_OPS :
+                                                       CEPH_OSD_MAX_OPS)) {
+                                       redirty_page_for_writepage(wbc, page);
+                                       unlock_page(page);
+                                       break;
+                               }
+
+                               num_ops++;
+                               offset = (u64)page_offset(page);
+                               len = 0;
                        }
 
                        /* note position of first page in pvec */
@@ -913,18 +920,16 @@ get_more_pages:
                        dout("%p will write page %p idx %lu\n",
                             inode, page, page->index);
 
-                       writeback_stat =
-                              atomic_long_inc_return(&fsc->writeback_count);
-                       if (writeback_stat > CONGESTION_ON_THRESH(
+                       if (atomic_long_inc_return(&fsc->writeback_count) >
+                           CONGESTION_ON_THRESH(
                                    fsc->mount_options->congestion_kb)) {
                                set_bdi_congested(&fsc->backing_dev_info,
                                                  BLK_RW_ASYNC);
                        }
 
-                       set_page_writeback(page);
                        pages[locked_pages] = page;
                        locked_pages++;
-                       next = page->index + 1;
+                       len += PAGE_CACHE_SIZE;
                }
 
                /* did we get anything? */
@@ -944,38 +949,119 @@ get_more_pages:
                        /* shift unused pages over in the pvec...  we
                         * will need to release them below. */
                        for (j = i; j < pvec_pages; j++) {
-                               dout(" pvec leftover page %p\n",
-                                    pvec.pages[j]);
+                               dout(" pvec leftover page %p\n", pvec.pages[j]);
                                pvec.pages[j-i+first] = pvec.pages[j];
                        }
                        pvec.nr -= i-first;
                }
 
-               /* Format the osd request message and submit the write */
+new_request:
                offset = page_offset(pages[0]);
-               len = (u64)locked_pages << PAGE_CACHE_SHIFT;
-               if (snap_size == -1) {
-                       len = min(len, (u64)i_size_read(inode) - offset);
-                        /* writepages_finish() clears writeback pages
-                         * according to the data length, so make sure
-                         * data length covers all locked pages */
-                       len = max(len, 1 +
-                               ((u64)(locked_pages - 1) << PAGE_CACHE_SHIFT));
-               } else {
-                       len = min(len, snap_size - offset);
+               len = wsize;
+
+               req = ceph_osdc_new_request(&fsc->client->osdc,
+                                       &ci->i_layout, vino,
+                                       offset, &len, 0, num_ops,
+                                       CEPH_OSD_OP_WRITE,
+                                       CEPH_OSD_FLAG_WRITE |
+                                       CEPH_OSD_FLAG_ONDISK,
+                                       snapc, truncate_seq,
+                                       truncate_size, false);
+               if (IS_ERR(req)) {
+                       req = ceph_osdc_new_request(&fsc->client->osdc,
+                                               &ci->i_layout, vino,
+                                               offset, &len, 0,
+                                               min(num_ops,
+                                                   CEPH_OSD_SLAB_OPS),
+                                               CEPH_OSD_OP_WRITE,
+                                               CEPH_OSD_FLAG_WRITE |
+                                               CEPH_OSD_FLAG_ONDISK,
+                                               snapc, truncate_seq,
+                                               truncate_size, true);
+                       BUG_ON(IS_ERR(req));
                }
-               dout("writepages got %d pages at %llu~%llu\n",
-                    locked_pages, offset, len);
+               BUG_ON(len < page_offset(pages[locked_pages - 1]) +
+                            PAGE_CACHE_SIZE - offset);
+
+               req->r_callback = writepages_finish;
+               req->r_inode = inode;
 
-               osd_req_op_extent_osd_data_pages(req, 0, pages, len, 0,
+               /* Format the osd request message and submit the write */
+               len = 0;
+               data_pages = pages;
+               op_idx = 0;
+               for (i = 0; i < locked_pages; i++) {
+                       u64 cur_offset = page_offset(pages[i]);
+                       if (offset + len != cur_offset) {
+                               if (op_idx + do_sync + 1 == req->r_num_ops)
+                                       break;
+                               osd_req_op_extent_dup_last(req, op_idx,
+                                                          cur_offset - offset);
+                               dout("writepages got pages at %llu~%llu\n",
+                                    offset, len);
+                               osd_req_op_extent_osd_data_pages(req, op_idx,
+                                                       data_pages, len, 0,
                                                        !!pool, false);
+                               osd_req_op_extent_update(req, op_idx, len);
 
-               pages = NULL;   /* request message now owns the pages array */
-               pool = NULL;
+                               len = 0;
+                               offset = cur_offset; 
+                               data_pages = pages + i;
+                               op_idx++;
+                       }
 
-               /* Update the write op length in case we changed it */
+                       set_page_writeback(pages[i]);
+                       len += PAGE_CACHE_SIZE;
+               }
+
+               if (snap_size != -1) {
+                       len = min(len, snap_size - offset);
+               } else if (i == locked_pages) {
+                       /* writepages_finish() clears writeback pages
+                        * according to the data length, so make sure
+                        * data length covers all locked pages */
+                       u64 min_len = len + 1 - PAGE_CACHE_SIZE;
+                       len = min(len, (u64)i_size_read(inode) - offset);
+                       len = max(len, min_len);
+               }
+               dout("writepages got pages at %llu~%llu\n", offset, len);
+
+               osd_req_op_extent_osd_data_pages(req, op_idx, data_pages, len,
+                                                0, !!pool, false);
+               osd_req_op_extent_update(req, op_idx, len);
 
-               osd_req_op_extent_update(req, 0, len);
+               if (do_sync) {
+                       op_idx++;
+                       osd_req_op_init(req, op_idx, CEPH_OSD_OP_STARTSYNC, 0);
+               }
+               BUG_ON(op_idx + 1 != req->r_num_ops);
+
+               pool = NULL;
+               if (i < locked_pages) {
+                       BUG_ON(num_ops <= req->r_num_ops);
+                       num_ops -= req->r_num_ops;
+                       num_ops += do_sync;
+                       locked_pages -= i;
+
+                       /* allocate new pages array for next request */
+                       data_pages = pages;
+                       pages = kmalloc(locked_pages * sizeof (*pages),
+                                       GFP_NOFS);
+                       if (!pages) {
+                               pool = fsc->wb_pagevec_pool;
+                               pages = mempool_alloc(pool, GFP_NOFS);
+                               BUG_ON(!pages);
+                       }
+                       memcpy(pages, data_pages + i,
+                              locked_pages * sizeof(*pages));
+                       memset(data_pages + i, 0,
+                              locked_pages * sizeof(*pages));
+               } else {
+                       BUG_ON(num_ops != req->r_num_ops);
+                       index = pages[i - 1]->index + 1;
+                       /* request message now owns the pages array */
+                       pages = NULL;
+               }
 
                vino = ceph_vino(inode);
                ceph_osdc_build_request(req, offset, snapc, vino.snap,
@@ -985,9 +1071,10 @@ get_more_pages:
                BUG_ON(rc);
                req = NULL;
 
-               /* continue? */
-               index = next;
-               wbc->nr_to_write -= locked_pages;
+               wbc->nr_to_write -= i;
+               if (pages)
+                       goto new_request;
+
                if (wbc->nr_to_write <= 0)
                        done = 1;
 
@@ -1522,7 +1609,7 @@ int ceph_uninline_data(struct file *filp, struct page *locked_page)
                                    ceph_vino(inode), 0, &len, 0, 1,
                                    CEPH_OSD_OP_CREATE,
                                    CEPH_OSD_FLAG_ONDISK | CEPH_OSD_FLAG_WRITE,
-                                   ceph_empty_snapc, 0, 0, false);
+                                   NULL, 0, 0, false);
        if (IS_ERR(req)) {
                err = PTR_ERR(req);
                goto out;
@@ -1540,9 +1627,8 @@ int ceph_uninline_data(struct file *filp, struct page *locked_page)
                                    ceph_vino(inode), 0, &len, 1, 3,
                                    CEPH_OSD_OP_WRITE,
                                    CEPH_OSD_FLAG_ONDISK | CEPH_OSD_FLAG_WRITE,
-                                   ceph_empty_snapc,
-                                   ci->i_truncate_seq, ci->i_truncate_size,
-                                   false);
+                                   NULL, ci->i_truncate_seq,
+                                   ci->i_truncate_size, false);
        if (IS_ERR(req)) {
                err = PTR_ERR(req);
                goto out;
@@ -1663,8 +1749,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
                goto out;
        }
 
-       rd_req = ceph_osdc_alloc_request(&fsc->client->osdc,
-                                        ceph_empty_snapc,
+       rd_req = ceph_osdc_alloc_request(&fsc->client->osdc, NULL,
                                         1, false, GFP_NOFS);
        if (!rd_req) {
                err = -ENOMEM;
@@ -1678,8 +1763,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
                 "%llx.00000000", ci->i_vino.ino);
        rd_req->r_base_oid.name_len = strlen(rd_req->r_base_oid.name);
 
-       wr_req = ceph_osdc_alloc_request(&fsc->client->osdc,
-                                        ceph_empty_snapc,
+       wr_req = ceph_osdc_alloc_request(&fsc->client->osdc, NULL,
                                         1, false, GFP_NOFS);
        if (!wr_req) {
                err = -ENOMEM;
index 6fe0ad2..de17bb2 100644 (file)
@@ -991,7 +991,7 @@ static int send_cap_msg(struct ceph_mds_session *session,
                        u32 seq, u64 flush_tid, u64 oldest_flush_tid,
                        u32 issue_seq, u32 mseq, u64 size, u64 max_size,
                        struct timespec *mtime, struct timespec *atime,
-                       u64 time_warp_seq,
+                       struct timespec *ctime, u64 time_warp_seq,
                        kuid_t uid, kgid_t gid, umode_t mode,
                        u64 xattr_version,
                        struct ceph_buffer *xattrs_buf,
@@ -1042,6 +1042,8 @@ static int send_cap_msg(struct ceph_mds_session *session,
                ceph_encode_timespec(&fc->mtime, mtime);
        if (atime)
                ceph_encode_timespec(&fc->atime, atime);
+       if (ctime)
+               ceph_encode_timespec(&fc->ctime, ctime);
        fc->time_warp_seq = cpu_to_le32(time_warp_seq);
 
        fc->uid = cpu_to_le32(from_kuid(&init_user_ns, uid));
@@ -1116,7 +1118,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        int held, revoking, dropping, keep;
        u64 seq, issue_seq, mseq, time_warp_seq, follows;
        u64 size, max_size;
-       struct timespec mtime, atime;
+       struct timespec mtime, atime, ctime;
        int wake = 0;
        umode_t mode;
        kuid_t uid;
@@ -1180,6 +1182,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        ci->i_requested_max_size = max_size;
        mtime = inode->i_mtime;
        atime = inode->i_atime;
+       ctime = inode->i_ctime;
        time_warp_seq = ci->i_time_warp_seq;
        uid = inode->i_uid;
        gid = inode->i_gid;
@@ -1198,7 +1201,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        ret = send_cap_msg(session, ceph_vino(inode).ino, cap_id,
                op, keep, want, flushing, seq,
                flush_tid, oldest_flush_tid, issue_seq, mseq,
-               size, max_size, &mtime, &atime, time_warp_seq,
+               size, max_size, &mtime, &atime, &ctime, time_warp_seq,
                uid, gid, mode, xattr_version, xattr_blob,
                follows, inline_data);
        if (ret < 0) {
@@ -1320,7 +1323,7 @@ retry:
                             capsnap->dirty, 0, capsnap->flush_tid, 0,
                             0, mseq, capsnap->size, 0,
                             &capsnap->mtime, &capsnap->atime,
-                            capsnap->time_warp_seq,
+                            &capsnap->ctime, capsnap->time_warp_seq,
                             capsnap->uid, capsnap->gid, capsnap->mode,
                             capsnap->xattr_version, capsnap->xattr_blob,
                             capsnap->follows, capsnap->inline_data);
index fd11fb2..fadc243 100644 (file)
@@ -38,7 +38,7 @@ int ceph_init_dentry(struct dentry *dentry)
        if (dentry->d_fsdata)
                return 0;
 
-       di = kmem_cache_alloc(ceph_dentry_cachep, GFP_KERNEL | __GFP_ZERO);
+       di = kmem_cache_zalloc(ceph_dentry_cachep, GFP_KERNEL);
        if (!di)
                return -ENOMEM;          /* oh well */
 
@@ -68,23 +68,6 @@ out_unlock:
        return 0;
 }
 
-struct inode *ceph_get_dentry_parent_inode(struct dentry *dentry)
-{
-       struct inode *inode = NULL;
-
-       if (!dentry)
-               return NULL;
-
-       spin_lock(&dentry->d_lock);
-       if (!IS_ROOT(dentry)) {
-               inode = d_inode(dentry->d_parent);
-               ihold(inode);
-       }
-       spin_unlock(&dentry->d_lock);
-       return inode;
-}
-
-
 /*
  * for readdir, we encode the directory frag and offset within that
  * frag into f_pos.
@@ -624,6 +607,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int op;
+       int mask;
        int err;
 
        dout("lookup %p dentry %p '%pd'\n",
@@ -666,8 +650,12 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
                return ERR_CAST(req);
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
-       /* we only need inode linkage */
-       req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
+
+       mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED;
+       if (ceph_security_xattr_wanted(dir))
+               mask |= CEPH_CAP_XATTR_SHARED;
+       req->r_args.getattr.mask = cpu_to_le32(mask);
+
        req->r_locked_dir = dir;
        err = ceph_mdsc_do_request(mdsc, NULL, req);
        err = ceph_handle_snapdir(req, dentry, err);
@@ -1095,6 +1083,7 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
 static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        int valid = 0;
+       struct dentry *parent;
        struct inode *dir;
 
        if (flags & LOOKUP_RCU)
@@ -1103,7 +1092,8 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
        dout("d_revalidate %p '%pd' inode %p offset %lld\n", dentry,
             dentry, d_inode(dentry), ceph_dentry(dentry)->offset);
 
-       dir = ceph_get_dentry_parent_inode(dentry);
+       parent = dget_parent(dentry);
+       dir = d_inode(parent);
 
        /* always trust cached snapped dentries, snapdir dentry */
        if (ceph_snap(dir) != CEPH_NOSNAP) {
@@ -1121,13 +1111,48 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                        valid = 1;
        }
 
+       if (!valid) {
+               struct ceph_mds_client *mdsc =
+                       ceph_sb_to_client(dir->i_sb)->mdsc;
+               struct ceph_mds_request *req;
+               int op, mask, err;
+
+               op = ceph_snap(dir) == CEPH_SNAPDIR ?
+                       CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP;
+               req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS);
+               if (!IS_ERR(req)) {
+                       req->r_dentry = dget(dentry);
+                       req->r_num_caps = 2;
+
+                       mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED;
+                       if (ceph_security_xattr_wanted(dir))
+                               mask |= CEPH_CAP_XATTR_SHARED;
+                       req->r_args.getattr.mask = mask;
+
+                       req->r_locked_dir = dir;
+                       err = ceph_mdsc_do_request(mdsc, NULL, req);
+                       if (err == 0 || err == -ENOENT) {
+                               if (dentry == req->r_dentry) {
+                                       valid = !d_unhashed(dentry);
+                               } else {
+                                       d_invalidate(req->r_dentry);
+                                       err = -EAGAIN;
+                               }
+                       }
+                       ceph_mdsc_put_request(req);
+                       dout("d_revalidate %p lookup result=%d\n",
+                            dentry, err);
+               }
+       }
+
        dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid");
        if (valid) {
                ceph_dentry_lru_touch(dentry);
        } else {
                ceph_dir_clear_complete(dir);
        }
-       iput(dir);
+
+       dput(parent);
        return valid;
 }
 
index 3b31723..6e72c98 100644 (file)
@@ -71,12 +71,18 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
        inode = ceph_find_inode(sb, vino);
        if (!inode) {
                struct ceph_mds_request *req;
+               int mask;
 
                req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
                                               USE_ANY_MDS);
                if (IS_ERR(req))
                        return ERR_CAST(req);
 
+               mask = CEPH_STAT_CAP_INODE;
+               if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
+                       mask |= CEPH_CAP_XATTR_SHARED;
+               req->r_args.getattr.mask = cpu_to_le32(mask);
+
                req->r_ino1 = vino;
                req->r_num_caps = 1;
                err = ceph_mdsc_do_request(mdsc, NULL, req);
@@ -128,6 +134,7 @@ static struct dentry *__get_parent(struct super_block *sb,
        struct ceph_mds_request *req;
        struct inode *inode;
        struct dentry *dentry;
+       int mask;
        int err;
 
        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
@@ -144,6 +151,12 @@ static struct dentry *__get_parent(struct super_block *sb,
                        .snap = CEPH_NOSNAP,
                };
        }
+
+       mask = CEPH_STAT_CAP_INODE;
+       if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
+               mask |= CEPH_CAP_XATTR_SHARED;
+       req->r_args.getattr.mask = cpu_to_le32(mask);
+
        req->r_num_caps = 1;
        err = ceph_mdsc_do_request(mdsc, NULL, req);
        inode = req->r_target_inode;
index eb9028e..ef38f01 100644 (file)
@@ -157,7 +157,7 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
        case S_IFDIR:
                dout("init_file %p %p 0%o (regular)\n", inode, file,
                     inode->i_mode);
-               cf = kmem_cache_alloc(ceph_file_cachep, GFP_KERNEL | __GFP_ZERO);
+               cf = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
                if (cf == NULL) {
                        ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
                        return -ENOMEM;
@@ -300,6 +300,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        struct ceph_mds_request *req;
        struct dentry *dn;
        struct ceph_acls_info acls = {};
+       int mask;
        int err;
 
        dout("atomic_open %p dentry %p '%pd' %s flags %d mode 0%o\n",
@@ -335,6 +336,12 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
                        acls.pagelist = NULL;
                }
        }
+
+       mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED;
+       if (ceph_security_xattr_wanted(dir))
+               mask |= CEPH_CAP_XATTR_SHARED;
+       req->r_args.open.mask = cpu_to_le32(mask);
+
        req->r_locked_dir = dir;           /* caller holds dir->i_mutex */
        err = ceph_mdsc_do_request(mdsc,
                                   (flags & (O_CREAT|O_TRUNC)) ? dir : NULL,
@@ -725,7 +732,6 @@ static void ceph_aio_retry_work(struct work_struct *work)
        ret = ceph_osdc_start_request(req->r_osdc, req, false);
 out:
        if (ret < 0) {
-               BUG_ON(ret == -EOLDSNAPC);
                req->r_result = ret;
                ceph_aio_complete_req(req, NULL);
        }
@@ -783,7 +789,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
        int num_pages = 0;
        int flags;
        int ret;
-       struct timespec mtime = CURRENT_TIME;
+       struct timespec mtime = current_fs_time(inode->i_sb);
        size_t count = iov_iter_count(iter);
        loff_t pos = iocb->ki_pos;
        bool write = iov_iter_rw(iter) == WRITE;
@@ -949,7 +955,6 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                                ret = ceph_osdc_start_request(req->r_osdc,
                                                              req, false);
                        if (ret < 0) {
-                               BUG_ON(ret == -EOLDSNAPC);
                                req->r_result = ret;
                                ceph_aio_complete_req(req, NULL);
                        }
@@ -988,7 +993,7 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,
        int flags;
        int check_caps = 0;
        int ret;
-       struct timespec mtime = CURRENT_TIME;
+       struct timespec mtime = current_fs_time(inode->i_sb);
        size_t count = iov_iter_count(from);
 
        if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
index e48fd8b..ed58b16 100644 (file)
@@ -549,6 +549,10 @@ int ceph_fill_file_size(struct inode *inode, int issued,
        if (ceph_seq_cmp(truncate_seq, ci->i_truncate_seq) > 0 ||
            (truncate_seq == ci->i_truncate_seq && size > inode->i_size)) {
                dout("size %lld -> %llu\n", inode->i_size, size);
+               if (size > 0 && S_ISDIR(inode->i_mode)) {
+                       pr_err("fill_file_size non-zero size for directory\n");
+                       size = 0;
+               }
                i_size_write(inode, size);
                inode->i_blocks = (size + (1<<9) - 1) >> 9;
                ci->i_reported_size = size;
@@ -1261,6 +1265,7 @@ retry_lookup:
                        dout(" %p links to %p %llx.%llx, not %llx.%llx\n",
                             dn, d_inode(dn), ceph_vinop(d_inode(dn)),
                             ceph_vinop(in));
+                       d_invalidate(dn);
                        have_lease = false;
                }
 
@@ -1349,15 +1354,20 @@ static int fill_readdir_cache(struct inode *dir, struct dentry *dn,
 
        if (!ctl->page || pgoff != page_index(ctl->page)) {
                ceph_readdir_cache_release(ctl);
-               ctl->page  = grab_cache_page(&dir->i_data, pgoff);
+               if (idx == 0)
+                       ctl->page = grab_cache_page(&dir->i_data, pgoff);
+               else
+                       ctl->page = find_lock_page(&dir->i_data, pgoff);
                if (!ctl->page) {
                        ctl->index = -1;
-                       return -ENOMEM;
+                       return idx == 0 ? -ENOMEM : 0;
                }
                /* reading/filling the cache are serialized by
                 * i_mutex, no need to use page lock */
                unlock_page(ctl->page);
                ctl->dentries = kmap(ctl->page);
+               if (idx == 0)
+                       memset(ctl->dentries, 0, PAGE_CACHE_SIZE);
        }
 
        if (req->r_dir_release_cnt == atomic64_read(&ci->i_release_count) &&
@@ -1380,7 +1390,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
        struct qstr dname;
        struct dentry *dn;
        struct inode *in;
-       int err = 0, ret, i;
+       int err = 0, skipped = 0, ret, i;
        struct inode *snapdir = NULL;
        struct ceph_mds_request_head *rhead = req->r_request->front.iov_base;
        struct ceph_dentry_info *di;
@@ -1492,7 +1502,17 @@ retry_lookup:
                }
 
                if (d_really_is_negative(dn)) {
-                       struct dentry *realdn = splice_dentry(dn, in);
+                       struct dentry *realdn;
+
+                       if (ceph_security_xattr_deadlock(in)) {
+                               dout(" skip splicing dn %p to inode %p"
+                                    " (security xattr deadlock)\n", dn, in);
+                               iput(in);
+                               skipped++;
+                               goto next_item;
+                       }
+
+                       realdn = splice_dentry(dn, in);
                        if (IS_ERR(realdn)) {
                                err = PTR_ERR(realdn);
                                d_drop(dn);
@@ -1509,7 +1529,7 @@ retry_lookup:
                                    req->r_session,
                                    req->r_request_started);
 
-               if (err == 0 && cache_ctl.index >= 0) {
+               if (err == 0 && skipped == 0 && cache_ctl.index >= 0) {
                        ret = fill_readdir_cache(d_inode(parent), dn,
                                                 &cache_ctl, req);
                        if (ret < 0)
@@ -1520,7 +1540,7 @@ next_item:
                        dput(dn);
        }
 out:
-       if (err == 0) {
+       if (err == 0 && skipped == 0) {
                req->r_did_prepopulate = true;
                req->r_readdir_cache_idx = cache_ctl.index;
        }
@@ -1950,7 +1970,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        if (dirtied) {
                inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied,
                                                           &prealloc_cf);
-               inode->i_ctime = CURRENT_TIME;
+               inode->i_ctime = current_fs_time(inode->i_sb);
        }
 
        release &= issued;
index 911d64d..44852c3 100644 (file)
@@ -1729,7 +1729,7 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
        init_completion(&req->r_safe_completion);
        INIT_LIST_HEAD(&req->r_unsafe_item);
 
-       req->r_stamp = CURRENT_TIME;
+       req->r_stamp = current_fs_time(mdsc->fsc->sb);
 
        req->r_op = op;
        req->r_direct_mode = mode;
@@ -2540,6 +2540,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
 
        /* insert trace into our cache */
        mutex_lock(&req->r_fill_mutex);
+       current->journal_info = req;
        err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session);
        if (err == 0) {
                if (result == 0 && (req->r_op == CEPH_MDS_OP_READDIR ||
@@ -2547,6 +2548,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
                        ceph_readdir_prepopulate(req, req->r_session);
                ceph_unreserve_caps(mdsc, &req->r_caps_reservation);
        }
+       current->journal_info = NULL;
        mutex_unlock(&req->r_fill_mutex);
 
        up_read(&mdsc->snap_rwsem);
@@ -3764,7 +3766,6 @@ void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
        dout("handle_map epoch %u len %d\n", epoch, (int)maplen);
 
        /* do we need it? */
-       ceph_monc_got_mdsmap(&mdsc->fsc->client->monc, epoch);
        mutex_lock(&mdsc->mutex);
        if (mdsc->mdsmap && epoch <= mdsc->mdsmap->m_epoch) {
                dout("handle_map epoch %u <= our %u\n",
@@ -3791,6 +3792,8 @@ void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
        mdsc->fsc->sb->s_maxbytes = mdsc->mdsmap->m_max_file_size;
 
        __wake_requests(mdsc, &mdsc->waiting_for_map);
+       ceph_monc_got_map(&mdsc->fsc->client->monc, CEPH_SUB_MDSMAP,
+                         mdsc->mdsmap->m_epoch);
 
        mutex_unlock(&mdsc->mutex);
        schedule_delayed(mdsc);
index 4aa7122..9caaa7f 100644 (file)
@@ -296,8 +296,6 @@ static int cmpu64_rev(const void *a, const void *b)
 }
 
 
-struct ceph_snap_context *ceph_empty_snapc;
-
 /*
  * build the snap context for a given realm.
  */
@@ -987,17 +985,3 @@ out:
                up_write(&mdsc->snap_rwsem);
        return;
 }
-
-int __init ceph_snap_init(void)
-{
-       ceph_empty_snapc = ceph_create_snap_context(0, GFP_NOFS);
-       if (!ceph_empty_snapc)
-               return -ENOMEM;
-       ceph_empty_snapc->seq = 1;
-       return 0;
-}
-
-void ceph_snap_exit(void)
-{
-       ceph_put_snap_context(ceph_empty_snapc);
-}
index ca4d5e8..c973043 100644 (file)
@@ -439,8 +439,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
 
        if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT)
                seq_puts(m, ",dirstat");
-       if ((fsopt->flags & CEPH_MOUNT_OPT_RBYTES) == 0)
-               seq_puts(m, ",norbytes");
+       if ((fsopt->flags & CEPH_MOUNT_OPT_RBYTES))
+               seq_puts(m, ",rbytes");
        if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR)
                seq_puts(m, ",noasyncreaddir");
        if ((fsopt->flags & CEPH_MOUNT_OPT_DCACHE) == 0)
@@ -530,7 +530,7 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
                goto fail;
        }
        fsc->client->extra_mon_dispatch = extra_mon_dispatch;
-       fsc->client->monc.want_mdsmap = 1;
+       ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP, 0, true);
 
        fsc->mount_options = fsopt;
 
@@ -793,22 +793,20 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
        struct dentry *root;
        int first = 0;   /* first vfsmount for this super_block */
 
-       dout("mount start\n");
+       dout("mount start %p\n", fsc);
        mutex_lock(&fsc->client->mount_mutex);
 
-       err = __ceph_open_session(fsc->client, started);
-       if (err < 0)
-               goto out;
+       if (!fsc->sb->s_root) {
+               err = __ceph_open_session(fsc->client, started);
+               if (err < 0)
+                       goto out;
 
-       dout("mount opening root\n");
-       root = open_root_dentry(fsc, "", started);
-       if (IS_ERR(root)) {
-               err = PTR_ERR(root);
-               goto out;
-       }
-       if (fsc->sb->s_root) {
-               dput(root);
-       } else {
+               dout("mount opening root\n");
+               root = open_root_dentry(fsc, "", started);
+               if (IS_ERR(root)) {
+                       err = PTR_ERR(root);
+                       goto out;
+               }
                fsc->sb->s_root = root;
                first = 1;
 
@@ -818,6 +816,7 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
        }
 
        if (path[0] == 0) {
+               root = fsc->sb->s_root;
                dget(root);
        } else {
                dout("mount opening base mountpoint\n");
@@ -833,16 +832,14 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
        mutex_unlock(&fsc->client->mount_mutex);
        return root;
 
-out:
-       mutex_unlock(&fsc->client->mount_mutex);
-       return ERR_PTR(err);
-
 fail:
        if (first) {
                dput(fsc->sb->s_root);
                fsc->sb->s_root = NULL;
        }
-       goto out;
+out:
+       mutex_unlock(&fsc->client->mount_mutex);
+       return ERR_PTR(err);
 }
 
 static int ceph_set_super(struct super_block *s, void *data)
@@ -1042,19 +1039,14 @@ static int __init init_ceph(void)
 
        ceph_flock_init();
        ceph_xattr_init();
-       ret = ceph_snap_init();
-       if (ret)
-               goto out_xattr;
        ret = register_filesystem(&ceph_fs_type);
        if (ret)
-               goto out_snap;
+               goto out_xattr;
 
        pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL);
 
        return 0;
 
-out_snap:
-       ceph_snap_exit();
 out_xattr:
        ceph_xattr_exit();
        destroy_caches();
@@ -1066,7 +1058,6 @@ static void __exit exit_ceph(void)
 {
        dout("exit_ceph\n");
        unregister_filesystem(&ceph_fs_type);
-       ceph_snap_exit();
        ceph_xattr_exit();
        destroy_caches();
 }
index 9c458eb..e705c4d 100644 (file)
@@ -37,8 +37,7 @@
 #define CEPH_MOUNT_OPT_FSCACHE         (1<<10) /* use fscache */
 #define CEPH_MOUNT_OPT_NOPOOLPERM      (1<<11) /* no pool permission check */
 
-#define CEPH_MOUNT_OPT_DEFAULT    (CEPH_MOUNT_OPT_RBYTES | \
-                                  CEPH_MOUNT_OPT_DCACHE)
+#define CEPH_MOUNT_OPT_DEFAULT    CEPH_MOUNT_OPT_DCACHE
 
 #define ceph_set_mount_opt(fsc, opt) \
        (fsc)->mount_options->flags |= CEPH_MOUNT_OPT_##opt;
@@ -469,7 +468,7 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
 #define CEPH_I_POOL_PERM       (1 << 4)  /* pool rd/wr bits are valid */
 #define CEPH_I_POOL_RD         (1 << 5)  /* can read from pool */
 #define CEPH_I_POOL_WR         (1 << 6)  /* can write to pool */
-
+#define CEPH_I_SEC_INITED      (1 << 7)  /* security initialized */
 
 static inline void __ceph_dir_set_complete(struct ceph_inode_info *ci,
                                           long long release_count,
@@ -721,7 +720,6 @@ static inline int default_congestion_kb(void)
 
 
 /* snap.c */
-extern struct ceph_snap_context *ceph_empty_snapc;
 struct ceph_snap_realm *ceph_lookup_snap_realm(struct ceph_mds_client *mdsc,
                                               u64 ino);
 extern void ceph_get_snap_realm(struct ceph_mds_client *mdsc,
@@ -738,8 +736,6 @@ extern void ceph_queue_cap_snap(struct ceph_inode_info *ci);
 extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
                                  struct ceph_cap_snap *capsnap);
 extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc);
-extern int ceph_snap_init(void);
-extern void ceph_snap_exit(void);
 
 /*
  * a cap_snap is "pending" if it is still awaiting an in-progress
@@ -808,6 +804,20 @@ extern void __init ceph_xattr_init(void);
 extern void ceph_xattr_exit(void);
 extern const struct xattr_handler *ceph_xattr_handlers[];
 
+#ifdef CONFIG_SECURITY
+extern bool ceph_security_xattr_deadlock(struct inode *in);
+extern bool ceph_security_xattr_wanted(struct inode *in);
+#else
+static inline bool ceph_security_xattr_deadlock(struct inode *in)
+{
+       return false;
+}
+static inline bool ceph_security_xattr_wanted(struct inode *in)
+{
+       return false;
+}
+#endif
+
 /* acl.c */
 struct ceph_acls_info {
        void *default_acl;
@@ -947,7 +957,6 @@ extern void ceph_dentry_lru_touch(struct dentry *dn);
 extern void ceph_dentry_lru_del(struct dentry *dn);
 extern void ceph_invalidate_dentry_lease(struct dentry *dentry);
 extern unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn);
-extern struct inode *ceph_get_dentry_parent_inode(struct dentry *dentry);
 extern void ceph_readdir_cache_release(struct ceph_readdir_cache_control *ctl);
 
 /*
index 819163d..9410abd 100644 (file)
@@ -714,31 +714,62 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
        }
 }
 
+static inline int __get_request_mask(struct inode *in) {
+       struct ceph_mds_request *req = current->journal_info;
+       int mask = 0;
+       if (req && req->r_target_inode == in) {
+               if (req->r_op == CEPH_MDS_OP_LOOKUP ||
+                   req->r_op == CEPH_MDS_OP_LOOKUPINO ||
+                   req->r_op == CEPH_MDS_OP_LOOKUPPARENT ||
+                   req->r_op == CEPH_MDS_OP_GETATTR) {
+                       mask = le32_to_cpu(req->r_args.getattr.mask);
+               } else if (req->r_op == CEPH_MDS_OP_OPEN ||
+                          req->r_op == CEPH_MDS_OP_CREATE) {
+                       mask = le32_to_cpu(req->r_args.open.mask);
+               }
+       }
+       return mask;
+}
+
 ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
                      size_t size)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int err;
        struct ceph_inode_xattr *xattr;
        struct ceph_vxattr *vxattr = NULL;
+       int req_mask;
+       int err;
 
        if (!ceph_is_valid_xattr(name))
                return -ENODATA;
 
        /* let's see if a virtual xattr was requested */
        vxattr = ceph_match_vxattr(inode, name);
-       if (vxattr && !(vxattr->exists_cb && !vxattr->exists_cb(ci))) {
-               err = vxattr->getxattr_cb(ci, value, size);
+       if (vxattr) {
+               err = -ENODATA;
+               if (!(vxattr->exists_cb && !vxattr->exists_cb(ci)))
+                       err = vxattr->getxattr_cb(ci, value, size);
                return err;
        }
 
+       req_mask = __get_request_mask(inode);
+
        spin_lock(&ci->i_ceph_lock);
        dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
             ci->i_xattrs.version, ci->i_xattrs.index_version);
 
        if (ci->i_xattrs.version == 0 ||
-           !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) {
+           !((req_mask & CEPH_CAP_XATTR_SHARED) ||
+             __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1))) {
                spin_unlock(&ci->i_ceph_lock);
+
+               /* security module gets xattr while filling trace */
+               if (current->journal_info != NULL) {
+                       pr_warn_ratelimited("sync getxattr %p "
+                                           "during filling trace\n", inode);
+                       return -EBUSY;
+               }
+
                /* get xattrs from mds (if we don't already have them) */
                err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
                if (err)
@@ -765,6 +796,9 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
 
        memcpy(value, xattr->val, xattr->val_len);
 
+       if (current->journal_info != NULL &&
+           !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN))
+               ci->i_ceph_flags |= CEPH_I_SEC_INITED;
 out:
        spin_unlock(&ci->i_ceph_lock);
        return err;
@@ -999,7 +1033,7 @@ retry:
                dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
                                               &prealloc_cf);
                ci->i_xattrs.dirty = true;
-               inode->i_ctime = CURRENT_TIME;
+               inode->i_ctime = current_fs_time(inode->i_sb);
        }
 
        spin_unlock(&ci->i_ceph_lock);
@@ -1015,7 +1049,15 @@ do_sync:
 do_sync_unlocked:
        if (lock_snap_rwsem)
                up_read(&mdsc->snap_rwsem);
-       err = ceph_sync_setxattr(dentry, name, value, size, flags);
+
+       /* security module set xattr while filling trace */
+       if (current->journal_info != NULL) {
+               pr_warn_ratelimited("sync setxattr %p "
+                                   "during filling trace\n", inode);
+               err = -EBUSY;
+       } else {
+               err = ceph_sync_setxattr(dentry, name, value, size, flags);
+       }
 out:
        ceph_free_cap_flush(prealloc_cf);
        kfree(newname);
@@ -1136,7 +1178,7 @@ retry:
        dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
                                       &prealloc_cf);
        ci->i_xattrs.dirty = true;
-       inode->i_ctime = CURRENT_TIME;
+       inode->i_ctime = current_fs_time(inode->i_sb);
        spin_unlock(&ci->i_ceph_lock);
        if (lock_snap_rwsem)
                up_read(&mdsc->snap_rwsem);
@@ -1164,3 +1206,25 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
 
        return __ceph_removexattr(dentry, name);
 }
+
+#ifdef CONFIG_SECURITY
+bool ceph_security_xattr_wanted(struct inode *in)
+{
+       return in->i_security != NULL;
+}
+
+bool ceph_security_xattr_deadlock(struct inode *in)
+{
+       struct ceph_inode_info *ci;
+       bool ret;
+       if (in->i_security == NULL)
+               return false;
+       ci = ceph_inode(in);
+       spin_lock(&ci->i_ceph_lock);
+       ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) &&
+             !(ci->i_xattrs.version > 0 &&
+               __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0));
+       spin_unlock(&ci->i_ceph_lock);
+       return ret;
+}
+#endif
index aed9ccc..06cd1a2 100644 (file)
@@ -170,7 +170,7 @@ static int do_page_crypto(struct inode *inode,
                fscrypt_complete, &ecr);
 
        BUILD_BUG_ON(FS_XTS_TWEAK_SIZE < sizeof(index));
-       memcpy(xts_tweak, &inode->i_ino, sizeof(index));
+       memcpy(xts_tweak, &index, sizeof(index));
        memset(&xts_tweak[sizeof(index)], 0,
                        FS_XTS_TWEAK_SIZE - sizeof(index));
 
index 5191121..1669f62 100644 (file)
@@ -343,13 +343,12 @@ static struct config_group *make_cluster(struct config_group *g,
        struct dlm_cluster *cl = NULL;
        struct dlm_spaces *sps = NULL;
        struct dlm_comms *cms = NULL;
-       void *gps = NULL;
 
        cl = kzalloc(sizeof(struct dlm_cluster), GFP_NOFS);
        sps = kzalloc(sizeof(struct dlm_spaces), GFP_NOFS);
        cms = kzalloc(sizeof(struct dlm_comms), GFP_NOFS);
 
-       if (!cl || !gps || !sps || !cms)
+       if (!cl || !sps || !cms)
                goto fail;
 
        config_group_init_type_name(&cl->group, name, &cluster_type);
index 5c46ed9..fee81e8 100644 (file)
@@ -281,13 +281,15 @@ locked_inode_to_wb_and_lock_list(struct inode *inode)
                wb_get(wb);
                spin_unlock(&inode->i_lock);
                spin_lock(&wb->list_lock);
-               wb_put(wb);             /* not gonna deref it anymore */
 
                /* i_wb may have changed inbetween, can't use inode_to_wb() */
-               if (likely(wb == inode->i_wb))
-                       return wb;      /* @inode already has ref */
+               if (likely(wb == inode->i_wb)) {
+                       wb_put(wb);     /* @inode already has ref */
+                       return wb;
+               }
 
                spin_unlock(&wb->list_lock);
+               wb_put(wb);
                cpu_relax();
                spin_lock(&inode->i_lock);
        }
@@ -1337,10 +1339,10 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
  * we go e.g. from filesystem. Flusher thread uses __writeback_single_inode()
  * and does more profound writeback list handling in writeback_sb_inodes().
  */
-static int
-writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
-                      struct writeback_control *wbc)
+static int writeback_single_inode(struct inode *inode,
+                                 struct writeback_control *wbc)
 {
+       struct bdi_writeback *wb;
        int ret = 0;
 
        spin_lock(&inode->i_lock);
@@ -1378,7 +1380,8 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
        ret = __writeback_single_inode(inode, wbc);
 
        wbc_detach_inode(wbc);
-       spin_lock(&wb->list_lock);
+
+       wb = inode_to_wb_and_lock_list(inode);
        spin_lock(&inode->i_lock);
        /*
         * If inode is clean, remove it from writeback lists. Otherwise don't
@@ -1453,6 +1456,7 @@ static long writeback_sb_inodes(struct super_block *sb,
 
        while (!list_empty(&wb->b_io)) {
                struct inode *inode = wb_inode(wb->b_io.prev);
+               struct bdi_writeback *tmp_wb;
 
                if (inode->i_sb != sb) {
                        if (work->sb) {
@@ -1543,15 +1547,23 @@ static long writeback_sb_inodes(struct super_block *sb,
                        cond_resched();
                }
 
-
-               spin_lock(&wb->list_lock);
+               /*
+                * Requeue @inode if still dirty.  Be careful as @inode may
+                * have been switched to another wb in the meantime.
+                */
+               tmp_wb = inode_to_wb_and_lock_list(inode);
                spin_lock(&inode->i_lock);
                if (!(inode->i_state & I_DIRTY_ALL))
                        wrote++;
-               requeue_inode(inode, wb, &wbc);
+               requeue_inode(inode, tmp_wb, &wbc);
                inode_sync_complete(inode);
                spin_unlock(&inode->i_lock);
 
+               if (unlikely(tmp_wb != wb)) {
+                       spin_unlock(&tmp_wb->list_lock);
+                       spin_lock(&wb->list_lock);
+               }
+
                /*
                 * bail out to wb_writeback() often enough to check
                 * background threshold and other termination conditions.
@@ -2338,7 +2350,6 @@ EXPORT_SYMBOL(sync_inodes_sb);
  */
 int write_inode_now(struct inode *inode, int sync)
 {
-       struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
        struct writeback_control wbc = {
                .nr_to_write = LONG_MAX,
                .sync_mode = sync ? WB_SYNC_ALL : WB_SYNC_NONE,
@@ -2350,7 +2361,7 @@ int write_inode_now(struct inode *inode, int sync)
                wbc.nr_to_write = 0;
 
        might_sleep();
-       return writeback_single_inode(inode, wb, &wbc);
+       return writeback_single_inode(inode, &wbc);
 }
 EXPORT_SYMBOL(write_inode_now);
 
@@ -2367,7 +2378,7 @@ EXPORT_SYMBOL(write_inode_now);
  */
 int sync_inode(struct inode *inode, struct writeback_control *wbc)
 {
-       return writeback_single_inode(inode, &inode_to_bdi(inode)->wb, wbc);
+       return writeback_single_inode(inode, wbc);
 }
 EXPORT_SYMBOL(sync_inode);
 
index 95d5880..7e553f2 100644 (file)
@@ -134,37 +134,59 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
        if (mutex_lock_interruptible(&c->alloc_sem))
                return -EINTR;
 
+
        for (;;) {
+               /* We can't start doing GC until we've finished checking
+                  the node CRCs etc. */
+               int bucket, want_ino;
+
                spin_lock(&c->erase_completion_lock);
                if (!c->unchecked_size)
                        break;
-
-               /* We can't start doing GC yet. We haven't finished checking
-                  the node CRCs etc. Do it now. */
-
-               /* checked_ino is protected by the alloc_sem */
-               if (c->checked_ino > c->highest_ino && xattr) {
-                       pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n",
-                               c->unchecked_size);
-                       jffs2_dbg_dump_block_lists_nolock(c);
-                       spin_unlock(&c->erase_completion_lock);
-                       mutex_unlock(&c->alloc_sem);
-                       return -ENOSPC;
-               }
-
                spin_unlock(&c->erase_completion_lock);
 
                if (!xattr)
                        xattr = jffs2_verify_xattr(c);
 
                spin_lock(&c->inocache_lock);
+               /* Instead of doing the inodes in numeric order, doing a lookup
+                * in the hash for each possible number, just walk the hash
+                * buckets of *existing* inodes. This means that we process
+                * them out-of-order, but it can be a lot faster if there's
+                * a sparse inode# space. Which there often is. */
+               want_ino = c->check_ino;
+               for (bucket = c->check_ino % c->inocache_hashsize ; bucket < c->inocache_hashsize; bucket++) {
+                       for (ic = c->inocache_list[bucket]; ic; ic = ic->next) {
+                               if (ic->ino < want_ino)
+                                       continue;
+
+                               if (ic->state != INO_STATE_CHECKEDABSENT &&
+                                   ic->state != INO_STATE_PRESENT)
+                                       goto got_next; /* with inocache_lock held */
+
+                               jffs2_dbg(1, "Skipping ino #%u already checked\n",
+                                         ic->ino);
+                       }
+                       want_ino = 0;
+               }
 
-               ic = jffs2_get_ino_cache(c, c->checked_ino++);
+               /* Point c->check_ino past the end of the last bucket. */
+               c->check_ino = ((c->highest_ino + c->inocache_hashsize + 1) &
+                               ~c->inocache_hashsize) - 1;
 
-               if (!ic) {
-                       spin_unlock(&c->inocache_lock);
-                       continue;
-               }
+               spin_unlock(&c->inocache_lock);
+
+               pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n",
+                       c->unchecked_size);
+               jffs2_dbg_dump_block_lists_nolock(c);
+               mutex_unlock(&c->alloc_sem);
+               return -ENOSPC;
+
+       got_next:
+               /* For next time round the loop, we want c->checked_ino to indicate
+                * the *next* one we want to check. And since we're walking the
+                * buckets rather than doing it sequentially, it's: */
+               c->check_ino = ic->ino + c->inocache_hashsize;
 
                if (!ic->pino_nlink) {
                        jffs2_dbg(1, "Skipping check of ino #%d with nlink/pino zero\n",
@@ -176,8 +198,6 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                switch(ic->state) {
                case INO_STATE_CHECKEDABSENT:
                case INO_STATE_PRESENT:
-                       jffs2_dbg(1, "Skipping ino #%u already checked\n",
-                                 ic->ino);
                        spin_unlock(&c->inocache_lock);
                        continue;
 
@@ -196,7 +216,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                                  ic->ino);
                        /* We need to come back again for the _same_ inode. We've
                         made no progress in this case, but that should be OK */
-                       c->checked_ino--;
+                       c->check_ino = ic->ino;
 
                        mutex_unlock(&c->alloc_sem);
                        sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
index 046fee8..778275f 100644 (file)
@@ -49,7 +49,7 @@ struct jffs2_sb_info {
        struct mtd_info *mtd;
 
        uint32_t highest_ino;
-       uint32_t checked_ino;
+       uint32_t check_ino;             /* *NEXT* inode to be checked */
 
        unsigned int flags;
 
index b6bd4af..cda0774 100644 (file)
@@ -846,8 +846,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
                return 1;
 
        if (c->unchecked_size) {
-               jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
-                         c->unchecked_size, c->checked_ino);
+               jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, check_ino #%d\n",
+                         c->unchecked_size, c->check_ino);
                return 1;
        }
 
index 5a3da3f..b25d28a 100644 (file)
@@ -1183,22 +1183,20 @@ void jffs2_dirty_trigger(struct jffs2_sb_info *c)
 
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
 {
-       struct nand_ecclayout *oinfo = c->mtd->ecclayout;
-
        if (!c->mtd->oobsize)
                return 0;
 
        /* Cleanmarker is out-of-band, so inline size zero */
        c->cleanmarker_size = 0;
 
-       if (!oinfo || oinfo->oobavail == 0) {
+       if (c->mtd->oobavail == 0) {
                pr_err("inconsistent device description\n");
                return -EINVAL;
        }
 
        jffs2_dbg(1, "using OOB on NAND\n");
 
-       c->oobavail = oinfo->oobavail;
+       c->oobavail = c->mtd->oobavail;
 
        /* Initialise write buffer */
        init_rwsem(&c->wbuf_sem);
index 794f81d..1d9ca2d 100644 (file)
@@ -1740,15 +1740,17 @@ static int walk_component(struct nameidata *nd, int flags)
                                          nd->flags);
                if (IS_ERR(path.dentry))
                        return PTR_ERR(path.dentry);
-               if (unlikely(d_is_negative(path.dentry))) {
-                       dput(path.dentry);
-                       return -ENOENT;
-               }
+
                path.mnt = nd->path.mnt;
                err = follow_managed(&path, nd);
                if (unlikely(err < 0))
                        return err;
 
+               if (unlikely(d_is_negative(path.dentry))) {
+                       path_to_nameidata(&path, nd);
+                       return -ENOENT;
+               }
+
                seq = 0;        /* we are already out of RCU mode */
                inode = d_backing_inode(path.dentry);
        }
index 8bc870e..02e4d87 100644 (file)
@@ -446,8 +446,8 @@ static void bl_free_layout_hdr(struct pnfs_layout_hdr *lo)
        kfree(bl);
 }
 
-static struct pnfs_layout_hdr *bl_alloc_layout_hdr(struct inode *inode,
-                                                  gfp_t gfp_flags)
+static struct pnfs_layout_hdr *__bl_alloc_layout_hdr(struct inode *inode,
+               gfp_t gfp_flags, bool is_scsi_layout)
 {
        struct pnfs_block_layout *bl;
 
@@ -460,9 +460,22 @@ static struct pnfs_layout_hdr *bl_alloc_layout_hdr(struct inode *inode,
        bl->bl_ext_ro = RB_ROOT;
        spin_lock_init(&bl->bl_ext_lock);
 
+       bl->bl_scsi_layout = is_scsi_layout;
        return &bl->bl_layout;
 }
 
+static struct pnfs_layout_hdr *bl_alloc_layout_hdr(struct inode *inode,
+                                                  gfp_t gfp_flags)
+{
+       return __bl_alloc_layout_hdr(inode, gfp_flags, false);
+}
+
+static struct pnfs_layout_hdr *sl_alloc_layout_hdr(struct inode *inode,
+                                                  gfp_t gfp_flags)
+{
+       return __bl_alloc_layout_hdr(inode, gfp_flags, true);
+}
+
 static void bl_free_lseg(struct pnfs_layout_segment *lseg)
 {
        dprintk("%s enter\n", __func__);
@@ -889,22 +902,53 @@ static struct pnfs_layoutdriver_type blocklayout_type = {
        .sync                           = pnfs_generic_sync,
 };
 
+static struct pnfs_layoutdriver_type scsilayout_type = {
+       .id                             = LAYOUT_SCSI,
+       .name                           = "LAYOUT_SCSI",
+       .owner                          = THIS_MODULE,
+       .flags                          = PNFS_LAYOUTRET_ON_SETATTR |
+                                         PNFS_READ_WHOLE_PAGE,
+       .read_pagelist                  = bl_read_pagelist,
+       .write_pagelist                 = bl_write_pagelist,
+       .alloc_layout_hdr               = sl_alloc_layout_hdr,
+       .free_layout_hdr                = bl_free_layout_hdr,
+       .alloc_lseg                     = bl_alloc_lseg,
+       .free_lseg                      = bl_free_lseg,
+       .return_range                   = bl_return_range,
+       .prepare_layoutcommit           = bl_prepare_layoutcommit,
+       .cleanup_layoutcommit           = bl_cleanup_layoutcommit,
+       .set_layoutdriver               = bl_set_layoutdriver,
+       .alloc_deviceid_node            = bl_alloc_deviceid_node,
+       .free_deviceid_node             = bl_free_deviceid_node,
+       .pg_read_ops                    = &bl_pg_read_ops,
+       .pg_write_ops                   = &bl_pg_write_ops,
+       .sync                           = pnfs_generic_sync,
+};
+
+
 static int __init nfs4blocklayout_init(void)
 {
        int ret;
 
        dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__);
 
-       ret = pnfs_register_layoutdriver(&blocklayout_type);
+       ret = bl_init_pipefs();
        if (ret)
                goto out;
-       ret = bl_init_pipefs();
+
+       ret = pnfs_register_layoutdriver(&blocklayout_type);
        if (ret)
-               goto out_unregister;
+               goto out_cleanup_pipe;
+
+       ret = pnfs_register_layoutdriver(&scsilayout_type);
+       if (ret)
+               goto out_unregister_block;
        return 0;
 
-out_unregister:
+out_unregister_block:
        pnfs_unregister_layoutdriver(&blocklayout_type);
+out_cleanup_pipe:
+       bl_cleanup_pipefs();
 out:
        return ret;
 }
@@ -914,8 +958,9 @@ static void __exit nfs4blocklayout_exit(void)
        dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
               __func__);
 
-       bl_cleanup_pipefs();
+       pnfs_unregister_layoutdriver(&scsilayout_type);
        pnfs_unregister_layoutdriver(&blocklayout_type);
+       bl_cleanup_pipefs();
 }
 
 MODULE_ALIAS("nfs-layouttype4-3");
index c556640..bc21205 100644 (file)
@@ -55,7 +55,6 @@ struct pnfs_block_dev;
  */
 #define PNFS_BLOCK_UUID_LEN    128
 
-
 struct pnfs_block_volume {
        enum pnfs_block_volume_type     type;
        union {
@@ -82,6 +81,13 @@ struct pnfs_block_volume {
                        u32             volumes_count;
                        u32             volumes[PNFS_BLOCK_MAX_DEVICES];
                } stripe;
+               struct {
+                       enum scsi_code_set              code_set;
+                       enum scsi_designator_type       designator_type;
+                       int                             designator_len;
+                       u8                              designator[256];
+                       u64                             pr_key;
+               } scsi;
        };
 };
 
@@ -106,6 +112,9 @@ struct pnfs_block_dev {
        struct block_device             *bdev;
        u64                             disk_offset;
 
+       u64                             pr_key;
+       bool                            pr_registered;
+
        bool (*map)(struct pnfs_block_dev *dev, u64 offset,
                        struct pnfs_block_dev_map *map);
 };
@@ -131,6 +140,7 @@ struct pnfs_block_layout {
        struct rb_root          bl_ext_rw;
        struct rb_root          bl_ext_ro;
        spinlock_t              bl_ext_lock;   /* Protects list manipulation */
+       bool                    bl_scsi_layout;
 };
 
 static inline struct pnfs_block_layout *
@@ -182,6 +192,6 @@ void ext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status);
 dev_t bl_resolve_deviceid(struct nfs_server *server,
                struct pnfs_block_volume *b, gfp_t gfp_mask);
 int __init bl_init_pipefs(void);
-void __exit bl_cleanup_pipefs(void);
+void bl_cleanup_pipefs(void);
 
 #endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
index a861bbd..e5b8967 100644 (file)
@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2014 Christoph Hellwig.
+ * Copyright (c) 2014-2016 Christoph Hellwig.
  */
 #include <linux/sunrpc/svc.h>
 #include <linux/blkdev.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_xdr.h>
+#include <linux/pr.h>
 
 #include "blocklayout.h"
 
@@ -21,6 +22,17 @@ bl_free_device(struct pnfs_block_dev *dev)
                        bl_free_device(&dev->children[i]);
                kfree(dev->children);
        } else {
+               if (dev->pr_registered) {
+                       const struct pr_ops *ops =
+                               dev->bdev->bd_disk->fops->pr_ops;
+                       int error;
+
+                       error = ops->pr_register(dev->bdev, dev->pr_key, 0,
+                               false);
+                       if (error)
+                               pr_err("failed to unregister PR key.\n");
+               }
+
                if (dev->bdev)
                        blkdev_put(dev->bdev, FMODE_READ | FMODE_WRITE);
        }
@@ -113,6 +125,24 @@ nfs4_block_decode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
                for (i = 0; i < b->stripe.volumes_count; i++)
                        b->stripe.volumes[i] = be32_to_cpup(p++);
                break;
+       case PNFS_BLOCK_VOLUME_SCSI:
+               p = xdr_inline_decode(xdr, 4 + 4 + 4);
+               if (!p)
+                       return -EIO;
+               b->scsi.code_set = be32_to_cpup(p++);
+               b->scsi.designator_type = be32_to_cpup(p++);
+               b->scsi.designator_len = be32_to_cpup(p++);
+               p = xdr_inline_decode(xdr, b->scsi.designator_len);
+               if (!p)
+                       return -EIO;
+               if (b->scsi.designator_len > 256)
+                       return -EIO;
+               memcpy(&b->scsi.designator, p, b->scsi.designator_len);
+               p = xdr_inline_decode(xdr, 8);
+               if (!p)
+                       return -EIO;
+               p = xdr_decode_hyper(p, &b->scsi.pr_key);
+               break;
        default:
                dprintk("unknown volume type!\n");
                return -EIO;
@@ -216,6 +246,116 @@ bl_parse_simple(struct nfs_server *server, struct pnfs_block_dev *d,
        return 0;
 }
 
+static bool
+bl_validate_designator(struct pnfs_block_volume *v)
+{
+       switch (v->scsi.designator_type) {
+       case PS_DESIGNATOR_EUI64:
+               if (v->scsi.code_set != PS_CODE_SET_BINARY)
+                       return false;
+
+               if (v->scsi.designator_len != 8 &&
+                   v->scsi.designator_len != 10 &&
+                   v->scsi.designator_len != 16)
+                       return false;
+
+               return true;
+       case PS_DESIGNATOR_NAA:
+               if (v->scsi.code_set != PS_CODE_SET_BINARY)
+                       return false;
+
+               if (v->scsi.designator_len != 8 &&
+                   v->scsi.designator_len != 16)
+                       return false;
+
+               return true;
+       case PS_DESIGNATOR_T10:
+       case PS_DESIGNATOR_NAME:
+               pr_err("pNFS: unsupported designator "
+                       "(code set %d, type %d, len %d.\n",
+                       v->scsi.code_set,
+                       v->scsi.designator_type,
+                       v->scsi.designator_len);
+               return false;
+       default:
+               pr_err("pNFS: invalid designator "
+                       "(code set %d, type %d, len %d.\n",
+                       v->scsi.code_set,
+                       v->scsi.designator_type,
+                       v->scsi.designator_len);
+               return false;
+       }
+}
+
+static int
+bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d,
+               struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
+{
+       struct pnfs_block_volume *v = &volumes[idx];
+       const struct pr_ops *ops;
+       const char *devname;
+       int error;
+
+       if (!bl_validate_designator(v))
+               return -EINVAL;
+
+       switch (v->scsi.designator_len) {
+       case 8:
+               devname = kasprintf(GFP_KERNEL, "/dev/disk/by-id/wwn-0x%8phN",
+                               v->scsi.designator);
+               break;
+       case 12:
+               devname = kasprintf(GFP_KERNEL, "/dev/disk/by-id/wwn-0x%12phN",
+                               v->scsi.designator);
+               break;
+       case 16:
+               devname = kasprintf(GFP_KERNEL, "/dev/disk/by-id/wwn-0x%16phN",
+                               v->scsi.designator);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       d->bdev = blkdev_get_by_path(devname, FMODE_READ, NULL);
+       if (IS_ERR(d->bdev)) {
+               pr_warn("pNFS: failed to open device %s (%ld)\n",
+                       devname, PTR_ERR(d->bdev));
+               kfree(devname);
+               return PTR_ERR(d->bdev);
+       }
+
+       kfree(devname);
+
+       d->len = i_size_read(d->bdev->bd_inode);
+       d->map = bl_map_simple;
+       d->pr_key = v->scsi.pr_key;
+
+       pr_info("pNFS: using block device %s (reservation key 0x%llx)\n",
+               d->bdev->bd_disk->disk_name, d->pr_key);
+
+       ops = d->bdev->bd_disk->fops->pr_ops;
+       if (!ops) {
+               pr_err("pNFS: block device %s does not support reservations.",
+                               d->bdev->bd_disk->disk_name);
+               error = -EINVAL;
+               goto out_blkdev_put;
+       }
+
+       error = ops->pr_register(d->bdev, 0, d->pr_key, true);
+       if (error) {
+               pr_err("pNFS: failed to register key for block device %s.",
+                               d->bdev->bd_disk->disk_name);
+               goto out_blkdev_put;
+       }
+
+       d->pr_registered = true;
+       return 0;
+
+out_blkdev_put:
+       blkdev_put(d->bdev, FMODE_READ);
+       return error;
+}
+
 static int
 bl_parse_slice(struct nfs_server *server, struct pnfs_block_dev *d,
                struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
@@ -303,6 +443,8 @@ bl_parse_deviceid(struct nfs_server *server, struct pnfs_block_dev *d,
                return bl_parse_concat(server, d, volumes, idx, gfp_mask);
        case PNFS_BLOCK_VOLUME_STRIPE:
                return bl_parse_stripe(server, d, volumes, idx, gfp_mask);
+       case PNFS_BLOCK_VOLUME_SCSI:
+               return bl_parse_scsi(server, d, volumes, idx, gfp_mask);
        default:
                dprintk("unsupported volume type: %d\n", volumes[idx].type);
                return -EIO;
index 35ab51c..720b3ff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Christoph Hellwig.
+ * Copyright (c) 2014-2016 Christoph Hellwig.
  */
 
 #include <linux/vmalloc.h>
@@ -462,10 +462,12 @@ out:
        return err;
 }
 
-static size_t ext_tree_layoutupdate_size(size_t count)
+static size_t ext_tree_layoutupdate_size(struct pnfs_block_layout *bl, size_t count)
 {
-       return sizeof(__be32) /* number of entries */ +
-               PNFS_BLOCK_EXTENT_SIZE * count;
+       if (bl->bl_scsi_layout)
+               return sizeof(__be32) + PNFS_SCSI_RANGE_SIZE * count;
+       else
+               return sizeof(__be32) + PNFS_BLOCK_EXTENT_SIZE * count;
 }
 
 static void ext_tree_free_commitdata(struct nfs4_layoutcommit_args *arg,
@@ -483,6 +485,23 @@ static void ext_tree_free_commitdata(struct nfs4_layoutcommit_args *arg,
        }
 }
 
+static __be32 *encode_block_extent(struct pnfs_block_extent *be, __be32 *p)
+{
+       p = xdr_encode_opaque_fixed(p, be->be_device->deviceid.data,
+                       NFS4_DEVICEID4_SIZE);
+       p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
+       p = xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
+       p = xdr_encode_hyper(p, 0LL);
+       *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
+       return p;
+}
+
+static __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p)
+{
+       p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
+       return xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
+}
+
 static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
                size_t buffer_size, size_t *count)
 {
@@ -496,19 +515,16 @@ static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
                        continue;
 
                (*count)++;
-               if (ext_tree_layoutupdate_size(*count) > buffer_size) {
+               if (ext_tree_layoutupdate_size(bl, *count) > buffer_size) {
                        /* keep counting.. */
                        ret = -ENOSPC;
                        continue;
                }
 
-               p = xdr_encode_opaque_fixed(p, be->be_device->deviceid.data,
-                               NFS4_DEVICEID4_SIZE);
-               p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
-               p = xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
-               p = xdr_encode_hyper(p, 0LL);
-               *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
-
+               if (bl->bl_scsi_layout)
+                       p = encode_scsi_range(be, p);
+               else
+                       p = encode_block_extent(be, p);
                be->be_tag = EXTENT_COMMITTING;
        }
        spin_unlock(&bl->bl_ext_lock);
@@ -537,7 +553,7 @@ retry:
        if (unlikely(ret)) {
                ext_tree_free_commitdata(arg, buffer_size);
 
-               buffer_size = ext_tree_layoutupdate_size(count);
+               buffer_size = ext_tree_layoutupdate_size(bl, count);
                count = 0;
 
                arg->layoutupdate_pages =
@@ -556,7 +572,7 @@ retry:
        }
 
        *start_p = cpu_to_be32(count);
-       arg->layoutupdate_len = ext_tree_layoutupdate_size(count);
+       arg->layoutupdate_len = ext_tree_layoutupdate_size(bl, count);
 
        if (unlikely(arg->layoutupdate_pages != &arg->layoutupdate_page)) {
                void *p = start_p, *end = p + arg->layoutupdate_len;
index dbe5839..9fb067a 100644 (file)
@@ -281,7 +281,7 @@ out:
        return ret;
 }
 
-void __exit bl_cleanup_pipefs(void)
+void bl_cleanup_pipefs(void)
 {
        rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
        unregister_pernet_subsys(&nfs4blocklayout_net_ops);
index a0b77fc..c9f583d 100644 (file)
@@ -84,12 +84,30 @@ config NFSD_V4
          If unsure, say N.
 
 config NFSD_PNFS
-       bool "NFSv4.1 server support for Parallel NFS (pNFS)"
-       depends on NFSD_V4
+       bool
+
+config NFSD_BLOCKLAYOUT
+       bool "NFSv4.1 server support for pNFS block layouts"
+       depends on NFSD_V4 && BLOCK
+       select NFSD_PNFS
+       help
+         This option enables support for the exporting pNFS block layouts
+         in the kernel's NFS server. The pNFS block layout enables NFS
+         clients to directly perform I/O to block devices accesible to both
+         the server and the clients.  See RFC 5663 for more details.
+
+         If unsure, say N.
+
+config NFSD_SCSILAYOUT
+       bool "NFSv4.1 server support for pNFS SCSI layouts"
+       depends on NFSD_V4 && BLOCK
+       select NFSD_PNFS
        help
-         This option enables support for the parallel NFS features of the
-         minor version 1 of the NFSv4 protocol (RFC5661) in the kernel's NFS
-         server.
+         This option enables support for the exporting pNFS SCSI layouts
+         in the kernel's NFS server. The pNFS SCSI layout enables NFS
+         clients to directly perform I/O to SCSI devices accesible to both
+         the server and the clients.  See draft-ietf-nfsv4-scsi-layout for
+         more details.
 
          If unsure, say N.
 
index 9a6028e..3ae5f3c 100644 (file)
@@ -17,4 +17,6 @@ nfsd-$(CONFIG_NFSD_V3)        += nfs3proc.o nfs3xdr.o
 nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
 nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
                           nfs4acl.o nfs4callback.o nfs4recover.o
-nfsd-$(CONFIG_NFSD_PNFS) += nfs4layouts.o blocklayout.o blocklayoutxdr.o
+nfsd-$(CONFIG_NFSD_PNFS) += nfs4layouts.o
+nfsd-$(CONFIG_NFSD_BLOCKLAYOUT) += blocklayout.o blocklayoutxdr.o
+nfsd-$(CONFIG_NFSD_SCSILAYOUT) += blocklayout.o blocklayoutxdr.o
index c29d942..e55b524 100644 (file)
@@ -1,11 +1,14 @@
 /*
- * Copyright (c) 2014 Christoph Hellwig.
+ * Copyright (c) 2014-2016 Christoph Hellwig.
  */
 #include <linux/exportfs.h>
 #include <linux/genhd.h>
 #include <linux/slab.h>
+#include <linux/pr.h>
 
 #include <linux/nfsd/debug.h>
+#include <scsi/scsi_proto.h>
+#include <scsi/scsi_common.h>
 
 #include "blocklayoutxdr.h"
 #include "pnfs.h"
 #define NFSDDBG_FACILITY       NFSDDBG_PNFS
 
 
-static int
-nfsd4_block_get_device_info_simple(struct super_block *sb,
-               struct nfsd4_getdeviceinfo *gdp)
-{
-       struct pnfs_block_deviceaddr *dev;
-       struct pnfs_block_volume *b;
-
-       dev = kzalloc(sizeof(struct pnfs_block_deviceaddr) +
-                     sizeof(struct pnfs_block_volume), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-       gdp->gd_device = dev;
-
-       dev->nr_volumes = 1;
-       b = &dev->volumes[0];
-
-       b->type = PNFS_BLOCK_VOLUME_SIMPLE;
-       b->simple.sig_len = PNFS_BLOCK_UUID_LEN;
-       return sb->s_export_op->get_uuid(sb, b->simple.sig, &b->simple.sig_len,
-                       &b->simple.offset);
-}
-
-static __be32
-nfsd4_block_proc_getdeviceinfo(struct super_block *sb,
-               struct nfsd4_getdeviceinfo *gdp)
-{
-       if (sb->s_bdev != sb->s_bdev->bd_contains)
-               return nfserr_inval;
-       return nfserrno(nfsd4_block_get_device_info_simple(sb, gdp));
-}
-
 static __be32
 nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
                struct nfsd4_layoutget *args)
@@ -141,20 +113,13 @@ out_layoutunavailable:
 }
 
 static __be32
-nfsd4_block_proc_layoutcommit(struct inode *inode,
-               struct nfsd4_layoutcommit *lcp)
+nfsd4_block_commit_blocks(struct inode *inode, struct nfsd4_layoutcommit *lcp,
+               struct iomap *iomaps, int nr_iomaps)
 {
        loff_t new_size = lcp->lc_last_wr + 1;
        struct iattr iattr = { .ia_valid = 0 };
-       struct iomap *iomaps;
-       int nr_iomaps;
        int error;
 
-       nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
-                       lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits);
-       if (nr_iomaps < 0)
-               return nfserrno(nr_iomaps);
-
        if (lcp->lc_mtime.tv_nsec == UTIME_NOW ||
            timespec_compare(&lcp->lc_mtime, &inode->i_mtime) < 0)
                lcp->lc_mtime = current_fs_time(inode->i_sb);
@@ -172,6 +137,54 @@ nfsd4_block_proc_layoutcommit(struct inode *inode,
        return nfserrno(error);
 }
 
+#ifdef CONFIG_NFSD_BLOCKLAYOUT
+static int
+nfsd4_block_get_device_info_simple(struct super_block *sb,
+               struct nfsd4_getdeviceinfo *gdp)
+{
+       struct pnfs_block_deviceaddr *dev;
+       struct pnfs_block_volume *b;
+
+       dev = kzalloc(sizeof(struct pnfs_block_deviceaddr) +
+                     sizeof(struct pnfs_block_volume), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       gdp->gd_device = dev;
+
+       dev->nr_volumes = 1;
+       b = &dev->volumes[0];
+
+       b->type = PNFS_BLOCK_VOLUME_SIMPLE;
+       b->simple.sig_len = PNFS_BLOCK_UUID_LEN;
+       return sb->s_export_op->get_uuid(sb, b->simple.sig, &b->simple.sig_len,
+                       &b->simple.offset);
+}
+
+static __be32
+nfsd4_block_proc_getdeviceinfo(struct super_block *sb,
+               struct nfs4_client *clp,
+               struct nfsd4_getdeviceinfo *gdp)
+{
+       if (sb->s_bdev != sb->s_bdev->bd_contains)
+               return nfserr_inval;
+       return nfserrno(nfsd4_block_get_device_info_simple(sb, gdp));
+}
+
+static __be32
+nfsd4_block_proc_layoutcommit(struct inode *inode,
+               struct nfsd4_layoutcommit *lcp)
+{
+       struct iomap *iomaps;
+       int nr_iomaps;
+
+       nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
+                       lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits);
+       if (nr_iomaps < 0)
+               return nfserrno(nr_iomaps);
+
+       return nfsd4_block_commit_blocks(inode, lcp, iomaps, nr_iomaps);
+}
+
 const struct nfsd4_layout_ops bl_layout_ops = {
        /*
         * Pretend that we send notification to the client.  This is a blatant
@@ -190,3 +203,206 @@ const struct nfsd4_layout_ops bl_layout_ops = {
        .encode_layoutget       = nfsd4_block_encode_layoutget,
        .proc_layoutcommit      = nfsd4_block_proc_layoutcommit,
 };
+#endif /* CONFIG_NFSD_BLOCKLAYOUT */
+
+#ifdef CONFIG_NFSD_SCSILAYOUT
+static int nfsd4_scsi_identify_device(struct block_device *bdev,
+               struct pnfs_block_volume *b)
+{
+       struct request_queue *q = bdev->bd_disk->queue;
+       struct request *rq;
+       size_t bufflen = 252, len, id_len;
+       u8 *buf, *d, type, assoc;
+       int error;
+
+       buf = kzalloc(bufflen, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       rq = blk_get_request(q, READ, GFP_KERNEL);
+       if (IS_ERR(rq)) {
+               error = -ENOMEM;
+               goto out_free_buf;
+       }
+       blk_rq_set_block_pc(rq);
+
+       error = blk_rq_map_kern(q, rq, buf, bufflen, GFP_KERNEL);
+       if (error)
+               goto out_put_request;
+
+       rq->cmd[0] = INQUIRY;
+       rq->cmd[1] = 1;
+       rq->cmd[2] = 0x83;
+       rq->cmd[3] = bufflen >> 8;
+       rq->cmd[4] = bufflen & 0xff;
+       rq->cmd_len = COMMAND_SIZE(INQUIRY);
+
+       error = blk_execute_rq(rq->q, NULL, rq, 1);
+       if (error) {
+               pr_err("pNFS: INQUIRY 0x83 failed with: %x\n",
+                       rq->errors);
+               goto out_put_request;
+       }
+
+       len = (buf[2] << 8) + buf[3] + 4;
+       if (len > bufflen) {
+               pr_err("pNFS: INQUIRY 0x83 response invalid (len = %zd)\n",
+                       len);
+               goto out_put_request;
+       }
+
+       d = buf + 4;
+       for (d = buf + 4; d < buf + len; d += id_len + 4) {
+               id_len = d[3];
+               type = d[1] & 0xf;
+               assoc = (d[1] >> 4) & 0x3;
+
+               /*
+                * We only care about a EUI-64 and NAA designator types
+                * with LU association.
+                */
+               if (assoc != 0x00)
+                       continue;
+               if (type != 0x02 && type != 0x03)
+                       continue;
+               if (id_len != 8 && id_len != 12 && id_len != 16)
+                       continue;
+
+               b->scsi.code_set = PS_CODE_SET_BINARY;
+               b->scsi.designator_type = type == 0x02 ?
+                       PS_DESIGNATOR_EUI64 : PS_DESIGNATOR_NAA;
+               b->scsi.designator_len = id_len;
+               memcpy(b->scsi.designator, d + 4, id_len);
+
+               /*
+                * If we found a 8 or 12 byte descriptor continue on to
+                * see if a 16 byte one is available.  If we find a
+                * 16 byte descriptor we're done.
+                */
+               if (id_len == 16)
+                       break;
+       }
+
+out_put_request:
+       blk_put_request(rq);
+out_free_buf:
+       kfree(buf);
+       return error;
+}
+
+#define NFSD_MDS_PR_KEY                0x0100000000000000
+
+/*
+ * We use the client ID as a unique key for the reservations.
+ * This allows us to easily fence a client when recalls fail.
+ */
+static u64 nfsd4_scsi_pr_key(struct nfs4_client *clp)
+{
+       return ((u64)clp->cl_clientid.cl_boot << 32) | clp->cl_clientid.cl_id;
+}
+
+static int
+nfsd4_block_get_device_info_scsi(struct super_block *sb,
+               struct nfs4_client *clp,
+               struct nfsd4_getdeviceinfo *gdp)
+{
+       struct pnfs_block_deviceaddr *dev;
+       struct pnfs_block_volume *b;
+       const struct pr_ops *ops;
+       int error;
+
+       dev = kzalloc(sizeof(struct pnfs_block_deviceaddr) +
+                     sizeof(struct pnfs_block_volume), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       gdp->gd_device = dev;
+
+       dev->nr_volumes = 1;
+       b = &dev->volumes[0];
+
+       b->type = PNFS_BLOCK_VOLUME_SCSI;
+       b->scsi.pr_key = nfsd4_scsi_pr_key(clp);
+
+       error = nfsd4_scsi_identify_device(sb->s_bdev, b);
+       if (error)
+               return error;
+
+       ops = sb->s_bdev->bd_disk->fops->pr_ops;
+       if (!ops) {
+               pr_err("pNFS: device %s does not support PRs.\n",
+                       sb->s_id);
+               return -EINVAL;
+       }
+
+       error = ops->pr_register(sb->s_bdev, 0, NFSD_MDS_PR_KEY, true);
+       if (error) {
+               pr_err("pNFS: failed to register key for device %s.\n",
+                       sb->s_id);
+               return -EINVAL;
+       }
+
+       error = ops->pr_reserve(sb->s_bdev, NFSD_MDS_PR_KEY,
+                       PR_EXCLUSIVE_ACCESS_REG_ONLY, 0);
+       if (error) {
+               pr_err("pNFS: failed to reserve device %s.\n",
+                       sb->s_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static __be32
+nfsd4_scsi_proc_getdeviceinfo(struct super_block *sb,
+               struct nfs4_client *clp,
+               struct nfsd4_getdeviceinfo *gdp)
+{
+       if (sb->s_bdev != sb->s_bdev->bd_contains)
+               return nfserr_inval;
+       return nfserrno(nfsd4_block_get_device_info_scsi(sb, clp, gdp));
+}
+static __be32
+nfsd4_scsi_proc_layoutcommit(struct inode *inode,
+               struct nfsd4_layoutcommit *lcp)
+{
+       struct iomap *iomaps;
+       int nr_iomaps;
+
+       nr_iomaps = nfsd4_scsi_decode_layoutupdate(lcp->lc_up_layout,
+                       lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits);
+       if (nr_iomaps < 0)
+               return nfserrno(nr_iomaps);
+
+       return nfsd4_block_commit_blocks(inode, lcp, iomaps, nr_iomaps);
+}
+
+static void
+nfsd4_scsi_fence_client(struct nfs4_layout_stateid *ls)
+{
+       struct nfs4_client *clp = ls->ls_stid.sc_client;
+       struct block_device *bdev = ls->ls_file->f_path.mnt->mnt_sb->s_bdev;
+
+       bdev->bd_disk->fops->pr_ops->pr_preempt(bdev, NFSD_MDS_PR_KEY,
+                       nfsd4_scsi_pr_key(clp), 0, true);
+}
+
+const struct nfsd4_layout_ops scsi_layout_ops = {
+       /*
+        * Pretend that we send notification to the client.  This is a blatant
+        * lie to force recent Linux clients to cache our device IDs.
+        * We rarely ever change the device ID, so the harm of leaking deviceids
+        * for a while isn't too bad.  Unfortunately RFC5661 is a complete mess
+        * in this regard, but I filed errata 4119 for this a while ago, and
+        * hopefully the Linux client will eventually start caching deviceids
+        * without this again.
+        */
+       .notify_types           =
+                       NOTIFY_DEVICEID4_DELETE | NOTIFY_DEVICEID4_CHANGE,
+       .proc_getdeviceinfo     = nfsd4_scsi_proc_getdeviceinfo,
+       .encode_getdeviceinfo   = nfsd4_block_encode_getdeviceinfo,
+       .proc_layoutget         = nfsd4_block_proc_layoutget,
+       .encode_layoutget       = nfsd4_block_encode_layoutget,
+       .proc_layoutcommit      = nfsd4_scsi_proc_layoutcommit,
+       .fence_client           = nfsd4_scsi_fence_client,
+};
+#endif /* CONFIG_NFSD_SCSILAYOUT */
index 6d834dc..6c3b316 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Christoph Hellwig.
+ * Copyright (c) 2014-2016 Christoph Hellwig.
  */
 #include <linux/sunrpc/svc.h>
 #include <linux/exportfs.h>
@@ -53,6 +53,18 @@ nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
                p = xdr_encode_hyper(p, b->simple.offset);
                p = xdr_encode_opaque(p, b->simple.sig, b->simple.sig_len);
                break;
+       case PNFS_BLOCK_VOLUME_SCSI:
+               len = 4 + 4 + 4 + 4 + b->scsi.designator_len + 8;
+               p = xdr_reserve_space(xdr, len);
+               if (!p)
+                       return -ETOOSMALL;
+
+               *p++ = cpu_to_be32(b->type);
+               *p++ = cpu_to_be32(b->scsi.code_set);
+               *p++ = cpu_to_be32(b->scsi.designator_type);
+               p = xdr_encode_opaque(p, b->scsi.designator, b->scsi.designator_len);
+               p = xdr_encode_hyper(p, b->scsi.pr_key);
+               break;
        default:
                return -ENOTSUPP;
        }
@@ -93,18 +105,22 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
                u32 block_size)
 {
        struct iomap *iomaps;
-       u32 nr_iomaps, expected, i;
+       u32 nr_iomaps, i;
 
        if (len < sizeof(u32)) {
                dprintk("%s: extent array too small: %u\n", __func__, len);
                return -EINVAL;
        }
+       len -= sizeof(u32);
+       if (len % PNFS_BLOCK_EXTENT_SIZE) {
+               dprintk("%s: extent array invalid: %u\n", __func__, len);
+               return -EINVAL;
+       }
 
        nr_iomaps = be32_to_cpup(p++);
-       expected = sizeof(__be32) + nr_iomaps * PNFS_BLOCK_EXTENT_SIZE;
-       if (len != expected) {
+       if (nr_iomaps != len / PNFS_BLOCK_EXTENT_SIZE) {
                dprintk("%s: extent array size mismatch: %u/%u\n",
-                       __func__, len, expected);
+                       __func__, len, nr_iomaps);
                return -EINVAL;
        }
 
@@ -155,3 +171,54 @@ fail:
        kfree(iomaps);
        return -EINVAL;
 }
+
+int
+nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
+               u32 block_size)
+{
+       struct iomap *iomaps;
+       u32 nr_iomaps, expected, i;
+
+       if (len < sizeof(u32)) {
+               dprintk("%s: extent array too small: %u\n", __func__, len);
+               return -EINVAL;
+       }
+
+       nr_iomaps = be32_to_cpup(p++);
+       expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE;
+       if (len != expected) {
+               dprintk("%s: extent array size mismatch: %u/%u\n",
+                       __func__, len, expected);
+               return -EINVAL;
+       }
+
+       iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
+       if (!iomaps) {
+               dprintk("%s: failed to allocate extent array\n", __func__);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < nr_iomaps; i++) {
+               u64 val;
+
+               p = xdr_decode_hyper(p, &val);
+               if (val & (block_size - 1)) {
+                       dprintk("%s: unaligned offset 0x%llx\n", __func__, val);
+                       goto fail;
+               }
+               iomaps[i].offset = val;
+
+               p = xdr_decode_hyper(p, &val);
+               if (val & (block_size - 1)) {
+                       dprintk("%s: unaligned length 0x%llx\n", __func__, val);
+                       goto fail;
+               }
+               iomaps[i].length = val;
+       }
+
+       *iomapp = iomaps;
+       return nr_iomaps;
+fail:
+       kfree(iomaps);
+       return -EINVAL;
+}
index 6de925f..397bc75 100644 (file)
@@ -15,6 +15,11 @@ struct pnfs_block_extent {
        enum pnfs_block_extent_state    es;
 };
 
+struct pnfs_block_range {
+       u64                             foff;
+       u64                             len;
+};
+
 /*
  * Random upper cap for the uuid length to avoid unbounded allocation.
  * Not actually limited by the protocol.
@@ -29,6 +34,13 @@ struct pnfs_block_volume {
                        u32             sig_len;
                        u8              sig[PNFS_BLOCK_UUID_LEN];
                } simple;
+               struct {
+                       enum scsi_code_set              code_set;
+                       enum scsi_designator_type       designator_type;
+                       int                             designator_len;
+                       u8                              designator[256];
+                       u64                             pr_key;
+               } scsi;
        };
 };
 
@@ -43,5 +55,7 @@ __be32 nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
                struct nfsd4_layoutget *lgp);
 int nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
                u32 block_size);
+int nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
+               u32 block_size);
 
 #endif /* _NFSD_BLOCKLAYOUTXDR_H */
index 7b755b7..51c3b06 100644 (file)
@@ -147,6 +147,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
 {
        __be32  nfserr;
        u32     max_blocksize = svc_max_payload(rqstp);
+       unsigned long cnt = min(argp->count, max_blocksize);
 
        dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
                                SVCFH_fmt(&argp->fh),
@@ -157,7 +158,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
         * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
         * + 1 (xdr opaque byte count) = 26
         */
-       resp->count = min(argp->count, max_blocksize);
+       resp->count = cnt;
        svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
 
        fh_copy(&resp->fh, &argp->fh);
@@ -167,8 +168,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
                                  &resp->count);
        if (nfserr == 0) {
                struct inode    *inode = d_inode(resp->fh.fh_dentry);
-
-               resp->eof = (argp->offset + resp->count) >= inode->i_size;
+               resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset,
+                                                       inode->i_size);
        }
 
        RETURN_STATUS(nfserr);
index ce2d010..825c7bc 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2014 Christoph Hellwig.
  */
+#include <linux/blkdev.h>
 #include <linux/kmod.h>
 #include <linux/file.h>
 #include <linux/jhash.h>
@@ -26,7 +27,12 @@ static const struct nfsd4_callback_ops nfsd4_cb_layout_ops;
 static const struct lock_manager_operations nfsd4_layouts_lm_ops;
 
 const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] =  {
+#ifdef CONFIG_NFSD_BLOCKLAYOUT
        [LAYOUT_BLOCK_VOLUME]   = &bl_layout_ops,
+#endif
+#ifdef CONFIG_NFSD_SCSILAYOUT
+       [LAYOUT_SCSI]           = &scsi_layout_ops,
+#endif
 };
 
 /* pNFS device ID to export fsid mapping */
@@ -121,10 +127,24 @@ void nfsd4_setup_layout_type(struct svc_export *exp)
        if (!(exp->ex_flags & NFSEXP_PNFS))
                return;
 
+       /*
+        * Check if the file system supports exporting a block-like layout.
+        * If the block device supports reservations prefer the SCSI layout,
+        * otherwise advertise the block layout.
+        */
+#ifdef CONFIG_NFSD_BLOCKLAYOUT
        if (sb->s_export_op->get_uuid &&
            sb->s_export_op->map_blocks &&
            sb->s_export_op->commit_blocks)
                exp->ex_layout_type = LAYOUT_BLOCK_VOLUME;
+#endif
+#ifdef CONFIG_NFSD_SCSILAYOUT
+       /* overwrite block layout selection if needed */
+       if (sb->s_export_op->map_blocks &&
+           sb->s_export_op->commit_blocks &&
+           sb->s_bdev && sb->s_bdev->bd_disk->fops->pr_ops)
+               exp->ex_layout_type = LAYOUT_SCSI;
+#endif
 }
 
 static void
@@ -590,8 +610,6 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
 
        rpc_ntop((struct sockaddr *)&clp->cl_addr, addr_str, sizeof(addr_str));
 
-       trace_layout_recall_fail(&ls->ls_stid.sc_stateid);
-
        printk(KERN_WARNING
                "nfsd: client %s failed to respond to layout recall. "
                "  Fencing..\n", addr_str);
@@ -626,6 +644,7 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
                container_of(cb, struct nfs4_layout_stateid, ls_recall);
        struct nfsd_net *nn;
        ktime_t now, cutoff;
+       const struct nfsd4_layout_ops *ops;
        LIST_HEAD(reaplist);
 
 
@@ -661,7 +680,13 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
                /*
                 * Unknown error or non-responding client, we'll need to fence.
                 */
-               nfsd4_cb_layout_fail(ls);
+               trace_layout_recall_fail(&ls->ls_stid.sc_stateid);
+
+               ops = nfsd4_layout_ops[ls->ls_layout_type];
+               if (ops->fence_client)
+                       ops->fence_client(ls);
+               else
+                       nfsd4_cb_layout_fail(ls);
                return -1;
        }
 }
index 40b9124..de1ff1d 100644 (file)
@@ -1268,8 +1268,10 @@ nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
                goto out;
 
        nfserr = nfs_ok;
-       if (gdp->gd_maxcount != 0)
-               nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb, gdp);
+       if (gdp->gd_maxcount != 0) {
+               nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb,
+                                       cstate->session->se_client, gdp);
+       }
 
        gdp->gd_notify_types &= ops->notify_types;
 out:
index aa87954..9df898b 100644 (file)
@@ -3365,6 +3365,7 @@ static __be32 nfsd4_encode_splice_read(
        struct xdr_stream *xdr = &resp->xdr;
        struct xdr_buf *buf = xdr->buf;
        u32 eof;
+       long len;
        int space_left;
        __be32 nfserr;
        __be32 *p = xdr->p - 2;
@@ -3373,6 +3374,7 @@ static __be32 nfsd4_encode_splice_read(
        if (xdr->end - xdr->p < 1)
                return nfserr_resource;
 
+       len = maxcount;
        nfserr = nfsd_splice_read(read->rd_rqstp, file,
                                  read->rd_offset, &maxcount);
        if (nfserr) {
@@ -3385,8 +3387,8 @@ static __be32 nfsd4_encode_splice_read(
                return nfserr;
        }
 
-       eof = (read->rd_offset + maxcount >=
-              d_inode(read->rd_fhp->fh_dentry)->i_size);
+       eof = nfsd_eof_on_read(len, maxcount, read->rd_offset,
+                               d_inode(read->rd_fhp->fh_dentry)->i_size);
 
        *(p++) = htonl(eof);
        *(p++) = htonl(maxcount);
@@ -3456,14 +3458,15 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
        }
        read->rd_vlen = v;
 
+       len = maxcount;
        nfserr = nfsd_readv(file, read->rd_offset, resp->rqstp->rq_vec,
                        read->rd_vlen, &maxcount);
        if (nfserr)
                return nfserr;
        xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
 
-       eof = (read->rd_offset + maxcount >=
-              d_inode(read->rd_fhp->fh_dentry)->i_size);
+       eof = nfsd_eof_on_read(len, maxcount, read->rd_offset,
+                               d_inode(read->rd_fhp->fh_dentry)->i_size);
 
        tmp = htonl(eof);
        write_bytes_to_xdr_buf(xdr->buf, starting_len    , &tmp, 4);
index d4c4453..7d073b9 100644 (file)
@@ -21,6 +21,7 @@ struct nfsd4_layout_ops {
        u32             notify_types;
 
        __be32 (*proc_getdeviceinfo)(struct super_block *sb,
+                       struct nfs4_client *clp,
                        struct nfsd4_getdeviceinfo *gdevp);
        __be32 (*encode_getdeviceinfo)(struct xdr_stream *xdr,
                        struct nfsd4_getdeviceinfo *gdevp);
@@ -32,10 +33,17 @@ struct nfsd4_layout_ops {
 
        __be32 (*proc_layoutcommit)(struct inode *inode,
                        struct nfsd4_layoutcommit *lcp);
+
+       void (*fence_client)(struct nfs4_layout_stateid *ls);
 };
 
 extern const struct nfsd4_layout_ops *nfsd4_layout_ops[];
+#ifdef CONFIG_NFSD_BLOCKLAYOUT
 extern const struct nfsd4_layout_ops bl_layout_ops;
+#endif
+#ifdef CONFIG_NFSD_SCSILAYOUT
+extern const struct nfsd4_layout_ops scsi_layout_ops;
+#endif
 
 __be32 nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp,
                struct nfsd4_compound_state *cstate, stateid_t *stateid,
index c11ba31..2d573ec 100644 (file)
@@ -139,4 +139,23 @@ static inline int nfsd_create_is_exclusive(int createmode)
               || createmode == NFS4_CREATE_EXCLUSIVE4_1;
 }
 
+static inline bool nfsd_eof_on_read(long requested, long read,
+                               loff_t offset, loff_t size)
+{
+       /* We assume a short read means eof: */
+       if (requested > read)
+               return true;
+       /*
+        * A non-short read might also reach end of file.  The spec
+        * still requires us to set eof in that case.
+        *
+        * Further operations may have modified the file size since
+        * the read, so the following check is not atomic with the read.
+        * We've only seen that cause a problem for a client in the case
+        * where the read returned a count of 0 without setting eof.
+        * That case was fixed by the addition of the above check.
+        */
+       return (offset + read >= size);
+}
+
 #endif /* LINUX_NFSD_VFS_H */
index d002579..70907d6 100644 (file)
@@ -2516,21 +2516,6 @@ static int ocfs2_update_edge_lengths(handle_t *handle,
        struct ocfs2_extent_block *eb;
        u32 range;
 
-       /*
-        * In normal tree rotation process, we will never touch the
-        * tree branch above subtree_index and ocfs2_extend_rotate_transaction
-        * doesn't reserve the credits for them either.
-        *
-        * But we do have a special case here which will update the rightmost
-        * records for all the bh in the path.
-        * So we have to allocate extra credits and access them.
-        */
-       ret = ocfs2_extend_trans(handle, subtree_index);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
-
        ret = ocfs2_journal_access_path(et->et_ci, handle, path);
        if (ret) {
                mlog_errno(ret);
@@ -2956,7 +2941,7 @@ static int __ocfs2_rotate_tree_left(handle_t *handle,
                     right_path->p_node[subtree_root].bh->b_blocknr,
                     right_path->p_tree_depth);
 
-               ret = ocfs2_extend_rotate_transaction(handle, subtree_root,
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
                                                      orig_credits, left_path);
                if (ret) {
                        mlog_errno(ret);
@@ -3029,21 +3014,9 @@ static int ocfs2_remove_rightmost_path(handle_t *handle,
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list *el;
 
-
        ret = ocfs2_et_sanity_check(et);
        if (ret)
                goto out;
-       /*
-        * There's two ways we handle this depending on
-        * whether path is the only existing one.
-        */
-       ret = ocfs2_extend_rotate_transaction(handle, 0,
-                                             handle->h_buffer_credits,
-                                             path);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
 
        ret = ocfs2_journal_access_path(et->et_ci, handle, path);
        if (ret) {
@@ -3641,6 +3614,14 @@ static int ocfs2_merge_rec_left(struct ocfs2_path *right_path,
                 */
                if (le16_to_cpu(right_rec->e_leaf_clusters) == 0 &&
                    le16_to_cpu(el->l_next_free_rec) == 1) {
+                       /* extend credit for ocfs2_remove_rightmost_path */
+                       ret = ocfs2_extend_rotate_transaction(handle, 0,
+                                       handle->h_buffer_credits,
+                                       right_path);
+                       if (ret) {
+                               mlog_errno(ret);
+                               goto out;
+                       }
 
                        ret = ocfs2_remove_rightmost_path(handle, et,
                                                          right_path,
@@ -3679,6 +3660,14 @@ static int ocfs2_try_to_merge_extent(handle_t *handle,
        BUG_ON(ctxt->c_contig_type == CONTIG_NONE);
 
        if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) {
+               /* extend credit for ocfs2_remove_rightmost_path */
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
+                               handle->h_buffer_credits,
+                               path);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
                /*
                 * The merge code will need to create an empty
                 * extent to take the place of the newly
@@ -3727,6 +3716,15 @@ static int ocfs2_try_to_merge_extent(handle_t *handle,
                 */
                BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0]));
 
+               /* extend credit for ocfs2_remove_rightmost_path */
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
+                                       handle->h_buffer_credits,
+                                       path);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
                /* The merge left us with an empty extent, remove it. */
                ret = ocfs2_rotate_tree_left(handle, et, path, dealloc);
                if (ret) {
@@ -3748,6 +3746,15 @@ static int ocfs2_try_to_merge_extent(handle_t *handle,
                        goto out;
                }
 
+               /* extend credit for ocfs2_remove_rightmost_path */
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
+                               handle->h_buffer_credits,
+                               path);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
                ret = ocfs2_rotate_tree_left(handle, et, path, dealloc);
                /*
                 * Error from this last rotate is not critical, so
@@ -3783,6 +3790,16 @@ static int ocfs2_try_to_merge_extent(handle_t *handle,
                }
 
                if (ctxt->c_split_covers_rec) {
+                       /* extend credit for ocfs2_remove_rightmost_path */
+                       ret = ocfs2_extend_rotate_transaction(handle, 0,
+                                       handle->h_buffer_credits,
+                                       path);
+                       if (ret) {
+                               mlog_errno(ret);
+                               ret = 0;
+                               goto out;
+                       }
+
                        /*
                         * The merge may have left an empty extent in
                         * our leaf. Try to rotate it away.
@@ -5342,6 +5359,15 @@ static int ocfs2_truncate_rec(handle_t *handle,
        struct ocfs2_extent_block *eb;
 
        if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) {
+               /* extend credit for ocfs2_remove_rightmost_path */
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
+                               handle->h_buffer_credits,
+                               path);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
                ret = ocfs2_rotate_tree_left(handle, et, path, dealloc);
                if (ret) {
                        mlog_errno(ret);
@@ -5928,16 +5954,6 @@ static int ocfs2_replay_truncate_records(struct ocfs2_super *osb,
 
                ocfs2_journal_dirty(handle, tl_bh);
 
-               /* TODO: Perhaps we can calculate the bulk of the
-                * credits up front rather than extending like
-                * this. */
-               status = ocfs2_extend_trans(handle,
-                                           OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
-
                rec = tl->tl_recs[i];
                start_blk = ocfs2_clusters_to_blocks(data_alloc_inode->i_sb,
                                                    le32_to_cpu(rec.t_start));
@@ -5958,6 +5974,13 @@ static int ocfs2_replay_truncate_records(struct ocfs2_super *osb,
                                goto bail;
                        }
                }
+
+               status = ocfs2_extend_trans(handle,
+                               OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC);
+               if (status < 0) {
+                       mlog_errno(status);
+                       goto bail;
+               }
                i--;
        }
 
@@ -6016,7 +6039,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
                goto out_mutex;
        }
 
-       handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_UPDATE);
+       handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC);
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
                mlog_errno(status);
@@ -6079,7 +6102,7 @@ void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb,
                if (cancel)
                        cancel_delayed_work(&osb->osb_truncate_log_wq);
 
-               queue_delayed_work(ocfs2_wq, &osb->osb_truncate_log_wq,
+               queue_delayed_work(osb->ocfs2_wq, &osb->osb_truncate_log_wq,
                                   OCFS2_TRUNCATE_LOG_FLUSH_INTERVAL);
        }
 }
@@ -6253,7 +6276,7 @@ void ocfs2_truncate_log_shutdown(struct ocfs2_super *osb)
 
        if (tl_inode) {
                cancel_delayed_work(&osb->osb_truncate_log_wq);
-               flush_workqueue(ocfs2_wq);
+               flush_workqueue(osb->ocfs2_wq);
 
                status = ocfs2_flush_truncate_log(osb);
                if (status < 0)
index 043110e..1581240 100644 (file)
@@ -499,158 +499,6 @@ bail:
        return status;
 }
 
-/*
- * TODO: Make this into a generic get_blocks function.
- *
- * From do_direct_io in direct-io.c:
- *  "So what we do is to permit the ->get_blocks function to populate
- *   bh.b_size with the size of IO which is permitted at this offset and
- *   this i_blkbits."
- *
- * This function is called directly from get_more_blocks in direct-io.c.
- *
- * called like this: dio->get_blocks(dio->inode, fs_startblk,
- *                                     fs_count, map_bh, dio->rw == WRITE);
- */
-static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
-                                    struct buffer_head *bh_result, int create)
-{
-       int ret;
-       u32 cpos = 0;
-       int alloc_locked = 0;
-       u64 p_blkno, inode_blocks, contig_blocks;
-       unsigned int ext_flags;
-       unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
-       unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
-       unsigned long len = bh_result->b_size;
-       unsigned int clusters_to_alloc = 0, contig_clusters = 0;
-
-       cpos = ocfs2_blocks_to_clusters(inode->i_sb, iblock);
-
-       /* This function won't even be called if the request isn't all
-        * nicely aligned and of the right size, so there's no need
-        * for us to check any of that. */
-
-       inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
-
-       down_read(&OCFS2_I(inode)->ip_alloc_sem);
-
-       /* This figures out the size of the next contiguous block, and
-        * our logical offset */
-       ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno,
-                                         &contig_blocks, &ext_flags);
-       up_read(&OCFS2_I(inode)->ip_alloc_sem);
-
-       if (ret) {
-               mlog(ML_ERROR, "get_blocks() failed iblock=%llu\n",
-                    (unsigned long long)iblock);
-               ret = -EIO;
-               goto bail;
-       }
-
-       /* We should already CoW the refcounted extent in case of create. */
-       BUG_ON(create && (ext_flags & OCFS2_EXT_REFCOUNTED));
-
-       /* allocate blocks if no p_blkno is found, and create == 1 */
-       if (!p_blkno && create) {
-               ret = ocfs2_inode_lock(inode, NULL, 1);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto bail;
-               }
-
-               alloc_locked = 1;
-
-               down_write(&OCFS2_I(inode)->ip_alloc_sem);
-
-               /* fill hole, allocate blocks can't be larger than the size
-                * of the hole */
-               clusters_to_alloc = ocfs2_clusters_for_bytes(inode->i_sb, len);
-               contig_clusters = ocfs2_clusters_for_blocks(inode->i_sb,
-                               contig_blocks);
-               if (clusters_to_alloc > contig_clusters)
-                       clusters_to_alloc = contig_clusters;
-
-               /* allocate extent and insert them into the extent tree */
-               ret = ocfs2_extend_allocation(inode, cpos,
-                               clusters_to_alloc, 0);
-               if (ret < 0) {
-                       up_write(&OCFS2_I(inode)->ip_alloc_sem);
-                       mlog_errno(ret);
-                       goto bail;
-               }
-
-               ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno,
-                               &contig_blocks, &ext_flags);
-               if (ret < 0) {
-                       up_write(&OCFS2_I(inode)->ip_alloc_sem);
-                       mlog(ML_ERROR, "get_blocks() failed iblock=%llu\n",
-                                       (unsigned long long)iblock);
-                       ret = -EIO;
-                       goto bail;
-               }
-               set_buffer_new(bh_result);
-               up_write(&OCFS2_I(inode)->ip_alloc_sem);
-       }
-
-       /*
-        * get_more_blocks() expects us to describe a hole by clearing
-        * the mapped bit on bh_result().
-        *
-        * Consider an unwritten extent as a hole.
-        */
-       if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN))
-               map_bh(bh_result, inode->i_sb, p_blkno);
-       else
-               clear_buffer_mapped(bh_result);
-
-       /* make sure we don't map more than max_blocks blocks here as
-          that's all the kernel will handle at this point. */
-       if (max_blocks < contig_blocks)
-               contig_blocks = max_blocks;
-       bh_result->b_size = contig_blocks << blocksize_bits;
-bail:
-       if (alloc_locked)
-               ocfs2_inode_unlock(inode, 1);
-       return ret;
-}
-
-/*
- * ocfs2_dio_end_io is called by the dio core when a dio is finished.  We're
- * particularly interested in the aio/dio case.  We use the rw_lock DLM lock
- * to protect io on one node from truncation on another.
- */
-static int ocfs2_dio_end_io(struct kiocb *iocb,
-                            loff_t offset,
-                            ssize_t bytes,
-                            void *private)
-{
-       struct inode *inode = file_inode(iocb->ki_filp);
-       int level;
-
-       if (bytes <= 0)
-               return 0;
-
-       /* this io's submitter should not have unlocked this before we could */
-       BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
-
-       if (ocfs2_iocb_is_unaligned_aio(iocb)) {
-               ocfs2_iocb_clear_unaligned_aio(iocb);
-
-               mutex_unlock(&OCFS2_I(inode)->ip_unaligned_aio);
-       }
-
-       /* Let rw unlock to be done later to protect append direct io write */
-       if (offset + bytes <= i_size_read(inode)) {
-               ocfs2_iocb_clear_rw_locked(iocb);
-
-               level = ocfs2_iocb_rw_locked_level(iocb);
-               ocfs2_rw_unlock(inode, level);
-       }
-
-       return 0;
-}
-
 static int ocfs2_releasepage(struct page *page, gfp_t wait)
 {
        if (!page_has_buffers(page))
@@ -658,363 +506,6 @@ static int ocfs2_releasepage(struct page *page, gfp_t wait)
        return try_to_free_buffers(page);
 }
 
-static int ocfs2_is_overwrite(struct ocfs2_super *osb,
-               struct inode *inode, loff_t offset)
-{
-       int ret = 0;
-       u32 v_cpos = 0;
-       u32 p_cpos = 0;
-       unsigned int num_clusters = 0;
-       unsigned int ext_flags = 0;
-
-       v_cpos = ocfs2_bytes_to_clusters(osb->sb, offset);
-       ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos,
-                       &num_clusters, &ext_flags);
-       if (ret < 0) {
-               mlog_errno(ret);
-               return ret;
-       }
-
-       if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN))
-               return 1;
-
-       return 0;
-}
-
-static int ocfs2_direct_IO_zero_extend(struct ocfs2_super *osb,
-               struct inode *inode, loff_t offset,
-               u64 zero_len, int cluster_align)
-{
-       u32 p_cpos = 0;
-       u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, i_size_read(inode));
-       unsigned int num_clusters = 0;
-       unsigned int ext_flags = 0;
-       int ret = 0;
-
-       if (offset <= i_size_read(inode) || cluster_align)
-               return 0;
-
-       ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos, &num_clusters,
-                       &ext_flags);
-       if (ret < 0) {
-               mlog_errno(ret);
-               return ret;
-       }
-
-       if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) {
-               u64 s = i_size_read(inode);
-               sector_t sector = ((u64)p_cpos << (osb->s_clustersize_bits - 9)) +
-                       (do_div(s, osb->s_clustersize) >> 9);
-
-               ret = blkdev_issue_zeroout(osb->sb->s_bdev, sector,
-                               zero_len >> 9, GFP_NOFS, false);
-               if (ret < 0)
-                       mlog_errno(ret);
-       }
-
-       return ret;
-}
-
-static int ocfs2_direct_IO_extend_no_holes(struct ocfs2_super *osb,
-               struct inode *inode, loff_t offset)
-{
-       u64 zero_start, zero_len, total_zero_len;
-       u32 p_cpos = 0, clusters_to_add;
-       u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, i_size_read(inode));
-       unsigned int num_clusters = 0;
-       unsigned int ext_flags = 0;
-       u32 size_div, offset_div;
-       int ret = 0;
-
-       {
-               u64 o = offset;
-               u64 s = i_size_read(inode);
-
-               offset_div = do_div(o, osb->s_clustersize);
-               size_div = do_div(s, osb->s_clustersize);
-       }
-
-       if (offset <= i_size_read(inode))
-               return 0;
-
-       clusters_to_add = ocfs2_bytes_to_clusters(inode->i_sb, offset) -
-               ocfs2_bytes_to_clusters(inode->i_sb, i_size_read(inode));
-       total_zero_len = offset - i_size_read(inode);
-       if (clusters_to_add)
-               total_zero_len -= offset_div;
-
-       /* Allocate clusters to fill out holes, and this is only needed
-        * when we add more than one clusters. Otherwise the cluster will
-        * be allocated during direct IO */
-       if (clusters_to_add > 1) {
-               ret = ocfs2_extend_allocation(inode,
-                               OCFS2_I(inode)->ip_clusters,
-                               clusters_to_add - 1, 0);
-               if (ret) {
-                       mlog_errno(ret);
-                       goto out;
-               }
-       }
-
-       while (total_zero_len) {
-               ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos, &num_clusters,
-                               &ext_flags);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto out;
-               }
-
-               zero_start = ocfs2_clusters_to_bytes(osb->sb, p_cpos) +
-                       size_div;
-               zero_len = ocfs2_clusters_to_bytes(osb->sb, num_clusters) -
-                       size_div;
-               zero_len = min(total_zero_len, zero_len);
-
-               if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) {
-                       ret = blkdev_issue_zeroout(osb->sb->s_bdev,
-                                       zero_start >> 9, zero_len >> 9,
-                                       GFP_NOFS, false);
-                       if (ret < 0) {
-                               mlog_errno(ret);
-                               goto out;
-                       }
-               }
-
-               total_zero_len -= zero_len;
-               v_cpos += ocfs2_bytes_to_clusters(osb->sb, zero_len + size_div);
-
-               /* Only at first iteration can be cluster not aligned.
-                * So set size_div to 0 for the rest */
-               size_div = 0;
-       }
-
-out:
-       return ret;
-}
-
-static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb,
-               struct iov_iter *iter,
-               loff_t offset)
-{
-       ssize_t ret = 0;
-       ssize_t written = 0;
-       bool orphaned = false;
-       int is_overwrite = 0;
-       struct file *file = iocb->ki_filp;
-       struct inode *inode = file_inode(file)->i_mapping->host;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       struct buffer_head *di_bh = NULL;
-       size_t count = iter->count;
-       journal_t *journal = osb->journal->j_journal;
-       u64 zero_len_head, zero_len_tail;
-       int cluster_align_head, cluster_align_tail;
-       loff_t final_size = offset + count;
-       int append_write = offset >= i_size_read(inode) ? 1 : 0;
-       unsigned int num_clusters = 0;
-       unsigned int ext_flags = 0;
-
-       {
-               u64 o = offset;
-               u64 s = i_size_read(inode);
-
-               zero_len_head = do_div(o, 1 << osb->s_clustersize_bits);
-               cluster_align_head = !zero_len_head;
-
-               zero_len_tail = osb->s_clustersize -
-                       do_div(s, osb->s_clustersize);
-               if ((offset - i_size_read(inode)) < zero_len_tail)
-                       zero_len_tail = offset - i_size_read(inode);
-               cluster_align_tail = !zero_len_tail;
-       }
-
-       /*
-        * when final_size > inode->i_size, inode->i_size will be
-        * updated after direct write, so add the inode to orphan
-        * dir first.
-        */
-       if (final_size > i_size_read(inode)) {
-               ret = ocfs2_add_inode_to_orphan(osb, inode);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto out;
-               }
-               orphaned = true;
-       }
-
-       if (append_write) {
-               ret = ocfs2_inode_lock(inode, NULL, 1);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto clean_orphan;
-               }
-
-               /* zeroing out the previously allocated cluster tail
-                * that but not zeroed */
-               if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
-                       down_read(&OCFS2_I(inode)->ip_alloc_sem);
-                       ret = ocfs2_direct_IO_zero_extend(osb, inode, offset,
-                                       zero_len_tail, cluster_align_tail);
-                       up_read(&OCFS2_I(inode)->ip_alloc_sem);
-               } else {
-                       down_write(&OCFS2_I(inode)->ip_alloc_sem);
-                       ret = ocfs2_direct_IO_extend_no_holes(osb, inode,
-                                       offset);
-                       up_write(&OCFS2_I(inode)->ip_alloc_sem);
-               }
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       ocfs2_inode_unlock(inode, 1);
-                       goto clean_orphan;
-               }
-
-               is_overwrite = ocfs2_is_overwrite(osb, inode, offset);
-               if (is_overwrite < 0) {
-                       mlog_errno(is_overwrite);
-                       ret = is_overwrite;
-                       ocfs2_inode_unlock(inode, 1);
-                       goto clean_orphan;
-               }
-
-               ocfs2_inode_unlock(inode, 1);
-       }
-
-       written = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter,
-                                      offset, ocfs2_direct_IO_get_blocks,
-                                      ocfs2_dio_end_io, NULL, 0);
-       /* overwrite aio may return -EIOCBQUEUED, and it is not an error */
-       if ((written < 0) && (written != -EIOCBQUEUED)) {
-               loff_t i_size = i_size_read(inode);
-
-               if (offset + count > i_size) {
-                       ret = ocfs2_inode_lock(inode, &di_bh, 1);
-                       if (ret < 0) {
-                               mlog_errno(ret);
-                               goto clean_orphan;
-                       }
-
-                       if (i_size == i_size_read(inode)) {
-                               ret = ocfs2_truncate_file(inode, di_bh,
-                                               i_size);
-                               if (ret < 0) {
-                                       if (ret != -ENOSPC)
-                                               mlog_errno(ret);
-
-                                       ocfs2_inode_unlock(inode, 1);
-                                       brelse(di_bh);
-                                       di_bh = NULL;
-                                       goto clean_orphan;
-                               }
-                       }
-
-                       ocfs2_inode_unlock(inode, 1);
-                       brelse(di_bh);
-                       di_bh = NULL;
-
-                       ret = jbd2_journal_force_commit(journal);
-                       if (ret < 0)
-                               mlog_errno(ret);
-               }
-       } else if (written > 0 && append_write && !is_overwrite &&
-                       !cluster_align_head) {
-               /* zeroing out the allocated cluster head */
-               u32 p_cpos = 0;
-               u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, offset);
-
-               ret = ocfs2_inode_lock(inode, NULL, 0);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto clean_orphan;
-               }
-
-               ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos,
-                               &num_clusters, &ext_flags);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       ocfs2_inode_unlock(inode, 0);
-                       goto clean_orphan;
-               }
-
-               BUG_ON(!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN));
-
-               ret = blkdev_issue_zeroout(osb->sb->s_bdev,
-                               (u64)p_cpos << (osb->s_clustersize_bits - 9),
-                               zero_len_head >> 9, GFP_NOFS, false);
-               if (ret < 0)
-                       mlog_errno(ret);
-
-               ocfs2_inode_unlock(inode, 0);
-       }
-
-clean_orphan:
-       if (orphaned) {
-               int tmp_ret;
-               int update_isize = written > 0 ? 1 : 0;
-               loff_t end = update_isize ? offset + written : 0;
-
-               tmp_ret = ocfs2_inode_lock(inode, &di_bh, 1);
-               if (tmp_ret < 0) {
-                       ret = tmp_ret;
-                       mlog_errno(ret);
-                       goto out;
-               }
-
-               tmp_ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
-                               update_isize, end);
-               if (tmp_ret < 0) {
-                       ocfs2_inode_unlock(inode, 1);
-                       ret = tmp_ret;
-                       mlog_errno(ret);
-                       brelse(di_bh);
-                       goto out;
-               }
-
-               ocfs2_inode_unlock(inode, 1);
-               brelse(di_bh);
-
-               tmp_ret = jbd2_journal_force_commit(journal);
-               if (tmp_ret < 0) {
-                       ret = tmp_ret;
-                       mlog_errno(tmp_ret);
-               }
-       }
-
-out:
-       if (ret >= 0)
-               ret = written;
-       return ret;
-}
-
-static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
-                              loff_t offset)
-{
-       struct file *file = iocb->ki_filp;
-       struct inode *inode = file_inode(file)->i_mapping->host;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       int full_coherency = !(osb->s_mount_opt &
-                       OCFS2_MOUNT_COHERENCY_BUFFERED);
-
-       /*
-        * Fallback to buffered I/O if we see an inode without
-        * extents.
-        */
-       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
-               return 0;
-
-       /* Fallback to buffered I/O if we are appending and
-        * concurrent O_DIRECT writes are allowed.
-        */
-       if (i_size_read(inode) <= offset && !full_coherency)
-               return 0;
-
-       if (iov_iter_rw(iter) == READ)
-               return __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
-                                           iter, offset,
-                                           ocfs2_direct_IO_get_blocks,
-                                           ocfs2_dio_end_io, NULL, 0);
-       else
-               return ocfs2_direct_IO_write(iocb, iter, offset);
-}
-
 static void ocfs2_figure_cluster_boundaries(struct ocfs2_super *osb,
                                            u32 cpos,
                                            unsigned int *start,
@@ -1201,6 +692,13 @@ next_bh:
 
 #define OCFS2_MAX_CLUSTERS_PER_PAGE    (PAGE_CACHE_SIZE / OCFS2_MIN_CLUSTERSIZE)
 
+struct ocfs2_unwritten_extent {
+       struct list_head        ue_node;
+       struct list_head        ue_ip_node;
+       u32                     ue_cpos;
+       u32                     ue_phys;
+};
+
 /*
  * Describe the state of a single cluster to be written to.
  */
@@ -1212,7 +710,7 @@ struct ocfs2_write_cluster_desc {
         * filled.
         */
        unsigned        c_new;
-       unsigned        c_unwritten;
+       unsigned        c_clear_unwritten;
        unsigned        c_needs_zero;
 };
 
@@ -1224,6 +722,9 @@ struct ocfs2_write_ctxt {
        /* First cluster allocated in a nonsparse extend */
        u32                             w_first_new_cpos;
 
+       /* Type of caller. Must be one of buffer, mmap, direct.  */
+       ocfs2_write_type_t              w_type;
+
        struct ocfs2_write_cluster_desc w_desc[OCFS2_MAX_CLUSTERS_PER_PAGE];
 
        /*
@@ -1272,6 +773,8 @@ struct ocfs2_write_ctxt {
        struct buffer_head              *w_di_bh;
 
        struct ocfs2_cached_dealloc_ctxt w_dealloc;
+
+       struct list_head                w_unwritten_list;
 };
 
 void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages)
@@ -1310,8 +813,25 @@ static void ocfs2_unlock_pages(struct ocfs2_write_ctxt *wc)
        ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages);
 }
 
-static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
+static void ocfs2_free_unwritten_list(struct inode *inode,
+                                struct list_head *head)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_unwritten_extent *ue = NULL, *tmp = NULL;
+
+       list_for_each_entry_safe(ue, tmp, head, ue_node) {
+               list_del(&ue->ue_node);
+               spin_lock(&oi->ip_lock);
+               list_del(&ue->ue_ip_node);
+               spin_unlock(&oi->ip_lock);
+               kfree(ue);
+       }
+}
+
+static void ocfs2_free_write_ctxt(struct inode *inode,
+                                 struct ocfs2_write_ctxt *wc)
 {
+       ocfs2_free_unwritten_list(inode, &wc->w_unwritten_list);
        ocfs2_unlock_pages(wc);
        brelse(wc->w_di_bh);
        kfree(wc);
@@ -1319,7 +839,8 @@ static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
 
 static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp,
                                  struct ocfs2_super *osb, loff_t pos,
-                                 unsigned len, struct buffer_head *di_bh)
+                                 unsigned len, ocfs2_write_type_t type,
+                                 struct buffer_head *di_bh)
 {
        u32 cend;
        struct ocfs2_write_ctxt *wc;
@@ -1334,6 +855,7 @@ static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp,
        wc->w_clen = cend - wc->w_cpos + 1;
        get_bh(di_bh);
        wc->w_di_bh = di_bh;
+       wc->w_type = type;
 
        if (unlikely(PAGE_CACHE_SHIFT > osb->s_clustersize_bits))
                wc->w_large_pages = 1;
@@ -1341,6 +863,7 @@ static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp,
                wc->w_large_pages = 0;
 
        ocfs2_init_dealloc_ctxt(&wc->w_dealloc);
+       INIT_LIST_HEAD(&wc->w_unwritten_list);
 
        *wcp = wc;
 
@@ -1401,12 +924,13 @@ static void ocfs2_write_failure(struct inode *inode,
                to = user_pos + user_len;
        struct page *tmppage;
 
-       ocfs2_zero_new_buffers(wc->w_target_page, from, to);
+       if (wc->w_target_page)
+               ocfs2_zero_new_buffers(wc->w_target_page, from, to);
 
        for(i = 0; i < wc->w_num_pages; i++) {
                tmppage = wc->w_pages[i];
 
-               if (page_has_buffers(tmppage)) {
+               if (tmppage && page_has_buffers(tmppage)) {
                        if (ocfs2_should_order_data(inode))
                                ocfs2_jbd2_file_inode(wc->w_handle, inode);
 
@@ -1536,11 +1060,13 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping,
                wc->w_num_pages = 1;
                start = target_index;
        }
+       end_index = (user_pos + user_len - 1) >> PAGE_CACHE_SHIFT;
 
        for(i = 0; i < wc->w_num_pages; i++) {
                index = start + i;
 
-               if (index == target_index && mmap_page) {
+               if (index >= target_index && index <= end_index &&
+                   wc->w_type == OCFS2_WRITE_MMAP) {
                        /*
                         * ocfs2_pagemkwrite() is a little different
                         * and wants us to directly use the page
@@ -1559,6 +1085,11 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping,
                        page_cache_get(mmap_page);
                        wc->w_pages[i] = mmap_page;
                        wc->w_target_locked = true;
+               } else if (index >= target_index && index <= end_index &&
+                          wc->w_type == OCFS2_WRITE_DIRECT) {
+                       /* Direct write has no mapping page. */
+                       wc->w_pages[i] = NULL;
+                       continue;
                } else {
                        wc->w_pages[i] = find_or_create_page(mapping, index,
                                                             GFP_NOFS);
@@ -1583,19 +1114,20 @@ out:
  * Prepare a single cluster for write one cluster into the file.
  */
 static int ocfs2_write_cluster(struct address_space *mapping,
-                              u32 phys, unsigned int unwritten,
+                              u32 *phys, unsigned int new,
+                              unsigned int clear_unwritten,
                               unsigned int should_zero,
                               struct ocfs2_alloc_context *data_ac,
                               struct ocfs2_alloc_context *meta_ac,
                               struct ocfs2_write_ctxt *wc, u32 cpos,
                               loff_t user_pos, unsigned user_len)
 {
-       int ret, i, new;
-       u64 v_blkno, p_blkno;
+       int ret, i;
+       u64 p_blkno;
        struct inode *inode = mapping->host;
        struct ocfs2_extent_tree et;
+       int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
 
-       new = phys == 0 ? 1 : 0;
        if (new) {
                u32 tmp_pos;
 
@@ -1605,9 +1137,9 @@ static int ocfs2_write_cluster(struct address_space *mapping,
                 */
                tmp_pos = cpos;
                ret = ocfs2_add_inode_data(OCFS2_SB(inode->i_sb), inode,
-                                          &tmp_pos, 1, 0, wc->w_di_bh,
-                                          wc->w_handle, data_ac,
-                                          meta_ac, NULL);
+                                          &tmp_pos, 1, !clear_unwritten,
+                                          wc->w_di_bh, wc->w_handle,
+                                          data_ac, meta_ac, NULL);
                /*
                 * This shouldn't happen because we must have already
                 * calculated the correct meta data allocation required. The
@@ -1624,11 +1156,11 @@ static int ocfs2_write_cluster(struct address_space *mapping,
                        mlog_errno(ret);
                        goto out;
                }
-       } else if (unwritten) {
+       } else if (clear_unwritten) {
                ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode),
                                              wc->w_di_bh);
                ret = ocfs2_mark_extent_written(inode, &et,
-                                               wc->w_handle, cpos, 1, phys,
+                                               wc->w_handle, cpos, 1, *phys,
                                                meta_ac, &wc->w_dealloc);
                if (ret < 0) {
                        mlog_errno(ret);
@@ -1636,30 +1168,33 @@ static int ocfs2_write_cluster(struct address_space *mapping,
                }
        }
 
-       if (should_zero)
-               v_blkno = ocfs2_clusters_to_blocks(inode->i_sb, cpos);
-       else
-               v_blkno = user_pos >> inode->i_sb->s_blocksize_bits;
-
        /*
         * The only reason this should fail is due to an inability to
         * find the extent added.
         */
-       ret = ocfs2_extent_map_get_blocks(inode, v_blkno, &p_blkno, NULL,
-                                         NULL);
+       ret = ocfs2_get_clusters(inode, cpos, phys, NULL, NULL);
        if (ret < 0) {
                mlog(ML_ERROR, "Get physical blkno failed for inode %llu, "
-                           "at logical block %llu",
-                           (unsigned long long)OCFS2_I(inode)->ip_blkno,
-                           (unsigned long long)v_blkno);
+                           "at logical cluster %u",
+                           (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos);
                goto out;
        }
 
-       BUG_ON(p_blkno == 0);
+       BUG_ON(*phys == 0);
+
+       p_blkno = ocfs2_clusters_to_blocks(inode->i_sb, *phys);
+       if (!should_zero)
+               p_blkno += (user_pos >> inode->i_sb->s_blocksize_bits) & (u64)(bpc - 1);
 
        for(i = 0; i < wc->w_num_pages; i++) {
                int tmpret;
 
+               /* This is the direct io target page. */
+               if (wc->w_pages[i] == NULL) {
+                       p_blkno++;
+                       continue;
+               }
+
                tmpret = ocfs2_prepare_page_for_write(inode, &p_blkno, wc,
                                                      wc->w_pages[i], cpos,
                                                      user_pos, user_len,
@@ -1706,8 +1241,9 @@ static int ocfs2_write_cluster_by_desc(struct address_space *mapping,
                if ((cluster_off + local_len) > osb->s_clustersize)
                        local_len = osb->s_clustersize - cluster_off;
 
-               ret = ocfs2_write_cluster(mapping, desc->c_phys,
-                                         desc->c_unwritten,
+               ret = ocfs2_write_cluster(mapping, &desc->c_phys,
+                                         desc->c_new,
+                                         desc->c_clear_unwritten,
                                          desc->c_needs_zero,
                                          data_ac, meta_ac,
                                          wc, desc->c_cpos, pos, local_len);
@@ -1777,6 +1313,66 @@ static void ocfs2_set_target_boundaries(struct ocfs2_super *osb,
        }
 }
 
+/*
+ * Check if this extent is marked UNWRITTEN by direct io. If so, we need not to
+ * do the zero work. And should not to clear UNWRITTEN since it will be cleared
+ * by the direct io procedure.
+ * If this is a new extent that allocated by direct io, we should mark it in
+ * the ip_unwritten_list.
+ */
+static int ocfs2_unwritten_check(struct inode *inode,
+                                struct ocfs2_write_ctxt *wc,
+                                struct ocfs2_write_cluster_desc *desc)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_unwritten_extent *ue = NULL, *new = NULL;
+       int ret = 0;
+
+       if (!desc->c_needs_zero)
+               return 0;
+
+retry:
+       spin_lock(&oi->ip_lock);
+       /* Needs not to zero no metter buffer or direct. The one who is zero
+        * the cluster is doing zero. And he will clear unwritten after all
+        * cluster io finished. */
+       list_for_each_entry(ue, &oi->ip_unwritten_list, ue_ip_node) {
+               if (desc->c_cpos == ue->ue_cpos) {
+                       BUG_ON(desc->c_new);
+                       desc->c_needs_zero = 0;
+                       desc->c_clear_unwritten = 0;
+                       goto unlock;
+               }
+       }
+
+       if (wc->w_type != OCFS2_WRITE_DIRECT)
+               goto unlock;
+
+       if (new == NULL) {
+               spin_unlock(&oi->ip_lock);
+               new = kmalloc(sizeof(struct ocfs2_unwritten_extent),
+                            GFP_NOFS);
+               if (new == NULL) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               goto retry;
+       }
+       /* This direct write will doing zero. */
+       new->ue_cpos = desc->c_cpos;
+       new->ue_phys = desc->c_phys;
+       desc->c_clear_unwritten = 0;
+       list_add_tail(&new->ue_ip_node, &oi->ip_unwritten_list);
+       list_add_tail(&new->ue_node, &wc->w_unwritten_list);
+       new = NULL;
+unlock:
+       spin_unlock(&oi->ip_lock);
+out:
+       if (new)
+               kfree(new);
+       return ret;
+}
+
 /*
  * Populate each single-cluster write descriptor in the write context
  * with information about the i/o to be done.
@@ -1852,14 +1448,21 @@ static int ocfs2_populate_write_desc(struct inode *inode,
                if (phys == 0) {
                        desc->c_new = 1;
                        desc->c_needs_zero = 1;
+                       desc->c_clear_unwritten = 1;
                        *clusters_to_alloc = *clusters_to_alloc + 1;
                }
 
                if (ext_flags & OCFS2_EXT_UNWRITTEN) {
-                       desc->c_unwritten = 1;
+                       desc->c_clear_unwritten = 1;
                        desc->c_needs_zero = 1;
                }
 
+               ret = ocfs2_unwritten_check(inode, wc, desc);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
                num_clusters--;
        }
 
@@ -2022,8 +1625,10 @@ static int ocfs2_expand_nonsparse_inode(struct inode *inode,
        if (ret)
                mlog_errno(ret);
 
-       wc->w_first_new_cpos =
-               ocfs2_clusters_for_bytes(inode->i_sb, i_size_read(inode));
+       /* There is no wc if this is call from direct. */
+       if (wc)
+               wc->w_first_new_cpos =
+                       ocfs2_clusters_for_bytes(inode->i_sb, i_size_read(inode));
 
        return ret;
 }
@@ -2077,9 +1682,8 @@ out:
        return ret;
 }
 
-int ocfs2_write_begin_nolock(struct file *filp,
-                            struct address_space *mapping,
-                            loff_t pos, unsigned len, unsigned flags,
+int ocfs2_write_begin_nolock(struct address_space *mapping,
+                            loff_t pos, unsigned len, ocfs2_write_type_t type,
                             struct page **pagep, void **fsdata,
                             struct buffer_head *di_bh, struct page *mmap_page)
 {
@@ -2096,7 +1700,7 @@ int ocfs2_write_begin_nolock(struct file *filp,
        int try_free = 1, ret1;
 
 try_again:
-       ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh);
+       ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, type, di_bh);
        if (ret) {
                mlog_errno(ret);
                return ret;
@@ -2115,14 +1719,17 @@ try_again:
                }
        }
 
-       if (ocfs2_sparse_alloc(osb))
-               ret = ocfs2_zero_tail(inode, di_bh, pos);
-       else
-               ret = ocfs2_expand_nonsparse_inode(inode, di_bh, pos, len,
-                                                  wc);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
+       /* Direct io change i_size late, should not zero tail here. */
+       if (type != OCFS2_WRITE_DIRECT) {
+               if (ocfs2_sparse_alloc(osb))
+                       ret = ocfs2_zero_tail(inode, di_bh, pos);
+               else
+                       ret = ocfs2_expand_nonsparse_inode(inode, di_bh, pos,
+                                                          len, wc);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
        }
 
        ret = ocfs2_check_range_for_refcount(inode, pos, len);
@@ -2153,7 +1760,7 @@ try_again:
                        (unsigned long long)OCFS2_I(inode)->ip_blkno,
                        (long long)i_size_read(inode),
                        le32_to_cpu(di->i_clusters),
-                       pos, len, flags, mmap_page,
+                       pos, len, type, mmap_page,
                        clusters_to_alloc, extents_to_split);
 
        /*
@@ -2183,17 +1790,17 @@ try_again:
 
                credits = ocfs2_calc_extend_credits(inode->i_sb,
                                                    &di->id2.i_list);
-
-       }
+       } else if (type == OCFS2_WRITE_DIRECT)
+               /* direct write needs not to start trans if no extents alloc. */
+               goto success;
 
        /*
         * We have to zero sparse allocated clusters, unwritten extent clusters,
         * and non-sparse clusters we just extended.  For non-sparse writes,
         * we know zeros will only be needed in the first and/or last cluster.
         */
-       if (clusters_to_alloc || extents_to_split ||
-           (wc->w_clen && (wc->w_desc[0].c_needs_zero ||
-                           wc->w_desc[wc->w_clen - 1].c_needs_zero)))
+       if (wc->w_clen && (wc->w_desc[0].c_needs_zero ||
+                          wc->w_desc[wc->w_clen - 1].c_needs_zero))
                cluster_of_pages = 1;
        else
                cluster_of_pages = 0;
@@ -2260,7 +1867,8 @@ try_again:
                ocfs2_free_alloc_context(meta_ac);
 
 success:
-       *pagep = wc->w_target_page;
+       if (pagep)
+               *pagep = wc->w_target_page;
        *fsdata = wc;
        return 0;
 out_quota:
@@ -2271,7 +1879,7 @@ out_commit:
        ocfs2_commit_trans(osb, handle);
 
 out:
-       ocfs2_free_write_ctxt(wc);
+       ocfs2_free_write_ctxt(inode, wc);
 
        if (data_ac) {
                ocfs2_free_alloc_context(data_ac);
@@ -2323,8 +1931,8 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
         */
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
-       ret = ocfs2_write_begin_nolock(file, mapping, pos, len, flags, pagep,
-                                      fsdata, di_bh, NULL);
+       ret = ocfs2_write_begin_nolock(mapping, pos, len, OCFS2_WRITE_BUFFER,
+                                      pagep, fsdata, di_bh, NULL);
        if (ret) {
                mlog_errno(ret);
                goto out_fail;
@@ -2381,12 +1989,16 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
        handle_t *handle = wc->w_handle;
        struct page *tmppage;
 
-       ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), wc->w_di_bh,
-                       OCFS2_JOURNAL_ACCESS_WRITE);
-       if (ret) {
-               copied = ret;
-               mlog_errno(ret);
-               goto out;
+       BUG_ON(!list_empty(&wc->w_unwritten_list));
+
+       if (handle) {
+               ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
+                               wc->w_di_bh, OCFS2_JOURNAL_ACCESS_WRITE);
+               if (ret) {
+                       copied = ret;
+                       mlog_errno(ret);
+                       goto out;
+               }
        }
 
        if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
@@ -2394,18 +2006,23 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
                goto out_write_size;
        }
 
-       if (unlikely(copied < len)) {
+       if (unlikely(copied < len) && wc->w_target_page) {
                if (!PageUptodate(wc->w_target_page))
                        copied = 0;
 
                ocfs2_zero_new_buffers(wc->w_target_page, start+copied,
                                       start+len);
        }
-       flush_dcache_page(wc->w_target_page);
+       if (wc->w_target_page)
+               flush_dcache_page(wc->w_target_page);
 
        for(i = 0; i < wc->w_num_pages; i++) {
                tmppage = wc->w_pages[i];
 
+               /* This is the direct io target page. */
+               if (tmppage == NULL)
+                       continue;
+
                if (tmppage == wc->w_target_page) {
                        from = wc->w_target_from;
                        to = wc->w_target_to;
@@ -2424,25 +2041,29 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
                }
 
                if (page_has_buffers(tmppage)) {
-                       if (ocfs2_should_order_data(inode))
-                               ocfs2_jbd2_file_inode(wc->w_handle, inode);
+                       if (handle && ocfs2_should_order_data(inode))
+                               ocfs2_jbd2_file_inode(handle, inode);
                        block_commit_write(tmppage, from, to);
                }
        }
 
 out_write_size:
-       pos += copied;
-       if (pos > i_size_read(inode)) {
-               i_size_write(inode, pos);
-               mark_inode_dirty(inode);
-       }
-       inode->i_blocks = ocfs2_inode_sector_count(inode);
-       di->i_size = cpu_to_le64((u64)i_size_read(inode));
-       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec);
-       di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
-       ocfs2_update_inode_fsync_trans(handle, inode, 1);
-       ocfs2_journal_dirty(handle, wc->w_di_bh);
+       /* Direct io do not update i_size here. */
+       if (wc->w_type != OCFS2_WRITE_DIRECT) {
+               pos += copied;
+               if (pos > i_size_read(inode)) {
+                       i_size_write(inode, pos);
+                       mark_inode_dirty(inode);
+               }
+               inode->i_blocks = ocfs2_inode_sector_count(inode);
+               di->i_size = cpu_to_le64((u64)i_size_read(inode));
+               inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+               di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec);
+               di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
+               ocfs2_update_inode_fsync_trans(handle, inode, 1);
+       }
+       if (handle)
+               ocfs2_journal_dirty(handle, wc->w_di_bh);
 
 out:
        /* unlock pages before dealloc since it needs acquiring j_trans_barrier
@@ -2452,7 +2073,8 @@ out:
         */
        ocfs2_unlock_pages(wc);
 
-       ocfs2_commit_trans(osb, handle);
+       if (handle)
+               ocfs2_commit_trans(osb, handle);
 
        ocfs2_run_deallocs(osb, &wc->w_dealloc);
 
@@ -2477,6 +2099,360 @@ static int ocfs2_write_end(struct file *file, struct address_space *mapping,
        return ret;
 }
 
+struct ocfs2_dio_write_ctxt {
+       struct list_head        dw_zero_list;
+       unsigned                dw_zero_count;
+       int                     dw_orphaned;
+       pid_t                   dw_writer_pid;
+};
+
+static struct ocfs2_dio_write_ctxt *
+ocfs2_dio_alloc_write_ctx(struct buffer_head *bh, int *alloc)
+{
+       struct ocfs2_dio_write_ctxt *dwc = NULL;
+
+       if (bh->b_private)
+               return bh->b_private;
+
+       dwc = kmalloc(sizeof(struct ocfs2_dio_write_ctxt), GFP_NOFS);
+       if (dwc == NULL)
+               return NULL;
+       INIT_LIST_HEAD(&dwc->dw_zero_list);
+       dwc->dw_zero_count = 0;
+       dwc->dw_orphaned = 0;
+       dwc->dw_writer_pid = task_pid_nr(current);
+       bh->b_private = dwc;
+       *alloc = 1;
+
+       return dwc;
+}
+
+static void ocfs2_dio_free_write_ctx(struct inode *inode,
+                                    struct ocfs2_dio_write_ctxt *dwc)
+{
+       ocfs2_free_unwritten_list(inode, &dwc->dw_zero_list);
+       kfree(dwc);
+}
+
+/*
+ * TODO: Make this into a generic get_blocks function.
+ *
+ * From do_direct_io in direct-io.c:
+ *  "So what we do is to permit the ->get_blocks function to populate
+ *   bh.b_size with the size of IO which is permitted at this offset and
+ *   this i_blkbits."
+ *
+ * This function is called directly from get_more_blocks in direct-io.c.
+ *
+ * called like this: dio->get_blocks(dio->inode, fs_startblk,
+ *                                     fs_count, map_bh, dio->rw == WRITE);
+ */
+static int ocfs2_dio_get_block(struct inode *inode, sector_t iblock,
+                              struct buffer_head *bh_result, int create)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_write_ctxt *wc;
+       struct ocfs2_write_cluster_desc *desc = NULL;
+       struct ocfs2_dio_write_ctxt *dwc = NULL;
+       struct buffer_head *di_bh = NULL;
+       u64 p_blkno;
+       loff_t pos = iblock << inode->i_sb->s_blocksize_bits;
+       unsigned len, total_len = bh_result->b_size;
+       int ret = 0, first_get_block = 0;
+
+       len = osb->s_clustersize - (pos & (osb->s_clustersize - 1));
+       len = min(total_len, len);
+
+       mlog(0, "get block of %lu at %llu:%u req %u\n",
+                       inode->i_ino, pos, len, total_len);
+
+       /*
+        * Because we need to change file size in ocfs2_dio_end_io_write(), or
+        * we may need to add it to orphan dir. So can not fall to fast path
+        * while file size will be changed.
+        */
+       if (pos + total_len <= i_size_read(inode)) {
+               down_read(&oi->ip_alloc_sem);
+               /* This is the fast path for re-write. */
+               ret = ocfs2_get_block(inode, iblock, bh_result, create);
+
+               up_read(&oi->ip_alloc_sem);
+
+               if (buffer_mapped(bh_result) &&
+                   !buffer_new(bh_result) &&
+                   ret == 0)
+                       goto out;
+
+               /* Clear state set by ocfs2_get_block. */
+               bh_result->b_state = 0;
+       }
+
+       dwc = ocfs2_dio_alloc_write_ctx(bh_result, &first_get_block);
+       if (unlikely(dwc == NULL)) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (ocfs2_clusters_for_bytes(inode->i_sb, pos + total_len) >
+           ocfs2_clusters_for_bytes(inode->i_sb, i_size_read(inode)) &&
+           !dwc->dw_orphaned) {
+               /*
+                * when we are going to alloc extents beyond file size, add the
+                * inode to orphan dir, so we can recall those spaces when
+                * system crashed during write.
+                */
+               ret = ocfs2_add_inode_to_orphan(osb, inode);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+               dwc->dw_orphaned = 1;
+       }
+
+       ret = ocfs2_inode_lock(inode, &di_bh, 1);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       down_write(&oi->ip_alloc_sem);
+
+       if (first_get_block) {
+               if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+                       ret = ocfs2_zero_tail(inode, di_bh, pos);
+               else
+                       ret = ocfs2_expand_nonsparse_inode(inode, di_bh, pos,
+                                                          total_len, NULL);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto unlock;
+               }
+       }
+
+       ret = ocfs2_write_begin_nolock(inode->i_mapping, pos, len,
+                                      OCFS2_WRITE_DIRECT, NULL,
+                                      (void **)&wc, di_bh, NULL);
+       if (ret) {
+               mlog_errno(ret);
+               goto unlock;
+       }
+
+       desc = &wc->w_desc[0];
+
+       p_blkno = ocfs2_clusters_to_blocks(inode->i_sb, desc->c_phys);
+       BUG_ON(p_blkno == 0);
+       p_blkno += iblock & (u64)(ocfs2_clusters_to_blocks(inode->i_sb, 1) - 1);
+
+       map_bh(bh_result, inode->i_sb, p_blkno);
+       bh_result->b_size = len;
+       if (desc->c_needs_zero)
+               set_buffer_new(bh_result);
+
+       /* May sleep in end_io. It should not happen in a irq context. So defer
+        * it to dio work queue. */
+       set_buffer_defer_completion(bh_result);
+
+       if (!list_empty(&wc->w_unwritten_list)) {
+               struct ocfs2_unwritten_extent *ue = NULL;
+
+               ue = list_first_entry(&wc->w_unwritten_list,
+                                     struct ocfs2_unwritten_extent,
+                                     ue_node);
+               BUG_ON(ue->ue_cpos != desc->c_cpos);
+               /* The physical address may be 0, fill it. */
+               ue->ue_phys = desc->c_phys;
+
+               list_splice_tail_init(&wc->w_unwritten_list, &dwc->dw_zero_list);
+               dwc->dw_zero_count++;
+       }
+
+       ret = ocfs2_write_end_nolock(inode->i_mapping, pos, len, len, NULL, wc);
+       BUG_ON(ret != len);
+       ret = 0;
+unlock:
+       up_write(&oi->ip_alloc_sem);
+       ocfs2_inode_unlock(inode, 1);
+       brelse(di_bh);
+out:
+       if (ret < 0)
+               ret = -EIO;
+       return ret;
+}
+
+static void ocfs2_dio_end_io_write(struct inode *inode,
+                                  struct ocfs2_dio_write_ctxt *dwc,
+                                  loff_t offset,
+                                  ssize_t bytes)
+{
+       struct ocfs2_cached_dealloc_ctxt dealloc;
+       struct ocfs2_extent_tree et;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_unwritten_extent *ue = NULL;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_dinode *di;
+       struct ocfs2_alloc_context *data_ac = NULL;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       handle_t *handle = NULL;
+       loff_t end = offset + bytes;
+       int ret = 0, credits = 0, locked = 0;
+
+       ocfs2_init_dealloc_ctxt(&dealloc);
+
+       /* We do clear unwritten, delete orphan, change i_size here. If neither
+        * of these happen, we can skip all this. */
+       if (list_empty(&dwc->dw_zero_list) &&
+           end <= i_size_read(inode) &&
+           !dwc->dw_orphaned)
+               goto out;
+
+       /* ocfs2_file_write_iter will get i_mutex, so we need not lock if we
+        * are in that context. */
+       if (dwc->dw_writer_pid != task_pid_nr(current)) {
+               mutex_lock(&inode->i_mutex);
+               locked = 1;
+       }
+
+       ret = ocfs2_inode_lock(inode, &di_bh, 1);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       down_write(&oi->ip_alloc_sem);
+
+       /* Delete orphan before acquire i_mutex. */
+       if (dwc->dw_orphaned) {
+               BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
+
+               end = end > i_size_read(inode) ? end : 0;
+
+               ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
+                               !!end, end);
+               if (ret < 0)
+                       mlog_errno(ret);
+       }
+
+       di = (struct ocfs2_dinode *)di_bh;
+
+       ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
+
+       ret = ocfs2_lock_allocators(inode, &et, 0, dwc->dw_zero_count*2,
+                                   &data_ac, &meta_ac);
+       if (ret) {
+               mlog_errno(ret);
+               goto unlock;
+       }
+
+       credits = ocfs2_calc_extend_credits(inode->i_sb, &di->id2.i_list);
+
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto unlock;
+       }
+       ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto commit;
+       }
+
+       list_for_each_entry(ue, &dwc->dw_zero_list, ue_node) {
+               ret = ocfs2_mark_extent_written(inode, &et, handle,
+                                               ue->ue_cpos, 1,
+                                               ue->ue_phys,
+                                               meta_ac, &dealloc);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       break;
+               }
+       }
+
+       if (end > i_size_read(inode)) {
+               ret = ocfs2_set_inode_size(handle, inode, di_bh, end);
+               if (ret < 0)
+                       mlog_errno(ret);
+       }
+commit:
+       ocfs2_commit_trans(osb, handle);
+unlock:
+       up_write(&oi->ip_alloc_sem);
+       ocfs2_inode_unlock(inode, 1);
+       brelse(di_bh);
+out:
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
+       ocfs2_run_deallocs(osb, &dealloc);
+       if (locked)
+               mutex_unlock(&inode->i_mutex);
+       ocfs2_dio_free_write_ctx(inode, dwc);
+}
+
+/*
+ * ocfs2_dio_end_io is called by the dio core when a dio is finished.  We're
+ * particularly interested in the aio/dio case.  We use the rw_lock DLM lock
+ * to protect io on one node from truncation on another.
+ */
+static int ocfs2_dio_end_io(struct kiocb *iocb,
+                           loff_t offset,
+                           ssize_t bytes,
+                           void *private)
+{
+       struct inode *inode = file_inode(iocb->ki_filp);
+       int level;
+
+       if (bytes <= 0)
+               return 0;
+
+       /* this io's submitter should not have unlocked this before we could */
+       BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
+
+       if (private)
+               ocfs2_dio_end_io_write(inode, private, offset, bytes);
+
+       ocfs2_iocb_clear_rw_locked(iocb);
+
+       level = ocfs2_iocb_rw_locked_level(iocb);
+       ocfs2_rw_unlock(inode, level);
+       return 0;
+}
+
+static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
+                              loff_t offset)
+{
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file_inode(file)->i_mapping->host;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       loff_t end = offset + iter->count;
+       get_block_t *get_block;
+
+       /*
+        * Fallback to buffered I/O if we see an inode without
+        * extents.
+        */
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return 0;
+
+       /* Fallback to buffered I/O if we do not support append dio. */
+       if (end > i_size_read(inode) && !ocfs2_supports_append_dio(osb))
+               return 0;
+
+       if (iov_iter_rw(iter) == READ)
+               get_block = ocfs2_get_block;
+       else
+               get_block = ocfs2_dio_get_block;
+
+       return __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
+                                   iter, offset, get_block,
+                                   ocfs2_dio_end_io, NULL, 0);
+}
+
 const struct address_space_operations ocfs2_aops = {
        .readpage               = ocfs2_readpage,
        .readpages              = ocfs2_readpages,
index 24e496d..b1c9f28 100644 (file)
@@ -47,9 +47,14 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
                           loff_t pos, unsigned len, unsigned copied,
                           struct page *page, void *fsdata);
 
-int ocfs2_write_begin_nolock(struct file *filp,
-                            struct address_space *mapping,
-                            loff_t pos, unsigned len, unsigned flags,
+typedef enum {
+       OCFS2_WRITE_BUFFER = 0,
+       OCFS2_WRITE_DIRECT,
+       OCFS2_WRITE_MMAP,
+} ocfs2_write_type_t;
+
+int ocfs2_write_begin_nolock(struct address_space *mapping,
+                            loff_t pos, unsigned len, ocfs2_write_type_t type,
                             struct page **pagep, void **fsdata,
                             struct buffer_head *di_bh, struct page *mmap_page);
 
@@ -79,7 +84,6 @@ static inline void ocfs2_iocb_set_rw_locked(struct kiocb *iocb, int level)
 enum ocfs2_iocb_lock_bits {
        OCFS2_IOCB_RW_LOCK = 0,
        OCFS2_IOCB_RW_LOCK_LEVEL,
-       OCFS2_IOCB_UNALIGNED_IO,
        OCFS2_IOCB_NUM_LOCKS
 };
 
@@ -88,11 +92,4 @@ enum ocfs2_iocb_lock_bits {
 #define ocfs2_iocb_rw_locked_level(iocb) \
        test_bit(OCFS2_IOCB_RW_LOCK_LEVEL, (unsigned long *)&iocb->private)
 
-#define ocfs2_iocb_set_unaligned_aio(iocb) \
-       set_bit(OCFS2_IOCB_UNALIGNED_IO, (unsigned long *)&iocb->private)
-#define ocfs2_iocb_clear_unaligned_aio(iocb) \
-       clear_bit(OCFS2_IOCB_UNALIGNED_IO, (unsigned long *)&iocb->private)
-#define ocfs2_iocb_is_unaligned_aio(iocb) \
-       test_bit(OCFS2_IOCB_UNALIGNED_IO, (unsigned long *)&iocb->private)
-
 #endif /* OCFS2_FILE_H */
index ef6a2ec..bd15929 100644 (file)
@@ -1444,8 +1444,8 @@ static void o2hb_region_release(struct config_item *item)
        debugfs_remove(reg->hr_debug_dir);
        kfree(reg->hr_db_livenodes);
        kfree(reg->hr_db_regnum);
-       kfree(reg->hr_debug_elapsed_time);
-       kfree(reg->hr_debug_pinned);
+       kfree(reg->hr_db_elapsed_time);
+       kfree(reg->hr_db_pinned);
 
        spin_lock(&o2hb_live_lock);
        list_del(&reg->hr_all_item);
index e36d63f..cdeafb4 100644 (file)
@@ -212,6 +212,12 @@ grant:
        if (lock->lksb->flags & DLM_LKSB_PUT_LVB)
                memcpy(res->lvb, lock->lksb->lvb, DLM_LVB_LEN);
 
+       /*
+        * Move the lock to the tail because it may be the only lock which has
+        * an invalid lvb.
+        */
+       list_move_tail(&lock->list, &res->granted);
+
        status = DLM_NORMAL;
        *call_ast = 1;
        goto unlock_exit;
@@ -262,6 +268,7 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm,
                                  struct dlm_lock *lock, int flags, int type)
 {
        enum dlm_status status;
+       u8 old_owner = res->owner;
 
        mlog(0, "type=%d, convert_type=%d, busy=%d\n", lock->ml.type,
             lock->ml.convert_type, res->state & DLM_LOCK_RES_IN_PROGRESS);
@@ -287,6 +294,19 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm,
                status = DLM_DENIED;
                goto bail;
        }
+
+       if (lock->ml.type == type && lock->ml.convert_type == LKM_IVMODE) {
+               mlog(0, "last convert request returned DLM_RECOVERING, but "
+                    "owner has already queued and sent ast to me. res %.*s, "
+                    "(cookie=%u:%llu, type=%d, conv=%d)\n",
+                    res->lockname.len, res->lockname.name,
+                    dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+                    dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
+                    lock->ml.type, lock->ml.convert_type);
+               status = DLM_NORMAL;
+               goto bail;
+       }
+
        res->state |= DLM_LOCK_RES_IN_PROGRESS;
        /* move lock to local convert queue */
        /* do not alter lock refcount.  switching lists. */
@@ -316,11 +336,19 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm,
        spin_lock(&res->spinlock);
        res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
        lock->convert_pending = 0;
-       /* if it failed, move it back to granted queue */
+       /* if it failed, move it back to granted queue.
+        * if master returns DLM_NORMAL and then down before sending ast,
+        * it may have already been moved to granted queue, reset to
+        * DLM_RECOVERING and retry convert */
        if (status != DLM_NORMAL) {
                if (status != DLM_NOTQUEUED)
                        dlm_error(status);
                dlm_revert_pending_convert(res, lock);
+       } else if ((res->state & DLM_LOCK_RES_RECOVERING) ||
+                       (old_owner != res->owner)) {
+               mlog(0, "res %.*s is in recovering or has been recovered.\n",
+                               res->lockname.len, res->lockname.name);
+               status = DLM_RECOVERING;
        }
 bail:
        spin_unlock(&res->spinlock);
index cd38488..f6b3138 100644 (file)
@@ -2083,7 +2083,6 @@ void dlm_move_lockres_to_recovery_list(struct dlm_ctxt *dlm,
                        dlm_lock_get(lock);
                        if (lock->convert_pending) {
                                /* move converting lock back to granted */
-                               BUG_ON(i != DLM_CONVERTING_LIST);
                                mlog(0, "node died with convert pending "
                                     "on %.*s. move back to granted list.\n",
                                     res->lockname.len, res->lockname.name);
index 7cb38fd..c18ab45 100644 (file)
@@ -1381,44 +1381,6 @@ out:
        return ret;
 }
 
-/*
- * Will look for holes and unwritten extents in the range starting at
- * pos for count bytes (inclusive).
- */
-static int ocfs2_check_range_for_holes(struct inode *inode, loff_t pos,
-                                      size_t count)
-{
-       int ret = 0;
-       unsigned int extent_flags;
-       u32 cpos, clusters, extent_len, phys_cpos;
-       struct super_block *sb = inode->i_sb;
-
-       cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits;
-       clusters = ocfs2_clusters_for_bytes(sb, pos + count) - cpos;
-
-       while (clusters) {
-               ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &extent_len,
-                                        &extent_flags);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto out;
-               }
-
-               if (phys_cpos == 0 || (extent_flags & OCFS2_EXT_UNWRITTEN)) {
-                       ret = 1;
-                       break;
-               }
-
-               if (extent_len > clusters)
-                       extent_len = clusters;
-
-               clusters -= extent_len;
-               cpos += extent_len;
-       }
-out:
-       return ret;
-}
-
 static int ocfs2_write_remove_suid(struct inode *inode)
 {
        int ret;
@@ -2129,18 +2091,12 @@ out:
 
 static int ocfs2_prepare_inode_for_write(struct file *file,
                                         loff_t pos,
-                                        size_t count,
-                                        int appending,
-                                        int *direct_io,
-                                        int *has_refcount)
+                                        size_t count)
 {
        int ret = 0, meta_level = 0;
        struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = d_inode(dentry);
        loff_t end;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       int full_coherency = !(osb->s_mount_opt &
-               OCFS2_MOUNT_COHERENCY_BUFFERED);
 
        /*
         * We start with a read level meta lock and only jump to an ex
@@ -2189,10 +2145,6 @@ static int ocfs2_prepare_inode_for_write(struct file *file,
                                                               pos,
                                                               count,
                                                               &meta_level);
-                       if (has_refcount)
-                               *has_refcount = 1;
-                       if (direct_io)
-                               *direct_io = 0;
                }
 
                if (ret < 0) {
@@ -2200,67 +2152,12 @@ static int ocfs2_prepare_inode_for_write(struct file *file,
                        goto out_unlock;
                }
 
-               /*
-                * Skip the O_DIRECT checks if we don't need
-                * them.
-                */
-               if (!direct_io || !(*direct_io))
-                       break;
-
-               /*
-                * There's no sane way to do direct writes to an inode
-                * with inline data.
-                */
-               if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
-                       *direct_io = 0;
-                       break;
-               }
-
-               /*
-                * Allowing concurrent direct writes means
-                * i_size changes wouldn't be synchronized, so
-                * one node could wind up truncating another
-                * nodes writes.
-                */
-               if (end > i_size_read(inode) && !full_coherency) {
-                       *direct_io = 0;
-                       break;
-               }
-
-               /*
-                * Fallback to old way if the feature bit is not set.
-                */
-               if (end > i_size_read(inode) &&
-                               !ocfs2_supports_append_dio(osb)) {
-                       *direct_io = 0;
-                       break;
-               }
-
-               /*
-                * We don't fill holes during direct io, so
-                * check for them here. If any are found, the
-                * caller will have to retake some cluster
-                * locks and initiate the io as buffered.
-                */
-               ret = ocfs2_check_range_for_holes(inode, pos, count);
-               if (ret == 1) {
-                       /*
-                        * Fallback to old way if the feature bit is not set.
-                        * Otherwise try dio first and then complete the rest
-                        * request through buffer io.
-                        */
-                       if (!ocfs2_supports_append_dio(osb))
-                               *direct_io = 0;
-                       ret = 0;
-               } else if (ret < 0)
-                       mlog_errno(ret);
                break;
        }
 
 out_unlock:
        trace_ocfs2_prepare_inode_for_write(OCFS2_I(inode)->ip_blkno,
-                                           pos, appending, count,
-                                           direct_io, has_refcount);
+                                           pos, count);
 
        if (meta_level >= 0)
                ocfs2_inode_unlock(inode, meta_level);
@@ -2272,18 +2169,16 @@ out:
 static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
                                    struct iov_iter *from)
 {
-       int direct_io, appending, rw_level;
-       int can_do_direct, has_refcount = 0;
+       int direct_io, rw_level;
        ssize_t written = 0;
        ssize_t ret;
-       size_t count = iov_iter_count(from), orig_count;
+       size_t count = iov_iter_count(from);
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        int full_coherency = !(osb->s_mount_opt &
                               OCFS2_MOUNT_COHERENCY_BUFFERED);
-       int unaligned_dio = 0;
-       int dropped_dio = 0;
+       void *saved_ki_complete = NULL;
        int append_write = ((iocb->ki_pos + count) >=
                        i_size_read(inode) ? 1 : 0);
 
@@ -2296,12 +2191,10 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
        if (count == 0)
                return 0;
 
-       appending = iocb->ki_flags & IOCB_APPEND ? 1 : 0;
        direct_io = iocb->ki_flags & IOCB_DIRECT ? 1 : 0;
 
        inode_lock(inode);
 
-relock:
        /*
         * Concurrent O_DIRECT writes are allowed with
         * mount_option "coherency=buffered".
@@ -2334,7 +2227,6 @@ relock:
                ocfs2_inode_unlock(inode, 1);
        }
 
-       orig_count = iov_iter_count(from);
        ret = generic_write_checks(iocb, from);
        if (ret <= 0) {
                if (ret)
@@ -2343,41 +2235,18 @@ relock:
        }
        count = ret;
 
-       can_do_direct = direct_io;
-       ret = ocfs2_prepare_inode_for_write(file, iocb->ki_pos, count, appending,
-                                           &can_do_direct, &has_refcount);
+       ret = ocfs2_prepare_inode_for_write(file, iocb->ki_pos, count);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
        }
 
-       if (direct_io && !is_sync_kiocb(iocb))
-               unaligned_dio = ocfs2_is_io_unaligned(inode, count, iocb->ki_pos);
-
-       /*
-        * We can't complete the direct I/O as requested, fall back to
-        * buffered I/O.
-        */
-       if (direct_io && !can_do_direct) {
-               ocfs2_rw_unlock(inode, rw_level);
-
-               rw_level = -1;
-
-               direct_io = 0;
-               iocb->ki_flags &= ~IOCB_DIRECT;
-               iov_iter_reexpand(from, orig_count);
-               dropped_dio = 1;
-               goto relock;
-       }
-
-       if (unaligned_dio) {
+       if (direct_io && !is_sync_kiocb(iocb) &&
+           ocfs2_is_io_unaligned(inode, count, iocb->ki_pos)) {
                /*
-                * Wait on previous unaligned aio to complete before
-                * proceeding.
+                * Make it a sync io if it's an unaligned aio.
                 */
-               mutex_lock(&OCFS2_I(inode)->ip_unaligned_aio);
-               /* Mark the iocb as needing an unlock in ocfs2_dio_end_io */
-               ocfs2_iocb_set_unaligned_aio(iocb);
+               saved_ki_complete = xchg(&iocb->ki_complete, NULL);
        }
 
        /* communicate with ocfs2_dio_end_io */
@@ -2398,14 +2267,13 @@ relock:
         */
        if ((written == -EIOCBQUEUED) || (!ocfs2_iocb_is_rw_locked(iocb))) {
                rw_level = -1;
-               unaligned_dio = 0;
        }
 
        if (unlikely(written <= 0))
-               goto no_sync;
+               goto out;
 
        if (((file->f_flags & O_DSYNC) && !direct_io) ||
-           IS_SYNC(inode) || dropped_dio) {
+           IS_SYNC(inode)) {
                ret = filemap_fdatawrite_range(file->f_mapping,
                                               iocb->ki_pos - written,
                                               iocb->ki_pos - 1);
@@ -2424,13 +2292,10 @@ relock:
                                                      iocb->ki_pos - 1);
        }
 
-no_sync:
-       if (unaligned_dio && ocfs2_iocb_is_unaligned_aio(iocb)) {
-               ocfs2_iocb_clear_unaligned_aio(iocb);
-               mutex_unlock(&OCFS2_I(inode)->ip_unaligned_aio);
-       }
-
 out:
+       if (saved_ki_complete)
+               xchg(&iocb->ki_complete, saved_ki_complete);
+
        if (rw_level != -1)
                ocfs2_rw_unlock(inode, rw_level);
 
index ba495be..12f4a9e 100644 (file)
@@ -1170,6 +1170,9 @@ static void ocfs2_clear_inode(struct inode *inode)
        mlog_bug_on_msg(!list_empty(&oi->ip_io_markers),
                        "Clear inode of %llu, inode has io markers\n",
                        (unsigned long long)oi->ip_blkno);
+       mlog_bug_on_msg(!list_empty(&oi->ip_unwritten_list),
+                       "Clear inode of %llu, inode has unwritten extents\n",
+                       (unsigned long long)oi->ip_blkno);
 
        ocfs2_extent_map_trunc(inode, 0);
 
index 01635e0..d8f3fc8 100644 (file)
@@ -43,9 +43,6 @@ struct ocfs2_inode_info
        /* protects extended attribute changes on this inode */
        struct rw_semaphore             ip_xattr_sem;
 
-       /* Number of outstanding AIO's which are not page aligned */
-       struct mutex                    ip_unaligned_aio;
-
        /* These fields are protected by ip_lock */
        spinlock_t                      ip_lock;
        u32                             ip_open_count;
@@ -57,6 +54,9 @@ struct ocfs2_inode_info
        u32                             ip_flags; /* see below */
        u32                             ip_attr; /* inode attributes */
 
+       /* Record unwritten extents during direct io. */
+       struct list_head                ip_unwritten_list;
+
        /* protected by recovery_lock. */
        struct inode                    *ip_next_orphan;
 
index 61b833b..e607419 100644 (file)
@@ -231,7 +231,7 @@ void ocfs2_recovery_exit(struct ocfs2_super *osb)
        /* At this point, we know that no more recovery threads can be
         * launched, so wait for any recovery completion work to
         * complete. */
-       flush_workqueue(ocfs2_wq);
+       flush_workqueue(osb->ocfs2_wq);
 
        /*
         * Now that recovery is shut down, and the osb is about to be
@@ -1326,7 +1326,7 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,
 
        spin_lock(&journal->j_lock);
        list_add_tail(&item->lri_list, &journal->j_la_cleanups);
-       queue_work(ocfs2_wq, &journal->j_recovery_work);
+       queue_work(journal->j_osb->ocfs2_wq, &journal->j_recovery_work);
        spin_unlock(&journal->j_lock);
 }
 
@@ -1968,7 +1968,7 @@ static void ocfs2_orphan_scan_work(struct work_struct *work)
        mutex_lock(&os->os_lock);
        ocfs2_queue_orphan_scan(osb);
        if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE)
-               queue_delayed_work(ocfs2_wq, &os->os_orphan_scan_work,
+               queue_delayed_work(osb->ocfs2_wq, &os->os_orphan_scan_work,
                                      ocfs2_orphan_scan_timeout());
        mutex_unlock(&os->os_lock);
 }
@@ -2008,7 +2008,7 @@ void ocfs2_orphan_scan_start(struct ocfs2_super *osb)
                atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE);
        else {
                atomic_set(&os->os_state, ORPHAN_SCAN_ACTIVE);
-               queue_delayed_work(ocfs2_wq, &os->os_orphan_scan_work,
+               queue_delayed_work(osb->ocfs2_wq, &os->os_orphan_scan_work,
                                   ocfs2_orphan_scan_timeout());
        }
 }
index 7d62c43..fe0d1f9 100644 (file)
@@ -386,7 +386,7 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
        struct ocfs2_dinode *alloc = NULL;
 
        cancel_delayed_work(&osb->la_enable_wq);
-       flush_workqueue(ocfs2_wq);
+       flush_workqueue(osb->ocfs2_wq);
 
        if (osb->local_alloc_state == OCFS2_LA_UNUSED)
                goto out;
@@ -1085,7 +1085,7 @@ static int ocfs2_recalc_la_window(struct ocfs2_super *osb,
                } else {
                        osb->local_alloc_state = OCFS2_LA_DISABLED;
                }
-               queue_delayed_work(ocfs2_wq, &osb->la_enable_wq,
+               queue_delayed_work(osb->ocfs2_wq, &osb->la_enable_wq,
                                   OCFS2_LA_ENABLE_INTERVAL);
                goto out_unlock;
        }
index 77ebc2b..9ea081f 100644 (file)
@@ -104,8 +104,8 @@ static int __ocfs2_page_mkwrite(struct file *file, struct buffer_head *di_bh,
        if (page->index == last_index)
                len = ((size - 1) & ~PAGE_CACHE_MASK) + 1;
 
-       ret = ocfs2_write_begin_nolock(file, mapping, pos, len, 0, &locked_page,
-                                      &fsdata, di_bh, page);
+       ret = ocfs2_write_begin_nolock(mapping, pos, len, OCFS2_WRITE_MMAP,
+                                      &locked_page, &fsdata, di_bh, page);
        if (ret) {
                if (ret != -ENOSPC)
                        mlog_errno(ret);
index 7a01262..6cf6538 100644 (file)
@@ -464,6 +464,14 @@ struct ocfs2_super
        struct ocfs2_refcount_tree *osb_ref_tree_lru;
 
        struct mutex system_file_mutex;
+
+       /*
+        * OCFS2 needs to schedule several different types of work which
+        * require cluster locking, disk I/O, recovery waits, etc. Since these
+        * types of work tend to be heavy we avoid using the kernel events
+        * workqueue and schedule on our own.
+        */
+       struct workqueue_struct *ocfs2_wq;
 };
 
 #define OCFS2_SB(sb)       ((struct ocfs2_super *)(sb)->s_fs_info)
index 24b7e7f..f8f5fc5 100644 (file)
@@ -1450,28 +1450,20 @@ DEFINE_OCFS2_ULL_ULL_ULL_EVENT(ocfs2_remove_inode_range);
 
 TRACE_EVENT(ocfs2_prepare_inode_for_write,
        TP_PROTO(unsigned long long ino, unsigned long long saved_pos,
-                int appending, unsigned long count,
-                int *direct_io, int *has_refcount),
-       TP_ARGS(ino, saved_pos, appending, count, direct_io, has_refcount),
+                unsigned long count),
+       TP_ARGS(ino, saved_pos, count),
        TP_STRUCT__entry(
                __field(unsigned long long, ino)
                __field(unsigned long long, saved_pos)
-               __field(int, appending)
                __field(unsigned long, count)
-               __field(int, direct_io)
-               __field(int, has_refcount)
        ),
        TP_fast_assign(
                __entry->ino = ino;
                __entry->saved_pos = saved_pos;
-               __entry->appending = appending;
                __entry->count = count;
-               __entry->direct_io = direct_io ? *direct_io : -1;
-               __entry->has_refcount = has_refcount ? *has_refcount : -1;
        ),
-       TP_printk("%llu %llu %d %lu %d %d", __entry->ino,
-                 __entry->saved_pos, __entry->appending, __entry->count,
-                 __entry->direct_io, __entry->has_refcount)
+       TP_printk("%llu %llu %lu", __entry->ino,
+                 __entry->saved_pos, __entry->count)
 );
 
 DEFINE_OCFS2_INT_EVENT(generic_file_aio_read_ret);
index 91bc674..3892f3c 100644 (file)
@@ -726,7 +726,7 @@ static int ocfs2_release_dquot(struct dquot *dquot)
                dqgrab(dquot);
                /* First entry on list -> queue work */
                if (llist_add(&OCFS2_DQUOT(dquot)->list, &osb->dquot_drop_list))
-                       queue_work(ocfs2_wq, &osb->dquot_drop_work);
+                       queue_work(osb->ocfs2_wq, &osb->dquot_drop_work);
                goto out;
        }
        status = ocfs2_lock_global_qf(oinfo, 1);
index 576b9a0..18451e0 100644 (file)
@@ -196,7 +196,7 @@ static int update_backups(struct inode * inode, u32 clusters, char *data)
        for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
                blkno = ocfs2_backup_super_blkno(inode->i_sb, i);
                cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
-               if (cluster > clusters)
+               if (cluster >= clusters)
                        break;
 
                ret = ocfs2_read_blocks_sync(osb, blkno, 1, &backup);
index ccc9386..7db631e 100644 (file)
@@ -80,12 +80,6 @@ static struct kmem_cache *ocfs2_inode_cachep;
 struct kmem_cache *ocfs2_dquot_cachep;
 struct kmem_cache *ocfs2_qf_chunk_cachep;
 
-/* OCFS2 needs to schedule several different types of work which
- * require cluster locking, disk I/O, recovery waits, etc. Since these
- * types of work tend to be heavy we avoid using the kernel events
- * workqueue and schedule on our own. */
-struct workqueue_struct *ocfs2_wq = NULL;
-
 static struct dentry *ocfs2_debugfs_root;
 
 MODULE_AUTHOR("Oracle");
@@ -1613,33 +1607,25 @@ static int __init ocfs2_init(void)
        if (status < 0)
                goto out2;
 
-       ocfs2_wq = create_singlethread_workqueue("ocfs2_wq");
-       if (!ocfs2_wq) {
-               status = -ENOMEM;
-               goto out3;
-       }
-
        ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL);
        if (!ocfs2_debugfs_root) {
                status = -ENOMEM;
                mlog(ML_ERROR, "Unable to create ocfs2 debugfs root.\n");
-               goto out4;
+               goto out3;
        }
 
        ocfs2_set_locking_protocol();
 
        status = register_quota_format(&ocfs2_quota_format);
        if (status < 0)
-               goto out4;
+               goto out3;
        status = register_filesystem(&ocfs2_fs_type);
        if (!status)
                return 0;
 
        unregister_quota_format(&ocfs2_quota_format);
-out4:
-       destroy_workqueue(ocfs2_wq);
-       debugfs_remove(ocfs2_debugfs_root);
 out3:
+       debugfs_remove(ocfs2_debugfs_root);
        ocfs2_free_mem_caches();
 out2:
        exit_ocfs2_uptodate_cache();
@@ -1650,11 +1636,6 @@ out1:
 
 static void __exit ocfs2_exit(void)
 {
-       if (ocfs2_wq) {
-               flush_workqueue(ocfs2_wq);
-               destroy_workqueue(ocfs2_wq);
-       }
-
        unregister_quota_format(&ocfs2_quota_format);
 
        debugfs_remove(ocfs2_debugfs_root);
@@ -1745,8 +1726,8 @@ static void ocfs2_inode_init_once(void *data)
        spin_lock_init(&oi->ip_lock);
        ocfs2_extent_map_init(&oi->vfs_inode);
        INIT_LIST_HEAD(&oi->ip_io_markers);
+       INIT_LIST_HEAD(&oi->ip_unwritten_list);
        oi->ip_dir_start_lookup = 0;
-       mutex_init(&oi->ip_unaligned_aio);
        init_rwsem(&oi->ip_alloc_sem);
        init_rwsem(&oi->ip_xattr_sem);
        mutex_init(&oi->ip_io_mutex);
@@ -2349,6 +2330,12 @@ static int ocfs2_initialize_super(struct super_block *sb,
        }
        cleancache_init_shared_fs(sb);
 
+       osb->ocfs2_wq = create_singlethread_workqueue("ocfs2_wq");
+       if (!osb->ocfs2_wq) {
+               status = -ENOMEM;
+               mlog_errno(status);
+       }
+
 bail:
        return status;
 }
@@ -2536,6 +2523,12 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb)
 {
        /* This function assumes that the caller has the main osb resource */
 
+       /* ocfs2_initializer_super have already created this workqueue */
+       if (osb->ocfs2_wq) {
+               flush_workqueue(osb->ocfs2_wq);
+               destroy_workqueue(osb->ocfs2_wq);
+       }
+
        ocfs2_free_slot_info(osb);
 
        kfree(osb->osb_orphan_wipes);
index b477d0b..b023e4f 100644 (file)
@@ -26,8 +26,6 @@
 #ifndef OCFS2_SUPER_H
 #define OCFS2_SUPER_H
 
-extern struct workqueue_struct *ocfs2_wq;
-
 int ocfs2_publish_get_mount_state(struct ocfs2_super *osb,
                                  int node_num);
 
diff --git a/fs/orangefs/Kconfig b/fs/orangefs/Kconfig
new file mode 100644 (file)
index 0000000..1554c02
--- /dev/null
@@ -0,0 +1,6 @@
+config ORANGEFS_FS
+       tristate "ORANGEFS (Powered by PVFS) support"
+       select FS_POSIX_ACL
+       help
+          Orange is a parallel file system designed for use on high end
+          computing (HEC) systems.
diff --git a/fs/orangefs/Makefile b/fs/orangefs/Makefile
new file mode 100644 (file)
index 0000000..a9d6a96
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the ORANGEFS filesystem.
+#
+
+obj-$(CONFIG_ORANGEFS_FS) += orangefs.o
+
+orangefs-objs := acl.o file.o orangefs-cache.o orangefs-utils.o xattr.o \
+                dcache.o inode.o orangefs-sysfs.o orangefs-mod.o super.o \
+                devorangefs-req.o namei.o symlink.o dir.o orangefs-bufmap.o \
+                orangefs-debugfs.o waitqueue.o
diff --git a/fs/orangefs/acl.c b/fs/orangefs/acl.c
new file mode 100644 (file)
index 0000000..03f89db
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+#include <linux/posix_acl_xattr.h>
+#include <linux/fs_struct.h>
+
+struct posix_acl *orangefs_get_acl(struct inode *inode, int type)
+{
+       struct posix_acl *acl;
+       int ret;
+       char *key = NULL, *value = NULL;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               key = ORANGEFS_XATTR_NAME_ACL_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               key = ORANGEFS_XATTR_NAME_ACL_DEFAULT;
+               break;
+       default:
+               gossip_err("orangefs_get_acl: bogus value of type %d\n", type);
+               return ERR_PTR(-EINVAL);
+       }
+       /*
+        * Rather than incurring a network call just to determine the exact
+        * length of the attribute, I just allocate a max length to save on
+        * the network call. Conceivably, we could pass NULL to
+        * orangefs_inode_getxattr() to probe the length of the value, but
+        * I don't do that for now.
+        */
+       value = kmalloc(ORANGEFS_MAX_XATTR_VALUELEN, GFP_KERNEL);
+       if (value == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       gossip_debug(GOSSIP_ACL_DEBUG,
+                    "inode %pU, key %s, type %d\n",
+                    get_khandle_from_ino(inode),
+                    key,
+                    type);
+       ret = orangefs_inode_getxattr(inode,
+                                  "",
+                                  key,
+                                  value,
+                                  ORANGEFS_MAX_XATTR_VALUELEN);
+       /* if the key exists, convert it to an in-memory rep */
+       if (ret > 0) {
+               acl = posix_acl_from_xattr(&init_user_ns, value, ret);
+       } else if (ret == -ENODATA || ret == -ENOSYS) {
+               acl = NULL;
+       } else {
+               gossip_err("inode %pU retrieving acl's failed with error %d\n",
+                          get_khandle_from_ino(inode),
+                          ret);
+               acl = ERR_PTR(ret);
+       }
+       /* kfree(NULL) is safe, so don't worry if value ever got used */
+       kfree(value);
+       return acl;
+}
+
+int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       int error = 0;
+       void *value = NULL;
+       size_t size = 0;
+       const char *name = NULL;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name = ORANGEFS_XATTR_NAME_ACL_ACCESS;
+               if (acl) {
+                       umode_t mode = inode->i_mode;
+                       /*
+                        * can we represent this with the traditional file
+                        * mode permission bits?
+                        */
+                       error = posix_acl_equiv_mode(acl, &mode);
+                       if (error < 0) {
+                               gossip_err("%s: posix_acl_equiv_mode err: %d\n",
+                                          __func__,
+                                          error);
+                               return error;
+                       }
+
+                       if (inode->i_mode != mode)
+                               SetModeFlag(orangefs_inode);
+                       inode->i_mode = mode;
+                       mark_inode_dirty_sync(inode);
+                       if (error == 0)
+                               acl = NULL;
+               }
+               break;
+       case ACL_TYPE_DEFAULT:
+               name = ORANGEFS_XATTR_NAME_ACL_DEFAULT;
+               break;
+       default:
+               gossip_err("%s: invalid type %d!\n", __func__, type);
+               return -EINVAL;
+       }
+
+       gossip_debug(GOSSIP_ACL_DEBUG,
+                    "%s: inode %pU, key %s type %d\n",
+                    __func__, get_khandle_from_ino(inode),
+                    name,
+                    type);
+
+       if (acl) {
+               size = posix_acl_xattr_size(acl->a_count);
+               value = kmalloc(size, GFP_KERNEL);
+               if (!value)
+                       return -ENOMEM;
+
+               error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
+               if (error < 0)
+                       goto out;
+       }
+
+       gossip_debug(GOSSIP_ACL_DEBUG,
+                    "%s: name %s, value %p, size %zd, acl %p\n",
+                    __func__, name, value, size, acl);
+       /*
+        * Go ahead and set the extended attribute now. NOTE: Suppose acl
+        * was NULL, then value will be NULL and size will be 0 and that
+        * will xlate to a removexattr. However, we don't want removexattr
+        * complain if attributes does not exist.
+        */
+       error = orangefs_inode_setxattr(inode, "", name, value, size, 0);
+
+out:
+       kfree(value);
+       if (!error)
+               set_cached_acl(inode, type, acl);
+       return error;
+}
+
+int orangefs_init_acl(struct inode *inode, struct inode *dir)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct posix_acl *default_acl, *acl;
+       umode_t mode = inode->i_mode;
+       int error = 0;
+
+       ClearModeFlag(orangefs_inode);
+
+       error = posix_acl_create(dir, &mode, &default_acl, &acl);
+       if (error)
+               return error;
+
+       if (default_acl) {
+               error = orangefs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+               posix_acl_release(default_acl);
+       }
+
+       if (acl) {
+               if (!error)
+                       error = orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
+               posix_acl_release(acl);
+       }
+
+       /* If mode of the inode was changed, then do a forcible ->setattr */
+       if (mode != inode->i_mode) {
+               SetModeFlag(orangefs_inode);
+               inode->i_mode = mode;
+               orangefs_flush_inode(inode);
+       }
+
+       return error;
+}
diff --git a/fs/orangefs/dcache.c b/fs/orangefs/dcache.c
new file mode 100644 (file)
index 0000000..5dfc4f3
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ *  Implementation of dentry (directory cache) functions.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+
+/* Returns 1 if dentry can still be trusted, else 0. */
+static int orangefs_revalidate_lookup(struct dentry *dentry)
+{
+       struct dentry *parent_dentry = dget_parent(dentry);
+       struct inode *parent_inode = parent_dentry->d_inode;
+       struct orangefs_inode_s *parent = ORANGEFS_I(parent_inode);
+       struct inode *inode = dentry->d_inode;
+       struct orangefs_kernel_op_s *new_op;
+       int ret = 0;
+       int err = 0;
+
+       gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
+       if (!new_op)
+               goto out_put_parent;
+
+       new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
+       new_op->upcall.req.lookup.parent_refn = parent->refn;
+       strncpy(new_op->upcall.req.lookup.d_name,
+               dentry->d_name.name,
+               ORANGEFS_NAME_MAX);
+
+       gossip_debug(GOSSIP_DCACHE_DEBUG,
+                    "%s:%s:%d interrupt flag [%d]\n",
+                    __FILE__,
+                    __func__,
+                    __LINE__,
+                    get_interruptible_flag(parent_inode));
+
+       err = service_operation(new_op, "orangefs_lookup",
+                       get_interruptible_flag(parent_inode));
+
+       /* Positive dentry: reject if error or not the same inode. */
+       if (inode) {
+               if (err) {
+                       gossip_debug(GOSSIP_DCACHE_DEBUG,
+                           "%s:%s:%d lookup failure.\n",
+                           __FILE__, __func__, __LINE__);
+                       goto out_drop;
+               }
+               if (!match_handle(new_op->downcall.resp.lookup.refn.khandle,
+                   inode)) {
+                       gossip_debug(GOSSIP_DCACHE_DEBUG,
+                           "%s:%s:%d no match.\n",
+                           __FILE__, __func__, __LINE__);
+                       goto out_drop;
+               }
+
+       /* Negative dentry: reject if success or error other than ENOENT. */
+       } else {
+               gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n",
+                   __func__);
+               if (!err || err != -ENOENT) {
+                       if (new_op->downcall.status != 0)
+                               gossip_debug(GOSSIP_DCACHE_DEBUG,
+                                   "%s:%s:%d lookup failure.\n",
+                                   __FILE__, __func__, __LINE__);
+                       goto out_drop;
+               }
+       }
+
+       ret = 1;
+out_release_op:
+       op_release(new_op);
+out_put_parent:
+       dput(parent_dentry);
+       return ret;
+out_drop:
+       gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n",
+           __FILE__, __func__, __LINE__);
+       goto out_release_op;
+}
+
+/*
+ * Verify that dentry is valid.
+ *
+ * Should return 1 if dentry can still be trusted, else 0.
+ */
+static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       int ret;
+
+       if (flags & LOOKUP_RCU)
+               return -ECHILD;
+
+       gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
+                    __func__, dentry);
+
+       /* skip root handle lookups. */
+       if (dentry->d_inode && is_root_handle(dentry->d_inode))
+               return 1;
+
+       /*
+        * If this passes, the positive dentry still exists or the negative
+        * dentry still does not exist.
+        */
+       if (!orangefs_revalidate_lookup(dentry))
+               return 0;
+
+       /* We do not need to continue with negative dentries. */
+       if (!dentry->d_inode)
+               goto out;
+
+       /* Now we must perform a getattr to validate the inode contents. */
+
+       ret = orangefs_inode_check_changed(dentry->d_inode);
+       if (ret < 0) {
+               gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",
+                   __FILE__, __func__, __LINE__);
+               return 0;
+       }
+       if (ret == 0)
+               return 0;
+
+out:
+       gossip_debug(GOSSIP_DCACHE_DEBUG,
+           "%s: negative dentry or positive dentry and inode valid.\n",
+           __func__);
+       return 1;
+}
+
+const struct dentry_operations orangefs_dentry_operations = {
+       .d_revalidate = orangefs_d_revalidate,
+};
diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c
new file mode 100644 (file)
index 0000000..db170be
--- /dev/null
@@ -0,0 +1,943 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * Changes by Acxiom Corporation to add protocol version to kernel
+ * communication, Copyright Acxiom Corporation, 2005.
+ *
+ * See COPYING in top-level directory.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-dev-proto.h"
+#include "orangefs-bufmap.h"
+
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+
+/* this file implements the /dev/pvfs2-req device node */
+
+static int open_access_count;
+
+#define DUMP_DEVICE_ERROR()                                                   \
+do {                                                                          \
+       gossip_err("*****************************************************\n");\
+       gossip_err("ORANGEFS Device Error:  You cannot open the device file ");  \
+       gossip_err("\n/dev/%s more than once.  Please make sure that\nthere " \
+                  "are no ", ORANGEFS_REQDEVICE_NAME);                          \
+       gossip_err("instances of a program using this device\ncurrently "     \
+                  "running. (You must verify this!)\n");                     \
+       gossip_err("For example, you can use the lsof program as follows:\n");\
+       gossip_err("'lsof | grep %s' (run this as root)\n",                   \
+                  ORANGEFS_REQDEVICE_NAME);                                     \
+       gossip_err("  open_access_count = %d\n", open_access_count);          \
+       gossip_err("*****************************************************\n");\
+} while (0)
+
+static int hash_func(__u64 tag, int table_size)
+{
+       return do_div(tag, (unsigned int)table_size);
+}
+
+static void orangefs_devreq_add_op(struct orangefs_kernel_op_s *op)
+{
+       int index = hash_func(op->tag, hash_table_size);
+
+       list_add_tail(&op->list, &htable_ops_in_progress[index]);
+}
+
+/*
+ * find the op with this tag and remove it from the in progress
+ * hash table.
+ */
+static struct orangefs_kernel_op_s *orangefs_devreq_remove_op(__u64 tag)
+{
+       struct orangefs_kernel_op_s *op, *next;
+       int index;
+
+       index = hash_func(tag, hash_table_size);
+
+       spin_lock(&htable_ops_in_progress_lock);
+       list_for_each_entry_safe(op,
+                                next,
+                                &htable_ops_in_progress[index],
+                                list) {
+               if (op->tag == tag && !op_state_purged(op) &&
+                   !op_state_given_up(op)) {
+                       list_del_init(&op->list);
+                       spin_unlock(&htable_ops_in_progress_lock);
+                       return op;
+               }
+       }
+
+       spin_unlock(&htable_ops_in_progress_lock);
+       return NULL;
+}
+
+/* Returns whether any FS are still pending remounted */
+static int mark_all_pending_mounts(void)
+{
+       int unmounted = 1;
+       struct orangefs_sb_info_s *orangefs_sb = NULL;
+
+       spin_lock(&orangefs_superblocks_lock);
+       list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
+               /* All of these file system require a remount */
+               orangefs_sb->mount_pending = 1;
+               unmounted = 0;
+       }
+       spin_unlock(&orangefs_superblocks_lock);
+       return unmounted;
+}
+
+/*
+ * Determine if a given file system needs to be remounted or not
+ *  Returns -1 on error
+ *           0 if already mounted
+ *           1 if needs remount
+ */
+static int fs_mount_pending(__s32 fsid)
+{
+       int mount_pending = -1;
+       struct orangefs_sb_info_s *orangefs_sb = NULL;
+
+       spin_lock(&orangefs_superblocks_lock);
+       list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
+               if (orangefs_sb->fs_id == fsid) {
+                       mount_pending = orangefs_sb->mount_pending;
+                       break;
+               }
+       }
+       spin_unlock(&orangefs_superblocks_lock);
+       return mount_pending;
+}
+
+static int orangefs_devreq_open(struct inode *inode, struct file *file)
+{
+       int ret = -EINVAL;
+
+       if (!(file->f_flags & O_NONBLOCK)) {
+               gossip_err("%s: device cannot be opened in blocking mode\n",
+                          __func__);
+               goto out;
+       }
+       ret = -EACCES;
+       gossip_debug(GOSSIP_DEV_DEBUG, "client-core: opening device\n");
+       mutex_lock(&devreq_mutex);
+
+       if (open_access_count == 0) {
+               open_access_count = 1;
+               ret = 0;
+       } else {
+               DUMP_DEVICE_ERROR();
+       }
+       mutex_unlock(&devreq_mutex);
+
+out:
+
+       gossip_debug(GOSSIP_DEV_DEBUG,
+                    "pvfs2-client-core: open device complete (ret = %d)\n",
+                    ret);
+       return ret;
+}
+
+/* Function for read() callers into the device */
+static ssize_t orangefs_devreq_read(struct file *file,
+                                char __user *buf,
+                                size_t count, loff_t *offset)
+{
+       struct orangefs_kernel_op_s *op, *temp;
+       __s32 proto_ver = ORANGEFS_KERNEL_PROTO_VERSION;
+       static __s32 magic = ORANGEFS_DEVREQ_MAGIC;
+       struct orangefs_kernel_op_s *cur_op = NULL;
+       unsigned long ret;
+
+       /* We do not support blocking IO. */
+       if (!(file->f_flags & O_NONBLOCK)) {
+               gossip_err("%s: blocking read from client-core.\n",
+                          __func__);
+               return -EINVAL;
+       }
+
+       /*
+        * The client will do an ioctl to find MAX_DEV_REQ_UPSIZE, then
+        * always read with that size buffer.
+        */
+       if (count != MAX_DEV_REQ_UPSIZE) {
+               gossip_err("orangefs: client-core tried to read wrong size\n");
+               return -EINVAL;
+       }
+
+restart:
+       /* Get next op (if any) from top of list. */
+       spin_lock(&orangefs_request_list_lock);
+       list_for_each_entry_safe(op, temp, &orangefs_request_list, list) {
+               __s32 fsid;
+               /* This lock is held past the end of the loop when we break. */
+               spin_lock(&op->lock);
+               if (unlikely(op_state_purged(op) || op_state_given_up(op))) {
+                       spin_unlock(&op->lock);
+                       continue;
+               }
+
+               fsid = fsid_of_op(op);
+               if (fsid != ORANGEFS_FS_ID_NULL) {
+                       int ret;
+                       /* Skip ops whose filesystem needs to be mounted. */
+                       ret = fs_mount_pending(fsid);
+                       if (ret == 1) {
+                               gossip_debug(GOSSIP_DEV_DEBUG,
+                                   "%s: mount pending, skipping op tag "
+                                   "%llu %s\n",
+                                   __func__,
+                                   llu(op->tag),
+                                   get_opname_string(op));
+                               spin_unlock(&op->lock);
+                               continue;
+                       /*
+                        * Skip ops whose filesystem we don't know about unless
+                        * it is being mounted.
+                        */
+                       /* XXX: is there a better way to detect this? */
+                       } else if (ret == -1 &&
+                                  !(op->upcall.type ==
+                                       ORANGEFS_VFS_OP_FS_MOUNT ||
+                                    op->upcall.type ==
+                                       ORANGEFS_VFS_OP_GETATTR)) {
+                               gossip_debug(GOSSIP_DEV_DEBUG,
+                                   "orangefs: skipping op tag %llu %s\n",
+                                   llu(op->tag), get_opname_string(op));
+                               gossip_err(
+                                   "orangefs: ERROR: fs_mount_pending %d\n",
+                                   fsid);
+                               spin_unlock(&op->lock);
+                               continue;
+                       }
+               }
+               /*
+                * Either this op does not pertain to a filesystem, is mounting
+                * a filesystem, or pertains to a mounted filesystem. Let it
+                * through.
+                */
+               cur_op = op;
+               break;
+       }
+
+       /*
+        * At this point we either have a valid op and can continue or have not
+        * found an op and must ask the client to try again later.
+        */
+       if (!cur_op) {
+               spin_unlock(&orangefs_request_list_lock);
+               return -EAGAIN;
+       }
+
+       gossip_debug(GOSSIP_DEV_DEBUG, "%s: reading op tag %llu %s\n",
+                    __func__,
+                    llu(cur_op->tag),
+                    get_opname_string(cur_op));
+
+       /*
+        * Such an op should never be on the list in the first place. If so, we
+        * will abort.
+        */
+       if (op_state_in_progress(cur_op) || op_state_serviced(cur_op)) {
+               gossip_err("orangefs: ERROR: Current op already queued.\n");
+               list_del_init(&cur_op->list);
+               spin_unlock(&cur_op->lock);
+               spin_unlock(&orangefs_request_list_lock);
+               return -EAGAIN;
+       }
+
+       list_del_init(&cur_op->list);
+       spin_unlock(&orangefs_request_list_lock);
+
+       spin_unlock(&cur_op->lock);
+
+       /* Push the upcall out. */
+       ret = copy_to_user(buf, &proto_ver, sizeof(__s32));
+       if (ret != 0)
+               goto error;
+       ret = copy_to_user(buf+sizeof(__s32), &magic, sizeof(__s32));
+       if (ret != 0)
+               goto error;
+       ret = copy_to_user(buf+2 * sizeof(__s32), &cur_op->tag, sizeof(__u64));
+       if (ret != 0)
+               goto error;
+       ret = copy_to_user(buf+2*sizeof(__s32)+sizeof(__u64), &cur_op->upcall,
+                          sizeof(struct orangefs_upcall_s));
+       if (ret != 0)
+               goto error;
+
+       spin_lock(&htable_ops_in_progress_lock);
+       spin_lock(&cur_op->lock);
+       if (unlikely(op_state_given_up(cur_op))) {
+               spin_unlock(&cur_op->lock);
+               spin_unlock(&htable_ops_in_progress_lock);
+               complete(&cur_op->waitq);
+               goto restart;
+       }
+
+       /*
+        * Set the operation to be in progress and move it between lists since
+        * it has been sent to the client.
+        */
+       set_op_state_inprogress(cur_op);
+       gossip_debug(GOSSIP_DEV_DEBUG,
+                    "%s: 1 op:%s: op_state:%d: process:%s:\n",
+                    __func__,
+                    get_opname_string(cur_op),
+                    cur_op->op_state,
+                    current->comm);
+       orangefs_devreq_add_op(cur_op);
+       spin_unlock(&cur_op->lock);
+       spin_unlock(&htable_ops_in_progress_lock);
+
+       /* The client only asks to read one size buffer. */
+       return MAX_DEV_REQ_UPSIZE;
+error:
+       /*
+        * We were unable to copy the op data to the client. Put the op back in
+        * list. If client has crashed, the op will be purged later when the
+        * device is released.
+        */
+       gossip_err("orangefs: Failed to copy data to user space\n");
+       spin_lock(&orangefs_request_list_lock);
+       spin_lock(&cur_op->lock);
+       if (likely(!op_state_given_up(cur_op))) {
+               set_op_state_waiting(cur_op);
+               gossip_debug(GOSSIP_DEV_DEBUG,
+                            "%s: 2 op:%s: op_state:%d: process:%s:\n",
+                            __func__,
+                            get_opname_string(cur_op),
+                            cur_op->op_state,
+                            current->comm);
+               list_add(&cur_op->list, &orangefs_request_list);
+               spin_unlock(&cur_op->lock);
+       } else {
+               spin_unlock(&cur_op->lock);
+               complete(&cur_op->waitq);
+       }
+       spin_unlock(&orangefs_request_list_lock);
+       return -EFAULT;
+}
+
+/*
+ * Function for writev() callers into the device.
+ *
+ * Userspace should have written:
+ *  - __u32 version
+ *  - __u32 magic
+ *  - __u64 tag
+ *  - struct orangefs_downcall_s
+ *  - trailer buffer (in the case of READDIR operations)
+ */
+static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb,
+                                     struct iov_iter *iter)
+{
+       ssize_t ret;
+       struct orangefs_kernel_op_s *op = NULL;
+       struct {
+               __u32 version;
+               __u32 magic;
+               __u64 tag;
+       } head;
+       int total = ret = iov_iter_count(iter);
+       int n;
+       int downcall_size = sizeof(struct orangefs_downcall_s);
+       int head_size = sizeof(head);
+
+       gossip_debug(GOSSIP_DEV_DEBUG, "%s: total:%d: ret:%zd:\n",
+                    __func__,
+                    total,
+                    ret);
+
+        if (total < MAX_DEV_REQ_DOWNSIZE) {
+               gossip_err("%s: total:%d: must be at least:%u:\n",
+                          __func__,
+                          total,
+                          (unsigned int) MAX_DEV_REQ_DOWNSIZE);
+               return -EFAULT;
+       }
+     
+       n = copy_from_iter(&head, head_size, iter);
+       if (n < head_size) {
+               gossip_err("%s: failed to copy head.\n", __func__);
+               return -EFAULT;
+       }
+
+       if (head.version < ORANGEFS_MINIMUM_USERSPACE_VERSION) {
+               gossip_err("%s: userspace claims version"
+                          "%d, minimum version required: %d.\n",
+                          __func__,
+                          head.version,
+                          ORANGEFS_MINIMUM_USERSPACE_VERSION);
+               return -EPROTO;
+       }
+
+       if (head.magic != ORANGEFS_DEVREQ_MAGIC) {
+               gossip_err("Error: Device magic number does not match.\n");
+               return -EPROTO;
+       }
+
+       /* remove the op from the in progress hash table */
+       op = orangefs_devreq_remove_op(head.tag);
+       if (!op) {
+               gossip_err("WARNING: No one's waiting for tag %llu\n",
+                          llu(head.tag));
+               return ret;
+       }
+
+       n = copy_from_iter(&op->downcall, downcall_size, iter);
+       if (n != downcall_size) {
+               gossip_err("%s: failed to copy downcall.\n", __func__);
+               goto Efault;
+       }
+
+       if (op->downcall.status)
+               goto wakeup;
+
+       /*
+        * We've successfully peeled off the head and the downcall. 
+        * Something has gone awry if total doesn't equal the
+        * sum of head_size, downcall_size and trailer_size.
+        */
+       if ((head_size + downcall_size + op->downcall.trailer_size) != total) {
+               gossip_err("%s: funky write, head_size:%d"
+                          ": downcall_size:%d: trailer_size:%lld"
+                          ": total size:%d:\n",
+                          __func__,
+                          head_size,
+                          downcall_size,
+                          op->downcall.trailer_size,
+                          total);
+               goto Efault;
+       }
+
+       /* Only READDIR operations should have trailers. */
+       if ((op->downcall.type != ORANGEFS_VFS_OP_READDIR) &&
+           (op->downcall.trailer_size != 0)) {
+               gossip_err("%s: %x operation with trailer.",
+                          __func__,
+                          op->downcall.type);
+               goto Efault;
+       }
+
+       /* READDIR operations should always have trailers. */
+       if ((op->downcall.type == ORANGEFS_VFS_OP_READDIR) &&
+           (op->downcall.trailer_size == 0)) {
+               gossip_err("%s: %x operation with no trailer.",
+                          __func__,
+                          op->downcall.type);
+               goto Efault;
+       }
+
+       if (op->downcall.type != ORANGEFS_VFS_OP_READDIR)
+               goto wakeup;
+
+       op->downcall.trailer_buf =
+               vmalloc(op->downcall.trailer_size);
+       if (op->downcall.trailer_buf == NULL) {
+               gossip_err("%s: failed trailer vmalloc.\n",
+                          __func__);
+               goto Enomem;
+       }
+       memset(op->downcall.trailer_buf, 0, op->downcall.trailer_size);
+       n = copy_from_iter(op->downcall.trailer_buf,
+                          op->downcall.trailer_size,
+                          iter);
+       if (n != op->downcall.trailer_size) {
+               gossip_err("%s: failed to copy trailer.\n", __func__);
+               vfree(op->downcall.trailer_buf);
+               goto Efault;
+       }
+
+wakeup:
+       /*
+        * Return to vfs waitqueue, and back to service_operation
+        * through wait_for_matching_downcall. 
+        */
+       spin_lock(&op->lock);
+       if (unlikely(op_is_cancel(op))) {
+               spin_unlock(&op->lock);
+               put_cancel(op);
+       } else if (unlikely(op_state_given_up(op))) {
+               spin_unlock(&op->lock);
+               complete(&op->waitq);
+       } else {
+               set_op_state_serviced(op);
+               gossip_debug(GOSSIP_DEV_DEBUG,
+                            "%s: op:%s: op_state:%d: process:%s:\n",
+                            __func__,
+                            get_opname_string(op),
+                            op->op_state,
+                            current->comm);
+               spin_unlock(&op->lock);
+       }
+       return ret;
+
+Efault:
+       op->downcall.status = -(ORANGEFS_ERROR_BIT | 9);
+       ret = -EFAULT;
+       goto wakeup;
+
+Enomem:
+       op->downcall.status = -(ORANGEFS_ERROR_BIT | 8);
+       ret = -ENOMEM;
+       goto wakeup;
+}
+
+/*
+ * NOTE: gets called when the last reference to this device is dropped.
+ * Using the open_access_count variable, we enforce a reference count
+ * on this file so that it can be opened by only one process at a time.
+ * the devreq_mutex is used to make sure all i/o has completed
+ * before we call orangefs_bufmap_finalize, and similar such tricky
+ * situations
+ */
+static int orangefs_devreq_release(struct inode *inode, struct file *file)
+{
+       int unmounted = 0;
+
+       gossip_debug(GOSSIP_DEV_DEBUG,
+                    "%s:pvfs2-client-core: exiting, closing device\n",
+                    __func__);
+
+       mutex_lock(&devreq_mutex);
+       orangefs_bufmap_finalize();
+
+       open_access_count = -1;
+
+       unmounted = mark_all_pending_mounts();
+       gossip_debug(GOSSIP_DEV_DEBUG, "ORANGEFS Device Close: Filesystem(s) %s\n",
+                    (unmounted ? "UNMOUNTED" : "MOUNTED"));
+
+       purge_waiting_ops();
+       purge_inprogress_ops();
+
+       orangefs_bufmap_run_down();
+
+       gossip_debug(GOSSIP_DEV_DEBUG,
+                    "pvfs2-client-core: device close complete\n");
+       open_access_count = 0;
+       mutex_unlock(&devreq_mutex);
+       return 0;
+}
+
+int is_daemon_in_service(void)
+{
+       int in_service;
+
+       /*
+        * What this function does is checks if client-core is alive
+        * based on the access count we maintain on the device.
+        */
+       mutex_lock(&devreq_mutex);
+       in_service = open_access_count == 1 ? 0 : -EIO;
+       mutex_unlock(&devreq_mutex);
+       return in_service;
+}
+
+bool __is_daemon_in_service(void)
+{
+       return open_access_count == 1;
+}
+
+static inline long check_ioctl_command(unsigned int command)
+{
+       /* Check for valid ioctl codes */
+       if (_IOC_TYPE(command) != ORANGEFS_DEV_MAGIC) {
+               gossip_err("device ioctl magic numbers don't match! Did you rebuild pvfs2-client-core/libpvfs2? [cmd %x, magic %x != %x]\n",
+                       command,
+                       _IOC_TYPE(command),
+                       ORANGEFS_DEV_MAGIC);
+               return -EINVAL;
+       }
+       /* and valid ioctl commands */
+       if (_IOC_NR(command) >= ORANGEFS_DEV_MAXNR || _IOC_NR(command) <= 0) {
+               gossip_err("Invalid ioctl command number [%d >= %d]\n",
+                          _IOC_NR(command), ORANGEFS_DEV_MAXNR);
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static long dispatch_ioctl_command(unsigned int command, unsigned long arg)
+{
+       static __s32 magic = ORANGEFS_DEVREQ_MAGIC;
+       static __s32 max_up_size = MAX_DEV_REQ_UPSIZE;
+       static __s32 max_down_size = MAX_DEV_REQ_DOWNSIZE;
+       struct ORANGEFS_dev_map_desc user_desc;
+       int ret = 0;
+       struct dev_mask_info_s mask_info = { 0 };
+       struct dev_mask2_info_s mask2_info = { 0, 0 };
+       int upstream_kmod = 1;
+       struct orangefs_sb_info_s *orangefs_sb;
+
+       /* mtmoore: add locking here */
+
+       switch (command) {
+       case ORANGEFS_DEV_GET_MAGIC:
+               return ((put_user(magic, (__s32 __user *) arg) == -EFAULT) ?
+                       -EIO :
+                       0);
+       case ORANGEFS_DEV_GET_MAX_UPSIZE:
+               return ((put_user(max_up_size,
+                                 (__s32 __user *) arg) == -EFAULT) ?
+                                       -EIO :
+                                       0);
+       case ORANGEFS_DEV_GET_MAX_DOWNSIZE:
+               return ((put_user(max_down_size,
+                                 (__s32 __user *) arg) == -EFAULT) ?
+                                       -EIO :
+                                       0);
+       case ORANGEFS_DEV_MAP:
+               ret = copy_from_user(&user_desc,
+                                    (struct ORANGEFS_dev_map_desc __user *)
+                                    arg,
+                                    sizeof(struct ORANGEFS_dev_map_desc));
+               /* WTF -EIO and not -EFAULT? */
+               return ret ? -EIO : orangefs_bufmap_initialize(&user_desc);
+       case ORANGEFS_DEV_REMOUNT_ALL:
+               gossip_debug(GOSSIP_DEV_DEBUG,
+                            "%s: got ORANGEFS_DEV_REMOUNT_ALL\n",
+                            __func__);
+
+               /*
+                * remount all mounted orangefs volumes to regain the lost
+                * dynamic mount tables (if any) -- NOTE: this is done
+                * without keeping the superblock list locked due to the
+                * upcall/downcall waiting.  also, the request mutex is
+                * used to ensure that no operations will be serviced until
+                * all of the remounts are serviced (to avoid ops between
+                * mounts to fail)
+                */
+               ret = mutex_lock_interruptible(&request_mutex);
+               if (ret < 0)
+                       return ret;
+               gossip_debug(GOSSIP_DEV_DEBUG,
+                            "%s: priority remount in progress\n",
+                            __func__);
+               spin_lock(&orangefs_superblocks_lock);
+               list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
+                       /*
+                        * We have to drop the spinlock, so entries can be
+                        * removed.  They can't be freed, though, so we just
+                        * keep the forward pointers and zero the back ones -
+                        * that way we can get to the rest of the list.
+                        */
+                       if (!orangefs_sb->list.prev)
+                               continue;
+                       gossip_debug(GOSSIP_DEV_DEBUG,
+                                    "%s: Remounting SB %p\n",
+                                    __func__,
+                                    orangefs_sb);
+
+                       spin_unlock(&orangefs_superblocks_lock);
+                       ret = orangefs_remount(orangefs_sb);
+                       spin_lock(&orangefs_superblocks_lock);
+                       if (ret) {
+                               gossip_debug(GOSSIP_DEV_DEBUG,
+                                            "SB %p remount failed\n",
+                                            orangefs_sb);
+                               break;
+                       }
+               }
+               spin_unlock(&orangefs_superblocks_lock);
+               gossip_debug(GOSSIP_DEV_DEBUG,
+                            "%s: priority remount complete\n",
+                            __func__);
+               mutex_unlock(&request_mutex);
+               return ret;
+
+       case ORANGEFS_DEV_UPSTREAM:
+               ret = copy_to_user((void __user *)arg,
+                                   &upstream_kmod,
+                                   sizeof(upstream_kmod));
+
+               if (ret != 0)
+                       return -EIO;
+               else
+                       return ret;
+
+       case ORANGEFS_DEV_CLIENT_MASK:
+               ret = copy_from_user(&mask2_info,
+                                    (void __user *)arg,
+                                    sizeof(struct dev_mask2_info_s));
+
+               if (ret != 0)
+                       return -EIO;
+
+               client_debug_mask.mask1 = mask2_info.mask1_value;
+               client_debug_mask.mask2 = mask2_info.mask2_value;
+
+               pr_info("%s: client debug mask has been been received "
+                       ":%llx: :%llx:\n",
+                       __func__,
+                       (unsigned long long)client_debug_mask.mask1,
+                       (unsigned long long)client_debug_mask.mask2);
+
+               return ret;
+
+       case ORANGEFS_DEV_CLIENT_STRING:
+               ret = copy_from_user(&client_debug_array_string,
+                                    (void __user *)arg,
+                                    ORANGEFS_MAX_DEBUG_STRING_LEN);
+               /*
+                * The real client-core makes an effort to ensure
+                * that actual strings that aren't too long to fit in
+                * this buffer is what we get here. We're going to use
+                * string functions on the stuff we got, so we'll make
+                * this extra effort to try and keep from
+                * flowing out of this buffer when we use the string
+                * functions, even if somehow the stuff we end up
+                * with here is garbage.
+                */
+               client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN - 1] =
+                       '\0';
+               
+               if (ret != 0) {
+                       pr_info("%s: CLIENT_STRING: copy_from_user failed\n",
+                               __func__);
+                       return -EIO;
+               }
+
+               pr_info("%s: client debug array string has been received.\n",
+                       __func__);
+
+               if (!help_string_initialized) {
+
+                       /* Free the "we don't know yet" default string... */
+                       kfree(debug_help_string);
+
+                       /* build a proper debug help string */
+                       if (orangefs_prepare_debugfs_help_string(0)) {
+                               gossip_err("%s: no debug help string \n",
+                                          __func__);
+                               return -EIO;
+                       }
+
+                       /* Replace the boilerplate boot-time debug-help file. */
+                       debugfs_remove(help_file_dentry);
+
+                       help_file_dentry =
+                               debugfs_create_file(
+                                       ORANGEFS_KMOD_DEBUG_HELP_FILE,
+                                       0444,
+                                       debug_dir,
+                                       debug_help_string,
+                                       &debug_help_fops);
+
+                       if (!help_file_dentry) {
+                               gossip_err("%s: debugfs_create_file failed for"
+                                          " :%s:!\n",
+                                          __func__,
+                                          ORANGEFS_KMOD_DEBUG_HELP_FILE);
+                               return -EIO;
+                       }
+               }
+
+               debug_mask_to_string(&client_debug_mask, 1);
+
+               debugfs_remove(client_debug_dentry);
+
+               orangefs_client_debug_init();
+
+               help_string_initialized++;
+
+               return ret;
+
+       case ORANGEFS_DEV_DEBUG:
+               ret = copy_from_user(&mask_info,
+                                    (void __user *)arg,
+                                    sizeof(mask_info));
+
+               if (ret != 0)
+                       return -EIO;
+
+               if (mask_info.mask_type == KERNEL_MASK) {
+                       if ((mask_info.mask_value == 0)
+                           && (kernel_mask_set_mod_init)) {
+                               /*
+                                * the kernel debug mask was set when the
+                                * kernel module was loaded; don't override
+                                * it if the client-core was started without
+                                * a value for ORANGEFS_KMODMASK.
+                                */
+                               return 0;
+                       }
+                       debug_mask_to_string(&mask_info.mask_value,
+                                            mask_info.mask_type);
+                       gossip_debug_mask = mask_info.mask_value;
+                       pr_info("%s: kernel debug mask has been modified to "
+                               ":%s: :%llx:\n",
+                               __func__,
+                               kernel_debug_string,
+                               (unsigned long long)gossip_debug_mask);
+               } else if (mask_info.mask_type == CLIENT_MASK) {
+                       debug_mask_to_string(&mask_info.mask_value,
+                                            mask_info.mask_type);
+                       pr_info("%s: client debug mask has been modified to"
+                               ":%s: :%llx:\n",
+                               __func__,
+                               client_debug_string,
+                               llu(mask_info.mask_value));
+               } else {
+                       gossip_lerr("Invalid mask type....\n");
+                       return -EINVAL;
+               }
+
+               return ret;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return -ENOIOCTLCMD;
+}
+
+static long orangefs_devreq_ioctl(struct file *file,
+                              unsigned int command, unsigned long arg)
+{
+       long ret;
+
+       /* Check for properly constructed commands */
+       ret = check_ioctl_command(command);
+       if (ret < 0)
+               return (int)ret;
+
+       return (int)dispatch_ioctl_command(command, arg);
+}
+
+#ifdef CONFIG_COMPAT           /* CONFIG_COMPAT is in .config */
+
+/*  Compat structure for the ORANGEFS_DEV_MAP ioctl */
+struct ORANGEFS_dev_map_desc32 {
+       compat_uptr_t ptr;
+       __s32 total_size;
+       __s32 size;
+       __s32 count;
+};
+
+static unsigned long translate_dev_map26(unsigned long args, long *error)
+{
+       struct ORANGEFS_dev_map_desc32 __user *p32 = (void __user *)args;
+       /*
+        * Depending on the architecture, allocate some space on the
+        * user-call-stack based on our expected layout.
+        */
+       struct ORANGEFS_dev_map_desc __user *p =
+           compat_alloc_user_space(sizeof(*p));
+       compat_uptr_t addr;
+
+       *error = 0;
+       /* get the ptr from the 32 bit user-space */
+       if (get_user(addr, &p32->ptr))
+               goto err;
+       /* try to put that into a 64-bit layout */
+       if (put_user(compat_ptr(addr), &p->ptr))
+               goto err;
+       /* copy the remaining fields */
+       if (copy_in_user(&p->total_size, &p32->total_size, sizeof(__s32)))
+               goto err;
+       if (copy_in_user(&p->size, &p32->size, sizeof(__s32)))
+               goto err;
+       if (copy_in_user(&p->count, &p32->count, sizeof(__s32)))
+               goto err;
+       return (unsigned long)p;
+err:
+       *error = -EFAULT;
+       return 0;
+}
+
+/*
+ * 32 bit user-space apps' ioctl handlers when kernel modules
+ * is compiled as a 64 bit one
+ */
+static long orangefs_devreq_compat_ioctl(struct file *filp, unsigned int cmd,
+                                     unsigned long args)
+{
+       long ret;
+       unsigned long arg = args;
+
+       /* Check for properly constructed commands */
+       ret = check_ioctl_command(cmd);
+       if (ret < 0)
+               return ret;
+       if (cmd == ORANGEFS_DEV_MAP) {
+               /*
+                * convert the arguments to what we expect internally
+                * in kernel space
+                */
+               arg = translate_dev_map26(args, &ret);
+               if (ret < 0) {
+                       gossip_err("Could not translate dev map\n");
+                       return ret;
+               }
+       }
+       /* no other ioctl requires translation */
+       return dispatch_ioctl_command(cmd, arg);
+}
+
+#endif /* CONFIG_COMPAT is in .config */
+
+/* the assigned character device major number */
+static int orangefs_dev_major;
+
+/*
+ * Initialize orangefs device specific state:
+ * Must be called at module load time only
+ */
+int orangefs_dev_init(void)
+{
+       /* register orangefs-req device  */
+       orangefs_dev_major = register_chrdev(0,
+                                         ORANGEFS_REQDEVICE_NAME,
+                                         &orangefs_devreq_file_operations);
+       if (orangefs_dev_major < 0) {
+               gossip_debug(GOSSIP_DEV_DEBUG,
+                            "Failed to register /dev/%s (error %d)\n",
+                            ORANGEFS_REQDEVICE_NAME, orangefs_dev_major);
+               return orangefs_dev_major;
+       }
+
+       gossip_debug(GOSSIP_DEV_DEBUG,
+                    "*** /dev/%s character device registered ***\n",
+                    ORANGEFS_REQDEVICE_NAME);
+       gossip_debug(GOSSIP_DEV_DEBUG, "'mknod /dev/%s c %d 0'.\n",
+                    ORANGEFS_REQDEVICE_NAME, orangefs_dev_major);
+       return 0;
+}
+
+void orangefs_dev_cleanup(void)
+{
+       unregister_chrdev(orangefs_dev_major, ORANGEFS_REQDEVICE_NAME);
+       gossip_debug(GOSSIP_DEV_DEBUG,
+                    "*** /dev/%s character device unregistered ***\n",
+                    ORANGEFS_REQDEVICE_NAME);
+}
+
+static unsigned int orangefs_devreq_poll(struct file *file,
+                                     struct poll_table_struct *poll_table)
+{
+       int poll_revent_mask = 0;
+
+       poll_wait(file, &orangefs_request_list_waitq, poll_table);
+
+       if (!list_empty(&orangefs_request_list))
+               poll_revent_mask |= POLL_IN;
+       return poll_revent_mask;
+}
+
+const struct file_operations orangefs_devreq_file_operations = {
+       .owner = THIS_MODULE,
+       .read = orangefs_devreq_read,
+       .write_iter = orangefs_devreq_write_iter,
+       .open = orangefs_devreq_open,
+       .release = orangefs_devreq_release,
+       .unlocked_ioctl = orangefs_devreq_ioctl,
+
+#ifdef CONFIG_COMPAT           /* CONFIG_COMPAT is in .config */
+       .compat_ioctl = orangefs_devreq_compat_ioctl,
+#endif
+       .poll = orangefs_devreq_poll
+};
diff --git a/fs/orangefs/dir.c b/fs/orangefs/dir.c
new file mode 100644 (file)
index 0000000..ba7dec4
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+
+/*
+ * decode routine used by kmod to deal with the blob sent from
+ * userspace for readdirs. The blob contains zero or more of these
+ * sub-blobs:
+ *   __u32 - represents length of the character string that follows.
+ *   string - between 1 and ORANGEFS_NAME_MAX bytes long.
+ *   padding - (if needed) to cause the __u32 plus the string to be
+ *             eight byte aligned.
+ *   khandle - sizeof(khandle) bytes.
+ */
+static long decode_dirents(char *ptr, size_t size,
+                           struct orangefs_readdir_response_s *readdir)
+{
+       int i;
+       struct orangefs_readdir_response_s *rd =
+               (struct orangefs_readdir_response_s *) ptr;
+       char *buf = ptr;
+       int khandle_size = sizeof(struct orangefs_khandle);
+       size_t offset = offsetof(struct orangefs_readdir_response_s,
+                               dirent_array);
+       /* 8 reflects eight byte alignment */
+       int smallest_blob = khandle_size + 8;
+       __u32 len;
+       int aligned_len;
+       int sizeof_u32 = sizeof(__u32);
+       long ret;
+
+       gossip_debug(GOSSIP_DIR_DEBUG, "%s: size:%zu:\n", __func__, size);
+
+       /* size is = offset on empty dirs, > offset on non-empty dirs... */
+       if (size < offset) {
+               gossip_err("%s: size:%zu: offset:%zu:\n",
+                          __func__,
+                          size,
+                          offset);
+               ret = -EINVAL;
+               goto out;
+       }
+
+        if ((size == offset) && (readdir->orangefs_dirent_outcount != 0)) {
+               gossip_err("%s: size:%zu: dirent_outcount:%d:\n",
+                          __func__,
+                          size,
+                          readdir->orangefs_dirent_outcount);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       readdir->token = rd->token;
+       readdir->orangefs_dirent_outcount = rd->orangefs_dirent_outcount;
+       readdir->dirent_array = kcalloc(readdir->orangefs_dirent_outcount,
+                                       sizeof(*readdir->dirent_array),
+                                       GFP_KERNEL);
+       if (readdir->dirent_array == NULL) {
+               gossip_err("%s: kcalloc failed.\n", __func__);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       buf += offset;
+       size -= offset;
+
+       for (i = 0; i < readdir->orangefs_dirent_outcount; i++) {
+               if (size < smallest_blob) {
+                       gossip_err("%s: size:%zu: smallest_blob:%d:\n",
+                                  __func__,
+                                  size,
+                                  smallest_blob);
+                       ret = -EINVAL;
+                       goto free;
+               }
+
+               len = *(__u32 *)buf;
+               if ((len < 1) || (len > ORANGEFS_NAME_MAX)) {
+                       gossip_err("%s: len:%d:\n", __func__, len);
+                       ret = -EINVAL;
+                       goto free;
+               }
+
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                            "%s: size:%zu: len:%d:\n",
+                            __func__,
+                            size,
+                            len);
+
+               readdir->dirent_array[i].d_name = buf + sizeof_u32;
+               readdir->dirent_array[i].d_length = len;
+
+               /*
+                * Calculate "aligned" length of this string and its
+                * associated __u32 descriptor.
+                */
+               aligned_len = ((sizeof_u32 + len + 1) + 7) & ~7;
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                            "%s: aligned_len:%d:\n",
+                            __func__,
+                            aligned_len);
+
+               /*
+                * The end of the blob should coincide with the end
+                * of the last sub-blob.
+                */
+               if (size < aligned_len + khandle_size) {
+                       gossip_err("%s: ran off the end of the blob.\n",
+                                  __func__);
+                       ret = -EINVAL;
+                       goto free;
+               }
+               size -= aligned_len + khandle_size;
+
+               buf += aligned_len;
+
+               readdir->dirent_array[i].khandle =
+                       *(struct orangefs_khandle *) buf;
+               buf += khandle_size;
+       }
+       ret = buf - ptr;
+       gossip_debug(GOSSIP_DIR_DEBUG, "%s: returning:%ld:\n", __func__, ret);
+       goto out;
+
+free:
+       kfree(readdir->dirent_array);
+       readdir->dirent_array = NULL;
+
+out:
+       return ret;
+}
+
+/*
+ * Read directory entries from an instance of an open directory.
+ */
+static int orangefs_readdir(struct file *file, struct dir_context *ctx)
+{
+       int ret = 0;
+       int buffer_index;
+       /*
+        * ptoken supports Orangefs' distributed directory logic, added
+        * in 2.9.2.
+        */
+       __u64 *ptoken = file->private_data;
+       __u64 pos = 0;
+       ino_t ino = 0;
+       struct dentry *dentry = file->f_path.dentry;
+       struct orangefs_kernel_op_s *new_op = NULL;
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode);
+       int buffer_full = 0;
+       struct orangefs_readdir_response_s readdir_response;
+       void *dents_buf;
+       int i = 0;
+       int len = 0;
+       ino_t current_ino = 0;
+       char *current_entry = NULL;
+       long bytes_decoded;
+
+       gossip_debug(GOSSIP_DIR_DEBUG,
+                    "%s: ctx->pos:%lld, ptoken = %llu\n",
+                    __func__,
+                    lld(ctx->pos),
+                    llu(*ptoken));
+
+       pos = (__u64) ctx->pos;
+
+       /* are we done? */
+       if (pos == ORANGEFS_READDIR_END) {
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                            "Skipping to termination path\n");
+               return 0;
+       }
+
+       gossip_debug(GOSSIP_DIR_DEBUG,
+                    "orangefs_readdir called on %s (pos=%llu)\n",
+                    dentry->d_name.name, llu(pos));
+
+       memset(&readdir_response, 0, sizeof(readdir_response));
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_READDIR);
+       if (!new_op)
+               return -ENOMEM;
+
+       /*
+        * Only the indices are shared. No memory is actually shared, but the
+        * mechanism is used.
+        */
+       new_op->uses_shared_memory = 1;
+       new_op->upcall.req.readdir.refn = orangefs_inode->refn;
+       new_op->upcall.req.readdir.max_dirent_count =
+           ORANGEFS_MAX_DIRENT_COUNT_READDIR;
+
+       gossip_debug(GOSSIP_DIR_DEBUG,
+                    "%s: upcall.req.readdir.refn.khandle: %pU\n",
+                    __func__,
+                    &new_op->upcall.req.readdir.refn.khandle);
+
+       new_op->upcall.req.readdir.token = *ptoken;
+
+get_new_buffer_index:
+       buffer_index = orangefs_readdir_index_get();
+       if (buffer_index < 0) {
+               ret = buffer_index;
+               gossip_lerr("orangefs_readdir: orangefs_readdir_index_get() failure (%d)\n",
+                           ret);
+               goto out_free_op;
+       }
+       new_op->upcall.req.readdir.buf_index = buffer_index;
+
+       ret = service_operation(new_op,
+                               "orangefs_readdir",
+                               get_interruptible_flag(dentry->d_inode));
+
+       gossip_debug(GOSSIP_DIR_DEBUG,
+                    "Readdir downcall status is %d.  ret:%d\n",
+                    new_op->downcall.status,
+                    ret);
+
+       orangefs_readdir_index_put(buffer_index);
+
+       if (ret == -EAGAIN && op_state_purged(new_op)) {
+               /* Client-core indices are invalid after it restarted. */
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                       "%s: Getting new buffer_index for retry of readdir..\n",
+                        __func__);
+               goto get_new_buffer_index;
+       }
+
+       if (ret == -EIO && op_state_purged(new_op)) {
+               gossip_err("%s: Client is down. Aborting readdir call.\n",
+                       __func__);
+               goto out_free_op;
+       }
+
+       if (ret < 0 || new_op->downcall.status != 0) {
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                            "Readdir request failed.  Status:%d\n",
+                            new_op->downcall.status);
+               if (ret >= 0)
+                       ret = new_op->downcall.status;
+               goto out_free_op;
+       }
+
+       dents_buf = new_op->downcall.trailer_buf;
+       if (dents_buf == NULL) {
+               gossip_err("Invalid NULL buffer in readdir response\n");
+               ret = -ENOMEM;
+               goto out_free_op;
+       }
+
+       bytes_decoded = decode_dirents(dents_buf, new_op->downcall.trailer_size,
+                                       &readdir_response);
+       if (bytes_decoded < 0) {
+               ret = bytes_decoded;
+               gossip_err("Could not decode readdir from buffer %d\n", ret);
+               goto out_vfree;
+       }
+
+       if (bytes_decoded != new_op->downcall.trailer_size) {
+               gossip_err("orangefs_readdir: # bytes decoded (%ld) "
+                          "!= trailer size (%ld)\n",
+                          bytes_decoded,
+                          (long)new_op->downcall.trailer_size);
+               ret = -EINVAL;
+               goto out_destroy_handle;
+       }
+
+       /*
+        *  orangefs doesn't actually store dot and dot-dot, but
+        *  we need to have them represented.
+        */
+       if (pos == 0) {
+               ino = get_ino_from_khandle(dentry->d_inode);
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                            "%s: calling dir_emit of \".\" with pos = %llu\n",
+                            __func__,
+                            llu(pos));
+               ret = dir_emit(ctx, ".", 1, ino, DT_DIR);
+               pos += 1;
+       }
+
+       if (pos == 1) {
+               ino = get_parent_ino_from_dentry(dentry);
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                            "%s: calling dir_emit of \"..\" with pos = %llu\n",
+                            __func__,
+                            llu(pos));
+               ret = dir_emit(ctx, "..", 2, ino, DT_DIR);
+               pos += 1;
+       }
+
+       /*
+        * we stored ORANGEFS_ITERATE_NEXT in ctx->pos last time around
+        * to prevent "finding" dot and dot-dot on any iteration
+        * other than the first.
+        */
+       if (ctx->pos == ORANGEFS_ITERATE_NEXT)
+               ctx->pos = 0;
+
+       gossip_debug(GOSSIP_DIR_DEBUG,
+                    "%s: dirent_outcount:%d:\n",
+                    __func__,
+                    readdir_response.orangefs_dirent_outcount);
+       for (i = ctx->pos;
+            i < readdir_response.orangefs_dirent_outcount;
+            i++) {
+               len = readdir_response.dirent_array[i].d_length;
+               current_entry = readdir_response.dirent_array[i].d_name;
+               current_ino = orangefs_khandle_to_ino(
+                       &readdir_response.dirent_array[i].khandle);
+
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                            "calling dir_emit for %s with len %d"
+                            ", ctx->pos %ld\n",
+                            current_entry,
+                            len,
+                            (unsigned long)ctx->pos);
+               /*
+                * type is unknown. We don't return object type
+                * in the dirent_array. This leaves getdents
+                * clueless about type.
+                */
+               ret =
+                   dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN);
+               if (!ret)
+                       break;
+               ctx->pos++;
+               gossip_debug(GOSSIP_DIR_DEBUG,
+                             "%s: ctx->pos:%lld\n",
+                             __func__,
+                             lld(ctx->pos));
+
+       }
+
+       /*
+        * we ran all the way through the last batch, set up for
+        * getting another batch...
+        */
+       if (ret) {
+               *ptoken = readdir_response.token;
+               ctx->pos = ORANGEFS_ITERATE_NEXT;
+       }
+
+       /*
+        * Did we hit the end of the directory?
+        */
+       if (readdir_response.token == ORANGEFS_READDIR_END &&
+           !buffer_full) {
+               gossip_debug(GOSSIP_DIR_DEBUG,
+               "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
+               ctx->pos = ORANGEFS_READDIR_END;
+       }
+
+out_destroy_handle:
+       /* kfree(NULL) is safe */
+       kfree(readdir_response.dirent_array);
+out_vfree:
+       gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", dents_buf);
+       vfree(dents_buf);
+out_free_op:
+       op_release(new_op);
+       gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret);
+       return ret;
+}
+
+static int orangefs_dir_open(struct inode *inode, struct file *file)
+{
+       __u64 *ptoken;
+
+       file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL);
+       if (!file->private_data)
+               return -ENOMEM;
+
+       ptoken = file->private_data;
+       *ptoken = ORANGEFS_READDIR_START;
+       return 0;
+}
+
+static int orangefs_dir_release(struct inode *inode, struct file *file)
+{
+       orangefs_flush_inode(inode);
+       kfree(file->private_data);
+       return 0;
+}
+
+/** ORANGEFS implementation of VFS directory operations */
+const struct file_operations orangefs_dir_operations = {
+       .read = generic_read_dir,
+       .iterate = orangefs_readdir,
+       .open = orangefs_dir_open,
+       .release = orangefs_dir_release,
+};
diff --git a/fs/orangefs/downcall.h b/fs/orangefs/downcall.h
new file mode 100644 (file)
index 0000000..66b9921
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ *  Definitions of downcalls used in Linux kernel module.
+ */
+
+#ifndef __DOWNCALL_H
+#define __DOWNCALL_H
+
+/*
+ * Sanitized the device-client core interaction
+ * for clean 32-64 bit usage
+ */
+struct orangefs_io_response {
+       __s64 amt_complete;
+};
+
+struct orangefs_lookup_response {
+       struct orangefs_object_kref refn;
+};
+
+struct orangefs_create_response {
+       struct orangefs_object_kref refn;
+};
+
+struct orangefs_symlink_response {
+       struct orangefs_object_kref refn;
+};
+
+struct orangefs_getattr_response {
+       struct ORANGEFS_sys_attr_s attributes;
+       char link_target[ORANGEFS_NAME_MAX];
+};
+
+struct orangefs_mkdir_response {
+       struct orangefs_object_kref refn;
+};
+
+/*
+ * duplication of some system interface structures so that I don't have
+ * to allocate extra memory
+ */
+struct orangefs_dirent {
+       char *d_name;
+       int d_length;
+       struct orangefs_khandle khandle;
+};
+
+struct orangefs_statfs_response {
+       __s64 block_size;
+       __s64 blocks_total;
+       __s64 blocks_avail;
+       __s64 files_total;
+       __s64 files_avail;
+};
+
+struct orangefs_fs_mount_response {
+       __s32 fs_id;
+       __s32 id;
+       struct orangefs_khandle root_khandle;
+};
+
+/* the getxattr response is the attribute value */
+struct orangefs_getxattr_response {
+       __s32 val_sz;
+       __s32 __pad1;
+       char val[ORANGEFS_MAX_XATTR_VALUELEN];
+};
+
+/* the listxattr response is an array of attribute names */
+struct orangefs_listxattr_response {
+       __s32 returned_count;
+       __s32 __pad1;
+       __u64 token;
+       char key[ORANGEFS_MAX_XATTR_LISTLEN * ORANGEFS_MAX_XATTR_NAMELEN];
+       __s32 keylen;
+       __s32 __pad2;
+       __s32 lengths[ORANGEFS_MAX_XATTR_LISTLEN];
+};
+
+struct orangefs_param_response {
+       __s64 value;
+};
+
+#define PERF_COUNT_BUF_SIZE 4096
+struct orangefs_perf_count_response {
+       char buffer[PERF_COUNT_BUF_SIZE];
+};
+
+#define FS_KEY_BUF_SIZE 4096
+struct orangefs_fs_key_response {
+       __s32 fs_keylen;
+       __s32 __pad1;
+       char fs_key[FS_KEY_BUF_SIZE];
+};
+
+struct orangefs_downcall_s {
+       __s32 type;
+       __s32 status;
+       /* currently trailer is used only by readdir */
+       __s64 trailer_size;
+       char *trailer_buf;
+
+       union {
+               struct orangefs_io_response io;
+               struct orangefs_lookup_response lookup;
+               struct orangefs_create_response create;
+               struct orangefs_symlink_response sym;
+               struct orangefs_getattr_response getattr;
+               struct orangefs_mkdir_response mkdir;
+               struct orangefs_statfs_response statfs;
+               struct orangefs_fs_mount_response fs_mount;
+               struct orangefs_getxattr_response getxattr;
+               struct orangefs_listxattr_response listxattr;
+               struct orangefs_param_response param;
+               struct orangefs_perf_count_response perf_count;
+               struct orangefs_fs_key_response fs_key;
+       } resp;
+};
+
+struct orangefs_readdir_response_s {
+       __u64 token;
+       __u64 directory_version;
+       __u32 __pad2;
+       __u32 orangefs_dirent_outcount;
+       struct orangefs_dirent *dirent_array;
+};
+
+#endif /* __DOWNCALL_H */
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
new file mode 100644 (file)
index 0000000..ae92795
--- /dev/null
@@ -0,0 +1,717 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ *  Linux VFS file operations.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+
+/*
+ * Copy to client-core's address space from the buffers specified
+ * by the iovec upto total_size bytes.
+ * NOTE: the iovector can either contain addresses which
+ *       can futher be kernel-space or user-space addresses.
+ *       or it can pointers to struct page's
+ */
+static int precopy_buffers(int buffer_index,
+                          struct iov_iter *iter,
+                          size_t total_size)
+{
+       int ret = 0;
+       /*
+        * copy data from application/kernel by pulling it out
+        * of the iovec.
+        */
+
+
+       if (total_size) {
+               ret = orangefs_bufmap_copy_from_iovec(iter,
+                                                     buffer_index,
+                                                     total_size);
+               if (ret < 0)
+               gossip_err("%s: Failed to copy-in buffers. Please make sure that the pvfs2-client is running. %ld\n",
+                          __func__,
+                          (long)ret);
+       }
+
+       if (ret < 0)
+               gossip_err("%s: Failed to copy-in buffers. Please make sure that the pvfs2-client is running. %ld\n",
+                       __func__,
+                       (long)ret);
+       return ret;
+}
+
+/*
+ * Copy from client-core's address space to the buffers specified
+ * by the iovec upto total_size bytes.
+ * NOTE: the iovector can either contain addresses which
+ *       can futher be kernel-space or user-space addresses.
+ *       or it can pointers to struct page's
+ */
+static int postcopy_buffers(int buffer_index,
+                           struct iov_iter *iter,
+                           size_t total_size)
+{
+       int ret = 0;
+       /*
+        * copy data to application/kernel by pushing it out to
+        * the iovec. NOTE; target buffers can be addresses or
+        * struct page pointers.
+        */
+       if (total_size) {
+               ret = orangefs_bufmap_copy_to_iovec(iter,
+                                                   buffer_index,
+                                                   total_size);
+               if (ret < 0)
+                       gossip_err("%s: Failed to copy-out buffers. Please make sure that the pvfs2-client is running (%ld)\n",
+                               __func__,
+                               (long)ret);
+       }
+       return ret;
+}
+
+/*
+ * Post and wait for the I/O upcall to finish
+ */
+static ssize_t wait_for_direct_io(enum ORANGEFS_io_type type, struct inode *inode,
+               loff_t *offset, struct iov_iter *iter,
+               size_t total_size, loff_t readahead_size)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_khandle *handle = &orangefs_inode->refn.khandle;
+       struct orangefs_kernel_op_s *new_op = NULL;
+       struct iov_iter saved = *iter;
+       int buffer_index = -1;
+       ssize_t ret;
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_FILE_IO);
+       if (!new_op)
+               return -ENOMEM;
+
+       /* synchronous I/O */
+       new_op->upcall.req.io.readahead_size = readahead_size;
+       new_op->upcall.req.io.io_type = type;
+       new_op->upcall.req.io.refn = orangefs_inode->refn;
+
+populate_shared_memory:
+       /* get a shared buffer index */
+       buffer_index = orangefs_bufmap_get();
+       if (buffer_index < 0) {
+               ret = buffer_index;
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s: orangefs_bufmap_get failure (%zd)\n",
+                            __func__, ret);
+               goto out;
+       }
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "%s(%pU): GET op %p -> buffer_index %d\n",
+                    __func__,
+                    handle,
+                    new_op,
+                    buffer_index);
+
+       new_op->uses_shared_memory = 1;
+       new_op->upcall.req.io.buf_index = buffer_index;
+       new_op->upcall.req.io.count = total_size;
+       new_op->upcall.req.io.offset = *offset;
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "%s(%pU): offset: %llu total_size: %zd\n",
+                    __func__,
+                    handle,
+                    llu(*offset),
+                    total_size);
+       /*
+        * Stage 1: copy the buffers into client-core's address space
+        * precopy_buffers only pertains to writes.
+        */
+       if (type == ORANGEFS_IO_WRITE) {
+               ret = precopy_buffers(buffer_index,
+                                     iter,
+                                     total_size);
+               if (ret < 0)
+                       goto out;
+       }
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "%s(%pU): Calling post_io_request with tag (%llu)\n",
+                    __func__,
+                    handle,
+                    llu(new_op->tag));
+
+       /* Stage 2: Service the I/O operation */
+       ret = service_operation(new_op,
+                               type == ORANGEFS_IO_WRITE ?
+                                       "file_write" :
+                                       "file_read",
+                               get_interruptible_flag(inode));
+
+       /*
+        * If service_operation() returns -EAGAIN #and# the operation was
+        * purged from orangefs_request_list or htable_ops_in_progress, then
+        * we know that the client was restarted, causing the shared memory
+        * area to be wiped clean.  To restart a  write operation in this
+        * case, we must re-copy the data from the user's iovec to a NEW
+        * shared memory location. To restart a read operation, we must get
+        * a new shared memory location.
+        */
+       if (ret == -EAGAIN && op_state_purged(new_op)) {
+               orangefs_bufmap_put(buffer_index);
+               buffer_index = -1;
+               if (type == ORANGEFS_IO_WRITE)
+                       *iter = saved;
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s:going to repopulate_shared_memory.\n",
+                            __func__);
+               goto populate_shared_memory;
+       }
+
+       if (ret < 0) {
+               if (ret == -EINTR) {
+                       /*
+                        * We can't return EINTR if any data was written,
+                        * it's not POSIX. It is minimally acceptable
+                        * to give a partial write, the way NFS does.
+                        *
+                        * It would be optimal to return all or nothing,
+                        * but if a userspace write is bigger than
+                        * an IO buffer, and the interrupt occurs
+                        * between buffer writes, that would not be
+                        * possible.
+                        */
+                       switch (new_op->op_state - OP_VFS_STATE_GIVEN_UP) {
+                       /*
+                        * If the op was waiting when the interrupt
+                        * occurred, then the client-core did not
+                        * trigger the write.
+                        */
+                       case OP_VFS_STATE_WAITING:
+                               if (*offset == 0)
+                                       ret = -EINTR;
+                               else
+                                       ret = 0;
+                               break;
+                       /* 
+                        * If the op was in progress when the interrupt
+                        * occurred, then the client-core was able to
+                        * trigger the write.
+                        */
+                       case OP_VFS_STATE_INPROGR:
+                               ret = total_size;
+                               break;
+                       default:
+                               gossip_err("%s: unexpected op state :%d:.\n",
+                                          __func__,
+                                          new_op->op_state);
+                               ret = 0;
+                               break;
+                       }
+                       gossip_debug(GOSSIP_FILE_DEBUG,
+                                    "%s: got EINTR, state:%d: %p\n",
+                                    __func__,
+                                    new_op->op_state,
+                                    new_op);
+               } else {
+                       gossip_err("%s: error in %s handle %pU, returning %zd\n",
+                               __func__,
+                               type == ORANGEFS_IO_READ ?
+                                       "read from" : "write to",
+                               handle, ret);
+               }
+               if (orangefs_cancel_op_in_progress(new_op))
+                       return ret;
+
+               goto out;
+       }
+
+       /*
+        * Stage 3: Post copy buffers from client-core's address space
+        * postcopy_buffers only pertains to reads.
+        */
+       if (type == ORANGEFS_IO_READ) {
+               ret = postcopy_buffers(buffer_index,
+                                      iter,
+                                      new_op->downcall.resp.io.amt_complete);
+               if (ret < 0)
+                       goto out;
+       }
+       gossip_debug(GOSSIP_FILE_DEBUG,
+           "%s(%pU): Amount %s, returned by the sys-io call:%d\n",
+           __func__,
+           handle,
+           type == ORANGEFS_IO_READ ?  "read" : "written",
+           (int)new_op->downcall.resp.io.amt_complete);
+
+       ret = new_op->downcall.resp.io.amt_complete;
+
+out:
+       if (buffer_index >= 0) {
+               orangefs_bufmap_put(buffer_index);
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s(%pU): PUT buffer_index %d\n",
+                            __func__, handle, buffer_index);
+               buffer_index = -1;
+       }
+       op_release(new_op);
+       return ret;
+}
+
+/*
+ * Common entry point for read/write/readv/writev
+ * This function will dispatch it to either the direct I/O
+ * or buffered I/O path depending on the mount options and/or
+ * augmented/extended metadata attached to the file.
+ * Note: File extended attributes override any mount options.
+ */
+static ssize_t do_readv_writev(enum ORANGEFS_io_type type, struct file *file,
+               loff_t *offset, struct iov_iter *iter)
+{
+       struct inode *inode = file->f_mapping->host;
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_khandle *handle = &orangefs_inode->refn.khandle;
+       size_t count = iov_iter_count(iter);
+       ssize_t total_count = 0;
+       ssize_t ret = -EINVAL;
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+               "%s-BEGIN(%pU): count(%d) after estimate_max_iovecs.\n",
+               __func__,
+               handle,
+               (int)count);
+
+       if (type == ORANGEFS_IO_WRITE) {
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s(%pU): proceeding with offset : %llu, "
+                            "size %d\n",
+                            __func__,
+                            handle,
+                            llu(*offset),
+                            (int)count);
+       }
+
+       if (count == 0) {
+               ret = 0;
+               goto out;
+       }
+
+       while (iov_iter_count(iter)) {
+               size_t each_count = iov_iter_count(iter);
+               size_t amt_complete;
+
+               /* how much to transfer in this loop iteration */
+               if (each_count > orangefs_bufmap_size_query())
+                       each_count = orangefs_bufmap_size_query();
+
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s(%pU): size of each_count(%d)\n",
+                            __func__,
+                            handle,
+                            (int)each_count);
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s(%pU): BEFORE wait_for_io: offset is %d\n",
+                            __func__,
+                            handle,
+                            (int)*offset);
+
+               ret = wait_for_direct_io(type, inode, offset, iter,
+                               each_count, 0);
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s(%pU): return from wait_for_io:%d\n",
+                            __func__,
+                            handle,
+                            (int)ret);
+
+               if (ret < 0)
+                       goto out;
+
+               *offset += ret;
+               total_count += ret;
+               amt_complete = ret;
+
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s(%pU): AFTER wait_for_io: offset is %d\n",
+                            __func__,
+                            handle,
+                            (int)*offset);
+
+               /*
+                * if we got a short I/O operations,
+                * fall out and return what we got so far
+                */
+               if (amt_complete < each_count)
+                       break;
+       } /*end while */
+
+out:
+       if (total_count > 0)
+               ret = total_count;
+       if (ret > 0) {
+               if (type == ORANGEFS_IO_READ) {
+                       file_accessed(file);
+               } else {
+                       SetMtimeFlag(orangefs_inode);
+                       inode->i_mtime = CURRENT_TIME;
+                       mark_inode_dirty_sync(inode);
+               }
+       }
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "%s(%pU): Value(%d) returned.\n",
+                    __func__,
+                    handle,
+                    (int)ret);
+
+       return ret;
+}
+
+/*
+ * Read data from a specified offset in a file (referenced by inode).
+ * Data may be placed either in a user or kernel buffer.
+ */
+ssize_t orangefs_inode_read(struct inode *inode,
+                           struct iov_iter *iter,
+                           loff_t *offset,
+                           loff_t readahead_size)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       size_t count = iov_iter_count(iter);
+       size_t bufmap_size;
+       ssize_t ret = -EINVAL;
+
+       g_orangefs_stats.reads++;
+
+       bufmap_size = orangefs_bufmap_size_query();
+       if (count > bufmap_size) {
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "%s: count is too large (%zd/%zd)!\n",
+                            __func__, count, bufmap_size);
+               return -EINVAL;
+       }
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "%s(%pU) %zd@%llu\n",
+                    __func__,
+                    &orangefs_inode->refn.khandle,
+                    count,
+                    llu(*offset));
+
+       ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, offset, iter,
+                       count, readahead_size);
+       if (ret > 0)
+               *offset += ret;
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "%s(%pU): Value(%zd) returned.\n",
+                    __func__,
+                    &orangefs_inode->refn.khandle,
+                    ret);
+
+       return ret;
+}
+
+static ssize_t orangefs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+       struct file *file = iocb->ki_filp;
+       loff_t pos = *(&iocb->ki_pos);
+       ssize_t rc = 0;
+
+       BUG_ON(iocb->private);
+
+       gossip_debug(GOSSIP_FILE_DEBUG, "orangefs_file_read_iter\n");
+
+       g_orangefs_stats.reads++;
+
+       rc = do_readv_writev(ORANGEFS_IO_READ, file, &pos, iter);
+       iocb->ki_pos = pos;
+
+       return rc;
+}
+
+static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+       struct file *file = iocb->ki_filp;
+       loff_t pos;
+       ssize_t rc;
+
+       BUG_ON(iocb->private);
+
+       gossip_debug(GOSSIP_FILE_DEBUG, "orangefs_file_write_iter\n");
+
+       mutex_lock(&file->f_mapping->host->i_mutex);
+
+       /* Make sure generic_write_checks sees an up to date inode size. */
+       if (file->f_flags & O_APPEND) {
+               rc = orangefs_inode_getattr(file->f_mapping->host, 0, 1);
+               if (rc == -ESTALE)
+                       rc = -EIO;
+               if (rc) {
+                       gossip_err("%s: orangefs_inode_getattr failed, "
+                           "rc:%zd:.\n", __func__, rc);
+                       goto out;
+               }
+       }
+
+       if (file->f_pos > i_size_read(file->f_mapping->host))
+               orangefs_i_size_write(file->f_mapping->host, file->f_pos);
+
+       rc = generic_write_checks(iocb, iter);
+
+       if (rc <= 0) {
+               gossip_err("%s: generic_write_checks failed, rc:%zd:.\n",
+                          __func__, rc);
+               goto out;
+       }
+
+       /*
+        * if we are appending, generic_write_checks would have updated
+        * pos to the end of the file, so we will wait till now to set
+        * pos...
+        */
+       pos = *(&iocb->ki_pos);
+
+       rc = do_readv_writev(ORANGEFS_IO_WRITE,
+                            file,
+                            &pos,
+                            iter);
+       if (rc < 0) {
+               gossip_err("%s: do_readv_writev failed, rc:%zd:.\n",
+                          __func__, rc);
+               goto out;
+       }
+
+       iocb->ki_pos = pos;
+       g_orangefs_stats.writes++;
+
+out:
+
+       mutex_unlock(&file->f_mapping->host->i_mutex);
+       return rc;
+}
+
+/*
+ * Perform a miscellaneous operation on a file.
+ */
+static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret = -ENOTTY;
+       __u64 val = 0;
+       unsigned long uval;
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "orangefs_ioctl: called with cmd %d\n",
+                    cmd);
+
+       /*
+        * we understand some general ioctls on files, such as the immutable
+        * and append flags
+        */
+       if (cmd == FS_IOC_GETFLAGS) {
+               val = 0;
+               ret = orangefs_inode_getxattr(file_inode(file),
+                                             ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
+                                             "user.pvfs2.meta_hint",
+                                             &val, sizeof(val));
+               if (ret < 0 && ret != -ENODATA)
+                       return ret;
+               else if (ret == -ENODATA)
+                       val = 0;
+               uval = val;
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "orangefs_ioctl: FS_IOC_GETFLAGS: %llu\n",
+                            (unsigned long long)uval);
+               return put_user(uval, (int __user *)arg);
+       } else if (cmd == FS_IOC_SETFLAGS) {
+               ret = 0;
+               if (get_user(uval, (int __user *)arg))
+                       return -EFAULT;
+               /*
+                * ORANGEFS_MIRROR_FL is set internally when the mirroring mode
+                * is turned on for a file. The user is not allowed to turn
+                * on this bit, but the bit is present if the user first gets
+                * the flags and then updates the flags with some new
+                * settings. So, we ignore it in the following edit. bligon.
+                */
+               if ((uval & ~ORANGEFS_MIRROR_FL) &
+                   (~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NOATIME_FL))) {
+                       gossip_err("orangefs_ioctl: the FS_IOC_SETFLAGS only supports setting one of FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NOATIME_FL\n");
+                       return -EINVAL;
+               }
+               val = uval;
+               gossip_debug(GOSSIP_FILE_DEBUG,
+                            "orangefs_ioctl: FS_IOC_SETFLAGS: %llu\n",
+                            (unsigned long long)val);
+               ret = orangefs_inode_setxattr(file_inode(file),
+                                             ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
+                                             "user.pvfs2.meta_hint",
+                                             &val, sizeof(val), 0);
+       }
+
+       return ret;
+}
+
+/*
+ * Memory map a region of a file.
+ */
+static int orangefs_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "orangefs_file_mmap: called on %s\n",
+                    (file ?
+                       (char *)file->f_path.dentry->d_name.name :
+                       (char *)"Unknown"));
+
+       /* set the sequential readahead hint */
+       vma->vm_flags |= VM_SEQ_READ;
+       vma->vm_flags &= ~VM_RAND_READ;
+
+       /* Use readonly mmap since we cannot support writable maps. */
+       return generic_file_readonly_mmap(file, vma);
+}
+
+#define mapping_nrpages(idata) ((idata)->nrpages)
+
+/*
+ * Called to notify the module that there are no more references to
+ * this file (i.e. no processes have it open).
+ *
+ * \note Not called when each file is closed.
+ */
+static int orangefs_file_release(struct inode *inode, struct file *file)
+{
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "orangefs_file_release: called on %s\n",
+                    file->f_path.dentry->d_name.name);
+
+       orangefs_flush_inode(inode);
+
+       /*
+        * remove all associated inode pages from the page cache and mmap
+        * readahead cache (if any); this forces an expensive refresh of
+        * data for the next caller of mmap (or 'get_block' accesses)
+        */
+       if (file->f_path.dentry->d_inode &&
+           file->f_path.dentry->d_inode->i_mapping &&
+           mapping_nrpages(&file->f_path.dentry->d_inode->i_data))
+               truncate_inode_pages(file->f_path.dentry->d_inode->i_mapping,
+                                    0);
+       return 0;
+}
+
+/*
+ * Push all data for a specific file onto permanent storage.
+ */
+static int orangefs_fsync(struct file *file,
+                      loff_t start,
+                      loff_t end,
+                      int datasync)
+{
+       int ret = -EINVAL;
+       struct orangefs_inode_s *orangefs_inode =
+               ORANGEFS_I(file->f_path.dentry->d_inode);
+       struct orangefs_kernel_op_s *new_op = NULL;
+
+       /* required call */
+       filemap_write_and_wait_range(file->f_mapping, start, end);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_FSYNC);
+       if (!new_op)
+               return -ENOMEM;
+       new_op->upcall.req.fsync.refn = orangefs_inode->refn;
+
+       ret = service_operation(new_op,
+                       "orangefs_fsync",
+                       get_interruptible_flag(file->f_path.dentry->d_inode));
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "orangefs_fsync got return value of %d\n",
+                    ret);
+
+       op_release(new_op);
+
+       orangefs_flush_inode(file->f_path.dentry->d_inode);
+       return ret;
+}
+
+/*
+ * Change the file pointer position for an instance of an open file.
+ *
+ * \note If .llseek is overriden, we must acquire lock as described in
+ *       Documentation/filesystems/Locking.
+ *
+ * Future upgrade could support SEEK_DATA and SEEK_HOLE but would
+ * require much changes to the FS
+ */
+static loff_t orangefs_file_llseek(struct file *file, loff_t offset, int origin)
+{
+       int ret = -EINVAL;
+       struct inode *inode = file_inode(file);
+
+       if (origin == SEEK_END) {
+               /*
+                * revalidate the inode's file size.
+                * NOTE: We are only interested in file size here,
+                * so we set mask accordingly.
+                */
+               ret = orangefs_inode_getattr(file->f_mapping->host, 0, 1);
+               if (ret == -ESTALE)
+                       ret = -EIO;
+               if (ret) {
+                       gossip_debug(GOSSIP_FILE_DEBUG,
+                                    "%s:%s:%d calling make bad inode\n",
+                                    __FILE__,
+                                    __func__,
+                                    __LINE__);
+                       return ret;
+               }
+       }
+
+       gossip_debug(GOSSIP_FILE_DEBUG,
+                    "orangefs_file_llseek: offset is %ld | origin is %d"
+                    " | inode size is %lu\n",
+                    (long)offset,
+                    origin,
+                    (unsigned long)i_size_read(inode));
+
+       return generic_file_llseek(file, offset, origin);
+}
+
+/*
+ * Support local locks (locks that only this kernel knows about)
+ * if Orangefs was mounted -o local_lock.
+ */
+static int orangefs_lock(struct file *filp, int cmd, struct file_lock *fl)
+{
+       int rc = -EINVAL;
+
+       if (ORANGEFS_SB(filp->f_inode->i_sb)->flags & ORANGEFS_OPT_LOCAL_LOCK) {
+               if (cmd == F_GETLK) {
+                       rc = 0;
+                       posix_test_lock(filp, fl);
+               } else {
+                       rc = posix_lock_file(filp, fl, NULL);
+               }
+       }
+
+       return rc;
+}
+
+/** ORANGEFS implementation of VFS file operations */
+const struct file_operations orangefs_file_operations = {
+       .llseek         = orangefs_file_llseek,
+       .read_iter      = orangefs_file_read_iter,
+       .write_iter     = orangefs_file_write_iter,
+       .lock           = orangefs_lock,
+       .unlocked_ioctl = orangefs_ioctl,
+       .mmap           = orangefs_file_mmap,
+       .open           = generic_file_open,
+       .release        = orangefs_file_release,
+       .fsync          = orangefs_fsync,
+};
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
new file mode 100644 (file)
index 0000000..2382e26
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ *  Linux VFS inode operations.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+
+static int read_one_page(struct page *page)
+{
+       int ret;
+       int max_block;
+       ssize_t bytes_read = 0;
+       struct inode *inode = page->mapping->host;
+       const __u32 blocksize = PAGE_CACHE_SIZE;        /* inode->i_blksize */
+       const __u32 blockbits = PAGE_CACHE_SHIFT;       /* inode->i_blkbits */
+       struct iov_iter to;
+       struct bio_vec bv = {.bv_page = page, .bv_len = PAGE_SIZE};
+
+       iov_iter_bvec(&to, ITER_BVEC | READ, &bv, 1, PAGE_SIZE);
+
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                   "orangefs_readpage called with page %p\n",
+                    page);
+
+       max_block = ((inode->i_size / blocksize) + 1);
+
+       if (page->index < max_block) {
+               loff_t blockptr_offset = (((loff_t) page->index) << blockbits);
+
+               bytes_read = orangefs_inode_read(inode,
+                                                &to,
+                                                &blockptr_offset,
+                                                inode->i_size);
+       }
+       /* this will only zero remaining unread portions of the page data */
+       iov_iter_zero(~0U, &to);
+       /* takes care of potential aliasing */
+       flush_dcache_page(page);
+       if (bytes_read < 0) {
+               ret = bytes_read;
+               SetPageError(page);
+       } else {
+               SetPageUptodate(page);
+               if (PageError(page))
+                       ClearPageError(page);
+               ret = 0;
+       }
+       /* unlock the page after the ->readpage() routine completes */
+       unlock_page(page);
+       return ret;
+}
+
+static int orangefs_readpage(struct file *file, struct page *page)
+{
+       return read_one_page(page);
+}
+
+static int orangefs_readpages(struct file *file,
+                          struct address_space *mapping,
+                          struct list_head *pages,
+                          unsigned nr_pages)
+{
+       int page_idx;
+       int ret;
+
+       gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_readpages called\n");
+
+       for (page_idx = 0; page_idx < nr_pages; page_idx++) {
+               struct page *page;
+
+               page = list_entry(pages->prev, struct page, lru);
+               list_del(&page->lru);
+               if (!add_to_page_cache(page,
+                                      mapping,
+                                      page->index,
+                                      GFP_KERNEL)) {
+                       ret = read_one_page(page);
+                       gossip_debug(GOSSIP_INODE_DEBUG,
+                               "failure adding page to cache, read_one_page returned: %d\n",
+                               ret);
+             } else {
+                       page_cache_release(page);
+             }
+       }
+       BUG_ON(!list_empty(pages));
+       return 0;
+}
+
+static void orangefs_invalidatepage(struct page *page,
+                                unsigned int offset,
+                                unsigned int length)
+{
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "orangefs_invalidatepage called on page %p "
+                    "(offset is %u)\n",
+                    page,
+                    offset);
+
+       ClearPageUptodate(page);
+       ClearPageMappedToDisk(page);
+       return;
+
+}
+
+static int orangefs_releasepage(struct page *page, gfp_t foo)
+{
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "orangefs_releasepage called on page %p\n",
+                    page);
+       return 0;
+}
+
+/*
+ * Having a direct_IO entry point in the address_space_operations
+ * struct causes the kernel to allows us to use O_DIRECT on
+ * open. Nothing will ever call this thing, but in the future we
+ * will need to be able to use O_DIRECT on open in order to support
+ * AIO. Modeled after NFS, they do this too.
+ */
+/*
+ * static ssize_t orangefs_direct_IO(int rw,
+ *                     struct kiocb *iocb,
+ *                     struct iov_iter *iter,
+ *                     loff_t offset)
+ *{
+ *     gossip_debug(GOSSIP_INODE_DEBUG,
+ *                  "orangefs_direct_IO: %s\n",
+ *                  iocb->ki_filp->f_path.dentry->d_name.name);
+ *
+ *     return -EINVAL;
+ *}
+ */
+
+struct backing_dev_info orangefs_backing_dev_info = {
+       .name = "orangefs",
+       .ra_pages = 0,
+       .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+};
+
+/** ORANGEFS2 implementation of address space operations */
+const struct address_space_operations orangefs_address_operations = {
+       .readpage = orangefs_readpage,
+       .readpages = orangefs_readpages,
+       .invalidatepage = orangefs_invalidatepage,
+       .releasepage = orangefs_releasepage,
+/*     .direct_IO = orangefs_direct_IO */
+};
+
+static int orangefs_setattr_size(struct inode *inode, struct iattr *iattr)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_kernel_op_s *new_op;
+       loff_t orig_size;
+       int ret = -EINVAL;
+
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "%s: %pU: Handle is %pU | fs_id %d | size is %llu\n",
+                    __func__,
+                    get_khandle_from_ino(inode),
+                    &orangefs_inode->refn.khandle,
+                    orangefs_inode->refn.fs_id,
+                    iattr->ia_size);
+
+       /* Ensure that we have a up to date size, so we know if it changed. */
+       ret = orangefs_inode_getattr(inode, 0, 1);
+       if (ret == -ESTALE)
+               ret = -EIO;
+       if (ret) {
+               gossip_err("%s: orangefs_inode_getattr failed, ret:%d:.\n",
+                   __func__, ret);
+               return ret;
+       }
+       orig_size = i_size_read(inode);
+
+       truncate_setsize(inode, iattr->ia_size);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_TRUNCATE);
+       if (!new_op)
+               return -ENOMEM;
+
+       new_op->upcall.req.truncate.refn = orangefs_inode->refn;
+       new_op->upcall.req.truncate.size = (__s64) iattr->ia_size;
+
+       ret = service_operation(new_op, __func__,
+                               get_interruptible_flag(inode));
+
+       /*
+        * the truncate has no downcall members to retrieve, but
+        * the status value tells us if it went through ok or not
+        */
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "orangefs: orangefs_truncate got return value of %d\n",
+                    ret);
+
+       op_release(new_op);
+
+       if (ret != 0)
+               return ret;
+
+       /*
+        * Only change the c/mtime if we are changing the size or we are
+        * explicitly asked to change it.  This handles the semantic difference
+        * between truncate() and ftruncate() as implemented in the VFS.
+        *
+        * The regular truncate() case without ATTR_CTIME and ATTR_MTIME is a
+        * special case where we need to update the times despite not having
+        * these flags set.  For all other operations the VFS set these flags
+        * explicitly if it wants a timestamp update.
+        */
+       if (orig_size != i_size_read(inode) &&
+           !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) {
+               iattr->ia_ctime = iattr->ia_mtime =
+                       current_fs_time(inode->i_sb);
+               iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
+       }
+
+       return ret;
+}
+
+/*
+ * Change attributes of an object referenced by dentry.
+ */
+int orangefs_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       int ret = -EINVAL;
+       struct inode *inode = dentry->d_inode;
+
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "orangefs_setattr: called on %s\n",
+                    dentry->d_name.name);
+
+       ret = inode_change_ok(inode, iattr);
+       if (ret)
+               goto out;
+
+       if ((iattr->ia_valid & ATTR_SIZE) &&
+           iattr->ia_size != i_size_read(inode)) {
+               ret = orangefs_setattr_size(inode, iattr);
+               if (ret)
+                       goto out;
+       }
+
+       setattr_copy(inode, iattr);
+       mark_inode_dirty(inode);
+
+       ret = orangefs_inode_setattr(inode, iattr);
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "orangefs_setattr: inode_setattr returned %d\n",
+                    ret);
+
+       if (!ret && (iattr->ia_valid & ATTR_MODE))
+               /* change mod on a file that has ACLs */
+               ret = posix_acl_chmod(inode, inode->i_mode);
+
+out:
+       gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_setattr: returning %d\n", ret);
+       return ret;
+}
+
+/*
+ * Obtain attributes of an object given a dentry
+ */
+int orangefs_getattr(struct vfsmount *mnt,
+                 struct dentry *dentry,
+                 struct kstat *kstat)
+{
+       int ret = -ENOENT;
+       struct inode *inode = dentry->d_inode;
+       struct orangefs_inode_s *orangefs_inode = NULL;
+
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "orangefs_getattr: called on %s\n",
+                    dentry->d_name.name);
+
+       ret = orangefs_inode_getattr(inode, 0, 1);
+       if (ret == 0) {
+               generic_fillattr(inode, kstat);
+
+               /* override block size reported to stat */
+               orangefs_inode = ORANGEFS_I(inode);
+               kstat->blksize = orangefs_inode->blksize;
+       }
+       return ret;
+}
+
+int orangefs_permission(struct inode *inode, int mask)
+{
+       int ret;
+
+       if (mask & MAY_NOT_BLOCK)
+               return -ECHILD;
+
+       gossip_debug(GOSSIP_INODE_DEBUG, "%s: refreshing\n", __func__);
+
+       /* Make sure the permission (and other common attrs) are up to date. */
+       ret = orangefs_inode_getattr(inode, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       return generic_permission(inode, mask);
+}
+
+/* ORANGEDS2 implementation of VFS inode operations for files */
+struct inode_operations orangefs_file_inode_operations = {
+       .get_acl = orangefs_get_acl,
+       .set_acl = orangefs_set_acl,
+       .setattr = orangefs_setattr,
+       .getattr = orangefs_getattr,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
+       .listxattr = orangefs_listxattr,
+       .removexattr = generic_removexattr,
+       .permission = orangefs_permission,
+};
+
+static int orangefs_init_iops(struct inode *inode)
+{
+       inode->i_mapping->a_ops = &orangefs_address_operations;
+
+       switch (inode->i_mode & S_IFMT) {
+       case S_IFREG:
+               inode->i_op = &orangefs_file_inode_operations;
+               inode->i_fop = &orangefs_file_operations;
+               inode->i_blkbits = PAGE_CACHE_SHIFT;
+               break;
+       case S_IFLNK:
+               inode->i_op = &orangefs_symlink_inode_operations;
+               break;
+       case S_IFDIR:
+               inode->i_op = &orangefs_dir_inode_operations;
+               inode->i_fop = &orangefs_dir_operations;
+               break;
+       default:
+               gossip_debug(GOSSIP_INODE_DEBUG,
+                            "%s: unsupported mode\n",
+                            __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Given a ORANGEFS object identifier (fsid, handle), convert it into a ino_t type
+ * that will be used as a hash-index from where the handle will
+ * be searched for in the VFS hash table of inodes.
+ */
+static inline ino_t orangefs_handle_hash(struct orangefs_object_kref *ref)
+{
+       if (!ref)
+               return 0;
+       return orangefs_khandle_to_ino(&(ref->khandle));
+}
+
+/*
+ * Called to set up an inode from iget5_locked.
+ */
+static int orangefs_set_inode(struct inode *inode, void *data)
+{
+       struct orangefs_object_kref *ref = (struct orangefs_object_kref *) data;
+       ORANGEFS_I(inode)->refn.fs_id = ref->fs_id;
+       ORANGEFS_I(inode)->refn.khandle = ref->khandle;
+       return 0;
+}
+
+/*
+ * Called to determine if handles match.
+ */
+static int orangefs_test_inode(struct inode *inode, void *data)
+{
+       struct orangefs_object_kref *ref = (struct orangefs_object_kref *) data;
+       struct orangefs_inode_s *orangefs_inode = NULL;
+
+       orangefs_inode = ORANGEFS_I(inode);
+       return (!ORANGEFS_khandle_cmp(&(orangefs_inode->refn.khandle), &(ref->khandle))
+               && orangefs_inode->refn.fs_id == ref->fs_id);
+}
+
+/*
+ * Front-end to lookup the inode-cache maintained by the VFS using the ORANGEFS
+ * file handle.
+ *
+ * @sb: the file system super block instance.
+ * @ref: The ORANGEFS object for which we are trying to locate an inode structure.
+ */
+struct inode *orangefs_iget(struct super_block *sb, struct orangefs_object_kref *ref)
+{
+       struct inode *inode = NULL;
+       unsigned long hash;
+       int error;
+
+       hash = orangefs_handle_hash(ref);
+       inode = iget5_locked(sb, hash, orangefs_test_inode, orangefs_set_inode, ref);
+       if (!inode || !(inode->i_state & I_NEW))
+               return inode;
+
+       error = orangefs_inode_getattr(inode, 1, 0);
+       if (error) {
+               iget_failed(inode);
+               return ERR_PTR(error);
+       }
+
+       inode->i_ino = hash;    /* needed for stat etc */
+       orangefs_init_iops(inode);
+       unlock_new_inode(inode);
+
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "iget handle %pU, fsid %d hash %ld i_ino %lu\n",
+                    &ref->khandle,
+                    ref->fs_id,
+                    hash,
+                    inode->i_ino);
+
+       return inode;
+}
+
+/*
+ * Allocate an inode for a newly created file and insert it into the inode hash.
+ */
+struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
+               int mode, dev_t dev, struct orangefs_object_kref *ref)
+{
+       unsigned long hash = orangefs_handle_hash(ref);
+       struct inode *inode;
+       int error;
+
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "%s:(sb is %p | MAJOR(dev)=%u | MINOR(dev)=%u mode=%o)\n",
+                    __func__,
+                    sb,
+                    MAJOR(dev),
+                    MINOR(dev),
+                    mode);
+
+       inode = new_inode(sb);
+       if (!inode)
+               return NULL;
+
+       orangefs_set_inode(inode, ref);
+       inode->i_ino = hash;    /* needed for stat etc */
+
+       error = orangefs_inode_getattr(inode, 1, 0);
+       if (error)
+               goto out_iput;
+
+       orangefs_init_iops(inode);
+
+       inode->i_mode = mode;
+       inode->i_uid = current_fsuid();
+       inode->i_gid = current_fsgid();
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       inode->i_size = PAGE_CACHE_SIZE;
+       inode->i_rdev = dev;
+
+       error = insert_inode_locked4(inode, hash, orangefs_test_inode, ref);
+       if (error < 0)
+               goto out_iput;
+
+       gossip_debug(GOSSIP_INODE_DEBUG,
+                    "Initializing ACL's for inode %pU\n",
+                    get_khandle_from_ino(inode));
+       orangefs_init_acl(inode, dir);
+       return inode;
+
+out_iput:
+       iput(inode);
+       return ERR_PTR(error);
+}
diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c
new file mode 100644 (file)
index 0000000..5a60c50
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ *  Linux VFS namei operations.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+
+/*
+ * Get a newly allocated inode to go with a negative dentry.
+ */
+static int orangefs_create(struct inode *dir,
+                       struct dentry *dentry,
+                       umode_t mode,
+                       bool exclusive)
+{
+       struct orangefs_inode_s *parent = ORANGEFS_I(dir);
+       struct orangefs_kernel_op_s *new_op;
+       struct inode *inode;
+       int ret;
+
+       gossip_debug(GOSSIP_NAME_DEBUG, "%s: %s\n",
+                    __func__,
+                    dentry->d_name.name);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_CREATE);
+       if (!new_op)
+               return -ENOMEM;
+
+       new_op->upcall.req.create.parent_refn = parent->refn;
+
+       fill_default_sys_attrs(new_op->upcall.req.create.attributes,
+                              ORANGEFS_TYPE_METAFILE, mode);
+
+       strncpy(new_op->upcall.req.create.d_name,
+               dentry->d_name.name, ORANGEFS_NAME_MAX);
+
+       ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "%s: %s: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
+                    __func__,
+                    dentry->d_name.name,
+                    &new_op->downcall.resp.create.refn.khandle,
+                    new_op->downcall.resp.create.refn.fs_id,
+                    new_op,
+                    ret);
+
+       if (ret < 0)
+               goto out;
+
+       inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0,
+                               &new_op->downcall.resp.create.refn);
+       if (IS_ERR(inode)) {
+               gossip_err("%s: Failed to allocate inode for file :%s:\n",
+                          __func__,
+                          dentry->d_name.name);
+               ret = PTR_ERR(inode);
+               goto out;
+       }
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "%s: Assigned inode :%pU: for file :%s:\n",
+                    __func__,
+                    get_khandle_from_ino(inode),
+                    dentry->d_name.name);
+
+       d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "%s: dentry instantiated for %s\n",
+                    __func__,
+                    dentry->d_name.name);
+
+       SetMtimeFlag(parent);
+       dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+       mark_inode_dirty_sync(dir);
+       ret = 0;
+out:
+       op_release(new_op);
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "%s: %s: returning %d\n",
+                    __func__,
+                    dentry->d_name.name,
+                    ret);
+       return ret;
+}
+
+/*
+ * Attempt to resolve an object name (dentry->d_name), parent handle, and
+ * fsid into a handle for the object.
+ */
+static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
+                                  unsigned int flags)
+{
+       struct orangefs_inode_s *parent = ORANGEFS_I(dir);
+       struct orangefs_kernel_op_s *new_op;
+       struct inode *inode;
+       struct dentry *res;
+       int ret = -EINVAL;
+
+       /*
+        * in theory we could skip a lookup here (if the intent is to
+        * create) in order to avoid a potentially failed lookup, but
+        * leaving it in can skip a valid lookup and try to create a file
+        * that already exists (e.g. the vfs already handles checking for
+        * -EEXIST on O_EXCL opens, which is broken if we skip this lookup
+        * in the create path)
+        */
+       gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %s\n",
+                    __func__, dentry->d_name.name);
+
+       if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1))
+               return ERR_PTR(-ENAMETOOLONG);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
+       if (!new_op)
+               return ERR_PTR(-ENOMEM);
+
+       new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
+
+       gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %pU\n",
+                    __FILE__,
+                    __func__,
+                    __LINE__,
+                    &parent->refn.khandle);
+       new_op->upcall.req.lookup.parent_refn = parent->refn;
+
+       strncpy(new_op->upcall.req.lookup.d_name, dentry->d_name.name,
+               ORANGEFS_NAME_MAX);
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "%s: doing lookup on %s under %pU,%d\n",
+                    __func__,
+                    new_op->upcall.req.lookup.d_name,
+                    &new_op->upcall.req.lookup.parent_refn.khandle,
+                    new_op->upcall.req.lookup.parent_refn.fs_id);
+
+       ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "Lookup Got %pU, fsid %d (ret=%d)\n",
+                    &new_op->downcall.resp.lookup.refn.khandle,
+                    new_op->downcall.resp.lookup.refn.fs_id,
+                    ret);
+
+       if (ret < 0) {
+               if (ret == -ENOENT) {
+                       /*
+                        * if no inode was found, add a negative dentry to
+                        * dcache anyway; if we don't, we don't hold expected
+                        * lookup semantics and we most noticeably break
+                        * during directory renames.
+                        *
+                        * however, if the operation failed or exited, do not
+                        * add the dentry (e.g. in the case that a touch is
+                        * issued on a file that already exists that was
+                        * interrupted during this lookup -- no need to add
+                        * another negative dentry for an existing file)
+                        */
+
+                       gossip_debug(GOSSIP_NAME_DEBUG,
+                                    "orangefs_lookup: Adding *negative* dentry "
+                                    "%p for %s\n",
+                                    dentry,
+                                    dentry->d_name.name);
+
+                       d_add(dentry, NULL);
+                       res = NULL;
+                       goto out;
+               }
+
+               /* must be a non-recoverable error */
+               res = ERR_PTR(ret);
+               goto out;
+       }
+
+       inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
+       if (IS_ERR(inode)) {
+               gossip_debug(GOSSIP_NAME_DEBUG,
+                       "error %ld from iget\n", PTR_ERR(inode));
+               res = ERR_CAST(inode);
+               goto out;
+       }
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "%s:%s:%d "
+                    "Found good inode [%lu] with count [%d]\n",
+                    __FILE__,
+                    __func__,
+                    __LINE__,
+                    inode->i_ino,
+                    (int)atomic_read(&inode->i_count));
+
+       /* update dentry/inode pair into dcache */
+       res = d_splice_alias(inode, dentry);
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "Lookup success (inode ct = %d)\n",
+                    (int)atomic_read(&inode->i_count));
+out:
+       op_release(new_op);
+       return res;
+}
+
+/* return 0 on success; non-zero otherwise */
+static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       struct orangefs_inode_s *parent = ORANGEFS_I(dir);
+       struct orangefs_kernel_op_s *new_op;
+       int ret;
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "%s: called on %s\n"
+                    "  (inode %pU): Parent is %pU | fs_id %d\n",
+                    __func__,
+                    dentry->d_name.name,
+                    get_khandle_from_ino(inode),
+                    &parent->refn.khandle,
+                    parent->refn.fs_id);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_REMOVE);
+       if (!new_op)
+               return -ENOMEM;
+
+       new_op->upcall.req.remove.parent_refn = parent->refn;
+       strncpy(new_op->upcall.req.remove.d_name, dentry->d_name.name,
+               ORANGEFS_NAME_MAX);
+
+       ret = service_operation(new_op, "orangefs_unlink",
+                               get_interruptible_flag(inode));
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "%s: service_operation returned:%d:\n",
+                    __func__,
+                    ret);
+
+       op_release(new_op);
+
+       if (!ret) {
+               drop_nlink(inode);
+
+               SetMtimeFlag(parent);
+               dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+               mark_inode_dirty_sync(dir);
+       }
+       return ret;
+}
+
+static int orangefs_symlink(struct inode *dir,
+                        struct dentry *dentry,
+                        const char *symname)
+{
+       struct orangefs_inode_s *parent = ORANGEFS_I(dir);
+       struct orangefs_kernel_op_s *new_op;
+       struct inode *inode;
+       int mode = 755;
+       int ret;
+
+       gossip_debug(GOSSIP_NAME_DEBUG, "%s: called\n", __func__);
+
+       if (!symname)
+               return -EINVAL;
+
+       if (strlen(symname)+1 > ORANGEFS_NAME_MAX)
+               return -ENAMETOOLONG;
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_SYMLINK);
+       if (!new_op)
+               return -ENOMEM;
+
+       new_op->upcall.req.sym.parent_refn = parent->refn;
+
+       fill_default_sys_attrs(new_op->upcall.req.sym.attributes,
+                              ORANGEFS_TYPE_SYMLINK,
+                              mode);
+
+       strncpy(new_op->upcall.req.sym.entry_name,
+               dentry->d_name.name,
+               ORANGEFS_NAME_MAX);
+       strncpy(new_op->upcall.req.sym.target, symname, ORANGEFS_NAME_MAX);
+
+       ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "Symlink Got ORANGEFS handle %pU on fsid %d (ret=%d)\n",
+                    &new_op->downcall.resp.sym.refn.khandle,
+                    new_op->downcall.resp.sym.refn.fs_id, ret);
+
+       if (ret < 0) {
+               gossip_debug(GOSSIP_NAME_DEBUG,
+                           "%s: failed with error code %d\n",
+                           __func__, ret);
+               goto out;
+       }
+
+       inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0,
+                               &new_op->downcall.resp.sym.refn);
+       if (IS_ERR(inode)) {
+               gossip_err
+                   ("*** Failed to allocate orangefs symlink inode\n");
+               ret = PTR_ERR(inode);
+               goto out;
+       }
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "Assigned symlink inode new number of %pU\n",
+                    get_khandle_from_ino(inode));
+
+       d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "Inode (Symlink) %pU -> %s\n",
+                    get_khandle_from_ino(inode),
+                    dentry->d_name.name);
+
+       SetMtimeFlag(parent);
+       dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+       mark_inode_dirty_sync(dir);
+       ret = 0;
+out:
+       op_release(new_op);
+       return ret;
+}
+
+static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct orangefs_inode_s *parent = ORANGEFS_I(dir);
+       struct orangefs_kernel_op_s *new_op;
+       struct inode *inode;
+       int ret;
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
+       if (!new_op)
+               return -ENOMEM;
+
+       new_op->upcall.req.mkdir.parent_refn = parent->refn;
+
+       fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes,
+                             ORANGEFS_TYPE_DIRECTORY, mode);
+
+       strncpy(new_op->upcall.req.mkdir.d_name,
+               dentry->d_name.name, ORANGEFS_NAME_MAX);
+
+       ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
+                    &new_op->downcall.resp.mkdir.refn.khandle,
+                    new_op->downcall.resp.mkdir.refn.fs_id);
+
+       if (ret < 0) {
+               gossip_debug(GOSSIP_NAME_DEBUG,
+                            "%s: failed with error code %d\n",
+                            __func__, ret);
+               goto out;
+       }
+
+       inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0,
+                               &new_op->downcall.resp.mkdir.refn);
+       if (IS_ERR(inode)) {
+               gossip_err("*** Failed to allocate orangefs dir inode\n");
+               ret = PTR_ERR(inode);
+               goto out;
+       }
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "Assigned dir inode new number of %pU\n",
+                    get_khandle_from_ino(inode));
+
+       d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "Inode (Directory) %pU -> %s\n",
+                    get_khandle_from_ino(inode),
+                    dentry->d_name.name);
+
+       /*
+        * NOTE: we have no good way to keep nlink consistent for directories
+        * across clients; keep constant at 1.
+        */
+       SetMtimeFlag(parent);
+       dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+       mark_inode_dirty_sync(dir);
+out:
+       op_release(new_op);
+       return ret;
+}
+
+static int orangefs_rename(struct inode *old_dir,
+                       struct dentry *old_dentry,
+                       struct inode *new_dir,
+                       struct dentry *new_dentry)
+{
+       struct orangefs_kernel_op_s *new_op;
+       int ret;
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "orangefs_rename: called (%s/%s => %s/%s) ct=%d\n",
+                    old_dentry->d_parent->d_name.name,
+                    old_dentry->d_name.name,
+                    new_dentry->d_parent->d_name.name,
+                    new_dentry->d_name.name,
+                    d_count(new_dentry));
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
+       if (!new_op)
+               return -EINVAL;
+
+       new_op->upcall.req.rename.old_parent_refn = ORANGEFS_I(old_dir)->refn;
+       new_op->upcall.req.rename.new_parent_refn = ORANGEFS_I(new_dir)->refn;
+
+       strncpy(new_op->upcall.req.rename.d_old_name,
+               old_dentry->d_name.name,
+               ORANGEFS_NAME_MAX);
+       strncpy(new_op->upcall.req.rename.d_new_name,
+               new_dentry->d_name.name,
+               ORANGEFS_NAME_MAX);
+
+       ret = service_operation(new_op,
+                               "orangefs_rename",
+                               get_interruptible_flag(old_dentry->d_inode));
+
+       gossip_debug(GOSSIP_NAME_DEBUG,
+                    "orangefs_rename: got downcall status %d\n",
+                    ret);
+
+       if (new_dentry->d_inode)
+               new_dentry->d_inode->i_ctime = CURRENT_TIME;
+
+       op_release(new_op);
+       return ret;
+}
+
+/* ORANGEFS implementation of VFS inode operations for directories */
+struct inode_operations orangefs_dir_inode_operations = {
+       .lookup = orangefs_lookup,
+       .get_acl = orangefs_get_acl,
+       .set_acl = orangefs_set_acl,
+       .create = orangefs_create,
+       .unlink = orangefs_unlink,
+       .symlink = orangefs_symlink,
+       .mkdir = orangefs_mkdir,
+       .rmdir = orangefs_unlink,
+       .rename = orangefs_rename,
+       .setattr = orangefs_setattr,
+       .getattr = orangefs_getattr,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
+       .removexattr = generic_removexattr,
+       .listxattr = orangefs_listxattr,
+       .permission = orangefs_permission,
+};
diff --git a/fs/orangefs/orangefs-bufmap.c b/fs/orangefs/orangefs-bufmap.c
new file mode 100644 (file)
index 0000000..1f8acc9
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+
+struct slot_map {
+       int c;
+       wait_queue_head_t q;
+       int count;
+       unsigned long *map;
+};
+
+static struct slot_map rw_map = {
+       .c = -1,
+       .q = __WAIT_QUEUE_HEAD_INITIALIZER(rw_map.q)
+};
+static struct slot_map readdir_map = {
+       .c = -1,
+       .q = __WAIT_QUEUE_HEAD_INITIALIZER(readdir_map.q)
+};
+
+
+static void install(struct slot_map *m, int count, unsigned long *map)
+{
+       spin_lock(&m->q.lock);
+       m->c = m->count = count;
+       m->map = map;
+       wake_up_all_locked(&m->q);
+       spin_unlock(&m->q.lock);
+}
+
+static void mark_killed(struct slot_map *m)
+{
+       spin_lock(&m->q.lock);
+       m->c -= m->count + 1;
+       spin_unlock(&m->q.lock);
+}
+
+static void run_down(struct slot_map *m)
+{
+       DEFINE_WAIT(wait);
+       spin_lock(&m->q.lock);
+       if (m->c != -1) {
+               for (;;) {
+                       if (likely(list_empty(&wait.task_list)))
+                               __add_wait_queue_tail(&m->q, &wait);
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+
+                       if (m->c == -1)
+                               break;
+
+                       spin_unlock(&m->q.lock);
+                       schedule();
+                       spin_lock(&m->q.lock);
+               }
+               __remove_wait_queue(&m->q, &wait);
+               __set_current_state(TASK_RUNNING);
+       }
+       m->map = NULL;
+       spin_unlock(&m->q.lock);
+}
+
+static void put(struct slot_map *m, int slot)
+{
+       int v;
+       spin_lock(&m->q.lock);
+       __clear_bit(slot, m->map);
+       v = ++m->c;
+       if (unlikely(v == 1))   /* no free slots -> one free slot */
+               wake_up_locked(&m->q);
+       else if (unlikely(v == -1))     /* finished dying */
+               wake_up_all_locked(&m->q);
+       spin_unlock(&m->q.lock);
+}
+
+static int wait_for_free(struct slot_map *m)
+{
+       long left = slot_timeout_secs * HZ;
+       DEFINE_WAIT(wait);
+
+       do {
+               long n = left, t;
+               if (likely(list_empty(&wait.task_list)))
+                       __add_wait_queue_tail_exclusive(&m->q, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (m->c > 0)
+                       break;
+
+               if (m->c < 0) {
+                       /* we are waiting for map to be installed */
+                       /* it would better be there soon, or we go away */
+                       if (n > ORANGEFS_BUFMAP_WAIT_TIMEOUT_SECS * HZ)
+                               n = ORANGEFS_BUFMAP_WAIT_TIMEOUT_SECS * HZ;
+               }
+               spin_unlock(&m->q.lock);
+               t = schedule_timeout(n);
+               spin_lock(&m->q.lock);
+               if (unlikely(!t) && n != left && m->c < 0)
+                       left = t;
+               else
+                       left = t + (left - n);
+               if (unlikely(signal_pending(current)))
+                       left = -EINTR;
+       } while (left > 0);
+
+       if (!list_empty(&wait.task_list))
+               list_del(&wait.task_list);
+       else if (left <= 0 && waitqueue_active(&m->q))
+               __wake_up_locked_key(&m->q, TASK_INTERRUPTIBLE, NULL);
+       __set_current_state(TASK_RUNNING);
+
+       if (likely(left > 0))
+               return 0;
+
+       return left < 0 ? -EINTR : -ETIMEDOUT;
+}
+
+static int get(struct slot_map *m)
+{
+       int res = 0;
+       spin_lock(&m->q.lock);
+       if (unlikely(m->c <= 0))
+               res = wait_for_free(m);
+       if (likely(!res)) {
+               m->c--;
+               res = find_first_zero_bit(m->map, m->count);
+               __set_bit(res, m->map);
+       }
+       spin_unlock(&m->q.lock);
+       return res;
+}
+
+/* used to describe mapped buffers */
+struct orangefs_bufmap_desc {
+       void *uaddr;                    /* user space address pointer */
+       struct page **page_array;       /* array of mapped pages */
+       int array_count;                /* size of above arrays */
+       struct list_head list_link;
+};
+
+static struct orangefs_bufmap {
+       int desc_size;
+       int desc_shift;
+       int desc_count;
+       int total_size;
+       int page_count;
+
+       struct page **page_array;
+       struct orangefs_bufmap_desc *desc_array;
+
+       /* array to track usage of buffer descriptors */
+       unsigned long *buffer_index_array;
+
+       /* array to track usage of buffer descriptors for readdir */
+#define N DIV_ROUND_UP(ORANGEFS_READDIR_DEFAULT_DESC_COUNT, BITS_PER_LONG)
+       unsigned long readdir_index_array[N];
+#undef N
+} *__orangefs_bufmap;
+
+static DEFINE_SPINLOCK(orangefs_bufmap_lock);
+
+static void
+orangefs_bufmap_unmap(struct orangefs_bufmap *bufmap)
+{
+       int i;
+
+       for (i = 0; i < bufmap->page_count; i++)
+               page_cache_release(bufmap->page_array[i]);
+}
+
+static void
+orangefs_bufmap_free(struct orangefs_bufmap *bufmap)
+{
+       kfree(bufmap->page_array);
+       kfree(bufmap->desc_array);
+       kfree(bufmap->buffer_index_array);
+       kfree(bufmap);
+}
+
+/*
+ * XXX: Can the size and shift change while the caller gives up the 
+ * XXX: lock between calling this and doing something useful?
+ */
+
+int orangefs_bufmap_size_query(void)
+{
+       struct orangefs_bufmap *bufmap;
+       int size = 0;
+       spin_lock(&orangefs_bufmap_lock);
+       bufmap = __orangefs_bufmap;
+       if (bufmap)
+               size = bufmap->desc_size;
+       spin_unlock(&orangefs_bufmap_lock);
+       return size;
+}
+
+int orangefs_bufmap_shift_query(void)
+{
+       struct orangefs_bufmap *bufmap;
+       int shift = 0;
+       spin_lock(&orangefs_bufmap_lock);
+       bufmap = __orangefs_bufmap;
+       if (bufmap)
+               shift = bufmap->desc_shift;
+       spin_unlock(&orangefs_bufmap_lock);
+       return shift;
+}
+
+static DECLARE_WAIT_QUEUE_HEAD(bufmap_waitq);
+static DECLARE_WAIT_QUEUE_HEAD(readdir_waitq);
+
+/*
+ * orangefs_get_bufmap_init
+ *
+ * If bufmap_init is 1, then the shared memory system, including the
+ * buffer_index_array, is available.  Otherwise, it is not.
+ *
+ * returns the value of bufmap_init
+ */
+int orangefs_get_bufmap_init(void)
+{
+       return __orangefs_bufmap ? 1 : 0;
+}
+
+
+static struct orangefs_bufmap *
+orangefs_bufmap_alloc(struct ORANGEFS_dev_map_desc *user_desc)
+{
+       struct orangefs_bufmap *bufmap;
+
+       bufmap = kzalloc(sizeof(*bufmap), GFP_KERNEL);
+       if (!bufmap)
+               goto out;
+
+       bufmap->total_size = user_desc->total_size;
+       bufmap->desc_count = user_desc->count;
+       bufmap->desc_size = user_desc->size;
+       bufmap->desc_shift = ilog2(bufmap->desc_size);
+
+       bufmap->buffer_index_array =
+               kzalloc(DIV_ROUND_UP(bufmap->desc_count, BITS_PER_LONG), GFP_KERNEL);
+       if (!bufmap->buffer_index_array) {
+               gossip_err("orangefs: could not allocate %d buffer indices\n",
+                               bufmap->desc_count);
+               goto out_free_bufmap;
+       }
+
+       bufmap->desc_array =
+               kcalloc(bufmap->desc_count, sizeof(struct orangefs_bufmap_desc),
+                       GFP_KERNEL);
+       if (!bufmap->desc_array) {
+               gossip_err("orangefs: could not allocate %d descriptors\n",
+                               bufmap->desc_count);
+               goto out_free_index_array;
+       }
+
+       bufmap->page_count = bufmap->total_size / PAGE_SIZE;
+
+       /* allocate storage to track our page mappings */
+       bufmap->page_array =
+               kcalloc(bufmap->page_count, sizeof(struct page *), GFP_KERNEL);
+       if (!bufmap->page_array)
+               goto out_free_desc_array;
+
+       return bufmap;
+
+out_free_desc_array:
+       kfree(bufmap->desc_array);
+out_free_index_array:
+       kfree(bufmap->buffer_index_array);
+out_free_bufmap:
+       kfree(bufmap);
+out:
+       return NULL;
+}
+
+static int
+orangefs_bufmap_map(struct orangefs_bufmap *bufmap,
+               struct ORANGEFS_dev_map_desc *user_desc)
+{
+       int pages_per_desc = bufmap->desc_size / PAGE_SIZE;
+       int offset = 0, ret, i;
+
+       /* map the pages */
+       ret = get_user_pages_fast((unsigned long)user_desc->ptr,
+                            bufmap->page_count, 1, bufmap->page_array);
+
+       if (ret < 0)
+               return ret;
+
+       if (ret != bufmap->page_count) {
+               gossip_err("orangefs error: asked for %d pages, only got %d.\n",
+                               bufmap->page_count, ret);
+
+               for (i = 0; i < ret; i++) {
+                       SetPageError(bufmap->page_array[i]);
+                       page_cache_release(bufmap->page_array[i]);
+               }
+               return -ENOMEM;
+       }
+
+       /*
+        * ideally we want to get kernel space pointers for each page, but
+        * we can't kmap that many pages at once if highmem is being used.
+        * so instead, we just kmap/kunmap the page address each time the
+        * kaddr is needed.
+        */
+       for (i = 0; i < bufmap->page_count; i++)
+               flush_dcache_page(bufmap->page_array[i]);
+
+       /* build a list of available descriptors */
+       for (offset = 0, i = 0; i < bufmap->desc_count; i++) {
+               bufmap->desc_array[i].page_array = &bufmap->page_array[offset];
+               bufmap->desc_array[i].array_count = pages_per_desc;
+               bufmap->desc_array[i].uaddr =
+                   (user_desc->ptr + (i * pages_per_desc * PAGE_SIZE));
+               offset += pages_per_desc;
+       }
+
+       return 0;
+}
+
+/*
+ * orangefs_bufmap_initialize()
+ *
+ * initializes the mapped buffer interface
+ *
+ * returns 0 on success, -errno on failure
+ */
+int orangefs_bufmap_initialize(struct ORANGEFS_dev_map_desc *user_desc)
+{
+       struct orangefs_bufmap *bufmap;
+       int ret = -EINVAL;
+
+       gossip_debug(GOSSIP_BUFMAP_DEBUG,
+                    "orangefs_bufmap_initialize: called (ptr ("
+                    "%p) sz (%d) cnt(%d).\n",
+                    user_desc->ptr,
+                    user_desc->size,
+                    user_desc->count);
+
+       /*
+        * sanity check alignment and size of buffer that caller wants to
+        * work with
+        */
+       if (PAGE_ALIGN((unsigned long)user_desc->ptr) !=
+           (unsigned long)user_desc->ptr) {
+               gossip_err("orangefs error: memory alignment (front). %p\n",
+                          user_desc->ptr);
+               goto out;
+       }
+
+       if (PAGE_ALIGN(((unsigned long)user_desc->ptr + user_desc->total_size))
+           != (unsigned long)(user_desc->ptr + user_desc->total_size)) {
+               gossip_err("orangefs error: memory alignment (back).(%p + %d)\n",
+                          user_desc->ptr,
+                          user_desc->total_size);
+               goto out;
+       }
+
+       if (user_desc->total_size != (user_desc->size * user_desc->count)) {
+               gossip_err("orangefs error: user provided an oddly sized buffer: (%d, %d, %d)\n",
+                          user_desc->total_size,
+                          user_desc->size,
+                          user_desc->count);
+               goto out;
+       }
+
+       if ((user_desc->size % PAGE_SIZE) != 0) {
+               gossip_err("orangefs error: bufmap size not page size divisible (%d).\n",
+                          user_desc->size);
+               goto out;
+       }
+
+       ret = -ENOMEM;
+       bufmap = orangefs_bufmap_alloc(user_desc);
+       if (!bufmap)
+               goto out;
+
+       ret = orangefs_bufmap_map(bufmap, user_desc);
+       if (ret)
+               goto out_free_bufmap;
+
+
+       spin_lock(&orangefs_bufmap_lock);
+       if (__orangefs_bufmap) {
+               spin_unlock(&orangefs_bufmap_lock);
+               gossip_err("orangefs: error: bufmap already initialized.\n");
+               ret = -EINVAL;
+               goto out_unmap_bufmap;
+       }
+       __orangefs_bufmap = bufmap;
+       install(&rw_map,
+               bufmap->desc_count,
+               bufmap->buffer_index_array);
+       install(&readdir_map,
+               ORANGEFS_READDIR_DEFAULT_DESC_COUNT,
+               bufmap->readdir_index_array);
+       spin_unlock(&orangefs_bufmap_lock);
+
+       gossip_debug(GOSSIP_BUFMAP_DEBUG,
+                    "orangefs_bufmap_initialize: exiting normally\n");
+       return 0;
+
+out_unmap_bufmap:
+       orangefs_bufmap_unmap(bufmap);
+out_free_bufmap:
+       orangefs_bufmap_free(bufmap);
+out:
+       return ret;
+}
+
+/*
+ * orangefs_bufmap_finalize()
+ *
+ * shuts down the mapped buffer interface and releases any resources
+ * associated with it
+ *
+ * no return value
+ */
+void orangefs_bufmap_finalize(void)
+{
+       struct orangefs_bufmap *bufmap = __orangefs_bufmap;
+       if (!bufmap)
+               return;
+       gossip_debug(GOSSIP_BUFMAP_DEBUG, "orangefs_bufmap_finalize: called\n");
+       mark_killed(&rw_map);
+       mark_killed(&readdir_map);
+       gossip_debug(GOSSIP_BUFMAP_DEBUG,
+                    "orangefs_bufmap_finalize: exiting normally\n");
+}
+
+void orangefs_bufmap_run_down(void)
+{
+       struct orangefs_bufmap *bufmap = __orangefs_bufmap;
+       if (!bufmap)
+               return;
+       run_down(&rw_map);
+       run_down(&readdir_map);
+       spin_lock(&orangefs_bufmap_lock);
+       __orangefs_bufmap = NULL;
+       spin_unlock(&orangefs_bufmap_lock);
+       orangefs_bufmap_unmap(bufmap);
+       orangefs_bufmap_free(bufmap);
+}
+
+/*
+ * orangefs_bufmap_get()
+ *
+ * gets a free mapped buffer descriptor, will sleep until one becomes
+ * available if necessary
+ *
+ * returns slot on success, -errno on failure
+ */
+int orangefs_bufmap_get(void)
+{
+       return get(&rw_map);
+}
+
+/*
+ * orangefs_bufmap_put()
+ *
+ * returns a mapped buffer descriptor to the collection
+ *
+ * no return value
+ */
+void orangefs_bufmap_put(int buffer_index)
+{
+       put(&rw_map, buffer_index);
+}
+
+/*
+ * orangefs_readdir_index_get()
+ *
+ * gets a free descriptor, will sleep until one becomes
+ * available if necessary.
+ * Although the readdir buffers are not mapped into kernel space
+ * we could do that at a later point of time. Regardless, these
+ * indices are used by the client-core.
+ *
+ * returns slot on success, -errno on failure
+ */
+int orangefs_readdir_index_get(void)
+{
+       return get(&readdir_map);
+}
+
+void orangefs_readdir_index_put(int buffer_index)
+{
+       put(&readdir_map, buffer_index);
+}
+
+/*
+ * we've been handed an iovec, we need to copy it to 
+ * the shared memory descriptor at "buffer_index".
+ */
+int orangefs_bufmap_copy_from_iovec(struct iov_iter *iter,
+                               int buffer_index,
+                               size_t size)
+{
+       struct orangefs_bufmap_desc *to;
+       int i;
+
+       gossip_debug(GOSSIP_BUFMAP_DEBUG,
+                    "%s: buffer_index:%d: size:%zu:\n",
+                    __func__, buffer_index, size);
+
+       to = &__orangefs_bufmap->desc_array[buffer_index];
+       for (i = 0; size; i++) {
+               struct page *page = to->page_array[i];
+               size_t n = size;
+               if (n > PAGE_SIZE)
+                       n = PAGE_SIZE;
+               n = copy_page_from_iter(page, 0, n, iter);
+               if (!n)
+                       return -EFAULT;
+               size -= n;
+       }
+       return 0;
+
+}
+
+/*
+ * we've been handed an iovec, we need to fill it from
+ * the shared memory descriptor at "buffer_index".
+ */
+int orangefs_bufmap_copy_to_iovec(struct iov_iter *iter,
+                                   int buffer_index,
+                                   size_t size)
+{
+       struct orangefs_bufmap_desc *from;
+       int i;
+
+       from = &__orangefs_bufmap->desc_array[buffer_index];
+       gossip_debug(GOSSIP_BUFMAP_DEBUG,
+                    "%s: buffer_index:%d: size:%zu:\n",
+                    __func__, buffer_index, size);
+
+
+       for (i = 0; size; i++) {
+               struct page *page = from->page_array[i];
+               size_t n = size;
+               if (n > PAGE_SIZE)
+                       n = PAGE_SIZE;
+               n = copy_page_to_iter(page, 0, n, iter);
+               if (!n)
+                       return -EFAULT;
+               size -= n;
+       }
+       return 0;
+}
diff --git a/fs/orangefs/orangefs-bufmap.h b/fs/orangefs/orangefs-bufmap.h
new file mode 100644 (file)
index 0000000..71f64f4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+#ifndef __ORANGEFS_BUFMAP_H
+#define __ORANGEFS_BUFMAP_H
+
+int orangefs_bufmap_size_query(void);
+
+int orangefs_bufmap_shift_query(void);
+
+int orangefs_bufmap_initialize(struct ORANGEFS_dev_map_desc *user_desc);
+
+void orangefs_bufmap_finalize(void);
+
+void orangefs_bufmap_run_down(void);
+
+int orangefs_bufmap_get(void);
+
+void orangefs_bufmap_put(int buffer_index);
+
+int orangefs_readdir_index_get(void);
+
+void orangefs_readdir_index_put(int buffer_index);
+
+int orangefs_bufmap_copy_from_iovec(struct iov_iter *iter,
+                               int buffer_index,
+                               size_t size);
+
+int orangefs_bufmap_copy_to_iovec(struct iov_iter *iter,
+                             int buffer_index,
+                             size_t size);
+
+#endif /* __ORANGEFS_BUFMAP_H */
diff --git a/fs/orangefs/orangefs-cache.c b/fs/orangefs/orangefs-cache.c
new file mode 100644 (file)
index 0000000..900a2e3
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+
+/* tags assigned to kernel upcall operations */
+static __u64 next_tag_value;
+static DEFINE_SPINLOCK(next_tag_value_lock);
+
+/* the orangefs memory caches */
+
+/* a cache for orangefs upcall/downcall operations */
+static struct kmem_cache *op_cache;
+
+int op_cache_initialize(void)
+{
+       op_cache = kmem_cache_create("orangefs_op_cache",
+                                    sizeof(struct orangefs_kernel_op_s),
+                                    0,
+                                    ORANGEFS_CACHE_CREATE_FLAGS,
+                                    NULL);
+
+       if (!op_cache) {
+               gossip_err("Cannot create orangefs_op_cache\n");
+               return -ENOMEM;
+       }
+
+       /* initialize our atomic tag counter */
+       spin_lock(&next_tag_value_lock);
+       next_tag_value = 100;
+       spin_unlock(&next_tag_value_lock);
+       return 0;
+}
+
+int op_cache_finalize(void)
+{
+       kmem_cache_destroy(op_cache);
+       return 0;
+}
+
+char *get_opname_string(struct orangefs_kernel_op_s *new_op)
+{
+       if (new_op) {
+               __s32 type = new_op->upcall.type;
+
+               if (type == ORANGEFS_VFS_OP_FILE_IO)
+                       return "OP_FILE_IO";
+               else if (type == ORANGEFS_VFS_OP_LOOKUP)
+                       return "OP_LOOKUP";
+               else if (type == ORANGEFS_VFS_OP_CREATE)
+                       return "OP_CREATE";
+               else if (type == ORANGEFS_VFS_OP_GETATTR)
+                       return "OP_GETATTR";
+               else if (type == ORANGEFS_VFS_OP_REMOVE)
+                       return "OP_REMOVE";
+               else if (type == ORANGEFS_VFS_OP_MKDIR)
+                       return "OP_MKDIR";
+               else if (type == ORANGEFS_VFS_OP_READDIR)
+                       return "OP_READDIR";
+               else if (type == ORANGEFS_VFS_OP_READDIRPLUS)
+                       return "OP_READDIRPLUS";
+               else if (type == ORANGEFS_VFS_OP_SETATTR)
+                       return "OP_SETATTR";
+               else if (type == ORANGEFS_VFS_OP_SYMLINK)
+                       return "OP_SYMLINK";
+               else if (type == ORANGEFS_VFS_OP_RENAME)
+                       return "OP_RENAME";
+               else if (type == ORANGEFS_VFS_OP_STATFS)
+                       return "OP_STATFS";
+               else if (type == ORANGEFS_VFS_OP_TRUNCATE)
+                       return "OP_TRUNCATE";
+               else if (type == ORANGEFS_VFS_OP_MMAP_RA_FLUSH)
+                       return "OP_MMAP_RA_FLUSH";
+               else if (type == ORANGEFS_VFS_OP_FS_MOUNT)
+                       return "OP_FS_MOUNT";
+               else if (type == ORANGEFS_VFS_OP_FS_UMOUNT)
+                       return "OP_FS_UMOUNT";
+               else if (type == ORANGEFS_VFS_OP_GETXATTR)
+                       return "OP_GETXATTR";
+               else if (type == ORANGEFS_VFS_OP_SETXATTR)
+                       return "OP_SETXATTR";
+               else if (type == ORANGEFS_VFS_OP_LISTXATTR)
+                       return "OP_LISTXATTR";
+               else if (type == ORANGEFS_VFS_OP_REMOVEXATTR)
+                       return "OP_REMOVEXATTR";
+               else if (type == ORANGEFS_VFS_OP_PARAM)
+                       return "OP_PARAM";
+               else if (type == ORANGEFS_VFS_OP_PERF_COUNT)
+                       return "OP_PERF_COUNT";
+               else if (type == ORANGEFS_VFS_OP_CANCEL)
+                       return "OP_CANCEL";
+               else if (type == ORANGEFS_VFS_OP_FSYNC)
+                       return "OP_FSYNC";
+               else if (type == ORANGEFS_VFS_OP_FSKEY)
+                       return "OP_FSKEY";
+       }
+       return "OP_UNKNOWN?";
+}
+
+void orangefs_new_tag(struct orangefs_kernel_op_s *op)
+{
+       spin_lock(&next_tag_value_lock);
+       op->tag = next_tag_value++;
+       if (next_tag_value == 0)
+               next_tag_value = 100;
+       spin_unlock(&next_tag_value_lock);
+}
+
+struct orangefs_kernel_op_s *op_alloc(__s32 type)
+{
+       struct orangefs_kernel_op_s *new_op = NULL;
+
+       new_op = kmem_cache_zalloc(op_cache, GFP_KERNEL);
+       if (new_op) {
+               INIT_LIST_HEAD(&new_op->list);
+               spin_lock_init(&new_op->lock);
+               init_completion(&new_op->waitq);
+
+               new_op->upcall.type = ORANGEFS_VFS_OP_INVALID;
+               new_op->downcall.type = ORANGEFS_VFS_OP_INVALID;
+               new_op->downcall.status = -1;
+
+               new_op->op_state = OP_VFS_STATE_UNKNOWN;
+
+               /* initialize the op specific tag and upcall credentials */
+               orangefs_new_tag(new_op);
+               new_op->upcall.type = type;
+               new_op->attempts = 0;
+               gossip_debug(GOSSIP_CACHE_DEBUG,
+                            "Alloced OP (%p: %llu %s)\n",
+                            new_op,
+                            llu(new_op->tag),
+                            get_opname_string(new_op));
+
+               new_op->upcall.uid = from_kuid(current_user_ns(),
+                                              current_fsuid());
+
+               new_op->upcall.gid = from_kgid(current_user_ns(),
+                                              current_fsgid());
+       } else {
+               gossip_err("op_alloc: kmem_cache_zalloc failed!\n");
+       }
+       return new_op;
+}
+
+void op_release(struct orangefs_kernel_op_s *orangefs_op)
+{
+       if (orangefs_op) {
+               gossip_debug(GOSSIP_CACHE_DEBUG,
+                            "Releasing OP (%p: %llu)\n",
+                            orangefs_op,
+                            llu(orangefs_op->tag));
+               kmem_cache_free(op_cache, orangefs_op);
+       } else {
+               gossip_err("NULL pointer in op_release\n");
+       }
+}
diff --git a/fs/orangefs/orangefs-debug.h b/fs/orangefs/orangefs-debug.h
new file mode 100644 (file)
index 0000000..387db17
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/* This file just defines debugging masks to be used with the gossip
+ * logging utility.  All debugging masks for ORANGEFS are kept here to make
+ * sure we don't have collisions.
+ */
+
+#ifndef __ORANGEFS_DEBUG_H
+#define __ORANGEFS_DEBUG_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+#define        GOSSIP_NO_DEBUG                 (__u64)0
+
+#define GOSSIP_SUPER_DEBUG             ((__u64)1 << 0)
+#define GOSSIP_INODE_DEBUG             ((__u64)1 << 1)
+#define GOSSIP_FILE_DEBUG              ((__u64)1 << 2)
+#define GOSSIP_DIR_DEBUG               ((__u64)1 << 3)
+#define GOSSIP_UTILS_DEBUG             ((__u64)1 << 4)
+#define GOSSIP_WAIT_DEBUG              ((__u64)1 << 5)
+#define GOSSIP_ACL_DEBUG               ((__u64)1 << 6)
+#define GOSSIP_DCACHE_DEBUG            ((__u64)1 << 7)
+#define GOSSIP_DEV_DEBUG               ((__u64)1 << 8)
+#define GOSSIP_NAME_DEBUG              ((__u64)1 << 9)
+#define GOSSIP_BUFMAP_DEBUG            ((__u64)1 << 10)
+#define GOSSIP_CACHE_DEBUG             ((__u64)1 << 11)
+#define GOSSIP_DEBUGFS_DEBUG           ((__u64)1 << 12)
+#define GOSSIP_XATTR_DEBUG             ((__u64)1 << 13)
+#define GOSSIP_INIT_DEBUG              ((__u64)1 << 14)
+#define GOSSIP_SYSFS_DEBUG             ((__u64)1 << 15)
+
+#define GOSSIP_MAX_NR                 16
+#define GOSSIP_MAX_DEBUG              (((__u64)1 << GOSSIP_MAX_NR) - 1)
+
+/*function prototypes*/
+__u64 ORANGEFS_kmod_eventlog_to_mask(const char *event_logging);
+__u64 ORANGEFS_debug_eventlog_to_mask(const char *event_logging);
+char *ORANGEFS_debug_mask_to_eventlog(__u64 mask);
+char *ORANGEFS_kmod_mask_to_eventlog(__u64 mask);
+
+/* a private internal type */
+struct __keyword_mask_s {
+       const char *keyword;
+       __u64 mask_val;
+};
+
+/*
+ * Map all kmod keywords to kmod debug masks here. Keep this
+ * structure "packed":
+ *
+ *   "all" is always last...
+ *
+ *   keyword     mask_val     index
+ *     foo          1           0
+ *     bar          2           1
+ *     baz          4           2
+ *     qux          8           3
+ *      .           .           .
+ */
+static struct __keyword_mask_s s_kmod_keyword_mask_map[] = {
+       {"super", GOSSIP_SUPER_DEBUG},
+       {"inode", GOSSIP_INODE_DEBUG},
+       {"file", GOSSIP_FILE_DEBUG},
+       {"dir", GOSSIP_DIR_DEBUG},
+       {"utils", GOSSIP_UTILS_DEBUG},
+       {"wait", GOSSIP_WAIT_DEBUG},
+       {"acl", GOSSIP_ACL_DEBUG},
+       {"dcache", GOSSIP_DCACHE_DEBUG},
+       {"dev", GOSSIP_DEV_DEBUG},
+       {"name", GOSSIP_NAME_DEBUG},
+       {"bufmap", GOSSIP_BUFMAP_DEBUG},
+       {"cache", GOSSIP_CACHE_DEBUG},
+       {"debugfs", GOSSIP_DEBUGFS_DEBUG},
+       {"xattr", GOSSIP_XATTR_DEBUG},
+       {"init", GOSSIP_INIT_DEBUG},
+       {"sysfs", GOSSIP_SYSFS_DEBUG},
+       {"none", GOSSIP_NO_DEBUG},
+       {"all", GOSSIP_MAX_DEBUG}
+};
+
+static const int num_kmod_keyword_mask_map = (int)
+       (sizeof(s_kmod_keyword_mask_map) / sizeof(struct __keyword_mask_s));
+
+#endif /* __ORANGEFS_DEBUG_H */
diff --git a/fs/orangefs/orangefs-debugfs.c b/fs/orangefs/orangefs-debugfs.c
new file mode 100644 (file)
index 0000000..19670b8
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * What:               /sys/kernel/debug/orangefs/debug-help
+ * Date:               June 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     List of client and kernel debug keywords.
+ *
+ *
+ * What:               /sys/kernel/debug/orangefs/client-debug
+ * Date:               June 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Debug setting for "the client", the userspace
+ *                     helper for the kernel module.
+ *
+ *
+ * What:               /sys/kernel/debug/orangefs/kernel-debug
+ * Date:               June 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Debug setting for the orangefs kernel module.
+ *
+ *                     Any of the keywords, or comma-separated lists
+ *                     of keywords, from debug-help can be catted to
+ *                     client-debug or kernel-debug.
+ *
+ *                     "none", "all" and "verbose" are special keywords
+ *                     for client-debug. Setting client-debug to "all"
+ *                     is kind of like trying to drink water from a
+ *                     fire hose, "verbose" triggers most of the same
+ *                     output except for the constant flow of output
+ *                     from the main wait loop.
+ *
+ *                     "none" and "all" are similar settings for kernel-debug
+ *                     no need for a "verbose".
+ */
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+
+#include <linux/uaccess.h>
+
+#include "orangefs-debugfs.h"
+#include "protocol.h"
+#include "orangefs-kernel.h"
+
+static int orangefs_debug_disabled = 1;
+
+static int orangefs_debug_help_open(struct inode *, struct file *);
+
+const struct file_operations debug_help_fops = {
+       .open           = orangefs_debug_help_open,
+       .read           = seq_read,
+       .release        = seq_release,
+       .llseek         = seq_lseek,
+};
+
+static void *help_start(struct seq_file *, loff_t *);
+static void *help_next(struct seq_file *, void *, loff_t *);
+static void help_stop(struct seq_file *, void *);
+static int help_show(struct seq_file *, void *);
+
+static const struct seq_operations help_debug_ops = {
+       .start  = help_start,
+       .next   = help_next,
+       .stop   = help_stop,
+       .show   = help_show,
+};
+
+/*
+ * Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and
+ * ORANGEFS_KMOD_DEBUG_FILE.
+ */
+static DEFINE_MUTEX(orangefs_debug_lock);
+
+int orangefs_debug_open(struct inode *, struct file *);
+
+static ssize_t orangefs_debug_read(struct file *,
+                                char __user *,
+                                size_t,
+                                loff_t *);
+
+static ssize_t orangefs_debug_write(struct file *,
+                                 const char __user *,
+                                 size_t,
+                                 loff_t *);
+
+static const struct file_operations kernel_debug_fops = {
+       .open           = orangefs_debug_open,
+       .read           = orangefs_debug_read,
+       .write          = orangefs_debug_write,
+       .llseek         = generic_file_llseek,
+};
+
+/*
+ * initialize kmod debug operations, create orangefs debugfs dir and
+ * ORANGEFS_KMOD_DEBUG_HELP_FILE.
+ */
+int orangefs_debugfs_init(void)
+{
+
+       int rc = -ENOMEM;
+
+       debug_dir = debugfs_create_dir("orangefs", NULL);
+       if (!debug_dir) {
+               pr_info("%s: debugfs_create_dir failed.\n", __func__);
+               goto out;
+       }
+
+       help_file_dentry = debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE,
+                                 0444,
+                                 debug_dir,
+                                 debug_help_string,
+                                 &debug_help_fops);
+       if (!help_file_dentry) {
+               pr_info("%s: debugfs_create_file failed.\n", __func__);
+               goto out;
+       }
+
+       orangefs_debug_disabled = 0;
+       rc = 0;
+
+out:
+
+       return rc;
+}
+
+void orangefs_debugfs_cleanup(void)
+{
+       if (debug_dir)
+               debugfs_remove_recursive(debug_dir);
+}
+
+/* open ORANGEFS_KMOD_DEBUG_HELP_FILE */
+static int orangefs_debug_help_open(struct inode *inode, struct file *file)
+{
+       int rc = -ENODEV;
+       int ret;
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                    "orangefs_debug_help_open: start\n");
+
+       if (orangefs_debug_disabled)
+               goto out;
+
+       ret = seq_open(file, &help_debug_ops);
+       if (ret)
+               goto out;
+
+       ((struct seq_file *)(file->private_data))->private = inode->i_private;
+
+       rc = 0;
+
+out:
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                    "orangefs_debug_help_open: rc:%d:\n",
+                    rc);
+       return rc;
+}
+
+/*
+ * I think start always gets called again after stop. Start
+ * needs to return NULL when it is done. The whole "payload"
+ * in this case is a single (long) string, so by the second
+ * time we get to start (pos = 1), we're done.
+ */
+static void *help_start(struct seq_file *m, loff_t *pos)
+{
+       void *payload = NULL;
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n");
+
+       if (*pos == 0)
+               payload = m->private;
+
+       return payload;
+}
+
+static void *help_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n");
+
+       return NULL;
+}
+
+static void help_stop(struct seq_file *m, void *p)
+{
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n");
+}
+
+static int help_show(struct seq_file *m, void *v)
+{
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_show: start\n");
+
+       seq_puts(m, v);
+
+       return 0;
+}
+
+/*
+ * initialize the kernel-debug file.
+ */
+int orangefs_kernel_debug_init(void)
+{
+       int rc = -ENOMEM;
+       struct dentry *ret;
+       char *k_buffer = NULL;
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
+
+       k_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
+       if (!k_buffer)
+               goto out;
+
+       if (strlen(kernel_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
+               strcpy(k_buffer, kernel_debug_string);
+               strcat(k_buffer, "\n");
+       } else {
+               strcpy(k_buffer, "none\n");
+               pr_info("%s: overflow 1!\n", __func__);
+       }
+
+       ret = debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE,
+                                 0444,
+                                 debug_dir,
+                                 k_buffer,
+                                 &kernel_debug_fops);
+       if (!ret) {
+               pr_info("%s: failed to create %s.\n",
+                       __func__,
+                       ORANGEFS_KMOD_DEBUG_FILE);
+               goto out;
+       }
+
+       rc = 0;
+
+out:
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
+       return rc;
+}
+
+/*
+ * initialize the client-debug file.
+ */
+int orangefs_client_debug_init(void)
+{
+
+       int rc = -ENOMEM;
+       char *c_buffer = NULL;
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
+
+       c_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
+       if (!c_buffer)
+               goto out;
+
+       if (strlen(client_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
+               strcpy(c_buffer, client_debug_string);
+               strcat(c_buffer, "\n");
+       } else {
+               strcpy(c_buffer, "none\n");
+               pr_info("%s: overflow! 2\n", __func__);
+       }
+
+       client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE,
+                                                 0444,
+                                                 debug_dir,
+                                                 c_buffer,
+                                                 &kernel_debug_fops);
+       if (!client_debug_dentry) {
+               pr_info("%s: failed to create updated %s.\n",
+                       __func__,
+                       ORANGEFS_CLIENT_DEBUG_FILE);
+               goto out;
+       }
+
+       rc = 0;
+
+out:
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
+       return rc;
+}
+
+/* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/
+int orangefs_debug_open(struct inode *inode, struct file *file)
+{
+       int rc = -ENODEV;
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                    "%s: orangefs_debug_disabled: %d\n",
+                    __func__,
+                    orangefs_debug_disabled);
+
+       if (orangefs_debug_disabled)
+               goto out;
+
+       rc = 0;
+       mutex_lock(&orangefs_debug_lock);
+       file->private_data = inode->i_private;
+       mutex_unlock(&orangefs_debug_lock);
+
+out:
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                    "orangefs_debug_open: rc: %d\n",
+                    rc);
+       return rc;
+}
+
+static ssize_t orangefs_debug_read(struct file *file,
+                                char __user *ubuf,
+                                size_t count,
+                                loff_t *ppos)
+{
+       char *buf;
+       int sprintf_ret;
+       ssize_t read_ret = -ENOMEM;
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_read: start\n");
+
+       buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
+       if (!buf)
+               goto out;
+
+       mutex_lock(&orangefs_debug_lock);
+       sprintf_ret = sprintf(buf, "%s", (char *)file->private_data);
+       mutex_unlock(&orangefs_debug_lock);
+
+       read_ret = simple_read_from_buffer(ubuf, count, ppos, buf, sprintf_ret);
+
+       kfree(buf);
+
+out:
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                    "orangefs_debug_read: ret: %zu\n",
+                    read_ret);
+
+       return read_ret;
+}
+
+static ssize_t orangefs_debug_write(struct file *file,
+                                 const char __user *ubuf,
+                                 size_t count,
+                                 loff_t *ppos)
+{
+       char *buf;
+       int rc = -EFAULT;
+       size_t silly = 0;
+       char *debug_string;
+       struct orangefs_kernel_op_s *new_op = NULL;
+       struct client_debug_mask c_mask = { NULL, 0, 0 };
+
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+               "orangefs_debug_write: %s\n",
+               file->f_path.dentry->d_name.name);
+
+       /*
+        * Thwart users who try to jamb a ridiculous number
+        * of bytes into the debug file...
+        */
+       if (count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1) {
+               silly = count;
+               count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1;
+       }
+
+       buf = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
+       if (!buf)
+               goto out;
+
+       if (copy_from_user(buf, ubuf, count - 1)) {
+               gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                            "%s: copy_from_user failed!\n",
+                            __func__);
+               goto out;
+       }
+
+       /*
+        * Map the keyword string from userspace into a valid debug mask.
+        * The mapping process involves mapping the human-inputted string
+        * into a valid mask, and then rebuilding the string from the
+        * verified valid mask.
+        *
+        * A service operation is required to set a new client-side
+        * debug mask.
+        */
+       if (!strcmp(file->f_path.dentry->d_name.name,
+                   ORANGEFS_KMOD_DEBUG_FILE)) {
+               debug_string_to_mask(buf, &gossip_debug_mask, 0);
+               debug_mask_to_string(&gossip_debug_mask, 0);
+               debug_string = kernel_debug_string;
+               gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                            "New kernel debug string is %s\n",
+                            kernel_debug_string);
+       } else {
+               /* Can't reset client debug mask if client is not running. */
+               if (is_daemon_in_service()) {
+                       pr_info("%s: Client not running :%d:\n",
+                               __func__,
+                               is_daemon_in_service());
+                       goto out;
+               }
+
+               debug_string_to_mask(buf, &c_mask, 1);
+               debug_mask_to_string(&c_mask, 1);
+               debug_string = client_debug_string;
+
+               new_op = op_alloc(ORANGEFS_VFS_OP_PARAM);
+               if (!new_op) {
+                       pr_info("%s: op_alloc failed!\n", __func__);
+                       goto out;
+               }
+
+               new_op->upcall.req.param.op =
+                       ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES;
+               new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET;
+               memset(new_op->upcall.req.param.s_value,
+                      0,
+                      ORANGEFS_MAX_DEBUG_STRING_LEN);
+               sprintf(new_op->upcall.req.param.s_value,
+                       "%llx %llx\n",
+                       c_mask.mask1,
+                       c_mask.mask2);
+
+               /* service_operation returns 0 on success... */
+               rc = service_operation(new_op,
+                                      "orangefs_param",
+                                       ORANGEFS_OP_INTERRUPTIBLE);
+
+               if (rc)
+                       gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                                    "%s: service_operation failed! rc:%d:\n",
+                                    __func__,
+                                    rc);
+
+               op_release(new_op);
+       }
+
+       mutex_lock(&orangefs_debug_lock);
+       memset(file->f_inode->i_private, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
+       sprintf((char *)file->f_inode->i_private, "%s\n", debug_string);
+       mutex_unlock(&orangefs_debug_lock);
+
+       *ppos += count;
+       if (silly)
+               rc = silly;
+       else
+               rc = count;
+
+out:
+       gossip_debug(GOSSIP_DEBUGFS_DEBUG,
+                    "orangefs_debug_write: rc: %d\n",
+                    rc);
+       kfree(buf);
+       return rc;
+}
diff --git a/fs/orangefs/orangefs-debugfs.h b/fs/orangefs/orangefs-debugfs.h
new file mode 100644 (file)
index 0000000..e4828c0
--- /dev/null
@@ -0,0 +1,3 @@
+int orangefs_debugfs_init(void);
+int orangefs_kernel_debug_init(void);
+void orangefs_debugfs_cleanup(void);
diff --git a/fs/orangefs/orangefs-dev-proto.h b/fs/orangefs/orangefs-dev-proto.h
new file mode 100644 (file)
index 0000000..9eac9d9
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+#ifndef _ORANGEFS_DEV_PROTO_H
+#define _ORANGEFS_DEV_PROTO_H
+
+/*
+ * types and constants shared between user space and kernel space for
+ * device interaction using a common protocol
+ */
+
+/*
+ * valid orangefs kernel operation types
+ */
+#define ORANGEFS_VFS_OP_INVALID           0xFF000000
+#define ORANGEFS_VFS_OP_FILE_IO        0xFF000001
+#define ORANGEFS_VFS_OP_LOOKUP         0xFF000002
+#define ORANGEFS_VFS_OP_CREATE         0xFF000003
+#define ORANGEFS_VFS_OP_GETATTR        0xFF000004
+#define ORANGEFS_VFS_OP_REMOVE         0xFF000005
+#define ORANGEFS_VFS_OP_MKDIR          0xFF000006
+#define ORANGEFS_VFS_OP_READDIR        0xFF000007
+#define ORANGEFS_VFS_OP_SETATTR        0xFF000008
+#define ORANGEFS_VFS_OP_SYMLINK        0xFF000009
+#define ORANGEFS_VFS_OP_RENAME         0xFF00000A
+#define ORANGEFS_VFS_OP_STATFS         0xFF00000B
+#define ORANGEFS_VFS_OP_TRUNCATE       0xFF00000C
+#define ORANGEFS_VFS_OP_MMAP_RA_FLUSH  0xFF00000D
+#define ORANGEFS_VFS_OP_FS_MOUNT       0xFF00000E
+#define ORANGEFS_VFS_OP_FS_UMOUNT      0xFF00000F
+#define ORANGEFS_VFS_OP_GETXATTR       0xFF000010
+#define ORANGEFS_VFS_OP_SETXATTR          0xFF000011
+#define ORANGEFS_VFS_OP_LISTXATTR         0xFF000012
+#define ORANGEFS_VFS_OP_REMOVEXATTR       0xFF000013
+#define ORANGEFS_VFS_OP_PARAM          0xFF000014
+#define ORANGEFS_VFS_OP_PERF_COUNT     0xFF000015
+#define ORANGEFS_VFS_OP_CANCEL            0xFF00EE00
+#define ORANGEFS_VFS_OP_FSYNC          0xFF00EE01
+#define ORANGEFS_VFS_OP_FSKEY             0xFF00EE02
+#define ORANGEFS_VFS_OP_READDIRPLUS       0xFF00EE03
+
+/*
+ * Misc constants. Please retain them as multiples of 8!
+ * Otherwise 32-64 bit interactions will be messed up :)
+ */
+#define ORANGEFS_MAX_DEBUG_STRING_LEN  0x00000400
+#define ORANGEFS_MAX_DEBUG_ARRAY_LEN   0x00000800
+
+/*
+ * The maximum number of directory entries in a single request is 96.
+ * XXX: Why can this not be higher. The client-side code can handle up to 512.
+ * XXX: What happens if we expect more than the client can return?
+ */
+#define ORANGEFS_MAX_DIRENT_COUNT_READDIR 96
+
+#include "upcall.h"
+#include "downcall.h"
+
+#endif
diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h
new file mode 100644 (file)
index 0000000..a9925e2
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ *  The ORANGEFS Linux kernel support allows ORANGEFS volumes to be mounted and
+ *  accessed through the Linux VFS (i.e. using standard I/O system calls).
+ *  This support is only needed on clients that wish to mount the file system.
+ *
+ */
+
+/*
+ *  Declarations and macros for the ORANGEFS Linux kernel support.
+ */
+
+#ifndef __ORANGEFSKERNEL_H
+#define __ORANGEFSKERNEL_H
+
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/statfs.h>
+#include <linux/backing-dev.h>
+#include <linux/device.h>
+#include <linux/mpage.h>
+#include <linux/namei.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+
+#include <linux/aio.h>
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/compat.h>
+#include <linux/mount.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/uio.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <linux/dcache.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/rwsem.h>
+#include <linux/xattr.h>
+#include <linux/exportfs.h>
+
+#include <asm/unaligned.h>
+
+#include "orangefs-dev-proto.h"
+
+#ifdef ORANGEFS_KERNEL_DEBUG
+#define ORANGEFS_DEFAULT_OP_TIMEOUT_SECS       10
+#else
+#define ORANGEFS_DEFAULT_OP_TIMEOUT_SECS       20
+#endif
+
+#define ORANGEFS_BUFMAP_WAIT_TIMEOUT_SECS   30
+
+#define ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS     900     /* 15 minutes */
+
+#define ORANGEFS_REQDEVICE_NAME          "pvfs2-req"
+
+#define ORANGEFS_DEVREQ_MAGIC             0x20030529
+#define ORANGEFS_LINK_MAX                 0x000000FF
+#define ORANGEFS_PURGE_RETRY_COUNT     0x00000005
+#define ORANGEFS_MAX_NUM_OPTIONS          0x00000004
+#define ORANGEFS_MAX_MOUNT_OPT_LEN        0x00000080
+#define ORANGEFS_MAX_FSKEY_LEN            64
+
+#define MAX_DEV_REQ_UPSIZE (2 * sizeof(__s32) +   \
+sizeof(__u64) + sizeof(struct orangefs_upcall_s))
+#define MAX_DEV_REQ_DOWNSIZE (2 * sizeof(__s32) + \
+sizeof(__u64) + sizeof(struct orangefs_downcall_s))
+
+/*
+ * valid orangefs kernel operation states
+ *
+ * unknown  - op was just initialized
+ * waiting  - op is on request_list (upward bound)
+ * inprogr  - op is in progress (waiting for downcall)
+ * serviced - op has matching downcall; ok
+ * purged   - op has to start a timer since client-core
+ *            exited uncleanly before servicing op
+ * given up - submitter has given up waiting for it
+ */
+enum orangefs_vfs_op_states {
+       OP_VFS_STATE_UNKNOWN = 0,
+       OP_VFS_STATE_WAITING = 1,
+       OP_VFS_STATE_INPROGR = 2,
+       OP_VFS_STATE_SERVICED = 4,
+       OP_VFS_STATE_PURGED = 8,
+       OP_VFS_STATE_GIVEN_UP = 16,
+};
+
+/*
+ * An array of client_debug_mask will be built to hold debug keyword/mask
+ * values fetched from userspace.
+ */
+struct client_debug_mask {
+       char *keyword;
+       __u64 mask1;
+       __u64 mask2;
+};
+
+/*
+ * orangefs kernel memory related flags
+ */
+
+#if ((defined ORANGEFS_KERNEL_DEBUG) && (defined CONFIG_DEBUG_SLAB))
+#define ORANGEFS_CACHE_CREATE_FLAGS SLAB_RED_ZONE
+#else
+#define ORANGEFS_CACHE_CREATE_FLAGS 0
+#endif /* ((defined ORANGEFS_KERNEL_DEBUG) && (defined CONFIG_DEBUG_SLAB)) */
+
+/* orangefs xattr and acl related defines */
+#define ORANGEFS_XATTR_INDEX_POSIX_ACL_ACCESS  1
+#define ORANGEFS_XATTR_INDEX_POSIX_ACL_DEFAULT 2
+#define ORANGEFS_XATTR_INDEX_TRUSTED           3
+#define ORANGEFS_XATTR_INDEX_DEFAULT           4
+
+#define ORANGEFS_XATTR_NAME_ACL_ACCESS XATTR_NAME_POSIX_ACL_ACCESS
+#define ORANGEFS_XATTR_NAME_ACL_DEFAULT XATTR_NAME_POSIX_ACL_DEFAULT
+#define ORANGEFS_XATTR_NAME_TRUSTED_PREFIX "trusted."
+#define ORANGEFS_XATTR_NAME_DEFAULT_PREFIX ""
+
+/* these functions are defined in orangefs-utils.c */
+int orangefs_prepare_cdm_array(char *debug_array_string);
+int orangefs_prepare_debugfs_help_string(int);
+
+/* defined in orangefs-debugfs.c */
+int orangefs_client_debug_init(void);
+
+void debug_string_to_mask(char *, void *, int);
+void do_c_mask(int, char *, struct client_debug_mask **);
+void do_k_mask(int, char *, __u64 **);
+
+void debug_mask_to_string(void *, int);
+void do_k_string(void *, int);
+void do_c_string(void *, int);
+int check_amalgam_keyword(void *, int);
+int keyword_is_amalgam(char *);
+
+/*these variables are defined in orangefs-mod.c */
+extern char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
+extern char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
+extern char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
+extern unsigned int kernel_mask_set_mod_init;
+
+extern int orangefs_init_acl(struct inode *inode, struct inode *dir);
+extern const struct xattr_handler *orangefs_xattr_handlers[];
+
+extern struct posix_acl *orangefs_get_acl(struct inode *inode, int type);
+extern int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+
+/*
+ * Redefine xtvec structure so that we could move helper functions out of
+ * the define
+ */
+struct xtvec {
+       __kernel_off_t xtv_off;         /* must be off_t */
+       __kernel_size_t xtv_len;        /* must be size_t */
+};
+
+/*
+ * orangefs data structures
+ */
+struct orangefs_kernel_op_s {
+       enum orangefs_vfs_op_states op_state;
+       __u64 tag;
+
+       /*
+        * Set uses_shared_memory to non zero if this operation uses
+        * shared memory. If true, then a retry on the op must also
+        * get a new shared memory buffer and re-populate it.
+        * Cancels don't care - it only matters for service_operation()
+        * retry logics and cancels don't go through it anymore. It
+        * safely stays non-zero when we use it as slot_to_free.
+        */
+       union {
+               int uses_shared_memory;
+               int slot_to_free;
+       };
+
+       struct orangefs_upcall_s upcall;
+       struct orangefs_downcall_s downcall;
+
+       struct completion waitq;
+       spinlock_t lock;
+
+       int attempts;
+
+       struct list_head list;
+};
+
+#define set_op_state_waiting(op)     ((op)->op_state = OP_VFS_STATE_WAITING)
+#define set_op_state_inprogress(op)  ((op)->op_state = OP_VFS_STATE_INPROGR)
+#define set_op_state_given_up(op)  ((op)->op_state = OP_VFS_STATE_GIVEN_UP)
+static inline void set_op_state_serviced(struct orangefs_kernel_op_s *op)
+{
+       op->op_state = OP_VFS_STATE_SERVICED;
+       complete(&op->waitq);
+}
+
+#define op_state_waiting(op)     ((op)->op_state & OP_VFS_STATE_WAITING)
+#define op_state_in_progress(op) ((op)->op_state & OP_VFS_STATE_INPROGR)
+#define op_state_serviced(op)    ((op)->op_state & OP_VFS_STATE_SERVICED)
+#define op_state_purged(op)      ((op)->op_state & OP_VFS_STATE_PURGED)
+#define op_state_given_up(op)    ((op)->op_state & OP_VFS_STATE_GIVEN_UP)
+#define op_is_cancel(op)         ((op)->upcall.type == ORANGEFS_VFS_OP_CANCEL)
+
+void op_release(struct orangefs_kernel_op_s *op);
+
+extern void orangefs_bufmap_put(int);
+static inline void put_cancel(struct orangefs_kernel_op_s *op)
+{
+       orangefs_bufmap_put(op->slot_to_free);
+       op_release(op);
+}
+
+static inline void set_op_state_purged(struct orangefs_kernel_op_s *op)
+{
+       spin_lock(&op->lock);
+       if (unlikely(op_is_cancel(op))) {
+               list_del_init(&op->list);
+               spin_unlock(&op->lock);
+               put_cancel(op);
+       } else {
+               op->op_state |= OP_VFS_STATE_PURGED;
+               complete(&op->waitq);
+               spin_unlock(&op->lock);
+       }
+}
+
+/* per inode private orangefs info */
+struct orangefs_inode_s {
+       struct orangefs_object_kref refn;
+       char link_target[ORANGEFS_NAME_MAX];
+       __s64 blksize;
+       /*
+        * Reading/Writing Extended attributes need to acquire the appropriate
+        * reader/writer semaphore on the orangefs_inode_s structure.
+        */
+       struct rw_semaphore xattr_sem;
+
+       struct inode vfs_inode;
+       sector_t last_failed_block_index_read;
+
+       /*
+        * State of in-memory attributes not yet flushed to disk associated
+        * with this object
+        */
+       unsigned long pinode_flags;
+};
+
+#define P_ATIME_FLAG 0
+#define P_MTIME_FLAG 1
+#define P_CTIME_FLAG 2
+#define P_MODE_FLAG  3
+
+#define ClearAtimeFlag(pinode) clear_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
+#define SetAtimeFlag(pinode)   set_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
+#define AtimeFlag(pinode)      test_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
+
+#define ClearMtimeFlag(pinode) clear_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
+#define SetMtimeFlag(pinode)   set_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
+#define MtimeFlag(pinode)      test_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
+
+#define ClearCtimeFlag(pinode) clear_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
+#define SetCtimeFlag(pinode)   set_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
+#define CtimeFlag(pinode)      test_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
+
+#define ClearModeFlag(pinode) clear_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
+#define SetModeFlag(pinode)   set_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
+#define ModeFlag(pinode)      test_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
+
+/* per superblock private orangefs info */
+struct orangefs_sb_info_s {
+       struct orangefs_khandle root_khandle;
+       __s32 fs_id;
+       int id;
+       int flags;
+#define ORANGEFS_OPT_INTR      0x01
+#define ORANGEFS_OPT_LOCAL_LOCK        0x02
+       char devname[ORANGEFS_MAX_SERVER_ADDR_LEN];
+       struct super_block *sb;
+       int mount_pending;
+       struct list_head list;
+};
+
+/*
+ * structure that holds the state of any async I/O operation issued
+ * through the VFS. Needed especially to handle cancellation requests
+ * or even completion notification so that the VFS client-side daemon
+ * can free up its vfs_request slots.
+ */
+struct orangefs_kiocb_s {
+       /* the pointer to the task that initiated the AIO */
+       struct task_struct *tsk;
+
+       /* pointer to the kiocb that kicked this operation */
+       struct kiocb *kiocb;
+
+       /* buffer index that was used for the I/O */
+       struct orangefs_bufmap *bufmap;
+       int buffer_index;
+
+       /* orangefs kernel operation type */
+       struct orangefs_kernel_op_s *op;
+
+       /* The user space buffers from/to which I/O is being staged */
+       struct iovec *iov;
+
+       /* number of elements in the iovector */
+       unsigned long nr_segs;
+
+       /* set to indicate the type of the operation */
+       int rw;
+
+       /* file offset */
+       loff_t offset;
+
+       /* and the count in bytes */
+       size_t bytes_to_be_copied;
+
+       ssize_t bytes_copied;
+       int needs_cleanup;
+};
+
+struct orangefs_stats {
+       unsigned long cache_hits;
+       unsigned long cache_misses;
+       unsigned long reads;
+       unsigned long writes;
+};
+
+extern struct orangefs_stats g_orangefs_stats;
+
+/*
+ * NOTE: See Documentation/filesystems/porting for information
+ * on implementing FOO_I and properly accessing fs private data
+ */
+static inline struct orangefs_inode_s *ORANGEFS_I(struct inode *inode)
+{
+       return container_of(inode, struct orangefs_inode_s, vfs_inode);
+}
+
+static inline struct orangefs_sb_info_s *ORANGEFS_SB(struct super_block *sb)
+{
+       return (struct orangefs_sb_info_s *) sb->s_fs_info;
+}
+
+/* ino_t descends from "unsigned long", 8 bytes, 64 bits. */
+static inline ino_t orangefs_khandle_to_ino(struct orangefs_khandle *khandle)
+{
+       union {
+               unsigned char u[8];
+               __u64 ino;
+       } ihandle;
+
+       ihandle.u[0] = khandle->u[0] ^ khandle->u[4];
+       ihandle.u[1] = khandle->u[1] ^ khandle->u[5];
+       ihandle.u[2] = khandle->u[2] ^ khandle->u[6];
+       ihandle.u[3] = khandle->u[3] ^ khandle->u[7];
+       ihandle.u[4] = khandle->u[12] ^ khandle->u[8];
+       ihandle.u[5] = khandle->u[13] ^ khandle->u[9];
+       ihandle.u[6] = khandle->u[14] ^ khandle->u[10];
+       ihandle.u[7] = khandle->u[15] ^ khandle->u[11];
+
+       return ihandle.ino;
+}
+
+static inline struct orangefs_khandle *get_khandle_from_ino(struct inode *inode)
+{
+       return &(ORANGEFS_I(inode)->refn.khandle);
+}
+
+static inline __s32 get_fsid_from_ino(struct inode *inode)
+{
+       return ORANGEFS_I(inode)->refn.fs_id;
+}
+
+static inline ino_t get_ino_from_khandle(struct inode *inode)
+{
+       struct orangefs_khandle *khandle;
+       ino_t ino;
+
+       khandle = get_khandle_from_ino(inode);
+       ino = orangefs_khandle_to_ino(khandle);
+       return ino;
+}
+
+static inline ino_t get_parent_ino_from_dentry(struct dentry *dentry)
+{
+       return get_ino_from_khandle(dentry->d_parent->d_inode);
+}
+
+static inline int is_root_handle(struct inode *inode)
+{
+       gossip_debug(GOSSIP_DCACHE_DEBUG,
+                    "%s: root handle: %pU, this handle: %pU:\n",
+                    __func__,
+                    &ORANGEFS_SB(inode->i_sb)->root_khandle,
+                    get_khandle_from_ino(inode));
+
+       if (ORANGEFS_khandle_cmp(&(ORANGEFS_SB(inode->i_sb)->root_khandle),
+                            get_khandle_from_ino(inode)))
+               return 0;
+       else
+               return 1;
+}
+
+static inline int match_handle(struct orangefs_khandle resp_handle,
+                              struct inode *inode)
+{
+       gossip_debug(GOSSIP_DCACHE_DEBUG,
+                    "%s: one handle: %pU, another handle:%pU:\n",
+                    __func__,
+                    &resp_handle,
+                    get_khandle_from_ino(inode));
+
+       if (ORANGEFS_khandle_cmp(&resp_handle, get_khandle_from_ino(inode)))
+               return 0;
+       else
+               return 1;
+}
+
+/*
+ * defined in orangefs-cache.c
+ */
+int op_cache_initialize(void);
+int op_cache_finalize(void);
+struct orangefs_kernel_op_s *op_alloc(__s32 type);
+void orangefs_new_tag(struct orangefs_kernel_op_s *op);
+char *get_opname_string(struct orangefs_kernel_op_s *new_op);
+
+int orangefs_inode_cache_initialize(void);
+int orangefs_inode_cache_finalize(void);
+
+/*
+ * defined in orangefs-mod.c
+ */
+void purge_inprogress_ops(void);
+
+/*
+ * defined in waitqueue.c
+ */
+void purge_waiting_ops(void);
+
+/*
+ * defined in super.c
+ */
+struct dentry *orangefs_mount(struct file_system_type *fst,
+                          int flags,
+                          const char *devname,
+                          void *data);
+
+void orangefs_kill_sb(struct super_block *sb);
+int orangefs_remount(struct orangefs_sb_info_s *);
+
+int fsid_key_table_initialize(void);
+void fsid_key_table_finalize(void);
+
+/*
+ * defined in inode.c
+ */
+__u32 convert_to_orangefs_mask(unsigned long lite_mask);
+struct inode *orangefs_new_inode(struct super_block *sb,
+                             struct inode *dir,
+                             int mode,
+                             dev_t dev,
+                             struct orangefs_object_kref *ref);
+
+int orangefs_setattr(struct dentry *dentry, struct iattr *iattr);
+
+int orangefs_getattr(struct vfsmount *mnt,
+                 struct dentry *dentry,
+                 struct kstat *kstat);
+
+int orangefs_permission(struct inode *inode, int mask);
+
+/*
+ * defined in xattr.c
+ */
+int orangefs_setxattr(struct dentry *dentry,
+                  const char *name,
+                  const void *value,
+                  size_t size,
+                  int flags);
+
+ssize_t orangefs_getxattr(struct dentry *dentry,
+                      const char *name,
+                      void *buffer,
+                      size_t size);
+
+ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+
+/*
+ * defined in namei.c
+ */
+struct inode *orangefs_iget(struct super_block *sb,
+                        struct orangefs_object_kref *ref);
+
+ssize_t orangefs_inode_read(struct inode *inode,
+                           struct iov_iter *iter,
+                           loff_t *offset,
+                           loff_t readahead_size);
+
+/*
+ * defined in devorangefs-req.c
+ */
+int orangefs_dev_init(void);
+void orangefs_dev_cleanup(void);
+int is_daemon_in_service(void);
+bool __is_daemon_in_service(void);
+
+/*
+ * defined in orangefs-utils.c
+ */
+__s32 fsid_of_op(struct orangefs_kernel_op_s *op);
+
+int orangefs_flush_inode(struct inode *inode);
+
+ssize_t orangefs_inode_getxattr(struct inode *inode,
+                            const char *prefix,
+                            const char *name,
+                            void *buffer,
+                            size_t size);
+
+int orangefs_inode_setxattr(struct inode *inode,
+                        const char *prefix,
+                        const char *name,
+                        const void *value,
+                        size_t size,
+                        int flags);
+
+int orangefs_inode_getattr(struct inode *inode, int new, int size);
+
+int orangefs_inode_check_changed(struct inode *inode);
+
+int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr);
+
+void orangefs_make_bad_inode(struct inode *inode);
+
+int orangefs_unmount_sb(struct super_block *sb);
+
+bool orangefs_cancel_op_in_progress(struct orangefs_kernel_op_s *op);
+
+int orangefs_normalize_to_errno(__s32 error_code);
+
+extern struct mutex devreq_mutex;
+extern struct mutex request_mutex;
+extern int debug;
+extern int op_timeout_secs;
+extern int slot_timeout_secs;
+extern struct list_head orangefs_superblocks;
+extern spinlock_t orangefs_superblocks_lock;
+extern struct list_head orangefs_request_list;
+extern spinlock_t orangefs_request_list_lock;
+extern wait_queue_head_t orangefs_request_list_waitq;
+extern struct list_head *htable_ops_in_progress;
+extern spinlock_t htable_ops_in_progress_lock;
+extern int hash_table_size;
+
+extern const struct address_space_operations orangefs_address_operations;
+extern struct backing_dev_info orangefs_backing_dev_info;
+extern struct inode_operations orangefs_file_inode_operations;
+extern const struct file_operations orangefs_file_operations;
+extern struct inode_operations orangefs_symlink_inode_operations;
+extern struct inode_operations orangefs_dir_inode_operations;
+extern const struct file_operations orangefs_dir_operations;
+extern const struct dentry_operations orangefs_dentry_operations;
+extern const struct file_operations orangefs_devreq_file_operations;
+
+extern wait_queue_head_t orangefs_bufmap_init_waitq;
+
+/*
+ * misc convenience macros
+ */
+
+#define ORANGEFS_OP_INTERRUPTIBLE 1   /* service_operation() is interruptible */
+#define ORANGEFS_OP_PRIORITY      2   /* service_operation() is high priority */
+#define ORANGEFS_OP_CANCELLATION  4   /* this is a cancellation */
+#define ORANGEFS_OP_NO_MUTEX      8   /* don't acquire request_mutex */
+#define ORANGEFS_OP_ASYNC         16  /* Queue it, but don't wait */
+
+int service_operation(struct orangefs_kernel_op_s *op,
+                     const char *op_name,
+                     int flags);
+
+#define get_interruptible_flag(inode) \
+       ((ORANGEFS_SB(inode->i_sb)->flags & ORANGEFS_OPT_INTR) ? \
+               ORANGEFS_OP_INTERRUPTIBLE : 0)
+
+#define fill_default_sys_attrs(sys_attr, type, mode)                   \
+do {                                                                   \
+       sys_attr.owner = from_kuid(current_user_ns(), current_fsuid()); \
+       sys_attr.group = from_kgid(current_user_ns(), current_fsgid()); \
+       sys_attr.perms = ORANGEFS_util_translate_mode(mode);            \
+       sys_attr.mtime = 0;                                             \
+       sys_attr.atime = 0;                                             \
+       sys_attr.ctime = 0;                                             \
+       sys_attr.mask = ORANGEFS_ATTR_SYS_ALL_SETABLE;                  \
+} while (0)
+
+static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size)
+{
+#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
+       mutex_lock(&inode->i_mutex);
+#endif
+       i_size_write(inode, i_size);
+#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
+       mutex_unlock(&inode->i_mutex);
+#endif
+}
+
+#endif /* __ORANGEFSKERNEL_H */
diff --git a/fs/orangefs/orangefs-mod.c b/fs/orangefs/orangefs-mod.c
new file mode 100644 (file)
index 0000000..6f072a8
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * Changes by Acxiom Corporation to add proc file handler for pvfs2 client
+ * parameters, Copyright Acxiom Corporation, 2005.
+ *
+ * See COPYING in top-level directory.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-debugfs.h"
+#include "orangefs-sysfs.h"
+
+/* ORANGEFS_VERSION is a ./configure define */
+#ifndef ORANGEFS_VERSION
+#define ORANGEFS_VERSION "upstream"
+#endif
+
+/*
+ * global variables declared here
+ */
+
+/* array of client debug keyword/mask values */
+struct client_debug_mask *cdm_array;
+int cdm_element_count;
+
+char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN] = "none";
+char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
+char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
+
+char *debug_help_string;
+int help_string_initialized;
+struct dentry *help_file_dentry;
+struct dentry *client_debug_dentry;
+struct dentry *debug_dir;
+int client_verbose_index;
+int client_all_index;
+struct orangefs_stats g_orangefs_stats;
+
+/* the size of the hash tables for ops in progress */
+int hash_table_size = 509;
+
+static ulong module_parm_debug_mask;
+__u64 gossip_debug_mask;
+struct client_debug_mask client_debug_mask = { NULL, 0, 0 };
+unsigned int kernel_mask_set_mod_init; /* implicitly false */
+int op_timeout_secs = ORANGEFS_DEFAULT_OP_TIMEOUT_SECS;
+int slot_timeout_secs = ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ORANGEFS Development Team");
+MODULE_DESCRIPTION("The Linux Kernel VFS interface to ORANGEFS");
+MODULE_PARM_DESC(module_parm_debug_mask, "debugging level (see orangefs-debug.h for values)");
+MODULE_PARM_DESC(op_timeout_secs, "Operation timeout in seconds");
+MODULE_PARM_DESC(slot_timeout_secs, "Slot timeout in seconds");
+MODULE_PARM_DESC(hash_table_size,
+                "size of hash table for operations in progress");
+
+static struct file_system_type orangefs_fs_type = {
+       .name = "pvfs2",
+       .mount = orangefs_mount,
+       .kill_sb = orangefs_kill_sb,
+       .owner = THIS_MODULE,
+};
+
+module_param(hash_table_size, int, 0);
+module_param(module_parm_debug_mask, ulong, 0644);
+module_param(op_timeout_secs, int, 0);
+module_param(slot_timeout_secs, int, 0);
+
+/* synchronizes the request device file */
+DEFINE_MUTEX(devreq_mutex);
+
+/*
+ * Blocks non-priority requests from being queued for servicing.  This
+ * could be used for protecting the request list data structure, but
+ * for now it's only being used to stall the op addition to the request
+ * list
+ */
+DEFINE_MUTEX(request_mutex);
+
+/* hash table for storing operations waiting for matching downcall */
+struct list_head *htable_ops_in_progress;
+DEFINE_SPINLOCK(htable_ops_in_progress_lock);
+
+/* list for queueing upcall operations */
+LIST_HEAD(orangefs_request_list);
+
+/* used to protect the above orangefs_request_list */
+DEFINE_SPINLOCK(orangefs_request_list_lock);
+
+/* used for incoming request notification */
+DECLARE_WAIT_QUEUE_HEAD(orangefs_request_list_waitq);
+
+static int __init orangefs_init(void)
+{
+       int ret = -1;
+       __u32 i = 0;
+
+       /* convert input debug mask to a 64-bit unsigned integer */
+       gossip_debug_mask = (unsigned long long) module_parm_debug_mask;
+
+       /*
+        * set the kernel's gossip debug string; invalid mask values will
+        * be ignored.
+        */
+       debug_mask_to_string(&gossip_debug_mask, 0);
+
+       /* remove any invalid values from the mask */
+       debug_string_to_mask(kernel_debug_string, &gossip_debug_mask, 0);
+
+       /*
+        * if the mask has a non-zero value, then indicate that the mask
+        * was set when the kernel module was loaded.  The orangefs dev ioctl
+        * command will look at this boolean to determine if the kernel's
+        * debug mask should be overwritten when the client-core is started.
+        */
+       if (gossip_debug_mask != 0)
+               kernel_mask_set_mod_init = true;
+
+       pr_info("%s: called with debug mask: :%s: :%llx:\n",
+               __func__,
+               kernel_debug_string,
+               (unsigned long long)gossip_debug_mask);
+
+       ret = bdi_init(&orangefs_backing_dev_info);
+
+       if (ret)
+               return ret;
+
+       if (op_timeout_secs < 0)
+               op_timeout_secs = 0;
+
+       if (slot_timeout_secs < 0)
+               slot_timeout_secs = 0;
+
+       /* initialize global book keeping data structures */
+       ret = op_cache_initialize();
+       if (ret < 0)
+               goto err;
+
+       ret = orangefs_inode_cache_initialize();
+       if (ret < 0)
+               goto cleanup_op;
+
+       htable_ops_in_progress =
+           kcalloc(hash_table_size, sizeof(struct list_head), GFP_KERNEL);
+       if (!htable_ops_in_progress) {
+               gossip_err("Failed to initialize op hashtable");
+               ret = -ENOMEM;
+               goto cleanup_inode;
+       }
+
+       /* initialize a doubly linked at each hash table index */
+       for (i = 0; i < hash_table_size; i++)
+               INIT_LIST_HEAD(&htable_ops_in_progress[i]);
+
+       ret = fsid_key_table_initialize();
+       if (ret < 0)
+               goto cleanup_progress_table;
+
+       /*
+        * Build the contents of /sys/kernel/debug/orangefs/debug-help
+        * from the keywords in the kernel keyword/mask array.
+        *
+        * The keywords in the client keyword/mask array are
+        * unknown at boot time.
+        *
+        * orangefs_prepare_debugfs_help_string will be used again
+        * later to rebuild the debug-help file after the client starts
+        * and passes along the needed info. The argument signifies
+        * which time orangefs_prepare_debugfs_help_string is being
+        * called.
+        */
+       ret = orangefs_prepare_debugfs_help_string(1);
+       if (ret)
+               goto cleanup_key_table;
+
+       ret = orangefs_debugfs_init();
+       if (ret)
+               goto debugfs_init_failed;
+
+       ret = orangefs_kernel_debug_init();
+       if (ret)
+               goto kernel_debug_init_failed;
+
+       ret = orangefs_sysfs_init();
+       if (ret)
+               goto sysfs_init_failed;
+
+       /* Initialize the orangefsdev subsystem. */
+       ret = orangefs_dev_init();
+       if (ret < 0) {
+               gossip_err("%s: could not initialize device subsystem %d!\n",
+                          __func__,
+                          ret);
+               goto cleanup_device;
+       }
+
+       ret = register_filesystem(&orangefs_fs_type);
+       if (ret == 0) {
+               pr_info("orangefs: module version %s loaded\n", ORANGEFS_VERSION);
+               ret = 0;
+               goto out;
+       }
+
+       orangefs_sysfs_exit();
+
+cleanup_device:
+       orangefs_dev_cleanup();
+
+sysfs_init_failed:
+
+kernel_debug_init_failed:
+
+debugfs_init_failed:
+       orangefs_debugfs_cleanup();
+
+cleanup_key_table:
+       fsid_key_table_finalize();
+
+cleanup_progress_table:
+       kfree(htable_ops_in_progress);
+
+cleanup_inode:
+       orangefs_inode_cache_finalize();
+
+cleanup_op:
+       op_cache_finalize();
+
+err:
+       bdi_destroy(&orangefs_backing_dev_info);
+
+out:
+       return ret;
+}
+
+static void __exit orangefs_exit(void)
+{
+       int i = 0;
+       gossip_debug(GOSSIP_INIT_DEBUG, "orangefs: orangefs_exit called\n");
+
+       unregister_filesystem(&orangefs_fs_type);
+       orangefs_debugfs_cleanup();
+       orangefs_sysfs_exit();
+       fsid_key_table_finalize();
+       orangefs_dev_cleanup();
+       BUG_ON(!list_empty(&orangefs_request_list));
+       for (i = 0; i < hash_table_size; i++)
+               BUG_ON(!list_empty(&htable_ops_in_progress[i]));
+
+       orangefs_inode_cache_finalize();
+       op_cache_finalize();
+
+       kfree(htable_ops_in_progress);
+
+       bdi_destroy(&orangefs_backing_dev_info);
+
+       pr_info("orangefs: module version %s unloaded\n", ORANGEFS_VERSION);
+}
+
+/*
+ * What we do in this function is to walk the list of operations
+ * that are in progress in the hash table and mark them as purged as well.
+ */
+void purge_inprogress_ops(void)
+{
+       int i;
+
+       for (i = 0; i < hash_table_size; i++) {
+               struct orangefs_kernel_op_s *op;
+               struct orangefs_kernel_op_s *next;
+
+               spin_lock(&htable_ops_in_progress_lock);
+               list_for_each_entry_safe(op,
+                                        next,
+                                        &htable_ops_in_progress[i],
+                                        list) {
+                       set_op_state_purged(op);
+                       gossip_debug(GOSSIP_DEV_DEBUG,
+                                    "%s: op:%s: op_state:%d: process:%s:\n",
+                                    __func__,
+                                    get_opname_string(op),
+                                    op->op_state,
+                                    current->comm);
+               }
+               spin_unlock(&htable_ops_in_progress_lock);
+       }
+}
+
+module_init(orangefs_init);
+module_exit(orangefs_exit);
diff --git a/fs/orangefs/orangefs-sysfs.c b/fs/orangefs/orangefs-sysfs.c
new file mode 100644 (file)
index 0000000..5c03113
--- /dev/null
@@ -0,0 +1,1772 @@
+/*
+ * Documentation/ABI/stable/orangefs-sysfs:
+ *
+ * What:               /sys/fs/orangefs/perf_counter_reset
+ * Date:               June 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     echo a 0 or a 1 into perf_counter_reset to
+ *                     reset all the counters in
+ *                     /sys/fs/orangefs/perf_counters
+ *                     except ones with PINT_PERF_PRESERVE set.
+ *
+ *
+ * What:               /sys/fs/orangefs/perf_counters/...
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Counters and settings for various caches.
+ *                     Read only.
+ *
+ *
+ * What:               /sys/fs/orangefs/perf_time_interval_secs
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Length of perf counter intervals in
+ *                     seconds.
+ *
+ *
+ * What:               /sys/fs/orangefs/perf_history_size
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     The perf_counters cache statistics have N, or
+ *                     perf_history_size, samples. The default is
+ *                     one.
+ *
+ *                     Every perf_time_interval_secs the (first)
+ *                     samples are reset.
+ *
+ *                     If N is greater than one, the "current" set
+ *                     of samples is reset, and the samples from the
+ *                     other N-1 intervals remain available.
+ *
+ *
+ * What:               /sys/fs/orangefs/op_timeout_secs
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Service operation timeout in seconds.
+ *
+ *
+ * What:               /sys/fs/orangefs/slot_timeout_secs
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     "Slot" timeout in seconds. A "slot"
+ *                     is an indexed buffer in the shared
+ *                     memory segment used for communication
+ *                     between the kernel module and userspace.
+ *                     Slots are requested and waited for,
+ *                     the wait times out after slot_timeout_secs.
+ *
+ *
+ * What:               /sys/fs/orangefs/acache/...
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Attribute cache configurable settings.
+ *
+ *
+ * What:               /sys/fs/orangefs/ncache/...
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Name cache configurable settings.
+ *
+ *
+ * What:               /sys/fs/orangefs/capcache/...
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Capability cache configurable settings.
+ *
+ *
+ * What:               /sys/fs/orangefs/ccache/...
+ * Date:               Jun 2015
+ * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Description:
+ *                     Credential cache configurable settings.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-sysfs.h"
+
+#define ORANGEFS_KOBJ_ID "orangefs"
+#define ACACHE_KOBJ_ID "acache"
+#define CAPCACHE_KOBJ_ID "capcache"
+#define CCACHE_KOBJ_ID "ccache"
+#define NCACHE_KOBJ_ID "ncache"
+#define PC_KOBJ_ID "pc"
+#define STATS_KOBJ_ID "stats"
+
+struct orangefs_obj {
+       struct kobject kobj;
+       int op_timeout_secs;
+       int perf_counter_reset;
+       int perf_history_size;
+       int perf_time_interval_secs;
+       int slot_timeout_secs;
+};
+
+struct acache_orangefs_obj {
+       struct kobject kobj;
+       int hard_limit;
+       int reclaim_percentage;
+       int soft_limit;
+       int timeout_msecs;
+};
+
+struct capcache_orangefs_obj {
+       struct kobject kobj;
+       int hard_limit;
+       int reclaim_percentage;
+       int soft_limit;
+       int timeout_secs;
+};
+
+struct ccache_orangefs_obj {
+       struct kobject kobj;
+       int hard_limit;
+       int reclaim_percentage;
+       int soft_limit;
+       int timeout_secs;
+};
+
+struct ncache_orangefs_obj {
+       struct kobject kobj;
+       int hard_limit;
+       int reclaim_percentage;
+       int soft_limit;
+       int timeout_msecs;
+};
+
+struct pc_orangefs_obj {
+       struct kobject kobj;
+       char *acache;
+       char *capcache;
+       char *ncache;
+};
+
+struct stats_orangefs_obj {
+       struct kobject kobj;
+       int reads;
+       int writes;
+};
+
+struct orangefs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct orangefs_obj *orangefs_obj,
+                       struct orangefs_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct orangefs_obj *orangefs_obj,
+                        struct orangefs_attribute *attr,
+                        const char *buf,
+                        size_t count);
+};
+
+struct acache_orangefs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct acache_orangefs_obj *acache_orangefs_obj,
+                       struct acache_orangefs_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct acache_orangefs_obj *acache_orangefs_obj,
+                        struct acache_orangefs_attribute *attr,
+                        const char *buf,
+                        size_t count);
+};
+
+struct capcache_orangefs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct capcache_orangefs_obj *capcache_orangefs_obj,
+                       struct capcache_orangefs_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct capcache_orangefs_obj *capcache_orangefs_obj,
+                        struct capcache_orangefs_attribute *attr,
+                        const char *buf,
+                        size_t count);
+};
+
+struct ccache_orangefs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct ccache_orangefs_obj *ccache_orangefs_obj,
+                       struct ccache_orangefs_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct ccache_orangefs_obj *ccache_orangefs_obj,
+                        struct ccache_orangefs_attribute *attr,
+                        const char *buf,
+                        size_t count);
+};
+
+struct ncache_orangefs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct ncache_orangefs_obj *ncache_orangefs_obj,
+                       struct ncache_orangefs_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct ncache_orangefs_obj *ncache_orangefs_obj,
+                        struct ncache_orangefs_attribute *attr,
+                        const char *buf,
+                        size_t count);
+};
+
+struct pc_orangefs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct pc_orangefs_obj *pc_orangefs_obj,
+                       struct pc_orangefs_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct pc_orangefs_obj *pc_orangefs_obj,
+                        struct pc_orangefs_attribute *attr,
+                        const char *buf,
+                        size_t count);
+};
+
+struct stats_orangefs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct stats_orangefs_obj *stats_orangefs_obj,
+                       struct stats_orangefs_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct stats_orangefs_obj *stats_orangefs_obj,
+                        struct stats_orangefs_attribute *attr,
+                        const char *buf,
+                        size_t count);
+};
+
+static ssize_t orangefs_attr_show(struct kobject *kobj,
+                                 struct attribute *attr,
+                                 char *buf)
+{
+       struct orangefs_attribute *attribute;
+       struct orangefs_obj *orangefs_obj;
+       int rc;
+
+       attribute = container_of(attr, struct orangefs_attribute, attr);
+       orangefs_obj = container_of(kobj, struct orangefs_obj, kobj);
+
+       if (!attribute->show) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->show(orangefs_obj, attribute, buf);
+
+out:
+       return rc;
+}
+
+static ssize_t orangefs_attr_store(struct kobject *kobj,
+                                  struct attribute *attr,
+                                  const char *buf,
+                                  size_t len)
+{
+       struct orangefs_attribute *attribute;
+       struct orangefs_obj *orangefs_obj;
+       int rc;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "orangefs_attr_store: start\n");
+
+       attribute = container_of(attr, struct orangefs_attribute, attr);
+       orangefs_obj = container_of(kobj, struct orangefs_obj, kobj);
+
+       if (!attribute->store) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->store(orangefs_obj, attribute, buf, len);
+
+out:
+       return rc;
+}
+
+static const struct sysfs_ops orangefs_sysfs_ops = {
+       .show = orangefs_attr_show,
+       .store = orangefs_attr_store,
+};
+
+static ssize_t acache_orangefs_attr_show(struct kobject *kobj,
+                                        struct attribute *attr,
+                                        char *buf)
+{
+       struct acache_orangefs_attribute *attribute;
+       struct acache_orangefs_obj *acache_orangefs_obj;
+       int rc;
+
+       attribute = container_of(attr, struct acache_orangefs_attribute, attr);
+       acache_orangefs_obj =
+               container_of(kobj, struct acache_orangefs_obj, kobj);
+
+       if (!attribute->show) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->show(acache_orangefs_obj, attribute, buf);
+
+out:
+       return rc;
+}
+
+static ssize_t acache_orangefs_attr_store(struct kobject *kobj,
+                                         struct attribute *attr,
+                                         const char *buf,
+                                         size_t len)
+{
+       struct acache_orangefs_attribute *attribute;
+       struct acache_orangefs_obj *acache_orangefs_obj;
+       int rc;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "acache_orangefs_attr_store: start\n");
+
+       attribute = container_of(attr, struct acache_orangefs_attribute, attr);
+       acache_orangefs_obj =
+               container_of(kobj, struct acache_orangefs_obj, kobj);
+
+       if (!attribute->store) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->store(acache_orangefs_obj, attribute, buf, len);
+
+out:
+       return rc;
+}
+
+static const struct sysfs_ops acache_orangefs_sysfs_ops = {
+       .show = acache_orangefs_attr_show,
+       .store = acache_orangefs_attr_store,
+};
+
+static ssize_t capcache_orangefs_attr_show(struct kobject *kobj,
+                                          struct attribute *attr,
+                                          char *buf)
+{
+       struct capcache_orangefs_attribute *attribute;
+       struct capcache_orangefs_obj *capcache_orangefs_obj;
+       int rc;
+
+       attribute =
+               container_of(attr, struct capcache_orangefs_attribute, attr);
+       capcache_orangefs_obj =
+               container_of(kobj, struct capcache_orangefs_obj, kobj);
+
+       if (!attribute->show) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->show(capcache_orangefs_obj, attribute, buf);
+
+out:
+       return rc;
+}
+
+static ssize_t capcache_orangefs_attr_store(struct kobject *kobj,
+                                           struct attribute *attr,
+                                           const char *buf,
+                                           size_t len)
+{
+       struct capcache_orangefs_attribute *attribute;
+       struct capcache_orangefs_obj *capcache_orangefs_obj;
+       int rc;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "capcache_orangefs_attr_store: start\n");
+
+       attribute =
+               container_of(attr, struct capcache_orangefs_attribute, attr);
+       capcache_orangefs_obj =
+               container_of(kobj, struct capcache_orangefs_obj, kobj);
+
+       if (!attribute->store) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->store(capcache_orangefs_obj, attribute, buf, len);
+
+out:
+       return rc;
+}
+
+static const struct sysfs_ops capcache_orangefs_sysfs_ops = {
+       .show = capcache_orangefs_attr_show,
+       .store = capcache_orangefs_attr_store,
+};
+
+static ssize_t ccache_orangefs_attr_show(struct kobject *kobj,
+                                        struct attribute *attr,
+                                        char *buf)
+{
+       struct ccache_orangefs_attribute *attribute;
+       struct ccache_orangefs_obj *ccache_orangefs_obj;
+       int rc;
+
+       attribute =
+               container_of(attr, struct ccache_orangefs_attribute, attr);
+       ccache_orangefs_obj =
+               container_of(kobj, struct ccache_orangefs_obj, kobj);
+
+       if (!attribute->show) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->show(ccache_orangefs_obj, attribute, buf);
+
+out:
+       return rc;
+}
+
+static ssize_t ccache_orangefs_attr_store(struct kobject *kobj,
+                                         struct attribute *attr,
+                                         const char *buf,
+                                         size_t len)
+{
+       struct ccache_orangefs_attribute *attribute;
+       struct ccache_orangefs_obj *ccache_orangefs_obj;
+       int rc;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "ccache_orangefs_attr_store: start\n");
+
+       attribute =
+               container_of(attr, struct ccache_orangefs_attribute, attr);
+       ccache_orangefs_obj =
+               container_of(kobj, struct ccache_orangefs_obj, kobj);
+
+       if (!attribute->store) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->store(ccache_orangefs_obj, attribute, buf, len);
+
+out:
+       return rc;
+}
+
+static const struct sysfs_ops ccache_orangefs_sysfs_ops = {
+       .show = ccache_orangefs_attr_show,
+       .store = ccache_orangefs_attr_store,
+};
+
+static ssize_t ncache_orangefs_attr_show(struct kobject *kobj,
+                                        struct attribute *attr,
+                                        char *buf)
+{
+       struct ncache_orangefs_attribute *attribute;
+       struct ncache_orangefs_obj *ncache_orangefs_obj;
+       int rc;
+
+       attribute = container_of(attr, struct ncache_orangefs_attribute, attr);
+       ncache_orangefs_obj =
+               container_of(kobj, struct ncache_orangefs_obj, kobj);
+
+       if (!attribute->show) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->show(ncache_orangefs_obj, attribute, buf);
+
+out:
+       return rc;
+}
+
+static ssize_t ncache_orangefs_attr_store(struct kobject *kobj,
+                                         struct attribute *attr,
+                                         const char *buf,
+                                         size_t len)
+{
+       struct ncache_orangefs_attribute *attribute;
+       struct ncache_orangefs_obj *ncache_orangefs_obj;
+       int rc;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "ncache_orangefs_attr_store: start\n");
+
+       attribute = container_of(attr, struct ncache_orangefs_attribute, attr);
+       ncache_orangefs_obj =
+               container_of(kobj, struct ncache_orangefs_obj, kobj);
+
+       if (!attribute->store) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->store(ncache_orangefs_obj, attribute, buf, len);
+
+out:
+       return rc;
+}
+
+static const struct sysfs_ops ncache_orangefs_sysfs_ops = {
+       .show = ncache_orangefs_attr_show,
+       .store = ncache_orangefs_attr_store,
+};
+
+static ssize_t pc_orangefs_attr_show(struct kobject *kobj,
+                                    struct attribute *attr,
+                                    char *buf)
+{
+       struct pc_orangefs_attribute *attribute;
+       struct pc_orangefs_obj *pc_orangefs_obj;
+       int rc;
+
+       attribute = container_of(attr, struct pc_orangefs_attribute, attr);
+       pc_orangefs_obj =
+               container_of(kobj, struct pc_orangefs_obj, kobj);
+
+       if (!attribute->show) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->show(pc_orangefs_obj, attribute, buf);
+
+out:
+       return rc;
+}
+
+static const struct sysfs_ops pc_orangefs_sysfs_ops = {
+       .show = pc_orangefs_attr_show,
+};
+
+static ssize_t stats_orangefs_attr_show(struct kobject *kobj,
+                                       struct attribute *attr,
+                                       char *buf)
+{
+       struct stats_orangefs_attribute *attribute;
+       struct stats_orangefs_obj *stats_orangefs_obj;
+       int rc;
+
+       attribute = container_of(attr, struct stats_orangefs_attribute, attr);
+       stats_orangefs_obj =
+               container_of(kobj, struct stats_orangefs_obj, kobj);
+
+       if (!attribute->show) {
+               rc = -EIO;
+               goto out;
+       }
+
+       rc = attribute->show(stats_orangefs_obj, attribute, buf);
+
+out:
+       return rc;
+}
+
+static const struct sysfs_ops stats_orangefs_sysfs_ops = {
+       .show = stats_orangefs_attr_show,
+};
+
+static void orangefs_release(struct kobject *kobj)
+{
+       struct orangefs_obj *orangefs_obj;
+
+       orangefs_obj = container_of(kobj, struct orangefs_obj, kobj);
+       kfree(orangefs_obj);
+}
+
+static void acache_orangefs_release(struct kobject *kobj)
+{
+       struct acache_orangefs_obj *acache_orangefs_obj;
+
+       acache_orangefs_obj =
+               container_of(kobj, struct acache_orangefs_obj, kobj);
+       kfree(acache_orangefs_obj);
+}
+
+static void capcache_orangefs_release(struct kobject *kobj)
+{
+       struct capcache_orangefs_obj *capcache_orangefs_obj;
+
+       capcache_orangefs_obj =
+               container_of(kobj, struct capcache_orangefs_obj, kobj);
+       kfree(capcache_orangefs_obj);
+}
+
+static void ccache_orangefs_release(struct kobject *kobj)
+{
+       struct ccache_orangefs_obj *ccache_orangefs_obj;
+
+       ccache_orangefs_obj =
+               container_of(kobj, struct ccache_orangefs_obj, kobj);
+       kfree(ccache_orangefs_obj);
+}
+
+static void ncache_orangefs_release(struct kobject *kobj)
+{
+       struct ncache_orangefs_obj *ncache_orangefs_obj;
+
+       ncache_orangefs_obj =
+               container_of(kobj, struct ncache_orangefs_obj, kobj);
+       kfree(ncache_orangefs_obj);
+}
+
+static void pc_orangefs_release(struct kobject *kobj)
+{
+       struct pc_orangefs_obj *pc_orangefs_obj;
+
+       pc_orangefs_obj =
+               container_of(kobj, struct pc_orangefs_obj, kobj);
+       kfree(pc_orangefs_obj);
+}
+
+static void stats_orangefs_release(struct kobject *kobj)
+{
+       struct stats_orangefs_obj *stats_orangefs_obj;
+
+       stats_orangefs_obj =
+               container_of(kobj, struct stats_orangefs_obj, kobj);
+       kfree(stats_orangefs_obj);
+}
+
+static ssize_t sysfs_int_show(char *kobj_id, char *buf, void *attr)
+{
+       int rc = -EIO;
+       struct orangefs_attribute *orangefs_attr;
+       struct stats_orangefs_attribute *stats_orangefs_attr;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG, "sysfs_int_show: id:%s:\n", kobj_id);
+
+       if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) {
+               orangefs_attr = (struct orangefs_attribute *)attr;
+
+               if (!strcmp(orangefs_attr->attr.name, "op_timeout_secs")) {
+                       rc = scnprintf(buf,
+                                      PAGE_SIZE,
+                                      "%d\n",
+                                      op_timeout_secs);
+                       goto out;
+               } else if (!strcmp(orangefs_attr->attr.name,
+                                  "slot_timeout_secs")) {
+                       rc = scnprintf(buf,
+                                      PAGE_SIZE,
+                                      "%d\n",
+                                      slot_timeout_secs);
+                       goto out;
+               } else {
+                       goto out;
+               }
+
+       } else if (!strcmp(kobj_id, STATS_KOBJ_ID)) {
+               stats_orangefs_attr = (struct stats_orangefs_attribute *)attr;
+
+               if (!strcmp(stats_orangefs_attr->attr.name, "reads")) {
+                       rc = scnprintf(buf,
+                                      PAGE_SIZE,
+                                      "%lu\n",
+                                      g_orangefs_stats.reads);
+                       goto out;
+               } else if (!strcmp(stats_orangefs_attr->attr.name, "writes")) {
+                       rc = scnprintf(buf,
+                                      PAGE_SIZE,
+                                      "%lu\n",
+                                      g_orangefs_stats.writes);
+                       goto out;
+               } else {
+                       goto out;
+               }
+       }
+
+out:
+
+       return rc;
+}
+
+static ssize_t int_orangefs_show(struct orangefs_obj *orangefs_obj,
+                                struct orangefs_attribute *attr,
+                                char *buf)
+{
+       int rc;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "int_orangefs_show:start attr->attr.name:%s:\n",
+                    attr->attr.name);
+
+       rc = sysfs_int_show(ORANGEFS_KOBJ_ID, buf, (void *) attr);
+
+       return rc;
+}
+
+static ssize_t int_stats_show(struct stats_orangefs_obj *stats_orangefs_obj,
+                       struct stats_orangefs_attribute *attr,
+                       char *buf)
+{
+       int rc;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "int_stats_show:start attr->attr.name:%s:\n",
+                    attr->attr.name);
+
+       rc = sysfs_int_show(STATS_KOBJ_ID, buf, (void *) attr);
+
+       return rc;
+}
+
+static ssize_t int_store(struct orangefs_obj *orangefs_obj,
+                        struct orangefs_attribute *attr,
+                        const char *buf,
+                        size_t count)
+{
+       int rc = 0;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "int_store: start attr->attr.name:%s: buf:%s:\n",
+                    attr->attr.name, buf);
+
+       if (!strcmp(attr->attr.name, "op_timeout_secs")) {
+               rc = kstrtoint(buf, 0, &op_timeout_secs);
+               goto out;
+       } else if (!strcmp(attr->attr.name, "slot_timeout_secs")) {
+               rc = kstrtoint(buf, 0, &slot_timeout_secs);
+               goto out;
+       } else {
+               goto out;
+       }
+
+out:
+       if (rc)
+               rc = -EINVAL;
+       else
+               rc = count;
+
+       return rc;
+}
+
+/*
+ * obtain attribute values from userspace with a service operation.
+ */
+static int sysfs_service_op_show(char *kobj_id, char *buf, void *attr)
+{
+       struct orangefs_kernel_op_s *new_op = NULL;
+       int rc = 0;
+       char *ser_op_type = NULL;
+       struct orangefs_attribute *orangefs_attr;
+       struct acache_orangefs_attribute *acache_attr;
+       struct capcache_orangefs_attribute *capcache_attr;
+       struct ccache_orangefs_attribute *ccache_attr;
+       struct ncache_orangefs_attribute *ncache_attr;
+       struct pc_orangefs_attribute *pc_attr;
+       __u32 op_alloc_type;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "sysfs_service_op_show: id:%s:\n",
+                    kobj_id);
+
+       if (strcmp(kobj_id, PC_KOBJ_ID))
+               op_alloc_type = ORANGEFS_VFS_OP_PARAM;
+       else
+               op_alloc_type = ORANGEFS_VFS_OP_PERF_COUNT;
+
+       new_op = op_alloc(op_alloc_type);
+       if (!new_op)
+               return -ENOMEM;
+
+       /* Can't do a service_operation if the client is not running... */
+       rc = is_daemon_in_service();
+       if (rc) {
+               pr_info("%s: Client not running :%d:\n",
+                       __func__,
+                       is_daemon_in_service());
+               goto out;
+       }
+
+       if (strcmp(kobj_id, PC_KOBJ_ID))
+               new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_GET;
+
+       if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) {
+               orangefs_attr = (struct orangefs_attribute *)attr;
+
+               if (!strcmp(orangefs_attr->attr.name, "perf_history_size"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_PERF_HISTORY_SIZE;
+               else if (!strcmp(orangefs_attr->attr.name,
+                                "perf_time_interval_secs"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_PERF_TIME_INTERVAL_SECS;
+               else if (!strcmp(orangefs_attr->attr.name,
+                                "perf_counter_reset"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_PERF_RESET;
+
+       } else if (!strcmp(kobj_id, ACACHE_KOBJ_ID)) {
+               acache_attr = (struct acache_orangefs_attribute *)attr;
+
+               if (!strcmp(acache_attr->attr.name, "timeout_msecs"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_ACACHE_TIMEOUT_MSECS;
+
+               if (!strcmp(acache_attr->attr.name, "hard_limit"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_ACACHE_HARD_LIMIT;
+
+               if (!strcmp(acache_attr->attr.name, "soft_limit"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_ACACHE_SOFT_LIMIT;
+
+               if (!strcmp(acache_attr->attr.name, "reclaim_percentage"))
+                       new_op->upcall.req.param.op =
+                         ORANGEFS_PARAM_REQUEST_OP_ACACHE_RECLAIM_PERCENTAGE;
+
+       } else if (!strcmp(kobj_id, CAPCACHE_KOBJ_ID)) {
+               capcache_attr = (struct capcache_orangefs_attribute *)attr;
+
+               if (!strcmp(capcache_attr->attr.name, "timeout_secs"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_TIMEOUT_SECS;
+
+               if (!strcmp(capcache_attr->attr.name, "hard_limit"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_HARD_LIMIT;
+
+               if (!strcmp(capcache_attr->attr.name, "soft_limit"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_SOFT_LIMIT;
+
+               if (!strcmp(capcache_attr->attr.name, "reclaim_percentage"))
+                       new_op->upcall.req.param.op =
+                         ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_RECLAIM_PERCENTAGE;
+
+       } else if (!strcmp(kobj_id, CCACHE_KOBJ_ID)) {
+               ccache_attr = (struct ccache_orangefs_attribute *)attr;
+
+               if (!strcmp(ccache_attr->attr.name, "timeout_secs"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_CCACHE_TIMEOUT_SECS;
+
+               if (!strcmp(ccache_attr->attr.name, "hard_limit"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_CCACHE_HARD_LIMIT;
+
+               if (!strcmp(ccache_attr->attr.name, "soft_limit"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_CCACHE_SOFT_LIMIT;
+
+               if (!strcmp(ccache_attr->attr.name, "reclaim_percentage"))
+                       new_op->upcall.req.param.op =
+                         ORANGEFS_PARAM_REQUEST_OP_CCACHE_RECLAIM_PERCENTAGE;
+
+       } else if (!strcmp(kobj_id, NCACHE_KOBJ_ID)) {
+               ncache_attr = (struct ncache_orangefs_attribute *)attr;
+
+               if (!strcmp(ncache_attr->attr.name, "timeout_msecs"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_NCACHE_TIMEOUT_MSECS;
+
+               if (!strcmp(ncache_attr->attr.name, "hard_limit"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_NCACHE_HARD_LIMIT;
+
+               if (!strcmp(ncache_attr->attr.name, "soft_limit"))
+                       new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_NCACHE_SOFT_LIMIT;
+
+               if (!strcmp(ncache_attr->attr.name, "reclaim_percentage"))
+                       new_op->upcall.req.param.op =
+                         ORANGEFS_PARAM_REQUEST_OP_NCACHE_RECLAIM_PERCENTAGE;
+
+       } else if (!strcmp(kobj_id, PC_KOBJ_ID)) {
+               pc_attr = (struct pc_orangefs_attribute *)attr;
+
+               if (!strcmp(pc_attr->attr.name, ACACHE_KOBJ_ID))
+                       new_op->upcall.req.perf_count.type =
+                               ORANGEFS_PERF_COUNT_REQUEST_ACACHE;
+
+               if (!strcmp(pc_attr->attr.name, CAPCACHE_KOBJ_ID))
+                       new_op->upcall.req.perf_count.type =
+                               ORANGEFS_PERF_COUNT_REQUEST_CAPCACHE;
+
+               if (!strcmp(pc_attr->attr.name, NCACHE_KOBJ_ID))
+                       new_op->upcall.req.perf_count.type =
+                               ORANGEFS_PERF_COUNT_REQUEST_NCACHE;
+
+       } else {
+               gossip_err("sysfs_service_op_show: unknown kobj_id:%s:\n",
+                          kobj_id);
+               rc = -EINVAL;
+               goto out;
+       }
+
+
+       if (strcmp(kobj_id, PC_KOBJ_ID))
+               ser_op_type = "orangefs_param";
+       else
+               ser_op_type = "orangefs_perf_count";
+
+       /*
+        * The service_operation will return an errno return code on
+        * error, and zero on success.
+        */
+       rc = service_operation(new_op, ser_op_type, ORANGEFS_OP_INTERRUPTIBLE);
+
+out:
+       if (!rc) {
+               if (strcmp(kobj_id, PC_KOBJ_ID)) {
+                       rc = scnprintf(buf,
+                                      PAGE_SIZE,
+                                      "%d\n",
+                                      (int)new_op->downcall.resp.param.value);
+               } else {
+                       rc = scnprintf(
+                               buf,
+                               PAGE_SIZE,
+                               "%s",
+                               new_op->downcall.resp.perf_count.buffer);
+               }
+       }
+
+       op_release(new_op);
+
+       return rc;
+
+}
+
+static ssize_t service_orangefs_show(struct orangefs_obj *orangefs_obj,
+                                    struct orangefs_attribute *attr,
+                                    char *buf)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_show(ORANGEFS_KOBJ_ID, buf, (void *)attr);
+
+       return rc;
+}
+
+static ssize_t
+       service_acache_show(struct acache_orangefs_obj *acache_orangefs_obj,
+                           struct acache_orangefs_attribute *attr,
+                           char *buf)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_show(ACACHE_KOBJ_ID, buf, (void *)attr);
+
+       return rc;
+}
+
+static ssize_t service_capcache_show(struct capcache_orangefs_obj
+                                       *capcache_orangefs_obj,
+                                    struct capcache_orangefs_attribute *attr,
+                                    char *buf)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_show(CAPCACHE_KOBJ_ID, buf, (void *)attr);
+
+       return rc;
+}
+
+static ssize_t service_ccache_show(struct ccache_orangefs_obj
+                                       *ccache_orangefs_obj,
+                                  struct ccache_orangefs_attribute *attr,
+                                  char *buf)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_show(CCACHE_KOBJ_ID, buf, (void *)attr);
+
+       return rc;
+}
+
+static ssize_t
+       service_ncache_show(struct ncache_orangefs_obj *ncache_orangefs_obj,
+                           struct ncache_orangefs_attribute *attr,
+                           char *buf)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_show(NCACHE_KOBJ_ID, buf, (void *)attr);
+
+       return rc;
+}
+
+static ssize_t
+       service_pc_show(struct pc_orangefs_obj *pc_orangefs_obj,
+                           struct pc_orangefs_attribute *attr,
+                           char *buf)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_show(PC_KOBJ_ID, buf, (void *)attr);
+
+       return rc;
+}
+
+/*
+ * pass attribute values back to userspace with a service operation.
+ *
+ * We have to do a memory allocation, an sscanf and a service operation.
+ * And we have to evaluate what the user entered, to make sure the
+ * value is within the range supported by the attribute. So, there's
+ * a lot of return code checking and mapping going on here.
+ *
+ * We want to return 1 if we think everything went OK, and
+ * EINVAL if not.
+ */
+static int sysfs_service_op_store(char *kobj_id, const char *buf, void *attr)
+{
+       struct orangefs_kernel_op_s *new_op = NULL;
+       int val = 0;
+       int rc = 0;
+       struct orangefs_attribute *orangefs_attr;
+       struct acache_orangefs_attribute *acache_attr;
+       struct capcache_orangefs_attribute *capcache_attr;
+       struct ccache_orangefs_attribute *ccache_attr;
+       struct ncache_orangefs_attribute *ncache_attr;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG,
+                    "sysfs_service_op_store: id:%s:\n",
+                    kobj_id);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_PARAM);
+       if (!new_op)
+               return -EINVAL; /* sic */
+
+       /* Can't do a service_operation if the client is not running... */
+       rc = is_daemon_in_service();
+       if (rc) {
+               pr_info("%s: Client not running :%d:\n",
+                       __func__,
+                       is_daemon_in_service());
+               goto out;
+       }
+
+       /*
+        * The value we want to send back to userspace is in buf.
+        */
+       rc = kstrtoint(buf, 0, &val);
+       if (rc)
+               goto out;
+
+       if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) {
+               orangefs_attr = (struct orangefs_attribute *)attr;
+
+               if (!strcmp(orangefs_attr->attr.name, "perf_history_size")) {
+                       if (val > 0) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_PERF_HISTORY_SIZE;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(orangefs_attr->attr.name,
+                                  "perf_time_interval_secs")) {
+                       if (val > 0) {
+                               new_op->upcall.req.param.op =
+                               ORANGEFS_PARAM_REQUEST_OP_PERF_TIME_INTERVAL_SECS;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(orangefs_attr->attr.name,
+                                  "perf_counter_reset")) {
+                       if ((val == 0) || (val == 1)) {
+                               new_op->upcall.req.param.op =
+                                       ORANGEFS_PARAM_REQUEST_OP_PERF_RESET;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               }
+
+       } else if (!strcmp(kobj_id, ACACHE_KOBJ_ID)) {
+               acache_attr = (struct acache_orangefs_attribute *)attr;
+
+               if (!strcmp(acache_attr->attr.name, "hard_limit")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_ACACHE_HARD_LIMIT;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(acache_attr->attr.name, "soft_limit")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_ACACHE_SOFT_LIMIT;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(acache_attr->attr.name,
+                                  "reclaim_percentage")) {
+                       if ((val > -1) && (val < 101)) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_ACACHE_RECLAIM_PERCENTAGE;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(acache_attr->attr.name, "timeout_msecs")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_ACACHE_TIMEOUT_MSECS;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               }
+
+       } else if (!strcmp(kobj_id, CAPCACHE_KOBJ_ID)) {
+               capcache_attr = (struct capcache_orangefs_attribute *)attr;
+
+               if (!strcmp(capcache_attr->attr.name, "hard_limit")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_HARD_LIMIT;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(capcache_attr->attr.name, "soft_limit")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_SOFT_LIMIT;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(capcache_attr->attr.name,
+                                  "reclaim_percentage")) {
+                       if ((val > -1) && (val < 101)) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_RECLAIM_PERCENTAGE;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(capcache_attr->attr.name, "timeout_secs")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_TIMEOUT_SECS;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               }
+
+       } else if (!strcmp(kobj_id, CCACHE_KOBJ_ID)) {
+               ccache_attr = (struct ccache_orangefs_attribute *)attr;
+
+               if (!strcmp(ccache_attr->attr.name, "hard_limit")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_CCACHE_HARD_LIMIT;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(ccache_attr->attr.name, "soft_limit")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_CCACHE_SOFT_LIMIT;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(ccache_attr->attr.name,
+                                  "reclaim_percentage")) {
+                       if ((val > -1) && (val < 101)) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_CCACHE_RECLAIM_PERCENTAGE;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(ccache_attr->attr.name, "timeout_secs")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_CCACHE_TIMEOUT_SECS;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               }
+
+       } else if (!strcmp(kobj_id, NCACHE_KOBJ_ID)) {
+               ncache_attr = (struct ncache_orangefs_attribute *)attr;
+
+               if (!strcmp(ncache_attr->attr.name, "hard_limit")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_NCACHE_HARD_LIMIT;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(ncache_attr->attr.name, "soft_limit")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_NCACHE_SOFT_LIMIT;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(ncache_attr->attr.name,
+                                  "reclaim_percentage")) {
+                       if ((val > -1) && (val < 101)) {
+                               new_op->upcall.req.param.op =
+                                       ORANGEFS_PARAM_REQUEST_OP_NCACHE_RECLAIM_PERCENTAGE;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               } else if (!strcmp(ncache_attr->attr.name, "timeout_msecs")) {
+                       if (val > -1) {
+                               new_op->upcall.req.param.op =
+                                 ORANGEFS_PARAM_REQUEST_OP_NCACHE_TIMEOUT_MSECS;
+                       } else {
+                               rc = 0;
+                               goto out;
+                       }
+               }
+
+       } else {
+               gossip_err("sysfs_service_op_store: unknown kobj_id:%s:\n",
+                          kobj_id);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET;
+
+       new_op->upcall.req.param.value = val;
+
+       /*
+        * The service_operation will return a errno return code on
+        * error, and zero on success.
+        */
+       rc = service_operation(new_op, "orangefs_param", ORANGEFS_OP_INTERRUPTIBLE);
+
+       if (rc < 0) {
+               gossip_err("sysfs_service_op_store: service op returned:%d:\n",
+                       rc);
+               rc = 0;
+       } else {
+               rc = 1;
+       }
+
+out:
+       op_release(new_op);
+
+       if (rc == -ENOMEM || rc == 0)
+               rc = -EINVAL;
+
+       return rc;
+}
+
+static ssize_t
+       service_orangefs_store(struct orangefs_obj *orangefs_obj,
+                              struct orangefs_attribute *attr,
+                              const char *buf,
+                              size_t count)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_store(ORANGEFS_KOBJ_ID, buf, (void *) attr);
+
+       /* rc should have an errno value if the service_op went bad. */
+       if (rc == 1)
+               rc = count;
+
+       return rc;
+}
+
+static ssize_t
+       service_acache_store(struct acache_orangefs_obj *acache_orangefs_obj,
+                            struct acache_orangefs_attribute *attr,
+                            const char *buf,
+                            size_t count)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_store(ACACHE_KOBJ_ID, buf, (void *) attr);
+
+       /* rc should have an errno value if the service_op went bad. */
+       if (rc == 1)
+               rc = count;
+
+       return rc;
+}
+
+static ssize_t
+       service_capcache_store(struct capcache_orangefs_obj
+                               *capcache_orangefs_obj,
+                              struct capcache_orangefs_attribute *attr,
+                              const char *buf,
+                              size_t count)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_store(CAPCACHE_KOBJ_ID, buf, (void *) attr);
+
+       /* rc should have an errno value if the service_op went bad. */
+       if (rc == 1)
+               rc = count;
+
+       return rc;
+}
+
+static ssize_t service_ccache_store(struct ccache_orangefs_obj
+                                       *ccache_orangefs_obj,
+                                   struct ccache_orangefs_attribute *attr,
+                                   const char *buf,
+                                   size_t count)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_store(CCACHE_KOBJ_ID, buf, (void *) attr);
+
+       /* rc should have an errno value if the service_op went bad. */
+       if (rc == 1)
+               rc = count;
+
+       return rc;
+}
+
+static ssize_t
+       service_ncache_store(struct ncache_orangefs_obj *ncache_orangefs_obj,
+                            struct ncache_orangefs_attribute *attr,
+                            const char *buf,
+                            size_t count)
+{
+       int rc = 0;
+
+       rc = sysfs_service_op_store(NCACHE_KOBJ_ID, buf, (void *) attr);
+
+       /* rc should have an errno value if the service_op went bad. */
+       if (rc == 1)
+               rc = count;
+
+       return rc;
+}
+
+static struct orangefs_attribute op_timeout_secs_attribute =
+       __ATTR(op_timeout_secs, 0664, int_orangefs_show, int_store);
+
+static struct orangefs_attribute slot_timeout_secs_attribute =
+       __ATTR(slot_timeout_secs, 0664, int_orangefs_show, int_store);
+
+static struct orangefs_attribute perf_counter_reset_attribute =
+       __ATTR(perf_counter_reset,
+              0664,
+              service_orangefs_show,
+              service_orangefs_store);
+
+static struct orangefs_attribute perf_history_size_attribute =
+       __ATTR(perf_history_size,
+              0664,
+              service_orangefs_show,
+              service_orangefs_store);
+
+static struct orangefs_attribute perf_time_interval_secs_attribute =
+       __ATTR(perf_time_interval_secs,
+              0664,
+              service_orangefs_show,
+              service_orangefs_store);
+
+static struct attribute *orangefs_default_attrs[] = {
+       &op_timeout_secs_attribute.attr,
+       &slot_timeout_secs_attribute.attr,
+       &perf_counter_reset_attribute.attr,
+       &perf_history_size_attribute.attr,
+       &perf_time_interval_secs_attribute.attr,
+       NULL,
+};
+
+static struct kobj_type orangefs_ktype = {
+       .sysfs_ops = &orangefs_sysfs_ops,
+       .release = orangefs_release,
+       .default_attrs = orangefs_default_attrs,
+};
+
+static struct acache_orangefs_attribute acache_hard_limit_attribute =
+       __ATTR(hard_limit,
+              0664,
+              service_acache_show,
+              service_acache_store);
+
+static struct acache_orangefs_attribute acache_reclaim_percent_attribute =
+       __ATTR(reclaim_percentage,
+              0664,
+              service_acache_show,
+              service_acache_store);
+
+static struct acache_orangefs_attribute acache_soft_limit_attribute =
+       __ATTR(soft_limit,
+              0664,
+              service_acache_show,
+              service_acache_store);
+
+static struct acache_orangefs_attribute acache_timeout_msecs_attribute =
+       __ATTR(timeout_msecs,
+              0664,
+              service_acache_show,
+              service_acache_store);
+
+static struct attribute *acache_orangefs_default_attrs[] = {
+       &acache_hard_limit_attribute.attr,
+       &acache_reclaim_percent_attribute.attr,
+       &acache_soft_limit_attribute.attr,
+       &acache_timeout_msecs_attribute.attr,
+       NULL,
+};
+
+static struct kobj_type acache_orangefs_ktype = {
+       .sysfs_ops = &acache_orangefs_sysfs_ops,
+       .release = acache_orangefs_release,
+       .default_attrs = acache_orangefs_default_attrs,
+};
+
+static struct capcache_orangefs_attribute capcache_hard_limit_attribute =
+       __ATTR(hard_limit,
+              0664,
+              service_capcache_show,
+              service_capcache_store);
+
+static struct capcache_orangefs_attribute capcache_reclaim_percent_attribute =
+       __ATTR(reclaim_percentage,
+              0664,
+              service_capcache_show,
+              service_capcache_store);
+
+static struct capcache_orangefs_attribute capcache_soft_limit_attribute =
+       __ATTR(soft_limit,
+              0664,
+              service_capcache_show,
+              service_capcache_store);
+
+static struct capcache_orangefs_attribute capcache_timeout_secs_attribute =
+       __ATTR(timeout_secs,
+              0664,
+              service_capcache_show,
+              service_capcache_store);
+
+static struct attribute *capcache_orangefs_default_attrs[] = {
+       &capcache_hard_limit_attribute.attr,
+       &capcache_reclaim_percent_attribute.attr,
+       &capcache_soft_limit_attribute.attr,
+       &capcache_timeout_secs_attribute.attr,
+       NULL,
+};
+
+static struct kobj_type capcache_orangefs_ktype = {
+       .sysfs_ops = &capcache_orangefs_sysfs_ops,
+       .release = capcache_orangefs_release,
+       .default_attrs = capcache_orangefs_default_attrs,
+};
+
+static struct ccache_orangefs_attribute ccache_hard_limit_attribute =
+       __ATTR(hard_limit,
+              0664,
+              service_ccache_show,
+              service_ccache_store);
+
+static struct ccache_orangefs_attribute ccache_reclaim_percent_attribute =
+       __ATTR(reclaim_percentage,
+              0664,
+              service_ccache_show,
+              service_ccache_store);
+
+static struct ccache_orangefs_attribute ccache_soft_limit_attribute =
+       __ATTR(soft_limit,
+              0664,
+              service_ccache_show,
+              service_ccache_store);
+
+static struct ccache_orangefs_attribute ccache_timeout_secs_attribute =
+       __ATTR(timeout_secs,
+              0664,
+              service_ccache_show,
+              service_ccache_store);
+
+static struct attribute *ccache_orangefs_default_attrs[] = {
+       &ccache_hard_limit_attribute.attr,
+       &ccache_reclaim_percent_attribute.attr,
+       &ccache_soft_limit_attribute.attr,
+       &ccache_timeout_secs_attribute.attr,
+       NULL,
+};
+
+static struct kobj_type ccache_orangefs_ktype = {
+       .sysfs_ops = &ccache_orangefs_sysfs_ops,
+       .release = ccache_orangefs_release,
+       .default_attrs = ccache_orangefs_default_attrs,
+};
+
+static struct ncache_orangefs_attribute ncache_hard_limit_attribute =
+       __ATTR(hard_limit,
+              0664,
+              service_ncache_show,
+              service_ncache_store);
+
+static struct ncache_orangefs_attribute ncache_reclaim_percent_attribute =
+       __ATTR(reclaim_percentage,
+              0664,
+              service_ncache_show,
+              service_ncache_store);
+
+static struct ncache_orangefs_attribute ncache_soft_limit_attribute =
+       __ATTR(soft_limit,
+              0664,
+              service_ncache_show,
+              service_ncache_store);
+
+static struct ncache_orangefs_attribute ncache_timeout_msecs_attribute =
+       __ATTR(timeout_msecs,
+              0664,
+              service_ncache_show,
+              service_ncache_store);
+
+static struct attribute *ncache_orangefs_default_attrs[] = {
+       &ncache_hard_limit_attribute.attr,
+       &ncache_reclaim_percent_attribute.attr,
+       &ncache_soft_limit_attribute.attr,
+       &ncache_timeout_msecs_attribute.attr,
+       NULL,
+};
+
+static struct kobj_type ncache_orangefs_ktype = {
+       .sysfs_ops = &ncache_orangefs_sysfs_ops,
+       .release = ncache_orangefs_release,
+       .default_attrs = ncache_orangefs_default_attrs,
+};
+
+static struct pc_orangefs_attribute pc_acache_attribute =
+       __ATTR(acache,
+              0664,
+              service_pc_show,
+              NULL);
+
+static struct pc_orangefs_attribute pc_capcache_attribute =
+       __ATTR(capcache,
+              0664,
+              service_pc_show,
+              NULL);
+
+static struct pc_orangefs_attribute pc_ncache_attribute =
+       __ATTR(ncache,
+              0664,
+              service_pc_show,
+              NULL);
+
+static struct attribute *pc_orangefs_default_attrs[] = {
+       &pc_acache_attribute.attr,
+       &pc_capcache_attribute.attr,
+       &pc_ncache_attribute.attr,
+       NULL,
+};
+
+static struct kobj_type pc_orangefs_ktype = {
+       .sysfs_ops = &pc_orangefs_sysfs_ops,
+       .release = pc_orangefs_release,
+       .default_attrs = pc_orangefs_default_attrs,
+};
+
+static struct stats_orangefs_attribute stats_reads_attribute =
+       __ATTR(reads,
+              0664,
+              int_stats_show,
+              NULL);
+
+static struct stats_orangefs_attribute stats_writes_attribute =
+       __ATTR(writes,
+              0664,
+              int_stats_show,
+              NULL);
+
+static struct attribute *stats_orangefs_default_attrs[] = {
+       &stats_reads_attribute.attr,
+       &stats_writes_attribute.attr,
+       NULL,
+};
+
+static struct kobj_type stats_orangefs_ktype = {
+       .sysfs_ops = &stats_orangefs_sysfs_ops,
+       .release = stats_orangefs_release,
+       .default_attrs = stats_orangefs_default_attrs,
+};
+
+static struct orangefs_obj *orangefs_obj;
+static struct acache_orangefs_obj *acache_orangefs_obj;
+static struct capcache_orangefs_obj *capcache_orangefs_obj;
+static struct ccache_orangefs_obj *ccache_orangefs_obj;
+static struct ncache_orangefs_obj *ncache_orangefs_obj;
+static struct pc_orangefs_obj *pc_orangefs_obj;
+static struct stats_orangefs_obj *stats_orangefs_obj;
+
+int orangefs_sysfs_init(void)
+{
+       int rc = -EINVAL;
+
+       gossip_debug(GOSSIP_SYSFS_DEBUG, "orangefs_sysfs_init: start\n");
+
+       /* create /sys/fs/orangefs. */
+       orangefs_obj = kzalloc(sizeof(*orangefs_obj), GFP_KERNEL);
+       if (!orangefs_obj)
+               goto out;
+
+       rc = kobject_init_and_add(&orangefs_obj->kobj,
+                                 &orangefs_ktype,
+                                 fs_kobj,
+                                 ORANGEFS_KOBJ_ID);
+
+       if (rc)
+               goto ofs_obj_bail;
+
+       kobject_uevent(&orangefs_obj->kobj, KOBJ_ADD);
+
+       /* create /sys/fs/orangefs/acache. */
+       acache_orangefs_obj = kzalloc(sizeof(*acache_orangefs_obj), GFP_KERNEL);
+       if (!acache_orangefs_obj) {
+               rc = -EINVAL;
+               goto ofs_obj_bail;
+       }
+
+       rc = kobject_init_and_add(&acache_orangefs_obj->kobj,
+                                 &acache_orangefs_ktype,
+                                 &orangefs_obj->kobj,
+                                 ACACHE_KOBJ_ID);
+
+       if (rc)
+               goto acache_obj_bail;
+
+       kobject_uevent(&acache_orangefs_obj->kobj, KOBJ_ADD);
+
+       /* create /sys/fs/orangefs/capcache. */
+       capcache_orangefs_obj =
+               kzalloc(sizeof(*capcache_orangefs_obj), GFP_KERNEL);
+       if (!capcache_orangefs_obj) {
+               rc = -EINVAL;
+               goto acache_obj_bail;
+       }
+
+       rc = kobject_init_and_add(&capcache_orangefs_obj->kobj,
+                                 &capcache_orangefs_ktype,
+                                 &orangefs_obj->kobj,
+                                 CAPCACHE_KOBJ_ID);
+       if (rc)
+               goto capcache_obj_bail;
+
+       kobject_uevent(&capcache_orangefs_obj->kobj, KOBJ_ADD);
+
+       /* create /sys/fs/orangefs/ccache. */
+       ccache_orangefs_obj =
+               kzalloc(sizeof(*ccache_orangefs_obj), GFP_KERNEL);
+       if (!ccache_orangefs_obj) {
+               rc = -EINVAL;
+               goto capcache_obj_bail;
+       }
+
+       rc = kobject_init_and_add(&ccache_orangefs_obj->kobj,
+                                 &ccache_orangefs_ktype,
+                                 &orangefs_obj->kobj,
+                                 CCACHE_KOBJ_ID);
+       if (rc)
+               goto ccache_obj_bail;
+
+       kobject_uevent(&ccache_orangefs_obj->kobj, KOBJ_ADD);
+
+       /* create /sys/fs/orangefs/ncache. */
+       ncache_orangefs_obj = kzalloc(sizeof(*ncache_orangefs_obj), GFP_KERNEL);
+       if (!ncache_orangefs_obj) {
+               rc = -EINVAL;
+               goto ccache_obj_bail;
+       }
+
+       rc = kobject_init_and_add(&ncache_orangefs_obj->kobj,
+                                 &ncache_orangefs_ktype,
+                                 &orangefs_obj->kobj,
+                                 NCACHE_KOBJ_ID);
+
+       if (rc)
+               goto ncache_obj_bail;
+
+       kobject_uevent(&ncache_orangefs_obj->kobj, KOBJ_ADD);
+
+       /* create /sys/fs/orangefs/perf_counters. */
+       pc_orangefs_obj = kzalloc(sizeof(*pc_orangefs_obj), GFP_KERNEL);
+       if (!pc_orangefs_obj) {
+               rc = -EINVAL;
+               goto ncache_obj_bail;
+       }
+
+       rc = kobject_init_and_add(&pc_orangefs_obj->kobj,
+                                 &pc_orangefs_ktype,
+                                 &orangefs_obj->kobj,
+                                 "perf_counters");
+
+       if (rc)
+               goto pc_obj_bail;
+
+       kobject_uevent(&pc_orangefs_obj->kobj, KOBJ_ADD);
+
+       /* create /sys/fs/orangefs/stats. */
+       stats_orangefs_obj = kzalloc(sizeof(*stats_orangefs_obj), GFP_KERNEL);
+       if (!stats_orangefs_obj) {
+               rc = -EINVAL;
+               goto pc_obj_bail;
+       }
+
+       rc = kobject_init_and_add(&stats_orangefs_obj->kobj,
+                                 &stats_orangefs_ktype,
+                                 &orangefs_obj->kobj,
+                                 STATS_KOBJ_ID);
+
+       if (rc)
+               goto stats_obj_bail;
+
+       kobject_uevent(&stats_orangefs_obj->kobj, KOBJ_ADD);
+       goto out;
+
+stats_obj_bail:
+               kobject_put(&stats_orangefs_obj->kobj);
+
+pc_obj_bail:
+               kobject_put(&pc_orangefs_obj->kobj);
+
+ncache_obj_bail:
+               kobject_put(&ncache_orangefs_obj->kobj);
+
+ccache_obj_bail:
+               kobject_put(&ccache_orangefs_obj->kobj);
+
+capcache_obj_bail:
+               kobject_put(&capcache_orangefs_obj->kobj);
+
+acache_obj_bail:
+               kobject_put(&acache_orangefs_obj->kobj);
+
+ofs_obj_bail:
+               kobject_put(&orangefs_obj->kobj);
+out:
+       return rc;
+}
+
+void orangefs_sysfs_exit(void)
+{
+       gossip_debug(GOSSIP_SYSFS_DEBUG, "orangefs_sysfs_exit: start\n");
+
+       kobject_put(&acache_orangefs_obj->kobj);
+       kobject_put(&capcache_orangefs_obj->kobj);
+       kobject_put(&ccache_orangefs_obj->kobj);
+       kobject_put(&ncache_orangefs_obj->kobj);
+       kobject_put(&pc_orangefs_obj->kobj);
+       kobject_put(&stats_orangefs_obj->kobj);
+
+       kobject_put(&orangefs_obj->kobj);
+}
diff --git a/fs/orangefs/orangefs-sysfs.h b/fs/orangefs/orangefs-sysfs.h
new file mode 100644 (file)
index 0000000..f0b7638
--- /dev/null
@@ -0,0 +1,2 @@
+extern int orangefs_sysfs_init(void);
+extern void orangefs_sysfs_exit(void);
diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c
new file mode 100644 (file)
index 0000000..40f5163
--- /dev/null
@@ -0,0 +1,1048 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-dev-proto.h"
+#include "orangefs-bufmap.h"
+
+__s32 fsid_of_op(struct orangefs_kernel_op_s *op)
+{
+       __s32 fsid = ORANGEFS_FS_ID_NULL;
+
+       if (op) {
+               switch (op->upcall.type) {
+               case ORANGEFS_VFS_OP_FILE_IO:
+                       fsid = op->upcall.req.io.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_LOOKUP:
+                       fsid = op->upcall.req.lookup.parent_refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_CREATE:
+                       fsid = op->upcall.req.create.parent_refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_GETATTR:
+                       fsid = op->upcall.req.getattr.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_REMOVE:
+                       fsid = op->upcall.req.remove.parent_refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_MKDIR:
+                       fsid = op->upcall.req.mkdir.parent_refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_READDIR:
+                       fsid = op->upcall.req.readdir.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_SETATTR:
+                       fsid = op->upcall.req.setattr.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_SYMLINK:
+                       fsid = op->upcall.req.sym.parent_refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_RENAME:
+                       fsid = op->upcall.req.rename.old_parent_refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_STATFS:
+                       fsid = op->upcall.req.statfs.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_TRUNCATE:
+                       fsid = op->upcall.req.truncate.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_MMAP_RA_FLUSH:
+                       fsid = op->upcall.req.ra_cache_flush.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_FS_UMOUNT:
+                       fsid = op->upcall.req.fs_umount.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_GETXATTR:
+                       fsid = op->upcall.req.getxattr.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_SETXATTR:
+                       fsid = op->upcall.req.setxattr.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_LISTXATTR:
+                       fsid = op->upcall.req.listxattr.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_REMOVEXATTR:
+                       fsid = op->upcall.req.removexattr.refn.fs_id;
+                       break;
+               case ORANGEFS_VFS_OP_FSYNC:
+                       fsid = op->upcall.req.fsync.refn.fs_id;
+                       break;
+               default:
+                       break;
+               }
+       }
+       return fsid;
+}
+
+static int orangefs_inode_flags(struct ORANGEFS_sys_attr_s *attrs)
+{
+       int flags = 0;
+       if (attrs->flags & ORANGEFS_IMMUTABLE_FL)
+               flags |= S_IMMUTABLE;
+       else
+               flags &= ~S_IMMUTABLE;
+       if (attrs->flags & ORANGEFS_APPEND_FL)
+               flags |= S_APPEND;
+       else
+               flags &= ~S_APPEND;
+       if (attrs->flags & ORANGEFS_NOATIME_FL)
+               flags |= S_NOATIME;
+       else
+               flags &= ~S_NOATIME;
+       return flags;
+}
+
+static int orangefs_inode_perms(struct ORANGEFS_sys_attr_s *attrs)
+{
+       int perm_mode = 0;
+
+       if (attrs->perms & ORANGEFS_O_EXECUTE)
+               perm_mode |= S_IXOTH;
+       if (attrs->perms & ORANGEFS_O_WRITE)
+               perm_mode |= S_IWOTH;
+       if (attrs->perms & ORANGEFS_O_READ)
+               perm_mode |= S_IROTH;
+
+       if (attrs->perms & ORANGEFS_G_EXECUTE)
+               perm_mode |= S_IXGRP;
+       if (attrs->perms & ORANGEFS_G_WRITE)
+               perm_mode |= S_IWGRP;
+       if (attrs->perms & ORANGEFS_G_READ)
+               perm_mode |= S_IRGRP;
+
+       if (attrs->perms & ORANGEFS_U_EXECUTE)
+               perm_mode |= S_IXUSR;
+       if (attrs->perms & ORANGEFS_U_WRITE)
+               perm_mode |= S_IWUSR;
+       if (attrs->perms & ORANGEFS_U_READ)
+               perm_mode |= S_IRUSR;
+
+       if (attrs->perms & ORANGEFS_G_SGID)
+               perm_mode |= S_ISGID;
+       if (attrs->perms & ORANGEFS_U_SUID)
+               perm_mode |= S_ISUID;
+
+       return perm_mode;
+}
+
+/*
+ * NOTE: in kernel land, we never use the sys_attr->link_target for
+ * anything, so don't bother copying it into the sys_attr object here.
+ */
+static inline int copy_attributes_from_inode(struct inode *inode,
+                                            struct ORANGEFS_sys_attr_s *attrs,
+                                            struct iattr *iattr)
+{
+       umode_t tmp_mode;
+
+       if (!iattr || !inode || !attrs) {
+               gossip_err("NULL iattr (%p), inode (%p), attrs (%p) "
+                          "in copy_attributes_from_inode!\n",
+                          iattr,
+                          inode,
+                          attrs);
+               return -EINVAL;
+       }
+       /*
+        * We need to be careful to only copy the attributes out of the
+        * iattr object that we know are valid.
+        */
+       attrs->mask = 0;
+       if (iattr->ia_valid & ATTR_UID) {
+               attrs->owner = from_kuid(current_user_ns(), iattr->ia_uid);
+               attrs->mask |= ORANGEFS_ATTR_SYS_UID;
+               gossip_debug(GOSSIP_UTILS_DEBUG, "(UID) %d\n", attrs->owner);
+       }
+       if (iattr->ia_valid & ATTR_GID) {
+               attrs->group = from_kgid(current_user_ns(), iattr->ia_gid);
+               attrs->mask |= ORANGEFS_ATTR_SYS_GID;
+               gossip_debug(GOSSIP_UTILS_DEBUG, "(GID) %d\n", attrs->group);
+       }
+
+       if (iattr->ia_valid & ATTR_ATIME) {
+               attrs->mask |= ORANGEFS_ATTR_SYS_ATIME;
+               if (iattr->ia_valid & ATTR_ATIME_SET) {
+                       attrs->atime = (time64_t)iattr->ia_atime.tv_sec;
+                       attrs->mask |= ORANGEFS_ATTR_SYS_ATIME_SET;
+               }
+       }
+       if (iattr->ia_valid & ATTR_MTIME) {
+               attrs->mask |= ORANGEFS_ATTR_SYS_MTIME;
+               if (iattr->ia_valid & ATTR_MTIME_SET) {
+                       attrs->mtime = (time64_t)iattr->ia_mtime.tv_sec;
+                       attrs->mask |= ORANGEFS_ATTR_SYS_MTIME_SET;
+               }
+       }
+       if (iattr->ia_valid & ATTR_CTIME)
+               attrs->mask |= ORANGEFS_ATTR_SYS_CTIME;
+
+       /*
+        * ORANGEFS cannot set size with a setattr operation.  Probably not likely
+        * to be requested through the VFS, but just in case, don't worry about
+        * ATTR_SIZE
+        */
+
+       if (iattr->ia_valid & ATTR_MODE) {
+               tmp_mode = iattr->ia_mode;
+               if (tmp_mode & (S_ISVTX)) {
+                       if (is_root_handle(inode)) {
+                               /*
+                                * allow sticky bit to be set on root (since
+                                * it shows up that way by default anyhow),
+                                * but don't show it to the server
+                                */
+                               tmp_mode -= S_ISVTX;
+                       } else {
+                               gossip_debug(GOSSIP_UTILS_DEBUG,
+                                            "User attempted to set sticky bit on non-root directory; returning EINVAL.\n");
+                               return -EINVAL;
+                       }
+               }
+
+               if (tmp_mode & (S_ISUID)) {
+                       gossip_debug(GOSSIP_UTILS_DEBUG,
+                                    "Attempting to set setuid bit (not supported); returning EINVAL.\n");
+                       return -EINVAL;
+               }
+
+               attrs->perms = ORANGEFS_util_translate_mode(tmp_mode);
+               attrs->mask |= ORANGEFS_ATTR_SYS_PERM;
+       }
+
+       return 0;
+}
+
+static int orangefs_inode_type(enum orangefs_ds_type objtype)
+{
+       if (objtype == ORANGEFS_TYPE_METAFILE)
+               return S_IFREG;
+       else if (objtype == ORANGEFS_TYPE_DIRECTORY)
+               return S_IFDIR;
+       else if (objtype == ORANGEFS_TYPE_SYMLINK)
+               return S_IFLNK;
+       else
+               return -1;
+}
+
+static int orangefs_inode_is_stale(struct inode *inode, int new,
+    struct ORANGEFS_sys_attr_s *attrs, char *link_target)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       int type = orangefs_inode_type(attrs->objtype);
+       if (!new) {
+               /*
+                * If the inode type or symlink target have changed then this
+                * inode is stale.
+                */
+               if (type == -1 || !(inode->i_mode & type)) {
+                       orangefs_make_bad_inode(inode);
+                       return 1;
+               }
+               if (type == S_IFLNK && strncmp(orangefs_inode->link_target,
+                   link_target, ORANGEFS_NAME_MAX)) {
+                       orangefs_make_bad_inode(inode);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+int orangefs_inode_getattr(struct inode *inode, int new, int size)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_kernel_op_s *new_op;
+       loff_t inode_size, rounded_up_size;
+       int ret, type;
+
+       gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
+           get_khandle_from_ino(inode));
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
+       if (!new_op)
+               return -ENOMEM;
+       new_op->upcall.req.getattr.refn = orangefs_inode->refn;
+       new_op->upcall.req.getattr.mask = size ?
+           ORANGEFS_ATTR_SYS_ALL_NOHINT : ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE;
+
+       ret = service_operation(new_op, __func__,
+           get_interruptible_flag(inode));
+       if (ret != 0)
+               goto out;
+
+       type = orangefs_inode_type(new_op->
+           downcall.resp.getattr.attributes.objtype);
+       ret = orangefs_inode_is_stale(inode, new,
+           &new_op->downcall.resp.getattr.attributes,
+           new_op->downcall.resp.getattr.link_target);
+       if (ret) {
+               ret = -ESTALE;
+               goto out;
+       }
+
+       switch (type) {
+       case S_IFREG:
+               inode->i_flags = orangefs_inode_flags(&new_op->
+                   downcall.resp.getattr.attributes);
+               if (size) {
+                       inode_size = (loff_t)new_op->
+                           downcall.resp.getattr.attributes.size;
+                       rounded_up_size =
+                           (inode_size + (4096 - (inode_size % 4096)));
+                       inode->i_size = inode_size;
+                       orangefs_inode->blksize =
+                           new_op->downcall.resp.getattr.attributes.blksize;
+                       spin_lock(&inode->i_lock);
+                       inode->i_bytes = inode_size;
+                       inode->i_blocks =
+                           (unsigned long)(rounded_up_size / 512);
+                       spin_unlock(&inode->i_lock);
+               }
+               break;
+       case S_IFDIR:
+               inode->i_size = PAGE_CACHE_SIZE;
+               orangefs_inode->blksize = (1 << inode->i_blkbits);
+               spin_lock(&inode->i_lock);
+               inode_set_bytes(inode, inode->i_size);
+               spin_unlock(&inode->i_lock);
+               set_nlink(inode, 1);
+               break;
+       case S_IFLNK:
+               if (new) {
+                       inode->i_size = (loff_t)strlen(new_op->
+                           downcall.resp.getattr.link_target);
+                       orangefs_inode->blksize = (1 << inode->i_blkbits);
+                       strlcpy(orangefs_inode->link_target,
+                           new_op->downcall.resp.getattr.link_target,
+                           ORANGEFS_NAME_MAX);
+                       inode->i_link = orangefs_inode->link_target;
+               }
+               break;
+       }
+
+       inode->i_uid = make_kuid(&init_user_ns, new_op->
+           downcall.resp.getattr.attributes.owner);
+       inode->i_gid = make_kgid(&init_user_ns, new_op->
+           downcall.resp.getattr.attributes.group);
+       inode->i_atime.tv_sec = (time64_t)new_op->
+           downcall.resp.getattr.attributes.atime;
+       inode->i_mtime.tv_sec = (time64_t)new_op->
+           downcall.resp.getattr.attributes.mtime;
+       inode->i_ctime.tv_sec = (time64_t)new_op->
+           downcall.resp.getattr.attributes.ctime;
+       inode->i_atime.tv_nsec = 0;
+       inode->i_mtime.tv_nsec = 0;
+       inode->i_ctime.tv_nsec = 0;
+
+       /* special case: mark the root inode as sticky */
+       inode->i_mode = type | (is_root_handle(inode) ? S_ISVTX : 0) |
+           orangefs_inode_perms(&new_op->downcall.resp.getattr.attributes);
+
+       ret = 0;
+out:
+       op_release(new_op);
+       return ret;
+}
+
+int orangefs_inode_check_changed(struct inode *inode)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_kernel_op_s *new_op;
+       int ret;
+
+       gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
+           get_khandle_from_ino(inode));
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
+       if (!new_op)
+               return -ENOMEM;
+       new_op->upcall.req.getattr.refn = orangefs_inode->refn;
+       new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_TYPE |
+           ORANGEFS_ATTR_SYS_LNK_TARGET;
+
+       ret = service_operation(new_op, __func__,
+           get_interruptible_flag(inode));
+       if (ret != 0)
+               goto out;
+
+       ret = orangefs_inode_is_stale(inode, 0,
+           &new_op->downcall.resp.getattr.attributes,
+           new_op->downcall.resp.getattr.link_target);
+out:
+       op_release(new_op);
+       return ret;
+}
+
+/*
+ * issues a orangefs setattr request to make sure the new attribute values
+ * take effect if successful.  returns 0 on success; -errno otherwise
+ */
+int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_kernel_op_s *new_op;
+       int ret;
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_SETATTR);
+       if (!new_op)
+               return -ENOMEM;
+
+       new_op->upcall.req.setattr.refn = orangefs_inode->refn;
+       ret = copy_attributes_from_inode(inode,
+                      &new_op->upcall.req.setattr.attributes,
+                      iattr);
+       if (ret >= 0) {
+               ret = service_operation(new_op, __func__,
+                               get_interruptible_flag(inode));
+
+               gossip_debug(GOSSIP_UTILS_DEBUG,
+                            "orangefs_inode_setattr: returning %d\n",
+                            ret);
+       }
+
+       op_release(new_op);
+
+       /*
+        * successful setattr should clear the atime, mtime and
+        * ctime flags.
+        */
+       if (ret == 0) {
+               ClearAtimeFlag(orangefs_inode);
+               ClearMtimeFlag(orangefs_inode);
+               ClearCtimeFlag(orangefs_inode);
+               ClearModeFlag(orangefs_inode);
+       }
+
+       return ret;
+}
+
+int orangefs_flush_inode(struct inode *inode)
+{
+       /*
+        * If it is a dirty inode, this function gets called.
+        * Gather all the information that needs to be setattr'ed
+        * Right now, this will only be used for mode, atime, mtime
+        * and/or ctime.
+        */
+       struct iattr wbattr;
+       int ret;
+       int mtime_flag;
+       int ctime_flag;
+       int atime_flag;
+       int mode_flag;
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+
+       memset(&wbattr, 0, sizeof(wbattr));
+
+       /*
+        * check inode flags up front, and clear them if they are set.  This
+        * will prevent multiple processes from all trying to flush the same
+        * inode if they call close() simultaneously
+        */
+       mtime_flag = MtimeFlag(orangefs_inode);
+       ClearMtimeFlag(orangefs_inode);
+       ctime_flag = CtimeFlag(orangefs_inode);
+       ClearCtimeFlag(orangefs_inode);
+       atime_flag = AtimeFlag(orangefs_inode);
+       ClearAtimeFlag(orangefs_inode);
+       mode_flag = ModeFlag(orangefs_inode);
+       ClearModeFlag(orangefs_inode);
+
+       /*  -- Lazy atime,mtime and ctime update --
+        * Note: all times are dictated by server in the new scheme
+        * and not by the clients
+        *
+        * Also mode updates are being handled now..
+        */
+
+       if (mtime_flag)
+               wbattr.ia_valid |= ATTR_MTIME;
+       if (ctime_flag)
+               wbattr.ia_valid |= ATTR_CTIME;
+       if (atime_flag)
+               wbattr.ia_valid |= ATTR_ATIME;
+
+       if (mode_flag) {
+               wbattr.ia_mode = inode->i_mode;
+               wbattr.ia_valid |= ATTR_MODE;
+       }
+
+       gossip_debug(GOSSIP_UTILS_DEBUG,
+                    "*********** orangefs_flush_inode: %pU "
+                    "(ia_valid %d)\n",
+                    get_khandle_from_ino(inode),
+                    wbattr.ia_valid);
+       if (wbattr.ia_valid == 0) {
+               gossip_debug(GOSSIP_UTILS_DEBUG,
+                            "orangefs_flush_inode skipping setattr()\n");
+               return 0;
+       }
+
+       gossip_debug(GOSSIP_UTILS_DEBUG,
+                    "orangefs_flush_inode (%pU) writing mode %o\n",
+                    get_khandle_from_ino(inode),
+                    inode->i_mode);
+
+       ret = orangefs_inode_setattr(inode, &wbattr);
+
+       return ret;
+}
+
+int orangefs_unmount_sb(struct super_block *sb)
+{
+       int ret = -EINVAL;
+       struct orangefs_kernel_op_s *new_op = NULL;
+
+       gossip_debug(GOSSIP_UTILS_DEBUG,
+                    "orangefs_unmount_sb called on sb %p\n",
+                    sb);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_FS_UMOUNT);
+       if (!new_op)
+               return -ENOMEM;
+       new_op->upcall.req.fs_umount.id = ORANGEFS_SB(sb)->id;
+       new_op->upcall.req.fs_umount.fs_id = ORANGEFS_SB(sb)->fs_id;
+       strncpy(new_op->upcall.req.fs_umount.orangefs_config_server,
+               ORANGEFS_SB(sb)->devname,
+               ORANGEFS_MAX_SERVER_ADDR_LEN);
+
+       gossip_debug(GOSSIP_UTILS_DEBUG,
+                    "Attempting ORANGEFS Unmount via host %s\n",
+                    new_op->upcall.req.fs_umount.orangefs_config_server);
+
+       ret = service_operation(new_op, "orangefs_fs_umount", 0);
+
+       gossip_debug(GOSSIP_UTILS_DEBUG,
+                    "orangefs_unmount: got return value of %d\n", ret);
+       if (ret)
+               sb = ERR_PTR(ret);
+       else
+               ORANGEFS_SB(sb)->mount_pending = 1;
+
+       op_release(new_op);
+       return ret;
+}
+
+void orangefs_make_bad_inode(struct inode *inode)
+{
+       if (is_root_handle(inode)) {
+               /*
+                * if this occurs, the pvfs2-client-core was killed but we
+                * can't afford to lose the inode operations and such
+                * associated with the root handle in any case.
+                */
+               gossip_debug(GOSSIP_UTILS_DEBUG,
+                            "*** NOT making bad root inode %pU\n",
+                            get_khandle_from_ino(inode));
+       } else {
+               gossip_debug(GOSSIP_UTILS_DEBUG,
+                            "*** making bad inode %pU\n",
+                            get_khandle_from_ino(inode));
+               make_bad_inode(inode);
+       }
+}
+
+/*
+ * The following is a very dirty hack that is now a permanent part of the
+ * ORANGEFS protocol. See protocol.h for more error definitions.
+ */
+
+/* The order matches include/orangefs-types.h in the OrangeFS source. */
+static int PINT_errno_mapping[] = {
+       0, EPERM, ENOENT, EINTR, EIO, ENXIO, EBADF, EAGAIN, ENOMEM,
+       EFAULT, EBUSY, EEXIST, ENODEV, ENOTDIR, EISDIR, EINVAL, EMFILE,
+       EFBIG, ENOSPC, EROFS, EMLINK, EPIPE, EDEADLK, ENAMETOOLONG,
+       ENOLCK, ENOSYS, ENOTEMPTY, ELOOP, EWOULDBLOCK, ENOMSG, EUNATCH,
+       EBADR, EDEADLOCK, ENODATA, ETIME, ENONET, EREMOTE, ECOMM,
+       EPROTO, EBADMSG, EOVERFLOW, ERESTART, EMSGSIZE, EPROTOTYPE,
+       ENOPROTOOPT, EPROTONOSUPPORT, EOPNOTSUPP, EADDRINUSE,
+       EADDRNOTAVAIL, ENETDOWN, ENETUNREACH, ENETRESET, ENOBUFS,
+       ETIMEDOUT, ECONNREFUSED, EHOSTDOWN, EHOSTUNREACH, EALREADY,
+       EACCES, ECONNRESET, ERANGE
+};
+
+int orangefs_normalize_to_errno(__s32 error_code)
+{
+       __u32 i;
+
+       /* Success */
+       if (error_code == 0) {
+               return 0;
+       /*
+        * This shouldn't ever happen. If it does it should be fixed on the
+        * server.
+        */
+       } else if (error_code > 0) {
+               gossip_err("orangefs: error status receieved.\n");
+               gossip_err("orangefs: assuming error code is inverted.\n");
+               error_code = -error_code;
+       }
+
+       /*
+        * XXX: This is very bad since error codes from ORANGEFS may not be
+        * suitable for return into userspace.
+        */
+
+       /*
+        * Convert ORANGEFS error values into errno values suitable for return
+        * from the kernel.
+        */
+       if ((-error_code) & ORANGEFS_NON_ERRNO_ERROR_BIT) {
+               if (((-error_code) &
+                   (ORANGEFS_ERROR_NUMBER_BITS|ORANGEFS_NON_ERRNO_ERROR_BIT|
+                   ORANGEFS_ERROR_BIT)) == ORANGEFS_ECANCEL) {
+                       /*
+                        * cancellation error codes generally correspond to
+                        * a timeout from the client's perspective
+                        */
+                       error_code = -ETIMEDOUT;
+               } else {
+                       /* assume a default error code */
+                       gossip_err("orangefs: warning: got error code without errno equivalent: %d.\n", error_code);
+                       error_code = -EINVAL;
+               }
+
+       /* Convert ORANGEFS encoded errno values into regular errno values. */
+       } else if ((-error_code) & ORANGEFS_ERROR_BIT) {
+               i = (-error_code) & ~(ORANGEFS_ERROR_BIT|ORANGEFS_ERROR_CLASS_BITS);
+               if (i < sizeof(PINT_errno_mapping)/sizeof(*PINT_errno_mapping))
+                       error_code = -PINT_errno_mapping[i];
+               else
+                       error_code = -EINVAL;
+
+       /*
+        * Only ORANGEFS protocol error codes should ever come here. Otherwise
+        * there is a bug somewhere.
+        */
+       } else {
+               gossip_err("orangefs: orangefs_normalize_to_errno: got error code which is not from ORANGEFS.\n");
+       }
+       return error_code;
+}
+
+#define NUM_MODES 11
+__s32 ORANGEFS_util_translate_mode(int mode)
+{
+       int ret = 0;
+       int i = 0;
+       static int modes[NUM_MODES] = {
+               S_IXOTH, S_IWOTH, S_IROTH,
+               S_IXGRP, S_IWGRP, S_IRGRP,
+               S_IXUSR, S_IWUSR, S_IRUSR,
+               S_ISGID, S_ISUID
+       };
+       static int orangefs_modes[NUM_MODES] = {
+               ORANGEFS_O_EXECUTE, ORANGEFS_O_WRITE, ORANGEFS_O_READ,
+               ORANGEFS_G_EXECUTE, ORANGEFS_G_WRITE, ORANGEFS_G_READ,
+               ORANGEFS_U_EXECUTE, ORANGEFS_U_WRITE, ORANGEFS_U_READ,
+               ORANGEFS_G_SGID, ORANGEFS_U_SUID
+       };
+
+       for (i = 0; i < NUM_MODES; i++)
+               if (mode & modes[i])
+                       ret |= orangefs_modes[i];
+
+       return ret;
+}
+#undef NUM_MODES
+
+/*
+ * After obtaining a string representation of the client's debug
+ * keywords and their associated masks, this function is called to build an
+ * array of these values.
+ */
+int orangefs_prepare_cdm_array(char *debug_array_string)
+{
+       int i;
+       int rc = -EINVAL;
+       char *cds_head = NULL;
+       char *cds_delimiter = NULL;
+       int keyword_len = 0;
+
+       gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
+
+       /*
+        * figure out how many elements the cdm_array needs.
+        */
+       for (i = 0; i < strlen(debug_array_string); i++)
+               if (debug_array_string[i] == '\n')
+                       cdm_element_count++;
+
+       if (!cdm_element_count) {
+               pr_info("No elements in client debug array string!\n");
+               goto out;
+       }
+
+       cdm_array =
+               kzalloc(cdm_element_count * sizeof(struct client_debug_mask),
+                       GFP_KERNEL);
+       if (!cdm_array) {
+               pr_info("malloc failed for cdm_array!\n");
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       cds_head = debug_array_string;
+
+       for (i = 0; i < cdm_element_count; i++) {
+               cds_delimiter = strchr(cds_head, '\n');
+               *cds_delimiter = '\0';
+
+               keyword_len = strcspn(cds_head, " ");
+
+               cdm_array[i].keyword = kzalloc(keyword_len + 1, GFP_KERNEL);
+               if (!cdm_array[i].keyword) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               sscanf(cds_head,
+                      "%s %llx %llx",
+                      cdm_array[i].keyword,
+                      (unsigned long long *)&(cdm_array[i].mask1),
+                      (unsigned long long *)&(cdm_array[i].mask2));
+
+               if (!strcmp(cdm_array[i].keyword, ORANGEFS_VERBOSE))
+                       client_verbose_index = i;
+
+               if (!strcmp(cdm_array[i].keyword, ORANGEFS_ALL))
+                       client_all_index = i;
+
+               cds_head = cds_delimiter + 1;
+       }
+
+       rc = cdm_element_count;
+
+       gossip_debug(GOSSIP_UTILS_DEBUG, "%s: rc:%d:\n", __func__, rc);
+
+out:
+
+       return rc;
+
+}
+
+/*
+ * /sys/kernel/debug/orangefs/debug-help can be catted to
+ * see all the available kernel and client debug keywords.
+ *
+ * When the kernel boots, we have no idea what keywords the
+ * client supports, nor their associated masks.
+ *
+ * We pass through this function once at boot and stamp a
+ * boilerplate "we don't know" message for the client in the
+ * debug-help file. We pass through here again when the client
+ * starts and then we can fill out the debug-help file fully.
+ *
+ * The client might be restarted any number of times between
+ * reboots, we only build the debug-help file the first time.
+ */
+int orangefs_prepare_debugfs_help_string(int at_boot)
+{
+       int rc = -EINVAL;
+       int i;
+       int byte_count = 0;
+       char *client_title = "Client Debug Keywords:\n";
+       char *kernel_title = "Kernel Debug Keywords:\n";
+
+       gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
+
+       if (at_boot) {
+               byte_count += strlen(HELP_STRING_UNINITIALIZED);
+               client_title = HELP_STRING_UNINITIALIZED;
+       } else {
+               /*
+                * fill the client keyword/mask array and remember
+                * how many elements there were.
+                */
+               cdm_element_count =
+                       orangefs_prepare_cdm_array(client_debug_array_string);
+               if (cdm_element_count <= 0)
+                       goto out;
+
+               /* Count the bytes destined for debug_help_string. */
+               byte_count += strlen(client_title);
+
+               for (i = 0; i < cdm_element_count; i++) {
+                       byte_count += strlen(cdm_array[i].keyword + 2);
+                       if (byte_count >= DEBUG_HELP_STRING_SIZE) {
+                               pr_info("%s: overflow 1!\n", __func__);
+                               goto out;
+                       }
+               }
+
+               gossip_debug(GOSSIP_UTILS_DEBUG,
+                            "%s: cdm_element_count:%d:\n",
+                            __func__,
+                            cdm_element_count);
+       }
+
+       byte_count += strlen(kernel_title);
+       for (i = 0; i < num_kmod_keyword_mask_map; i++) {
+               byte_count +=
+                       strlen(s_kmod_keyword_mask_map[i].keyword + 2);
+               if (byte_count >= DEBUG_HELP_STRING_SIZE) {
+                       pr_info("%s: overflow 2!\n", __func__);
+                       goto out;
+               }
+       }
+
+       /* build debug_help_string. */
+       debug_help_string = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL);
+       if (!debug_help_string) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       strcat(debug_help_string, client_title);
+
+       if (!at_boot) {
+               for (i = 0; i < cdm_element_count; i++) {
+                       strcat(debug_help_string, "\t");
+                       strcat(debug_help_string, cdm_array[i].keyword);
+                       strcat(debug_help_string, "\n");
+               }
+       }
+
+       strcat(debug_help_string, "\n");
+       strcat(debug_help_string, kernel_title);
+
+       for (i = 0; i < num_kmod_keyword_mask_map; i++) {
+               strcat(debug_help_string, "\t");
+               strcat(debug_help_string, s_kmod_keyword_mask_map[i].keyword);
+               strcat(debug_help_string, "\n");
+       }
+
+       rc = 0;
+
+out:
+
+       return rc;
+
+}
+
+/*
+ * kernel = type 0
+ * client = type 1
+ */
+void debug_mask_to_string(void *mask, int type)
+{
+       int i;
+       int len = 0;
+       char *debug_string;
+       int element_count = 0;
+
+       gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
+
+       if (type) {
+               debug_string = client_debug_string;
+               element_count = cdm_element_count;
+       } else {
+               debug_string = kernel_debug_string;
+               element_count = num_kmod_keyword_mask_map;
+       }
+
+       memset(debug_string, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
+
+       /*
+        * Some keywords, like "all" or "verbose", are amalgams of
+        * numerous other keywords. Make a special check for those
+        * before grinding through the whole mask only to find out
+        * later...
+        */
+       if (check_amalgam_keyword(mask, type))
+               goto out;
+
+       /* Build the debug string. */
+       for (i = 0; i < element_count; i++)
+               if (type)
+                       do_c_string(mask, i);
+               else
+                       do_k_string(mask, i);
+
+       len = strlen(debug_string);
+
+       if ((len) && (type))
+               client_debug_string[len - 1] = '\0';
+       else if (len)
+               kernel_debug_string[len - 1] = '\0';
+       else if (type)
+               strcpy(client_debug_string, "none");
+       else
+               strcpy(kernel_debug_string, "none");
+
+out:
+gossip_debug(GOSSIP_UTILS_DEBUG, "%s: string:%s:\n", __func__, debug_string);
+
+       return;
+
+}
+
+void do_k_string(void *k_mask, int index)
+{
+       __u64 *mask = (__u64 *) k_mask;
+
+       if (keyword_is_amalgam((char *) s_kmod_keyword_mask_map[index].keyword))
+               goto out;
+
+       if (*mask & s_kmod_keyword_mask_map[index].mask_val) {
+               if ((strlen(kernel_debug_string) +
+                    strlen(s_kmod_keyword_mask_map[index].keyword))
+                       < ORANGEFS_MAX_DEBUG_STRING_LEN - 1) {
+                               strcat(kernel_debug_string,
+                                      s_kmod_keyword_mask_map[index].keyword);
+                               strcat(kernel_debug_string, ",");
+                       } else {
+                               gossip_err("%s: overflow!\n", __func__);
+                               strcpy(kernel_debug_string, ORANGEFS_ALL);
+                               goto out;
+                       }
+       }
+
+out:
+
+       return;
+}
+
+void do_c_string(void *c_mask, int index)
+{
+       struct client_debug_mask *mask = (struct client_debug_mask *) c_mask;
+
+       if (keyword_is_amalgam(cdm_array[index].keyword))
+               goto out;
+
+       if ((mask->mask1 & cdm_array[index].mask1) ||
+           (mask->mask2 & cdm_array[index].mask2)) {
+               if ((strlen(client_debug_string) +
+                    strlen(cdm_array[index].keyword) + 1)
+                       < ORANGEFS_MAX_DEBUG_STRING_LEN - 2) {
+                               strcat(client_debug_string,
+                                      cdm_array[index].keyword);
+                               strcat(client_debug_string, ",");
+                       } else {
+                               gossip_err("%s: overflow!\n", __func__);
+                               strcpy(client_debug_string, ORANGEFS_ALL);
+                               goto out;
+                       }
+       }
+out:
+       return;
+}
+
+int keyword_is_amalgam(char *keyword)
+{
+       int rc = 0;
+
+       if ((!strcmp(keyword, ORANGEFS_ALL)) || (!strcmp(keyword, ORANGEFS_VERBOSE)))
+               rc = 1;
+
+       return rc;
+}
+
+/*
+ * kernel = type 0
+ * client = type 1
+ *
+ * return 1 if we found an amalgam.
+ */
+int check_amalgam_keyword(void *mask, int type)
+{
+       __u64 *k_mask;
+       struct client_debug_mask *c_mask;
+       int k_all_index = num_kmod_keyword_mask_map - 1;
+       int rc = 0;
+
+       if (type) {
+               c_mask = (struct client_debug_mask *) mask;
+
+               if ((c_mask->mask1 == cdm_array[client_all_index].mask1) &&
+                   (c_mask->mask2 == cdm_array[client_all_index].mask2)) {
+                       strcpy(client_debug_string, ORANGEFS_ALL);
+                       rc = 1;
+                       goto out;
+               }
+
+               if ((c_mask->mask1 == cdm_array[client_verbose_index].mask1) &&
+                   (c_mask->mask2 == cdm_array[client_verbose_index].mask2)) {
+                       strcpy(client_debug_string, ORANGEFS_VERBOSE);
+                       rc = 1;
+                       goto out;
+               }
+
+       } else {
+               k_mask = (__u64 *) mask;
+
+               if (*k_mask >= s_kmod_keyword_mask_map[k_all_index].mask_val) {
+                       strcpy(kernel_debug_string, ORANGEFS_ALL);
+                       rc = 1;
+                       goto out;
+               }
+       }
+
+out:
+
+       return rc;
+}
+
+/*
+ * kernel = type 0
+ * client = type 1
+ */
+void debug_string_to_mask(char *debug_string, void *mask, int type)
+{
+       char *unchecked_keyword;
+       int i;
+       char *strsep_fodder = kstrdup(debug_string, GFP_KERNEL);
+       char *original_pointer;
+       int element_count = 0;
+       struct client_debug_mask *c_mask;
+       __u64 *k_mask;
+
+       gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
+
+       if (type) {
+               c_mask = (struct client_debug_mask *)mask;
+               element_count = cdm_element_count;
+       } else {
+               k_mask = (__u64 *)mask;
+               *k_mask = 0;
+               element_count = num_kmod_keyword_mask_map;
+       }
+
+       original_pointer = strsep_fodder;
+       while ((unchecked_keyword = strsep(&strsep_fodder, ",")))
+               if (strlen(unchecked_keyword)) {
+                       for (i = 0; i < element_count; i++)
+                               if (type)
+                                       do_c_mask(i,
+                                                 unchecked_keyword,
+                                                 &c_mask);
+                               else
+                                       do_k_mask(i,
+                                                 unchecked_keyword,
+                                                 &k_mask);
+               }
+
+       kfree(original_pointer);
+}
+
+void do_c_mask(int i,
+              char *unchecked_keyword,
+              struct client_debug_mask **sane_mask)
+{
+
+       if (!strcmp(cdm_array[i].keyword, unchecked_keyword)) {
+               (**sane_mask).mask1 = (**sane_mask).mask1 | cdm_array[i].mask1;
+               (**sane_mask).mask2 = (**sane_mask).mask2 | cdm_array[i].mask2;
+       }
+}
+
+void do_k_mask(int i, char *unchecked_keyword, __u64 **sane_mask)
+{
+
+       if (!strcmp(s_kmod_keyword_mask_map[i].keyword, unchecked_keyword))
+               **sane_mask = (**sane_mask) |
+                               s_kmod_keyword_mask_map[i].mask_val;
+}
diff --git a/fs/orangefs/protocol.h b/fs/orangefs/protocol.h
new file mode 100644 (file)
index 0000000..50578a2
--- /dev/null
@@ -0,0 +1,452 @@
+#include <linux/types.h>
+#include <linux/spinlock_types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+
+extern struct client_debug_mask *cdm_array;
+extern char *debug_help_string;
+extern int help_string_initialized;
+extern struct dentry *debug_dir;
+extern struct dentry *help_file_dentry;
+extern struct dentry *client_debug_dentry;
+extern const struct file_operations debug_help_fops;
+extern int client_all_index;
+extern int client_verbose_index;
+extern int cdm_element_count;
+#define DEBUG_HELP_STRING_SIZE 4096
+#define HELP_STRING_UNINITIALIZED \
+       "Client Debug Keywords are unknown until the first time\n" \
+       "the client is started after boot.\n"
+#define ORANGEFS_KMOD_DEBUG_HELP_FILE "debug-help"
+#define ORANGEFS_KMOD_DEBUG_FILE "kernel-debug"
+#define ORANGEFS_CLIENT_DEBUG_FILE "client-debug"
+#define ORANGEFS_VERBOSE "verbose"
+#define ORANGEFS_ALL "all"
+
+/* pvfs2-config.h ***********************************************************/
+#define ORANGEFS_VERSION_MAJOR 2
+#define ORANGEFS_VERSION_MINOR 9
+#define ORANGEFS_VERSION_SUB 0
+
+/* khandle stuff  ***********************************************************/
+
+/*
+ * The 2.9 core will put 64 bit handles in here like this:
+ *    1234 0000 0000 5678
+ * The 3.0 and beyond cores will put 128 bit handles in here like this:
+ *    1234 5678 90AB CDEF
+ * The kernel module will always use the first four bytes and
+ * the last four bytes as an inum.
+ */
+struct orangefs_khandle {
+       unsigned char u[16];
+}  __aligned(8);
+
+/*
+ * kernel version of an object ref.
+ */
+struct orangefs_object_kref {
+       struct orangefs_khandle khandle;
+       __s32 fs_id;
+       __s32 __pad1;
+};
+
+/*
+ * compare 2 khandles assumes little endian thus from large address to
+ * small address
+ */
+static inline int ORANGEFS_khandle_cmp(const struct orangefs_khandle *kh1,
+                                  const struct orangefs_khandle *kh2)
+{
+       int i;
+
+       for (i = 15; i >= 0; i--) {
+               if (kh1->u[i] > kh2->u[i])
+                       return 1;
+               if (kh1->u[i] < kh2->u[i])
+                       return -1;
+       }
+
+       return 0;
+}
+
+static inline void ORANGEFS_khandle_to(const struct orangefs_khandle *kh,
+                                  void *p, int size)
+{
+
+       memset(p, 0, size);
+       memcpy(p, kh->u, 16);
+
+}
+
+static inline void ORANGEFS_khandle_from(struct orangefs_khandle *kh,
+                                    void *p, int size)
+{
+       memset(kh, 0, 16);
+       memcpy(kh->u, p, 16);
+
+}
+
+/* pvfs2-types.h ************************************************************/
+typedef __u32 ORANGEFS_uid;
+typedef __u32 ORANGEFS_gid;
+typedef __s32 ORANGEFS_fs_id;
+typedef __u32 ORANGEFS_permissions;
+typedef __u64 ORANGEFS_time;
+typedef __s64 ORANGEFS_size;
+typedef __u64 ORANGEFS_flags;
+typedef __u64 ORANGEFS_ds_position;
+typedef __s32 ORANGEFS_error;
+typedef __s64 ORANGEFS_offset;
+
+#define ORANGEFS_SUPER_MAGIC 0x20030528
+
+/*
+ * ORANGEFS error codes are a signed 32-bit integer. Error codes are negative, but
+ * the sign is stripped before decoding.
+ */
+
+/* Bit 31 is not used since it is the sign. */
+
+/*
+ * Bit 30 specifies that this is a ORANGEFS error. A ORANGEFS error is either an
+ * encoded errno value or a ORANGEFS protocol error.
+ */
+#define ORANGEFS_ERROR_BIT (1 << 30)
+
+/*
+ * Bit 29 specifies that this is a ORANGEFS protocol error and not an encoded
+ * errno value.
+ */
+#define ORANGEFS_NON_ERRNO_ERROR_BIT (1 << 29)
+
+/*
+ * Bits 9, 8, and 7 specify the error class, which encodes the section of
+ * server code the error originated in for logging purposes. It is not used
+ * in the kernel except to be masked out.
+ */
+#define ORANGEFS_ERROR_CLASS_BITS 0x380
+
+/* Bits 6 - 0 are reserved for the actual error code. */
+#define ORANGEFS_ERROR_NUMBER_BITS 0x7f
+
+/* Encoded errno values decoded by PINT_errno_mapping in orangefs-utils.c. */
+
+/* Our own ORANGEFS protocol error codes. */
+#define ORANGEFS_ECANCEL    (1|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+#define ORANGEFS_EDEVINIT   (2|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+#define ORANGEFS_EDETAIL    (3|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+#define ORANGEFS_EHOSTNTFD  (4|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+#define ORANGEFS_EADDRNTFD  (5|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+#define ORANGEFS_ENORECVR   (6|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+#define ORANGEFS_ETRYAGAIN  (7|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+#define ORANGEFS_ENOTPVFS   (8|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+#define ORANGEFS_ESECURITY  (9|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT)
+
+/* permission bits */
+#define ORANGEFS_O_EXECUTE (1 << 0)
+#define ORANGEFS_O_WRITE   (1 << 1)
+#define ORANGEFS_O_READ    (1 << 2)
+#define ORANGEFS_G_EXECUTE (1 << 3)
+#define ORANGEFS_G_WRITE   (1 << 4)
+#define ORANGEFS_G_READ    (1 << 5)
+#define ORANGEFS_U_EXECUTE (1 << 6)
+#define ORANGEFS_U_WRITE   (1 << 7)
+#define ORANGEFS_U_READ    (1 << 8)
+/* no ORANGEFS_U_VTX (sticky bit) */
+#define ORANGEFS_G_SGID    (1 << 10)
+#define ORANGEFS_U_SUID    (1 << 11)
+
+/* definition taken from stdint.h */
+#define INT32_MAX (2147483647)
+#define ORANGEFS_ITERATE_START    (INT32_MAX - 1)
+#define ORANGEFS_ITERATE_END      (INT32_MAX - 2)
+#define ORANGEFS_ITERATE_NEXT     (INT32_MAX - 3)
+#define ORANGEFS_READDIR_START ORANGEFS_ITERATE_START
+#define ORANGEFS_READDIR_END   ORANGEFS_ITERATE_END
+#define ORANGEFS_IMMUTABLE_FL FS_IMMUTABLE_FL
+#define ORANGEFS_APPEND_FL    FS_APPEND_FL
+#define ORANGEFS_NOATIME_FL   FS_NOATIME_FL
+#define ORANGEFS_MIRROR_FL    0x01000000ULL
+#define ORANGEFS_O_EXECUTE (1 << 0)
+#define ORANGEFS_FS_ID_NULL       ((__s32)0)
+#define ORANGEFS_ATTR_SYS_UID                   (1 << 0)
+#define ORANGEFS_ATTR_SYS_GID                   (1 << 1)
+#define ORANGEFS_ATTR_SYS_PERM                  (1 << 2)
+#define ORANGEFS_ATTR_SYS_ATIME                 (1 << 3)
+#define ORANGEFS_ATTR_SYS_CTIME                 (1 << 4)
+#define ORANGEFS_ATTR_SYS_MTIME                 (1 << 5)
+#define ORANGEFS_ATTR_SYS_TYPE                  (1 << 6)
+#define ORANGEFS_ATTR_SYS_ATIME_SET             (1 << 7)
+#define ORANGEFS_ATTR_SYS_MTIME_SET             (1 << 8)
+#define ORANGEFS_ATTR_SYS_SIZE                  (1 << 20)
+#define ORANGEFS_ATTR_SYS_LNK_TARGET            (1 << 24)
+#define ORANGEFS_ATTR_SYS_DFILE_COUNT           (1 << 25)
+#define ORANGEFS_ATTR_SYS_DIRENT_COUNT          (1 << 26)
+#define ORANGEFS_ATTR_SYS_BLKSIZE               (1 << 28)
+#define ORANGEFS_ATTR_SYS_MIRROR_COPIES_COUNT   (1 << 29)
+#define ORANGEFS_ATTR_SYS_COMMON_ALL   \
+       (ORANGEFS_ATTR_SYS_UID  |       \
+        ORANGEFS_ATTR_SYS_GID  |       \
+        ORANGEFS_ATTR_SYS_PERM |       \
+        ORANGEFS_ATTR_SYS_ATIME        |       \
+        ORANGEFS_ATTR_SYS_CTIME        |       \
+        ORANGEFS_ATTR_SYS_MTIME        |       \
+        ORANGEFS_ATTR_SYS_TYPE)
+
+#define ORANGEFS_ATTR_SYS_ALL_SETABLE          \
+(ORANGEFS_ATTR_SYS_COMMON_ALL-ORANGEFS_ATTR_SYS_TYPE)
+
+#define ORANGEFS_ATTR_SYS_ALL_NOHINT                   \
+       (ORANGEFS_ATTR_SYS_COMMON_ALL           |       \
+        ORANGEFS_ATTR_SYS_SIZE                 |       \
+        ORANGEFS_ATTR_SYS_LNK_TARGET           |       \
+        ORANGEFS_ATTR_SYS_DFILE_COUNT          |       \
+        ORANGEFS_ATTR_SYS_MIRROR_COPIES_COUNT  |       \
+        ORANGEFS_ATTR_SYS_DIRENT_COUNT         |       \
+        ORANGEFS_ATTR_SYS_BLKSIZE)
+
+#define ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE            \
+       (ORANGEFS_ATTR_SYS_COMMON_ALL           |       \
+        ORANGEFS_ATTR_SYS_LNK_TARGET           |       \
+        ORANGEFS_ATTR_SYS_DFILE_COUNT          |       \
+        ORANGEFS_ATTR_SYS_MIRROR_COPIES_COUNT  |       \
+        ORANGEFS_ATTR_SYS_DIRENT_COUNT         |       \
+        ORANGEFS_ATTR_SYS_BLKSIZE)
+
+#define ORANGEFS_XATTR_REPLACE 0x2
+#define ORANGEFS_XATTR_CREATE  0x1
+#define ORANGEFS_MAX_SERVER_ADDR_LEN 256
+#define ORANGEFS_NAME_MAX                256
+/*
+ * max extended attribute name len as imposed by the VFS and exploited for the
+ * upcall request types.
+ * NOTE: Please retain them as multiples of 8 even if you wish to change them
+ * This is *NECESSARY* for supporting 32 bit user-space binaries on a 64-bit
+ * kernel. Due to implementation within DBPF, this really needs to be
+ * ORANGEFS_NAME_MAX, which it was the same value as, but no reason to let it
+ * break if that changes in the future.
+ */
+#define ORANGEFS_MAX_XATTR_NAMELEN   ORANGEFS_NAME_MAX /* Not the same as
+                                                * XATTR_NAME_MAX defined
+                                                * by <linux/xattr.h>
+                                                */
+#define ORANGEFS_MAX_XATTR_VALUELEN  8192      /* Not the same as XATTR_SIZE_MAX
+                                        * defined by <linux/xattr.h>
+                                        */
+#define ORANGEFS_MAX_XATTR_LISTLEN   16        /* Not the same as XATTR_LIST_MAX
+                                        * defined by <linux/xattr.h>
+                                        */
+/*
+ * ORANGEFS I/O operation types, used in both system and server interfaces.
+ */
+enum ORANGEFS_io_type {
+       ORANGEFS_IO_READ = 1,
+       ORANGEFS_IO_WRITE = 2
+};
+
+/*
+ * If this enum is modified the server parameters related to the precreate pool
+ * batch and low threshold sizes may need to be modified  to reflect this
+ * change.
+ */
+enum orangefs_ds_type {
+       ORANGEFS_TYPE_NONE = 0,
+       ORANGEFS_TYPE_METAFILE = (1 << 0),
+       ORANGEFS_TYPE_DATAFILE = (1 << 1),
+       ORANGEFS_TYPE_DIRECTORY = (1 << 2),
+       ORANGEFS_TYPE_SYMLINK = (1 << 3),
+       ORANGEFS_TYPE_DIRDATA = (1 << 4),
+       ORANGEFS_TYPE_INTERNAL = (1 << 5)       /* for the server's private use */
+};
+
+/*
+ * ORANGEFS_certificate simply stores a buffer with the buffer size.
+ * The buffer can be converted to an OpenSSL X509 struct for use.
+ */
+struct ORANGEFS_certificate {
+       __u32 buf_size;
+       unsigned char *buf;
+};
+
+/*
+ * A credential identifies a user and is signed by the client/user
+ * private key.
+ */
+struct ORANGEFS_credential {
+       __u32 userid;   /* user id */
+       __u32 num_groups;       /* length of group_array */
+       __u32 *group_array;     /* groups for which the user is a member */
+       char *issuer;           /* alias of the issuing server */
+       __u64 timeout;  /* seconds after epoch to time out */
+       __u32 sig_size; /* length of the signature in bytes */
+       unsigned char *signature;       /* digital signature */
+       struct ORANGEFS_certificate certificate;        /* user certificate buffer */
+};
+#define extra_size_ORANGEFS_credential (ORANGEFS_REQ_LIMIT_GROUPS      *       \
+                                   sizeof(__u32)               +       \
+                                   ORANGEFS_REQ_LIMIT_ISSUER   +       \
+                                   ORANGEFS_REQ_LIMIT_SIGNATURE        +       \
+                                   extra_size_ORANGEFS_certificate)
+
+/* This structure is used by the VFS-client interaction alone */
+struct ORANGEFS_keyval_pair {
+       char key[ORANGEFS_MAX_XATTR_NAMELEN];
+       __s32 key_sz;   /* __s32 for portable, fixed-size structures */
+       __s32 val_sz;
+       char val[ORANGEFS_MAX_XATTR_VALUELEN];
+};
+
+/* pvfs2-sysint.h ***********************************************************/
+/* Describes attributes for a file, directory, or symlink. */
+struct ORANGEFS_sys_attr_s {
+       __u32 owner;
+       __u32 group;
+       __u32 perms;
+       __u64 atime;
+       __u64 mtime;
+       __u64 ctime;
+       __s64 size;
+
+       /* NOTE: caller must free if valid */
+       char *link_target;
+
+       /* Changed to __s32 so that size of structure does not change */
+       __s32 dfile_count;
+
+       /* Changed to __s32 so that size of structure does not change */
+       __s32 distr_dir_servers_initial;
+
+       /* Changed to __s32 so that size of structure does not change */
+       __s32 distr_dir_servers_max;
+
+       /* Changed to __s32 so that size of structure does not change */
+       __s32 distr_dir_split_size;
+
+       __u32 mirror_copies_count;
+
+       /* NOTE: caller must free if valid */
+       char *dist_name;
+
+       /* NOTE: caller must free if valid */
+       char *dist_params;
+
+       __s64 dirent_count;
+       enum orangefs_ds_type objtype;
+       __u64 flags;
+       __u32 mask;
+       __s64 blksize;
+};
+
+#define ORANGEFS_LOOKUP_LINK_NO_FOLLOW 0
+
+/* pint-dev.h ***************************************************************/
+
+/* parameter structure used in ORANGEFS_DEV_DEBUG ioctl command */
+struct dev_mask_info_s {
+       enum {
+               KERNEL_MASK,
+               CLIENT_MASK,
+       } mask_type;
+       __u64 mask_value;
+};
+
+struct dev_mask2_info_s {
+       __u64 mask1_value;
+       __u64 mask2_value;
+};
+
+/* pvfs2-util.h *************************************************************/
+__s32 ORANGEFS_util_translate_mode(int mode);
+
+/* pvfs2-debug.h ************************************************************/
+#include "orangefs-debug.h"
+
+/* pvfs2-internal.h *********************************************************/
+#define llu(x) (unsigned long long)(x)
+#define lld(x) (long long)(x)
+
+/* pint-dev-shared.h ********************************************************/
+#define ORANGEFS_DEV_MAGIC 'k'
+
+#define ORANGEFS_READDIR_DEFAULT_DESC_COUNT  5
+
+#define DEV_GET_MAGIC           0x1
+#define DEV_GET_MAX_UPSIZE      0x2
+#define DEV_GET_MAX_DOWNSIZE    0x3
+#define DEV_MAP                 0x4
+#define DEV_REMOUNT_ALL         0x5
+#define DEV_DEBUG               0x6
+#define DEV_UPSTREAM            0x7
+#define DEV_CLIENT_MASK         0x8
+#define DEV_CLIENT_STRING       0x9
+#define DEV_MAX_NR              0xa
+
+/* supported ioctls, codes are with respect to user-space */
+enum {
+       ORANGEFS_DEV_GET_MAGIC = _IOW(ORANGEFS_DEV_MAGIC, DEV_GET_MAGIC, __s32),
+       ORANGEFS_DEV_GET_MAX_UPSIZE =
+           _IOW(ORANGEFS_DEV_MAGIC, DEV_GET_MAX_UPSIZE, __s32),
+       ORANGEFS_DEV_GET_MAX_DOWNSIZE =
+           _IOW(ORANGEFS_DEV_MAGIC, DEV_GET_MAX_DOWNSIZE, __s32),
+       ORANGEFS_DEV_MAP = _IO(ORANGEFS_DEV_MAGIC, DEV_MAP),
+       ORANGEFS_DEV_REMOUNT_ALL = _IO(ORANGEFS_DEV_MAGIC, DEV_REMOUNT_ALL),
+       ORANGEFS_DEV_DEBUG = _IOR(ORANGEFS_DEV_MAGIC, DEV_DEBUG, __s32),
+       ORANGEFS_DEV_UPSTREAM = _IOW(ORANGEFS_DEV_MAGIC, DEV_UPSTREAM, int),
+       ORANGEFS_DEV_CLIENT_MASK = _IOW(ORANGEFS_DEV_MAGIC,
+                                   DEV_CLIENT_MASK,
+                                   struct dev_mask2_info_s),
+       ORANGEFS_DEV_CLIENT_STRING = _IOW(ORANGEFS_DEV_MAGIC,
+                                     DEV_CLIENT_STRING,
+                                     char *),
+       ORANGEFS_DEV_MAXNR = DEV_MAX_NR,
+};
+
+/*
+ * version number for use in communicating between kernel space and user
+ * space. Zero signifies the upstream version of the kernel module.
+ */
+#define ORANGEFS_KERNEL_PROTO_VERSION 0
+#define ORANGEFS_MINIMUM_USERSPACE_VERSION 20903
+
+/*
+ * describes memory regions to map in the ORANGEFS_DEV_MAP ioctl.
+ * NOTE: See devorangefs-req.c for 32 bit compat structure.
+ * Since this structure has a variable-sized layout that is different
+ * on 32 and 64 bit platforms, we need to normalize to a 64 bit layout
+ * on such systems before servicing ioctl calls from user-space binaries
+ * that may be 32 bit!
+ */
+struct ORANGEFS_dev_map_desc {
+       void *ptr;
+       __s32 total_size;
+       __s32 size;
+       __s32 count;
+};
+
+/* gossip.h *****************************************************************/
+
+#ifdef GOSSIP_DISABLE_DEBUG
+#define gossip_debug(mask, format, f...) do {} while (0)
+#else
+extern __u64 gossip_debug_mask;
+extern struct client_debug_mask client_debug_mask;
+
+/* try to avoid function call overhead by checking masks in macro */
+#define gossip_debug(mask, format, f...)                       \
+do {                                                           \
+       if (gossip_debug_mask & mask)                           \
+               printk(format, ##f);                            \
+} while (0)
+#endif /* GOSSIP_DISABLE_DEBUG */
+
+/* do file and line number printouts w/ the GNU preprocessor */
+#define gossip_ldebug(mask, format, f...)                              \
+               gossip_debug(mask, "%s: " format, __func__, ##f)
+
+#define gossip_err printk
+#define gossip_lerr(format, f...)                                      \
+               gossip_err("%s line %d: " format,                       \
+                          __FILE__,                                    \
+                          __LINE__,                                    \
+                          ##f)
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
new file mode 100644 (file)
index 0000000..b9da9a0
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+
+#include <linux/parser.h>
+
+/* a cache for orangefs-inode objects (i.e. orangefs inode private data) */
+static struct kmem_cache *orangefs_inode_cache;
+
+/* list for storing orangefs specific superblocks in use */
+LIST_HEAD(orangefs_superblocks);
+
+DEFINE_SPINLOCK(orangefs_superblocks_lock);
+
+enum {
+       Opt_intr,
+       Opt_acl,
+       Opt_local_lock,
+
+       Opt_err
+};
+
+static const match_table_t tokens = {
+       { Opt_acl,              "acl" },
+       { Opt_intr,             "intr" },
+       { Opt_local_lock,       "local_lock" },
+       { Opt_err,      NULL }
+};
+
+
+static int parse_mount_options(struct super_block *sb, char *options,
+               int silent)
+{
+       struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(sb);
+       substring_t args[MAX_OPT_ARGS];
+       char *p;
+
+       /*
+        * Force any potential flags that might be set from the mount
+        * to zero, ie, initialize to unset.
+        */
+       sb->s_flags &= ~MS_POSIXACL;
+       orangefs_sb->flags &= ~ORANGEFS_OPT_INTR;
+       orangefs_sb->flags &= ~ORANGEFS_OPT_LOCAL_LOCK;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_acl:
+                       sb->s_flags |= MS_POSIXACL;
+                       break;
+               case Opt_intr:
+                       orangefs_sb->flags |= ORANGEFS_OPT_INTR;
+                       break;
+               case Opt_local_lock:
+                       orangefs_sb->flags |= ORANGEFS_OPT_LOCAL_LOCK;
+                       break;
+               default:
+                       goto fail;
+               }
+       }
+
+       return 0;
+fail:
+       if (!silent)
+               gossip_err("Error: mount option [%s] is not supported.\n", p);
+       return -EINVAL;
+}
+
+static void orangefs_inode_cache_ctor(void *req)
+{
+       struct orangefs_inode_s *orangefs_inode = req;
+
+       inode_init_once(&orangefs_inode->vfs_inode);
+       init_rwsem(&orangefs_inode->xattr_sem);
+
+       orangefs_inode->vfs_inode.i_version = 1;
+}
+
+static struct inode *orangefs_alloc_inode(struct super_block *sb)
+{
+       struct orangefs_inode_s *orangefs_inode;
+
+       orangefs_inode = kmem_cache_alloc(orangefs_inode_cache, GFP_KERNEL);
+       if (orangefs_inode == NULL) {
+               gossip_err("Failed to allocate orangefs_inode\n");
+               return NULL;
+       }
+
+       /*
+        * We want to clear everything except for rw_semaphore and the
+        * vfs_inode.
+        */
+       memset(&orangefs_inode->refn.khandle, 0, 16);
+       orangefs_inode->refn.fs_id = ORANGEFS_FS_ID_NULL;
+       orangefs_inode->last_failed_block_index_read = 0;
+       memset(orangefs_inode->link_target, 0, sizeof(orangefs_inode->link_target));
+       orangefs_inode->pinode_flags = 0;
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "orangefs_alloc_inode: allocated %p\n",
+                    &orangefs_inode->vfs_inode);
+       return &orangefs_inode->vfs_inode;
+}
+
+static void orangefs_destroy_inode(struct inode *inode)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                       "%s: deallocated %p destroying inode %pU\n",
+                       __func__, orangefs_inode, get_khandle_from_ino(inode));
+
+       kmem_cache_free(orangefs_inode_cache, orangefs_inode);
+}
+
+/*
+ * NOTE: information filled in here is typically reflected in the
+ * output of the system command 'df'
+*/
+static int orangefs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       int ret = -ENOMEM;
+       struct orangefs_kernel_op_s *new_op = NULL;
+       int flags = 0;
+       struct super_block *sb = NULL;
+
+       sb = dentry->d_sb;
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "orangefs_statfs: called on sb %p (fs_id is %d)\n",
+                    sb,
+                    (int)(ORANGEFS_SB(sb)->fs_id));
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_STATFS);
+       if (!new_op)
+               return ret;
+       new_op->upcall.req.statfs.fs_id = ORANGEFS_SB(sb)->fs_id;
+
+       if (ORANGEFS_SB(sb)->flags & ORANGEFS_OPT_INTR)
+               flags = ORANGEFS_OP_INTERRUPTIBLE;
+
+       ret = service_operation(new_op, "orangefs_statfs", flags);
+
+       if (new_op->downcall.status < 0)
+               goto out_op_release;
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "%s: got %ld blocks available | "
+                    "%ld blocks total | %ld block size | "
+                    "%ld files total | %ld files avail\n",
+                    __func__,
+                    (long)new_op->downcall.resp.statfs.blocks_avail,
+                    (long)new_op->downcall.resp.statfs.blocks_total,
+                    (long)new_op->downcall.resp.statfs.block_size,
+                    (long)new_op->downcall.resp.statfs.files_total,
+                    (long)new_op->downcall.resp.statfs.files_avail);
+
+       buf->f_type = sb->s_magic;
+       memcpy(&buf->f_fsid, &ORANGEFS_SB(sb)->fs_id, sizeof(buf->f_fsid));
+       buf->f_bsize = new_op->downcall.resp.statfs.block_size;
+       buf->f_namelen = ORANGEFS_NAME_MAX;
+
+       buf->f_blocks = (sector_t) new_op->downcall.resp.statfs.blocks_total;
+       buf->f_bfree = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
+       buf->f_bavail = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
+       buf->f_files = (sector_t) new_op->downcall.resp.statfs.files_total;
+       buf->f_ffree = (sector_t) new_op->downcall.resp.statfs.files_avail;
+       buf->f_frsize = sb->s_blocksize;
+
+out_op_release:
+       op_release(new_op);
+       gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_statfs: returning %d\n", ret);
+       return ret;
+}
+
+/*
+ * Remount as initiated by VFS layer.  We just need to reparse the mount
+ * options, no need to signal pvfs2-client-core about it.
+ */
+static int orangefs_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+       gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount_fs: called\n");
+       return parse_mount_options(sb, data, 1);
+}
+
+/*
+ * Remount as initiated by pvfs2-client-core on restart.  This is used to
+ * repopulate mount information left from previous pvfs2-client-core.
+ *
+ * the idea here is that given a valid superblock, we're
+ * re-initializing the user space client with the initial mount
+ * information specified when the super block was first initialized.
+ * this is very different than the first initialization/creation of a
+ * superblock.  we use the special service_priority_operation to make
+ * sure that the mount gets ahead of any other pending operation that
+ * is waiting for servicing.  this means that the pvfs2-client won't
+ * fail to start several times for all other pending operations before
+ * the client regains all of the mount information from us.
+ * NOTE: this function assumes that the request_mutex is already acquired!
+ */
+int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb)
+{
+       struct orangefs_kernel_op_s *new_op;
+       int ret = -EINVAL;
+
+       gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount: called\n");
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
+       if (!new_op)
+               return -ENOMEM;
+       strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
+               orangefs_sb->devname,
+               ORANGEFS_MAX_SERVER_ADDR_LEN);
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "Attempting ORANGEFS Remount via host %s\n",
+                    new_op->upcall.req.fs_mount.orangefs_config_server);
+
+       /*
+        * we assume that the calling function has already acquired the
+        * request_mutex to prevent other operations from bypassing
+        * this one
+        */
+       ret = service_operation(new_op, "orangefs_remount",
+               ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "orangefs_remount: mount got return value of %d\n",
+                    ret);
+       if (ret == 0) {
+               /*
+                * store the id assigned to this sb -- it's just a
+                * short-lived mapping that the system interface uses
+                * to map this superblock to a particular mount entry
+                */
+               orangefs_sb->id = new_op->downcall.resp.fs_mount.id;
+               orangefs_sb->mount_pending = 0;
+       }
+
+       op_release(new_op);
+       return ret;
+}
+
+int fsid_key_table_initialize(void)
+{
+       return 0;
+}
+
+void fsid_key_table_finalize(void)
+{
+}
+
+/* Called whenever the VFS dirties the inode in response to atime updates */
+static void orangefs_dirty_inode(struct inode *inode, int flags)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "orangefs_dirty_inode: %pU\n",
+                    get_khandle_from_ino(inode));
+       SetAtimeFlag(orangefs_inode);
+}
+
+static const struct super_operations orangefs_s_ops = {
+       .alloc_inode = orangefs_alloc_inode,
+       .destroy_inode = orangefs_destroy_inode,
+       .dirty_inode = orangefs_dirty_inode,
+       .drop_inode = generic_delete_inode,
+       .statfs = orangefs_statfs,
+       .remount_fs = orangefs_remount_fs,
+       .show_options = generic_show_options,
+};
+
+static struct dentry *orangefs_fh_to_dentry(struct super_block *sb,
+                                 struct fid *fid,
+                                 int fh_len,
+                                 int fh_type)
+{
+       struct orangefs_object_kref refn;
+
+       if (fh_len < 5 || fh_type > 2)
+               return NULL;
+
+       ORANGEFS_khandle_from(&(refn.khandle), fid->raw, 16);
+       refn.fs_id = (u32) fid->raw[4];
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "fh_to_dentry: handle %pU, fs_id %d\n",
+                    &refn.khandle,
+                    refn.fs_id);
+
+       return d_obtain_alias(orangefs_iget(sb, &refn));
+}
+
+static int orangefs_encode_fh(struct inode *inode,
+                   __u32 *fh,
+                   int *max_len,
+                   struct inode *parent)
+{
+       int len = parent ? 10 : 5;
+       int type = 1;
+       struct orangefs_object_kref refn;
+
+       if (*max_len < len) {
+               gossip_lerr("fh buffer is too small for encoding\n");
+               *max_len = len;
+               type = 255;
+               goto out;
+       }
+
+       refn = ORANGEFS_I(inode)->refn;
+       ORANGEFS_khandle_to(&refn.khandle, fh, 16);
+       fh[4] = refn.fs_id;
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "Encoding fh: handle %pU, fsid %u\n",
+                    &refn.khandle,
+                    refn.fs_id);
+
+
+       if (parent) {
+               refn = ORANGEFS_I(parent)->refn;
+               ORANGEFS_khandle_to(&refn.khandle, (char *) fh + 20, 16);
+               fh[9] = refn.fs_id;
+
+               type = 2;
+               gossip_debug(GOSSIP_SUPER_DEBUG,
+                            "Encoding parent: handle %pU, fsid %u\n",
+                            &refn.khandle,
+                            refn.fs_id);
+       }
+       *max_len = len;
+
+out:
+       return type;
+}
+
+static const struct export_operations orangefs_export_ops = {
+       .encode_fh = orangefs_encode_fh,
+       .fh_to_dentry = orangefs_fh_to_dentry,
+};
+
+static int orangefs_fill_sb(struct super_block *sb,
+               struct orangefs_fs_mount_response *fs_mount,
+               void *data, int silent)
+{
+       int ret = -EINVAL;
+       struct inode *root = NULL;
+       struct dentry *root_dentry = NULL;
+       struct orangefs_object_kref root_object;
+
+       /* alloc and init our private orangefs sb info */
+       sb->s_fs_info = kzalloc(sizeof(struct orangefs_sb_info_s), GFP_KERNEL);
+       if (!ORANGEFS_SB(sb))
+               return -ENOMEM;
+       ORANGEFS_SB(sb)->sb = sb;
+
+       ORANGEFS_SB(sb)->root_khandle = fs_mount->root_khandle;
+       ORANGEFS_SB(sb)->fs_id = fs_mount->fs_id;
+       ORANGEFS_SB(sb)->id = fs_mount->id;
+
+       if (data) {
+               ret = parse_mount_options(sb, data, silent);
+               if (ret)
+                       return ret;
+       }
+
+       /* Hang the xattr handlers off the superblock */
+       sb->s_xattr = orangefs_xattr_handlers;
+       sb->s_magic = ORANGEFS_SUPER_MAGIC;
+       sb->s_op = &orangefs_s_ops;
+       sb->s_d_op = &orangefs_dentry_operations;
+
+       sb->s_blocksize = orangefs_bufmap_size_query();
+       sb->s_blocksize_bits = orangefs_bufmap_shift_query();
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
+
+       root_object.khandle = ORANGEFS_SB(sb)->root_khandle;
+       root_object.fs_id = ORANGEFS_SB(sb)->fs_id;
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "get inode %pU, fsid %d\n",
+                    &root_object.khandle,
+                    root_object.fs_id);
+
+       root = orangefs_iget(sb, &root_object);
+       if (IS_ERR(root))
+               return PTR_ERR(root);
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "Allocated root inode [%p] with mode %x\n",
+                    root,
+                    root->i_mode);
+
+       /* allocates and places root dentry in dcache */
+       root_dentry = d_make_root(root);
+       if (!root_dentry)
+               return -ENOMEM;
+
+       sb->s_export_op = &orangefs_export_ops;
+       sb->s_root = root_dentry;
+       return 0;
+}
+
+struct dentry *orangefs_mount(struct file_system_type *fst,
+                          int flags,
+                          const char *devname,
+                          void *data)
+{
+       int ret = -EINVAL;
+       struct super_block *sb = ERR_PTR(-EINVAL);
+       struct orangefs_kernel_op_s *new_op;
+       struct dentry *d = ERR_PTR(-EINVAL);
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "orangefs_mount: called with devname %s\n",
+                    devname);
+
+       if (!devname) {
+               gossip_err("ERROR: device name not specified.\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
+       if (!new_op)
+               return ERR_PTR(-ENOMEM);
+
+       strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
+               devname,
+               ORANGEFS_MAX_SERVER_ADDR_LEN);
+
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "Attempting ORANGEFS Mount via host %s\n",
+                    new_op->upcall.req.fs_mount.orangefs_config_server);
+
+       ret = service_operation(new_op, "orangefs_mount", 0);
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "orangefs_mount: mount got return value of %d\n", ret);
+       if (ret)
+               goto free_op;
+
+       if (new_op->downcall.resp.fs_mount.fs_id == ORANGEFS_FS_ID_NULL) {
+               gossip_err("ERROR: Retrieved null fs_id\n");
+               ret = -EINVAL;
+               goto free_op;
+       }
+
+       sb = sget(fst, NULL, set_anon_super, flags, NULL);
+
+       if (IS_ERR(sb)) {
+               d = ERR_CAST(sb);
+               goto free_op;
+       }
+
+       ret = orangefs_fill_sb(sb,
+             &new_op->downcall.resp.fs_mount, data,
+             flags & MS_SILENT ? 1 : 0);
+
+       if (ret) {
+               d = ERR_PTR(ret);
+               goto free_op;
+       }
+
+       /*
+        * on successful mount, store the devname and data
+        * used
+        */
+       strncpy(ORANGEFS_SB(sb)->devname,
+               devname,
+               ORANGEFS_MAX_SERVER_ADDR_LEN);
+
+       /* mount_pending must be cleared */
+       ORANGEFS_SB(sb)->mount_pending = 0;
+
+       /*
+        * finally, add this sb to our list of known orangefs
+        * sb's
+        */
+       gossip_debug(GOSSIP_SUPER_DEBUG,
+                    "Adding SB %p to orangefs superblocks\n",
+                    ORANGEFS_SB(sb));
+       spin_lock(&orangefs_superblocks_lock);
+       list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks);
+       spin_unlock(&orangefs_superblocks_lock);
+       op_release(new_op);
+       return dget(sb->s_root);
+
+free_op:
+       gossip_err("orangefs_mount: mount request failed with %d\n", ret);
+       if (ret == -EINVAL) {
+               gossip_err("Ensure that all orangefs-servers have the same FS configuration files\n");
+               gossip_err("Look at pvfs2-client-core log file (typically /tmp/pvfs2-client.log) for more details\n");
+       }
+
+       op_release(new_op);
+
+       return d;
+}
+
+void orangefs_kill_sb(struct super_block *sb)
+{
+       gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_kill_sb: called\n");
+
+       /* provided sb cleanup */
+       kill_anon_super(sb);
+
+       /*
+        * issue the unmount to userspace to tell it to remove the
+        * dynamic mount info it has for this superblock
+        */
+        orangefs_unmount_sb(sb);
+
+       /* remove the sb from our list of orangefs specific sb's */
+
+       spin_lock(&orangefs_superblocks_lock);
+       __list_del_entry(&ORANGEFS_SB(sb)->list);       /* not list_del_init */
+       ORANGEFS_SB(sb)->list.prev = NULL;
+       spin_unlock(&orangefs_superblocks_lock);
+
+       /*
+        * make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us
+        * gets completed before we free the dang thing.
+        */
+       mutex_lock(&request_mutex);
+       mutex_unlock(&request_mutex);
+
+       /* free the orangefs superblock private data */
+       kfree(ORANGEFS_SB(sb));
+}
+
+int orangefs_inode_cache_initialize(void)
+{
+       orangefs_inode_cache = kmem_cache_create("orangefs_inode_cache",
+                                             sizeof(struct orangefs_inode_s),
+                                             0,
+                                             ORANGEFS_CACHE_CREATE_FLAGS,
+                                             orangefs_inode_cache_ctor);
+
+       if (!orangefs_inode_cache) {
+               gossip_err("Cannot create orangefs_inode_cache\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+int orangefs_inode_cache_finalize(void)
+{
+       kmem_cache_destroy(orangefs_inode_cache);
+       return 0;
+}
diff --git a/fs/orangefs/symlink.c b/fs/orangefs/symlink.c
new file mode 100644 (file)
index 0000000..6418dd6
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+
+struct inode_operations orangefs_symlink_inode_operations = {
+       .readlink = generic_readlink,
+       .get_link = simple_get_link,
+       .setattr = orangefs_setattr,
+       .getattr = orangefs_getattr,
+       .listxattr = orangefs_listxattr,
+       .setxattr = generic_setxattr,
+       .permission = orangefs_permission,
+};
diff --git a/fs/orangefs/upcall.h b/fs/orangefs/upcall.h
new file mode 100644 (file)
index 0000000..001b202
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+#ifndef __UPCALL_H
+#define __UPCALL_H
+
+/*
+ * Sanitized this header file to fix
+ * 32-64 bit interaction issues between
+ * client-core and device
+ */
+struct orangefs_io_request_s {
+       __s32 __pad1;
+       __s32 buf_index;
+       __s32 count;
+       __s32 __pad2;
+       __s64 offset;
+       struct orangefs_object_kref refn;
+       enum ORANGEFS_io_type io_type;
+       __s32 readahead_size;
+};
+
+struct orangefs_lookup_request_s {
+       __s32 sym_follow;
+       __s32 __pad1;
+       struct orangefs_object_kref parent_refn;
+       char d_name[ORANGEFS_NAME_MAX];
+};
+
+struct orangefs_create_request_s {
+       struct orangefs_object_kref parent_refn;
+       struct ORANGEFS_sys_attr_s attributes;
+       char d_name[ORANGEFS_NAME_MAX];
+};
+
+struct orangefs_symlink_request_s {
+       struct orangefs_object_kref parent_refn;
+       struct ORANGEFS_sys_attr_s attributes;
+       char entry_name[ORANGEFS_NAME_MAX];
+       char target[ORANGEFS_NAME_MAX];
+};
+
+struct orangefs_getattr_request_s {
+       struct orangefs_object_kref refn;
+       __u32 mask;
+       __u32 __pad1;
+};
+
+struct orangefs_setattr_request_s {
+       struct orangefs_object_kref refn;
+       struct ORANGEFS_sys_attr_s attributes;
+};
+
+struct orangefs_remove_request_s {
+       struct orangefs_object_kref parent_refn;
+       char d_name[ORANGEFS_NAME_MAX];
+};
+
+struct orangefs_mkdir_request_s {
+       struct orangefs_object_kref parent_refn;
+       struct ORANGEFS_sys_attr_s attributes;
+       char d_name[ORANGEFS_NAME_MAX];
+};
+
+struct orangefs_readdir_request_s {
+       struct orangefs_object_kref refn;
+       __u64 token;
+       __s32 max_dirent_count;
+       __s32 buf_index;
+};
+
+struct orangefs_readdirplus_request_s {
+       struct orangefs_object_kref refn;
+       __u64 token;
+       __s32 max_dirent_count;
+       __u32 mask;
+       __s32 buf_index;
+       __s32 __pad1;
+};
+
+struct orangefs_rename_request_s {
+       struct orangefs_object_kref old_parent_refn;
+       struct orangefs_object_kref new_parent_refn;
+       char d_old_name[ORANGEFS_NAME_MAX];
+       char d_new_name[ORANGEFS_NAME_MAX];
+};
+
+struct orangefs_statfs_request_s {
+       __s32 fs_id;
+       __s32 __pad1;
+};
+
+struct orangefs_truncate_request_s {
+       struct orangefs_object_kref refn;
+       __s64 size;
+};
+
+struct orangefs_mmap_ra_cache_flush_request_s {
+       struct orangefs_object_kref refn;
+};
+
+struct orangefs_fs_mount_request_s {
+       char orangefs_config_server[ORANGEFS_MAX_SERVER_ADDR_LEN];
+};
+
+struct orangefs_fs_umount_request_s {
+       __s32 id;
+       __s32 fs_id;
+       char orangefs_config_server[ORANGEFS_MAX_SERVER_ADDR_LEN];
+};
+
+struct orangefs_getxattr_request_s {
+       struct orangefs_object_kref refn;
+       __s32 key_sz;
+       __s32 __pad1;
+       char key[ORANGEFS_MAX_XATTR_NAMELEN];
+};
+
+struct orangefs_setxattr_request_s {
+       struct orangefs_object_kref refn;
+       struct ORANGEFS_keyval_pair keyval;
+       __s32 flags;
+       __s32 __pad1;
+};
+
+struct orangefs_listxattr_request_s {
+       struct orangefs_object_kref refn;
+       __s32 requested_count;
+       __s32 __pad1;
+       __u64 token;
+};
+
+struct orangefs_removexattr_request_s {
+       struct orangefs_object_kref refn;
+       __s32 key_sz;
+       __s32 __pad1;
+       char key[ORANGEFS_MAX_XATTR_NAMELEN];
+};
+
+struct orangefs_op_cancel_s {
+       __u64 op_tag;
+};
+
+struct orangefs_fsync_request_s {
+       struct orangefs_object_kref refn;
+};
+
+enum orangefs_param_request_type {
+       ORANGEFS_PARAM_REQUEST_SET = 1,
+       ORANGEFS_PARAM_REQUEST_GET = 2
+};
+
+enum orangefs_param_request_op {
+       ORANGEFS_PARAM_REQUEST_OP_ACACHE_TIMEOUT_MSECS = 1,
+       ORANGEFS_PARAM_REQUEST_OP_ACACHE_HARD_LIMIT = 2,
+       ORANGEFS_PARAM_REQUEST_OP_ACACHE_SOFT_LIMIT = 3,
+       ORANGEFS_PARAM_REQUEST_OP_ACACHE_RECLAIM_PERCENTAGE = 4,
+       ORANGEFS_PARAM_REQUEST_OP_PERF_TIME_INTERVAL_SECS = 5,
+       ORANGEFS_PARAM_REQUEST_OP_PERF_HISTORY_SIZE = 6,
+       ORANGEFS_PARAM_REQUEST_OP_PERF_RESET = 7,
+       ORANGEFS_PARAM_REQUEST_OP_NCACHE_TIMEOUT_MSECS = 8,
+       ORANGEFS_PARAM_REQUEST_OP_NCACHE_HARD_LIMIT = 9,
+       ORANGEFS_PARAM_REQUEST_OP_NCACHE_SOFT_LIMIT = 10,
+       ORANGEFS_PARAM_REQUEST_OP_NCACHE_RECLAIM_PERCENTAGE = 11,
+       ORANGEFS_PARAM_REQUEST_OP_STATIC_ACACHE_TIMEOUT_MSECS = 12,
+       ORANGEFS_PARAM_REQUEST_OP_STATIC_ACACHE_HARD_LIMIT = 13,
+       ORANGEFS_PARAM_REQUEST_OP_STATIC_ACACHE_SOFT_LIMIT = 14,
+       ORANGEFS_PARAM_REQUEST_OP_STATIC_ACACHE_RECLAIM_PERCENTAGE = 15,
+       ORANGEFS_PARAM_REQUEST_OP_CLIENT_DEBUG = 16,
+       ORANGEFS_PARAM_REQUEST_OP_CCACHE_TIMEOUT_SECS = 17,
+       ORANGEFS_PARAM_REQUEST_OP_CCACHE_HARD_LIMIT = 18,
+       ORANGEFS_PARAM_REQUEST_OP_CCACHE_SOFT_LIMIT = 19,
+       ORANGEFS_PARAM_REQUEST_OP_CCACHE_RECLAIM_PERCENTAGE = 20,
+       ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_TIMEOUT_SECS = 21,
+       ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_HARD_LIMIT = 22,
+       ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_SOFT_LIMIT = 23,
+       ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_RECLAIM_PERCENTAGE = 24,
+       ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES = 25,
+};
+
+struct orangefs_param_request_s {
+       enum orangefs_param_request_type type;
+       enum orangefs_param_request_op op;
+       __s64 value;
+       char s_value[ORANGEFS_MAX_DEBUG_STRING_LEN];
+};
+
+enum orangefs_perf_count_request_type {
+       ORANGEFS_PERF_COUNT_REQUEST_ACACHE = 1,
+       ORANGEFS_PERF_COUNT_REQUEST_NCACHE = 2,
+       ORANGEFS_PERF_COUNT_REQUEST_CAPCACHE = 3,
+};
+
+struct orangefs_perf_count_request_s {
+       enum orangefs_perf_count_request_type type;
+       __s32 __pad1;
+};
+
+struct orangefs_fs_key_request_s {
+       __s32 fsid;
+       __s32 __pad1;
+};
+
+struct orangefs_upcall_s {
+       __s32 type;
+       __u32 uid;
+       __u32 gid;
+       int pid;
+       int tgid;
+       /* Trailers unused but must be retained for protocol compatibility. */
+       __s64 trailer_size;
+       char *trailer_buf;
+
+       union {
+               struct orangefs_io_request_s io;
+               struct orangefs_lookup_request_s lookup;
+               struct orangefs_create_request_s create;
+               struct orangefs_symlink_request_s sym;
+               struct orangefs_getattr_request_s getattr;
+               struct orangefs_setattr_request_s setattr;
+               struct orangefs_remove_request_s remove;
+               struct orangefs_mkdir_request_s mkdir;
+               struct orangefs_readdir_request_s readdir;
+               struct orangefs_readdirplus_request_s readdirplus;
+               struct orangefs_rename_request_s rename;
+               struct orangefs_statfs_request_s statfs;
+               struct orangefs_truncate_request_s truncate;
+               struct orangefs_mmap_ra_cache_flush_request_s ra_cache_flush;
+               struct orangefs_fs_mount_request_s fs_mount;
+               struct orangefs_fs_umount_request_s fs_umount;
+               struct orangefs_getxattr_request_s getxattr;
+               struct orangefs_setxattr_request_s setxattr;
+               struct orangefs_listxattr_request_s listxattr;
+               struct orangefs_removexattr_request_s removexattr;
+               struct orangefs_op_cancel_s cancel;
+               struct orangefs_fsync_request_s fsync;
+               struct orangefs_param_request_s param;
+               struct orangefs_perf_count_request_s perf_count;
+               struct orangefs_fs_key_request_s fs_key;
+       } req;
+};
+
+#endif /* __UPCALL_H */
diff --git a/fs/orangefs/waitqueue.c b/fs/orangefs/waitqueue.c
new file mode 100644 (file)
index 0000000..31635bc
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ * (C) 2011 Omnibond Systems
+ *
+ * Changes by Acxiom Corporation to implement generic service_operation()
+ * function, Copyright Acxiom Corporation, 2005.
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ *  In-kernel waitqueue operations.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+
+static int wait_for_matching_downcall(struct orangefs_kernel_op_s *, long, bool);
+static void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *);
+
+/*
+ * What we do in this function is to walk the list of operations that are
+ * present in the request queue and mark them as purged.
+ * NOTE: This is called from the device close after client-core has
+ * guaranteed that no new operations could appear on the list since the
+ * client-core is anyway going to exit.
+ */
+void purge_waiting_ops(void)
+{
+       struct orangefs_kernel_op_s *op;
+
+       spin_lock(&orangefs_request_list_lock);
+       list_for_each_entry(op, &orangefs_request_list, list) {
+               gossip_debug(GOSSIP_WAIT_DEBUG,
+                            "pvfs2-client-core: purging op tag %llu %s\n",
+                            llu(op->tag),
+                            get_opname_string(op));
+               set_op_state_purged(op);
+               gossip_debug(GOSSIP_DEV_DEBUG,
+                            "%s: op:%s: op_state:%d: process:%s:\n",
+                            __func__,
+                            get_opname_string(op),
+                            op->op_state,
+                            current->comm);
+       }
+       spin_unlock(&orangefs_request_list_lock);
+}
+
+/*
+ * submits a ORANGEFS operation and waits for it to complete
+ *
+ * Note op->downcall.status will contain the status of the operation (in
+ * errno format), whether provided by pvfs2-client or a result of failure to
+ * service the operation.  If the caller wishes to distinguish, then
+ * op->state can be checked to see if it was serviced or not.
+ *
+ * Returns contents of op->downcall.status for convenience
+ */
+int service_operation(struct orangefs_kernel_op_s *op,
+                     const char *op_name,
+                     int flags)
+{
+       long timeout = MAX_SCHEDULE_TIMEOUT;
+       int ret = 0;
+
+       DEFINE_WAIT(wait_entry);
+
+       op->upcall.tgid = current->tgid;
+       op->upcall.pid = current->pid;
+
+retry_servicing:
+       op->downcall.status = 0;
+       gossip_debug(GOSSIP_WAIT_DEBUG,
+                    "%s: %s op:%p: process:%s: pid:%d:\n",
+                    __func__,
+                    op_name,
+                    op,
+                    current->comm,
+                    current->pid);
+
+       /*
+        * If ORANGEFS_OP_NO_MUTEX was set in flags, we need to avoid
+        * acquiring the request_mutex because we're servicing a
+        * high priority remount operation and the request_mutex is
+        * already taken.
+        */
+       if (!(flags & ORANGEFS_OP_NO_MUTEX)) {
+               if (flags & ORANGEFS_OP_INTERRUPTIBLE)
+                       ret = mutex_lock_interruptible(&request_mutex);
+               else
+                       ret = mutex_lock_killable(&request_mutex);
+               /*
+                * check to see if we were interrupted while waiting for
+                * mutex
+                */
+               if (ret < 0) {
+                       op->downcall.status = ret;
+                       gossip_debug(GOSSIP_WAIT_DEBUG,
+                                    "%s: service_operation interrupted.\n",
+                                    __func__);
+                       return ret;
+               }
+       }
+
+       /* queue up the operation */
+       spin_lock(&orangefs_request_list_lock);
+       spin_lock(&op->lock);
+       set_op_state_waiting(op);
+       gossip_debug(GOSSIP_DEV_DEBUG,
+                    "%s: op:%s: op_state:%d: process:%s:\n",
+                    __func__,
+                    get_opname_string(op),
+                    op->op_state,
+                    current->comm);
+       /* add high priority remount op to the front of the line. */
+       if (flags & ORANGEFS_OP_PRIORITY)
+               list_add(&op->list, &orangefs_request_list);
+       else
+               list_add_tail(&op->list, &orangefs_request_list);
+       spin_unlock(&op->lock);
+       wake_up_interruptible(&orangefs_request_list_waitq);
+       if (!__is_daemon_in_service()) {
+               gossip_debug(GOSSIP_WAIT_DEBUG,
+                            "%s:client core is NOT in service.\n",
+                            __func__);
+               timeout = op_timeout_secs * HZ;
+       }
+       spin_unlock(&orangefs_request_list_lock);
+
+       if (!(flags & ORANGEFS_OP_NO_MUTEX))
+               mutex_unlock(&request_mutex);
+
+       ret = wait_for_matching_downcall(op, timeout,
+                                        flags & ORANGEFS_OP_INTERRUPTIBLE);
+
+       gossip_debug(GOSSIP_WAIT_DEBUG,
+                    "%s: wait_for_matching_downcall returned %d for %p\n",
+                    __func__,
+                    ret,
+                    op);
+
+       /* got matching downcall; make sure status is in errno format */
+       if (!ret) {
+               spin_unlock(&op->lock);
+               op->downcall.status =
+                   orangefs_normalize_to_errno(op->downcall.status);
+               ret = op->downcall.status;
+               goto out;
+       }
+
+       /* failed to get matching downcall */
+       if (ret == -ETIMEDOUT) {
+               gossip_err("%s: %s -- wait timed out; aborting attempt.\n",
+                          __func__,
+                          op_name);
+       }
+
+       /*
+        * remove a waiting op from the request list or
+        * remove an in-progress op from the in-progress list.
+        */
+       orangefs_clean_up_interrupted_operation(op);
+
+       op->downcall.status = ret;
+       /* retry if operation has not been serviced and if requested */
+       if (ret == -EAGAIN) {
+               op->attempts++;
+               timeout = op_timeout_secs * HZ;
+               gossip_debug(GOSSIP_WAIT_DEBUG,
+                            "orangefs: tag %llu (%s)"
+                            " -- operation to be retried (%d attempt)\n",
+                            llu(op->tag),
+                            op_name,
+                            op->attempts);
+
+               /*
+                * io ops (ops that use the shared memory buffer) have
+                * to be returned to their caller for a retry. Other ops
+                * can just be recycled here.
+                */
+               if (!op->uses_shared_memory)
+                       goto retry_servicing;
+       }
+
+out:
+       gossip_debug(GOSSIP_WAIT_DEBUG,
+                    "%s: %s returning: %d for %p.\n",
+                    __func__,
+                    op_name,
+                    ret,
+                    op);
+       return ret;
+}
+
+/* This can get called on an I/O op if it had a bad service_operation. */
+bool orangefs_cancel_op_in_progress(struct orangefs_kernel_op_s *op)
+{
+       u64 tag = op->tag;
+       if (!op_state_in_progress(op))
+               return false;
+
+       op->slot_to_free = op->upcall.req.io.buf_index;
+       memset(&op->upcall, 0, sizeof(op->upcall));
+       memset(&op->downcall, 0, sizeof(op->downcall));
+       op->upcall.type = ORANGEFS_VFS_OP_CANCEL;
+       op->upcall.req.cancel.op_tag = tag;
+       op->downcall.type = ORANGEFS_VFS_OP_INVALID;
+       op->downcall.status = -1;
+       orangefs_new_tag(op);
+
+       spin_lock(&orangefs_request_list_lock);
+       /* orangefs_request_list_lock is enough of a barrier here */
+       if (!__is_daemon_in_service()) {
+               spin_unlock(&orangefs_request_list_lock);
+               return false;
+       }
+       spin_lock(&op->lock);
+       set_op_state_waiting(op);
+       gossip_debug(GOSSIP_DEV_DEBUG,
+                    "%s: op:%s: op_state:%d: process:%s:\n",
+                    __func__,
+                    get_opname_string(op),
+                    op->op_state,
+                    current->comm);
+       list_add(&op->list, &orangefs_request_list);
+       spin_unlock(&op->lock);
+       spin_unlock(&orangefs_request_list_lock);
+
+       gossip_debug(GOSSIP_WAIT_DEBUG,
+                    "Attempting ORANGEFS operation cancellation of tag %llu\n",
+                    llu(tag));
+       return true;
+}
+
+/*
+ * Change an op to the "given up" state and remove it from its list.
+ */
+static void
+       orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op)
+{
+       /*
+        * handle interrupted cases depending on what state we were in when
+        * the interruption is detected.
+        *
+        * Called with op->lock held.
+        */
+
+       /*
+        * List manipulation code elsewhere will ignore ops that
+        * have been given up upon.
+        */
+       op->op_state |= OP_VFS_STATE_GIVEN_UP;
+
+       if (list_empty(&op->list)) {
+               /* caught copying to/from daemon */
+               BUG_ON(op_state_serviced(op));
+               spin_unlock(&op->lock);
+               wait_for_completion(&op->waitq);
+       } else if (op_state_waiting(op)) {
+               /*
+                * upcall hasn't been read; remove op from upcall request
+                * list.
+                */
+               spin_unlock(&op->lock);
+               spin_lock(&orangefs_request_list_lock);
+               list_del_init(&op->list);
+               spin_unlock(&orangefs_request_list_lock);
+               gossip_debug(GOSSIP_WAIT_DEBUG,
+                            "Interrupted: Removed op %p from request_list\n",
+                            op);
+       } else if (op_state_in_progress(op)) {
+               /* op must be removed from the in progress htable */
+               spin_unlock(&op->lock);
+               spin_lock(&htable_ops_in_progress_lock);
+               list_del_init(&op->list);
+               spin_unlock(&htable_ops_in_progress_lock);
+               gossip_debug(GOSSIP_WAIT_DEBUG,
+                            "Interrupted: Removed op %p"
+                            " from htable_ops_in_progress\n",
+                            op);
+       } else {
+               spin_unlock(&op->lock);
+               gossip_err("interrupted operation is in a weird state 0x%x\n",
+                          op->op_state);
+       }
+       reinit_completion(&op->waitq);
+}
+
+/*
+ * Sleeps on waitqueue waiting for matching downcall.
+ * If client-core finishes servicing, then we are good to go.
+ * else if client-core exits, we get woken up here, and retry with a timeout
+ *
+ * When this call returns to the caller, the specified op will no
+ * longer be in either the in_progress hash table or on the request list.
+ *
+ * Returns 0 on success and -errno on failure
+ * Errors are:
+ * EAGAIN in case we want the caller to requeue and try again..
+ * EINTR/EIO/ETIMEDOUT indicating we are done trying to service this
+ * operation since client-core seems to be exiting too often
+ * or if we were interrupted.
+ *
+ * Returns with op->lock taken.
+ */
+static int wait_for_matching_downcall(struct orangefs_kernel_op_s *op,
+                                     long timeout,
+                                     bool interruptible)
+{
+       long n;
+
+       /*
+        * There's a "schedule_timeout" inside of these wait
+        * primitives, during which the op is out of the hands of the
+        * user process that needs something done and is being
+        * manipulated by the client-core process.
+        */
+       if (interruptible)
+               n = wait_for_completion_interruptible_timeout(&op->waitq,
+                                                             timeout);
+       else
+               n = wait_for_completion_killable_timeout(&op->waitq, timeout);
+
+       spin_lock(&op->lock);
+
+       if (op_state_serviced(op))
+               return 0;
+
+       if (unlikely(n < 0)) {
+               gossip_debug(GOSSIP_WAIT_DEBUG,
+                            "%s: operation interrupted, tag %llu, %p\n",
+                            __func__,
+                            llu(op->tag),
+                            op);
+               return -EINTR;
+       }
+       if (op_state_purged(op)) {
+               gossip_debug(GOSSIP_WAIT_DEBUG,
+                            "%s: operation purged, tag %llu, %p, %d\n",
+                            __func__,
+                            llu(op->tag),
+                            op,
+                            op->attempts);
+               return (op->attempts < ORANGEFS_PURGE_RETRY_COUNT) ?
+                        -EAGAIN :
+                        -EIO;
+       }
+       /* must have timed out, then... */
+       gossip_debug(GOSSIP_WAIT_DEBUG,
+                    "%s: operation timed out, tag %llu, %p, %d)\n",
+                    __func__,
+                    llu(op->tag),
+                    op,
+                    op->attempts);
+       return -ETIMEDOUT;
+}
diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c
new file mode 100644 (file)
index 0000000..ef5da75
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ *  Linux VFS extended attribute operations.
+ */
+
+#include "protocol.h"
+#include "orangefs-kernel.h"
+#include "orangefs-bufmap.h"
+#include <linux/posix_acl_xattr.h>
+#include <linux/xattr.h>
+
+
+#define SYSTEM_ORANGEFS_KEY "system.pvfs2."
+#define SYSTEM_ORANGEFS_KEY_LEN 13
+
+/*
+ * this function returns
+ *   0 if the key corresponding to name is not meant to be printed as part
+ *     of a listxattr.
+ *   1 if the key corresponding to name is meant to be returned as part of
+ *     a listxattr.
+ * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing.
+ */
+static int is_reserved_key(const char *key, size_t size)
+{
+
+       if (size < SYSTEM_ORANGEFS_KEY_LEN)
+               return 1;
+
+       return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ?  1 : 0;
+}
+
+static inline int convert_to_internal_xattr_flags(int setxattr_flags)
+{
+       int internal_flag = 0;
+
+       if (setxattr_flags & XATTR_REPLACE) {
+               /* Attribute must exist! */
+               internal_flag = ORANGEFS_XATTR_REPLACE;
+       } else if (setxattr_flags & XATTR_CREATE) {
+               /* Attribute must not exist */
+               internal_flag = ORANGEFS_XATTR_CREATE;
+       }
+       return internal_flag;
+}
+
+
+/*
+ * Tries to get a specified key's attributes of a given
+ * file into a user-specified buffer. Note that the getxattr
+ * interface allows for the users to probe the size of an
+ * extended attribute by passing in a value of 0 to size.
+ * Thus our return value is always the size of the attribute
+ * unless the key does not exist for the file and/or if
+ * there were errors in fetching the attribute value.
+ */
+ssize_t orangefs_inode_getxattr(struct inode *inode, const char *prefix,
+               const char *name, void *buffer, size_t size)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_kernel_op_s *new_op = NULL;
+       ssize_t ret = -ENOMEM;
+       ssize_t length = 0;
+       int fsuid;
+       int fsgid;
+
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+                    "%s: prefix %s name %s, buffer_size %zd\n",
+                    __func__, prefix, name, size);
+
+       if (name == NULL || (size > 0 && buffer == NULL)) {
+               gossip_err("orangefs_inode_getxattr: bogus NULL pointers\n");
+               return -EINVAL;
+       }
+       if ((strlen(name) + strlen(prefix)) >= ORANGEFS_MAX_XATTR_NAMELEN) {
+               gossip_err("Invalid key length (%d)\n",
+                          (int)(strlen(name) + strlen(prefix)));
+               return -EINVAL;
+       }
+
+       fsuid = from_kuid(current_user_ns(), current_fsuid());
+       fsgid = from_kgid(current_user_ns(), current_fsgid());
+
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+                    "getxattr on inode %pU, name %s "
+                    "(uid %o, gid %o)\n",
+                    get_khandle_from_ino(inode),
+                    name,
+                    fsuid,
+                    fsgid);
+
+       down_read(&orangefs_inode->xattr_sem);
+
+       new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
+       if (!new_op)
+               goto out_unlock;
+
+       new_op->upcall.req.getxattr.refn = orangefs_inode->refn;
+       ret = snprintf((char *)new_op->upcall.req.getxattr.key,
+                      ORANGEFS_MAX_XATTR_NAMELEN, "%s%s", prefix, name);
+
+       /*
+        * NOTE: Although keys are meant to be NULL terminated textual
+        * strings, I am going to explicitly pass the length just in case
+        * we change this later on...
+        */
+       new_op->upcall.req.getxattr.key_sz = ret + 1;
+
+       ret = service_operation(new_op, "orangefs_inode_getxattr",
+                               get_interruptible_flag(inode));
+       if (ret != 0) {
+               if (ret == -ENOENT) {
+                       ret = -ENODATA;
+                       gossip_debug(GOSSIP_XATTR_DEBUG,
+                                    "orangefs_inode_getxattr: inode %pU key %s"
+                                    " does not exist!\n",
+                                    get_khandle_from_ino(inode),
+                                    (char *)new_op->upcall.req.getxattr.key);
+               }
+               goto out_release_op;
+       }
+
+       /*
+        * Length returned includes null terminator.
+        */
+       length = new_op->downcall.resp.getxattr.val_sz;
+
+       /*
+        * Just return the length of the queried attribute.
+        */
+       if (size == 0) {
+               ret = length;
+               goto out_release_op;
+       }
+
+       /*
+        * Check to see if key length is > provided buffer size.
+        */
+       if (length > size) {
+               ret = -ERANGE;
+               goto out_release_op;
+       }
+
+       memset(buffer, 0, size);
+       memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+            "orangefs_inode_getxattr: inode %pU "
+            "key %s key_sz %d, val_len %d\n",
+            get_khandle_from_ino(inode),
+            (char *)new_op->
+               upcall.req.getxattr.key,
+                    (int)new_op->
+               upcall.req.getxattr.key_sz,
+            (int)ret);
+
+       ret = length;
+
+out_release_op:
+       op_release(new_op);
+out_unlock:
+       up_read(&orangefs_inode->xattr_sem);
+       return ret;
+}
+
+static int orangefs_inode_removexattr(struct inode *inode,
+                           const char *prefix,
+                           const char *name,
+                           int flags)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_kernel_op_s *new_op = NULL;
+       int ret = -ENOMEM;
+
+       down_write(&orangefs_inode->xattr_sem);
+       new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR);
+       if (!new_op)
+               goto out_unlock;
+
+       new_op->upcall.req.removexattr.refn = orangefs_inode->refn;
+       /*
+        * NOTE: Although keys are meant to be NULL terminated
+        * textual strings, I am going to explicitly pass the
+        * length just in case we change this later on...
+        */
+       ret = snprintf((char *)new_op->upcall.req.removexattr.key,
+                      ORANGEFS_MAX_XATTR_NAMELEN,
+                      "%s%s",
+                      (prefix ? prefix : ""),
+                      name);
+       new_op->upcall.req.removexattr.key_sz = ret + 1;
+
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+                    "orangefs_inode_removexattr: key %s, key_sz %d\n",
+                    (char *)new_op->upcall.req.removexattr.key,
+                    (int)new_op->upcall.req.removexattr.key_sz);
+
+       ret = service_operation(new_op,
+                               "orangefs_inode_removexattr",
+                               get_interruptible_flag(inode));
+       if (ret == -ENOENT) {
+               /*
+                * Request to replace a non-existent attribute is an error.
+                */
+               if (flags & XATTR_REPLACE)
+                       ret = -ENODATA;
+               else
+                       ret = 0;
+       }
+
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+                    "orangefs_inode_removexattr: returning %d\n", ret);
+
+       op_release(new_op);
+out_unlock:
+       up_write(&orangefs_inode->xattr_sem);
+       return ret;
+}
+
+/*
+ * Tries to set an attribute for a given key on a file.
+ *
+ * Returns a -ve number on error and 0 on success.  Key is text, but value
+ * can be binary!
+ */
+int orangefs_inode_setxattr(struct inode *inode, const char *prefix,
+               const char *name, const void *value, size_t size, int flags)
+{
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_kernel_op_s *new_op;
+       int internal_flag = 0;
+       int ret = -ENOMEM;
+
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+                    "%s: prefix %s, name %s, buffer_size %zd\n",
+                    __func__, prefix, name, size);
+
+       if (size < 0 ||
+           size >= ORANGEFS_MAX_XATTR_VALUELEN ||
+           flags < 0) {
+               gossip_err("orangefs_inode_setxattr: bogus values of size(%d), flags(%d)\n",
+                          (int)size,
+                          flags);
+               return -EINVAL;
+       }
+
+       if (name == NULL ||
+           (size > 0 && value == NULL)) {
+               gossip_err("orangefs_inode_setxattr: bogus NULL pointers!\n");
+               return -EINVAL;
+       }
+
+       internal_flag = convert_to_internal_xattr_flags(flags);
+
+       if (prefix) {
+               if (strlen(name) + strlen(prefix) >= ORANGEFS_MAX_XATTR_NAMELEN) {
+                       gossip_err
+                           ("orangefs_inode_setxattr: bogus key size (%d)\n",
+                            (int)(strlen(name) + strlen(prefix)));
+                       return -EINVAL;
+               }
+       } else {
+               if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) {
+                       gossip_err
+                           ("orangefs_inode_setxattr: bogus key size (%d)\n",
+                            (int)(strlen(name)));
+                       return -EINVAL;
+               }
+       }
+
+       /* This is equivalent to a removexattr */
+       if (size == 0 && value == NULL) {
+               gossip_debug(GOSSIP_XATTR_DEBUG,
+                            "removing xattr (%s%s)\n",
+                            prefix,
+                            name);
+               return orangefs_inode_removexattr(inode, prefix, name, flags);
+       }
+
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+                    "setxattr on inode %pU, name %s\n",
+                    get_khandle_from_ino(inode),
+                    name);
+
+       down_write(&orangefs_inode->xattr_sem);
+       new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR);
+       if (!new_op)
+               goto out_unlock;
+
+
+       new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
+       new_op->upcall.req.setxattr.flags = internal_flag;
+       /*
+        * NOTE: Although keys are meant to be NULL terminated textual
+        * strings, I am going to explicitly pass the length just in
+        * case we change this later on...
+        */
+       ret = snprintf((char *)new_op->upcall.req.setxattr.keyval.key,
+                      ORANGEFS_MAX_XATTR_NAMELEN,
+                      "%s%s",
+                      prefix, name);
+       new_op->upcall.req.setxattr.keyval.key_sz = ret + 1;
+       memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
+       new_op->upcall.req.setxattr.keyval.val_sz = size;
+
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+                    "orangefs_inode_setxattr: key %s, key_sz %d "
+                    " value size %zd\n",
+                    (char *)new_op->upcall.req.setxattr.keyval.key,
+                    (int)new_op->upcall.req.setxattr.keyval.key_sz,
+                    size);
+
+       ret = service_operation(new_op,
+                               "orangefs_inode_setxattr",
+                               get_interruptible_flag(inode));
+
+       gossip_debug(GOSSIP_XATTR_DEBUG,
+                    "orangefs_inode_setxattr: returning %d\n",
+                    ret);
+
+       /* when request is serviced properly, free req op struct */
+       op_release(new_op);
+out_unlock:
+       up_write(&orangefs_inode->xattr_sem);
+       return ret;
+}
+
+/*
+ * Tries to get a specified object's keys into a user-specified buffer of a
+ * given size.  Note that like the previous instances of xattr routines, this
+ * also allows you to pass in a NULL pointer and 0 size to probe the size for
+ * subsequent memory allocations. Thus our return value is always the size of
+ * all the keys unless there were errors in fetching the keys!
+ */
+ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+       struct inode *inode = dentry->d_inode;
+       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
+       struct orangefs_kernel_op_s *new_op;
+       __u64 token = ORANGEFS_ITERATE_START;
+       ssize_t ret = -ENOMEM;
+       ssize_t total = 0;
+       int count_keys = 0;
+       int key_size;
+       int i = 0;
+       int returned_count = 0;
+
+       if (size > 0 && buffer == NULL) {
+               gossip_err("%s: bogus NULL pointers\n", __func__);
+               return -EINVAL;
+       }
+       if (size < 0) {
+               gossip_err("Invalid size (%d)\n", (int)size);
+               return -EINVAL;
+       }
+
+       down_read(&orangefs_inode->xattr_sem);
+       new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR);
+       if (!new_op)
+               goto out_unlock;
+
+       if (buffer && size > 0)
+               memset(buffer, 0, size);
+
+try_again:
+       key_size = 0;
+       new_op->upcall.req.listxattr.refn = orangefs_inode->refn;
+       new_op->upcall.req.listxattr.token = token;
+       new_op->upcall.req.listxattr.requested_count =
+           (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN;
+       ret = service_operation(new_op, __func__,
+                               get_interruptible_flag(inode));
+       if (ret != 0)
+               goto done;
+
+       if (size == 0) {
+               /*
+                * This is a bit of a big upper limit, but I did not want to
+                * spend too much time getting this correct, since users end
+                * up allocating memory rather than us...
+                */
+               total = new_op->downcall.resp.listxattr.returned_count *
+                       ORANGEFS_MAX_XATTR_NAMELEN;
+               goto done;
+       }
+
+       returned_count = new_op->downcall.resp.listxattr.returned_count;
+       if (returned_count < 0 ||
+           returned_count >= ORANGEFS_MAX_XATTR_LISTLEN) {
+               gossip_err("%s: impossible value for returned_count:%d:\n",
+               __func__,
+               returned_count);
+               ret = -EIO;
+               goto done;
+       }
+
+       /*
+        * Check to see how much can be fit in the buffer. Fit only whole keys.
+        */
+       for (i = 0; i < returned_count; i++) {
+               if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
+                   new_op->downcall.resp.listxattr.lengths[i] >
+                   ORANGEFS_MAX_XATTR_NAMELEN) {
+                       gossip_err("%s: impossible value for lengths[%d]\n",
+                           __func__,
+                           new_op->downcall.resp.listxattr.lengths[i]);
+                       ret = -EIO;
+                       goto done;
+               }
+               if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
+                       goto done;
+
+               /*
+                * Since many dumb programs try to setxattr() on our reserved
+                * xattrs this is a feeble attempt at defeating those by not
+                * listing them in the output of listxattr.. sigh
+                */
+               if (is_reserved_key(new_op->downcall.resp.listxattr.key +
+                                   key_size,
+                                   new_op->downcall.resp.
+                                       listxattr.lengths[i])) {
+                       gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
+                                       i, new_op->downcall.resp.listxattr.key +
+                                               key_size);
+                       memcpy(buffer + total,
+                               new_op->downcall.resp.listxattr.key + key_size,
+                               new_op->downcall.resp.listxattr.lengths[i]);
+                       total += new_op->downcall.resp.listxattr.lengths[i];
+                       count_keys++;
+               } else {
+                       gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
+                                       i, new_op->downcall.resp.listxattr.key +
+                                               key_size);
+               }
+               key_size += new_op->downcall.resp.listxattr.lengths[i];
+       }
+
+       /*
+        * Since the buffer was large enough, we might have to continue
+        * fetching more keys!
+        */
+       token = new_op->downcall.resp.listxattr.token;
+       if (token != ORANGEFS_ITERATE_END)
+               goto try_again;
+
+done:
+       gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
+                    " [size of buffer %ld] (filled in %d keys)\n",
+                    __func__,
+                    ret ? (int)ret : (int)total,
+                    (long)size,
+                    count_keys);
+       op_release(new_op);
+       if (ret == 0)
+               ret = total;
+out_unlock:
+       up_read(&orangefs_inode->xattr_sem);
+       return ret;
+}
+
+static int orangefs_xattr_set_default(const struct xattr_handler *handler,
+                                     struct dentry *dentry,
+                                     const char *name,
+                                     const void *buffer,
+                                     size_t size,
+                                     int flags)
+{
+       return orangefs_inode_setxattr(dentry->d_inode,
+                                   ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
+                                   name,
+                                   buffer,
+                                   size,
+                                   flags);
+}
+
+static int orangefs_xattr_get_default(const struct xattr_handler *handler,
+                                     struct dentry *dentry,
+                                     const char *name,
+                                     void *buffer,
+                                     size_t size)
+{
+       return orangefs_inode_getxattr(dentry->d_inode,
+                                   ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
+                                   name,
+                                   buffer,
+                                   size);
+
+}
+
+static int orangefs_xattr_set_trusted(const struct xattr_handler *handler,
+                                    struct dentry *dentry,
+                                    const char *name,
+                                    const void *buffer,
+                                    size_t size,
+                                    int flags)
+{
+       return orangefs_inode_setxattr(dentry->d_inode,
+                                   ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
+                                   name,
+                                   buffer,
+                                   size,
+                                   flags);
+}
+
+static int orangefs_xattr_get_trusted(const struct xattr_handler *handler,
+                                     struct dentry *dentry,
+                                     const char *name,
+                                     void *buffer,
+                                     size_t size)
+{
+       return orangefs_inode_getxattr(dentry->d_inode,
+                                   ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
+                                   name,
+                                   buffer,
+                                   size);
+}
+
+static struct xattr_handler orangefs_xattr_trusted_handler = {
+       .prefix = ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
+       .get = orangefs_xattr_get_trusted,
+       .set = orangefs_xattr_set_trusted,
+};
+
+static struct xattr_handler orangefs_xattr_default_handler = {
+       /*
+        * NOTE: this is set to be the empty string.
+        * so that all un-prefixed xattrs keys get caught
+        * here!
+        */
+       .prefix = ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
+       .get = orangefs_xattr_get_default,
+       .set = orangefs_xattr_set_default,
+};
+
+const struct xattr_handler *orangefs_xattr_handlers[] = {
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
+       &orangefs_xattr_trusted_handler,
+       &orangefs_xattr_default_handler,
+       NULL
+};
index 2c6f0cb..c54a243 100644 (file)
@@ -4,3 +4,4 @@ ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o
 ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
 ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
 ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
+ubifs-y += misc.o
diff --git a/fs/ubifs/misc.c b/fs/ubifs/misc.c
new file mode 100644 (file)
index 0000000..486a284
--- /dev/null
@@ -0,0 +1,57 @@
+#include <linux/kernel.h>
+#include "ubifs.h"
+
+/* Normal UBIFS messages */
+void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       pr_notice("UBIFS (ubi%d:%d): %pV\n",
+                 c->vi.ubi_num, c->vi.vol_id, &vaf);
+
+       va_end(args);
+}                                                                  \
+
+/* UBIFS error messages */
+void ubifs_err(const struct ubifs_info *c, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       pr_err("UBIFS error (ubi%d:%d pid %d): %ps: %pV\n",
+              c->vi.ubi_num, c->vi.vol_id, current->pid,
+              __builtin_return_address(0),
+              &vaf);
+
+       va_end(args);
+}                                                                  \
+
+/* UBIFS warning messages */
+void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       pr_warn("UBIFS warning (ubi%d:%d pid %d): %ps: %pV\n",
+               c->vi.ubi_num, c->vi.vol_id, current->pid,
+               __builtin_return_address(0),
+               &vaf);
+
+       va_end(args);
+}
index a5697de..c2a57e1 100644 (file)
 /* Version of this UBIFS implementation */
 #define UBIFS_VERSION 1
 
-/* Normal UBIFS messages */
-#define ubifs_msg(c, fmt, ...)                                      \
-       pr_notice("UBIFS (ubi%d:%d): " fmt "\n",                    \
-                 (c)->vi.ubi_num, (c)->vi.vol_id, ##__VA_ARGS__)
-/* UBIFS error messages */
-#define ubifs_err(c, fmt, ...)                                      \
-       pr_err("UBIFS error (ubi%d:%d pid %d): %s: " fmt "\n",      \
-              (c)->vi.ubi_num, (c)->vi.vol_id, current->pid,       \
-              __func__, ##__VA_ARGS__)
-/* UBIFS warning messages */
-#define ubifs_warn(c, fmt, ...)                                     \
-       pr_warn("UBIFS warning (ubi%d:%d pid %d): %s: " fmt "\n",   \
-               (c)->vi.ubi_num, (c)->vi.vol_id, current->pid,      \
-               __func__, ##__VA_ARGS__)
-/*
- * A variant of 'ubifs_err()' which takes the UBIFS file-sytem description
- * object as an argument.
- */
-#define ubifs_errc(c, fmt, ...)                                     \
-       do {                                                        \
-               if (!(c)->probing)                                  \
-                       ubifs_err(c, fmt, ##__VA_ARGS__);           \
-       } while (0)
-
 /* UBIFS file system VFS magic number */
 #define UBIFS_SUPER_MAGIC 0x24051905
 
@@ -1802,4 +1778,21 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
 #include "misc.h"
 #include "key.h"
 
+/* Normal UBIFS messages */
+__printf(2, 3)
+void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...);
+__printf(2, 3)
+void ubifs_err(const struct ubifs_info *c, const char *fmt, ...);
+__printf(2, 3)
+void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...);
+/*
+ * A variant of 'ubifs_err()' which takes the UBIFS file-sytem description
+ * object as an argument.
+ */
+#define ubifs_errc(c, fmt, ...)                                                \
+do {                                                                   \
+       if (!(c)->probing)                                              \
+               ubifs_err(c, fmt, ##__VA_ARGS__);                       \
+} while (0)
+
 #endif /* !__UBIFS_H__ */
index c7f4d43..b043e04 100644 (file)
@@ -59,7 +59,6 @@
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/xattr.h>
-#include <linux/posix_acl_xattr.h>
 
 /*
  * Limit the number of extended attributes per inode so that the total size
index f646391..3542d94 100644 (file)
@@ -121,4 +121,5 @@ xfs-$(CONFIG_XFS_RT)                += xfs_rtalloc.o
 xfs-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
 xfs-$(CONFIG_SYSCTL)           += xfs_sysctl.o
 xfs-$(CONFIG_COMPAT)           += xfs_ioctl32.o
-xfs-$(CONFIG_NFSD_PNFS)                += xfs_pnfs.o
+xfs-$(CONFIG_NFSD_BLOCKLAYOUT) += xfs_pnfs.o
+xfs-$(CONFIG_NFSD_SCSILAYOUT)  += xfs_pnfs.o
index 2816d42..a1b2dd8 100644 (file)
@@ -246,7 +246,7 @@ const struct export_operations xfs_export_operations = {
        .fh_to_parent           = xfs_fs_fh_to_parent,
        .get_parent             = xfs_fs_get_parent,
        .commit_metadata        = xfs_fs_nfs_commit_metadata,
-#ifdef CONFIG_NFSD_PNFS
+#ifdef CONFIG_NFSD_BLOCKLAYOUT
        .get_uuid               = xfs_fs_get_uuid,
        .map_blocks             = xfs_fs_map_blocks,
        .commit_blocks          = xfs_fs_commit_blocks,
index 8147ac1..93f7485 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _XFS_PNFS_H
 #define _XFS_PNFS_H 1
 
-#ifdef CONFIG_NFSD_PNFS
+#if defined(CONFIG_NFSD_BLOCKLAYOUT) || defined(CONFIG_NFSD_SCSILAYOUT)
 int xfs_fs_get_uuid(struct super_block *sb, u8 *buf, u32 *len, u64 *offset);
 int xfs_fs_map_blocks(struct inode *inode, loff_t offset, u64 length,
                struct iomap *iomap, bool write, u32 *device_generation);
index f90588a..6f96247 100644 (file)
@@ -151,7 +151,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
 #endif
 
 #ifndef HAVE_ARCH_BUG_ON
-#define BUG_ON(condition) do { if (condition) ; } while (0)
+#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
 #endif
 
 #ifndef HAVE_ARCH_WARN_ON
diff --git a/include/asm-generic/io-64-nonatomic-hi-lo.h b/include/asm-generic/io-64-nonatomic-hi-lo.h
deleted file mode 100644 (file)
index 32b73ab..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* XXX: delete asm-generic/io-64-nonatomic-hi-lo.h after converting new users */
-#include <linux/io-64-nonatomic-hi-lo.h>
diff --git a/include/asm-generic/io-64-nonatomic-lo-hi.h b/include/asm-generic/io-64-nonatomic-lo-hi.h
deleted file mode 100644 (file)
index 55a627c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* XXX: delete asm-generic/io-64-nonatomic-lo-hi.h after converting new users */
-#include <linux/io-64-nonatomic-lo-hi.h>
index 37d1fe2..67cfb7d 100644 (file)
@@ -24,9 +24,6 @@
 
 #ifndef __ASSEMBLY__
 
-#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)     free_page(addr)
-
 #define clear_page(page)       memset((page), 0, PAGE_SIZE)
 #define copy_page(to,from)     memcpy((to), (from), PAGE_SIZE)
 
index 8f5a12a..339125b 100644 (file)
                *(.entry.text)                                          \
                VMLINUX_SYMBOL(__entry_text_end) = .;
 
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
 #define IRQENTRY_TEXT                                                  \
                ALIGN_FUNCTION();                                       \
                VMLINUX_SYMBOL(__irqentry_text_start) = .;              \
 #define IRQENTRY_TEXT
 #endif
 
+#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
+#define SOFTIRQENTRY_TEXT                                              \
+               ALIGN_FUNCTION();                                       \
+               VMLINUX_SYMBOL(__softirqentry_text_start) = .;          \
+               *(.softirqentry.text)                                   \
+               VMLINUX_SYMBOL(__softirqentry_text_end) = .;
+#else
+#define SOFTIRQENTRY_TEXT
+#endif
+
 /* Section used for early init (in .S files) */
 #define HEAD_TEXT  *(.head.text)
 
index 15a73d4..9ac9799 100644 (file)
@@ -263,22 +263,8 @@ static inline void *blk_mq_rq_to_pdu(struct request *rq)
        for ((i) = 0; (i) < (q)->nr_hw_queues &&                        \
             ({ hctx = (q)->queue_hw_ctx[i]; 1; }); (i)++)
 
-#define queue_for_each_ctx(q, ctx, i)                                  \
-       for ((i) = 0; (i) < (q)->nr_queues &&                           \
-            ({ ctx = per_cpu_ptr((q)->queue_ctx, (i)); 1; }); (i)++)
-
 #define hctx_for_each_ctx(hctx, ctx, i)                                        \
        for ((i) = 0; (i) < (hctx)->nr_ctx &&                           \
             ({ ctx = (hctx)->ctxs[(i)]; 1; }); (i)++)
 
-#define blk_ctx_sum(q, sum)                                            \
-({                                                                     \
-       struct blk_mq_ctx *__x;                                         \
-       unsigned int __ret = 0, __i;                                    \
-                                                                       \
-       queue_for_each_ctx((q), __x, __i)                               \
-               __ret += sum;                                           \
-       __ret;                                                          \
-})
-
 #endif
index 15151f3..ae2f668 100644 (file)
@@ -105,6 +105,7 @@ static inline u64 ceph_sanitize_features(u64 features)
  */
 #define CEPH_FEATURES_SUPPORTED_DEFAULT                \
        (CEPH_FEATURE_NOSRCADDR |               \
+        CEPH_FEATURE_SUBSCRIBE2 |              \
         CEPH_FEATURE_RECONNECT_SEQ |           \
         CEPH_FEATURE_PGID64 |                  \
         CEPH_FEATURE_PGPOOL3 |                 \
@@ -127,6 +128,7 @@ static inline u64 ceph_sanitize_features(u64 features)
 
 #define CEPH_FEATURES_REQUIRED_DEFAULT   \
        (CEPH_FEATURE_NOSRCADDR |        \
+        CEPH_FEATURE_SUBSCRIBE2 |       \
         CEPH_FEATURE_RECONNECT_SEQ |    \
         CEPH_FEATURE_PGID64 |           \
         CEPH_FEATURE_PGPOOL3 |          \
index d7d072a..37f28bf 100644 (file)
@@ -198,8 +198,8 @@ struct ceph_client_mount {
 #define CEPH_SUBSCRIBE_ONETIME    1  /* i want only 1 update after have */
 
 struct ceph_mon_subscribe_item {
-       __le64 have_version;    __le64 have;
-       __u8 onetime;
+       __le64 start;
+       __u8 flags;
 } __attribute__ ((packed));
 
 struct ceph_mon_subscribe_ack {
@@ -376,7 +376,8 @@ union ceph_mds_request_args {
                __le32 stripe_count;         /* ... */
                __le32 object_size;
                __le32 file_replication;
-               __le32 unused;               /* used to be preferred osd */
+               __le32 mask;                 /* CEPH_CAP_* */
+               __le32 old_size;
        } __attribute__ ((packed)) open;
        struct {
                __le32 flags;
index 3e3799c..e7975e4 100644 (file)
@@ -47,7 +47,6 @@ struct ceph_options {
        unsigned long mount_timeout;            /* jiffies */
        unsigned long osd_idle_ttl;             /* jiffies */
        unsigned long osd_keepalive_timeout;    /* jiffies */
-       unsigned long monc_ping_timeout;        /* jiffies */
 
        /*
         * any type that can't be simply compared or doesn't need need
@@ -68,7 +67,12 @@ struct ceph_options {
 #define CEPH_MOUNT_TIMEOUT_DEFAULT     msecs_to_jiffies(60 * 1000)
 #define CEPH_OSD_KEEPALIVE_DEFAULT     msecs_to_jiffies(5 * 1000)
 #define CEPH_OSD_IDLE_TTL_DEFAULT      msecs_to_jiffies(60 * 1000)
-#define CEPH_MONC_PING_TIMEOUT_DEFAULT msecs_to_jiffies(30 * 1000)
+
+#define CEPH_MONC_HUNT_INTERVAL                msecs_to_jiffies(3 * 1000)
+#define CEPH_MONC_PING_INTERVAL                msecs_to_jiffies(10 * 1000)
+#define CEPH_MONC_PING_TIMEOUT         msecs_to_jiffies(30 * 1000)
+#define CEPH_MONC_HUNT_BACKOFF         2
+#define CEPH_MONC_HUNT_MAX_MULT                10
 
 #define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
 #define CEPH_MSG_MAX_MIDDLE_LEN        (16*1024*1024)
index 81810dc..e230e7e 100644 (file)
@@ -68,18 +68,24 @@ struct ceph_mon_client {
 
        bool hunting;
        int cur_mon;                       /* last monitor i contacted */
-       unsigned long sub_sent, sub_renew_after;
+       unsigned long sub_renew_after;
+       unsigned long sub_renew_sent;
        struct ceph_connection con;
 
+       bool had_a_connection;
+       int hunt_mult; /* [1..CEPH_MONC_HUNT_MAX_MULT] */
+
        /* pending generic requests */
        struct rb_root generic_request_tree;
        int num_generic_requests;
        u64 last_tid;
 
-       /* mds/osd map */
-       int want_mdsmap;
-       int want_next_osdmap; /* 1 = want, 2 = want+asked */
-       u32 have_osdmap, have_mdsmap;
+       /* subs, indexed with CEPH_SUB_* */
+       struct {
+               struct ceph_mon_subscribe_item item;
+               bool want;
+               u32 have; /* epoch */
+       } subs[3];
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_file;
@@ -93,14 +99,23 @@ extern int ceph_monmap_contains(struct ceph_monmap *m,
 extern int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl);
 extern void ceph_monc_stop(struct ceph_mon_client *monc);
 
+enum {
+       CEPH_SUB_MDSMAP = 0,
+       CEPH_SUB_MONMAP,
+       CEPH_SUB_OSDMAP,
+};
+
+extern const char *ceph_sub_str[];
+
 /*
  * The model here is to indicate that we need a new map of at least
- * epoch @want, and also call in when we receive a map.  We will
+ * epoch @epoch, and also call in when we receive a map.  We will
  * periodically rerequest the map from the monitor cluster until we
  * get what we want.
  */
-extern int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 have);
-extern int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 have);
+bool ceph_monc_want_map(struct ceph_mon_client *monc, int sub, u32 epoch,
+                       bool continuous);
+void ceph_monc_got_map(struct ceph_mon_client *monc, int sub, u32 epoch);
 
 extern void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc);
 extern int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch,
index 7506b48..4343df8 100644 (file)
@@ -43,7 +43,8 @@ struct ceph_osd {
 };
 
 
-#define CEPH_OSD_MAX_OP        3
+#define CEPH_OSD_SLAB_OPS      2
+#define CEPH_OSD_MAX_OPS       16
 
 enum ceph_osd_data_type {
        CEPH_OSD_DATA_TYPE_NONE = 0,
@@ -77,7 +78,10 @@ struct ceph_osd_data {
 struct ceph_osd_req_op {
        u16 op;           /* CEPH_OSD_OP_* */
        u32 flags;        /* CEPH_OSD_OP_FLAG_* */
-       u32 payload_len;
+       u32 indata_len;   /* request */
+       u32 outdata_len;  /* reply */
+       s32 rval;
+
        union {
                struct ceph_osd_data raw_data_in;
                struct {
@@ -136,7 +140,6 @@ struct ceph_osd_request {
 
        /* request osd ops array  */
        unsigned int            r_num_ops;
-       struct ceph_osd_req_op  r_ops[CEPH_OSD_MAX_OP];
 
        /* these are updated on each send */
        __le32           *r_request_osdmap_epoch;
@@ -148,8 +151,6 @@ struct ceph_osd_request {
        struct ceph_eversion *r_request_reassert_version;
 
        int               r_result;
-       int               r_reply_op_len[CEPH_OSD_MAX_OP];
-       s32               r_reply_op_result[CEPH_OSD_MAX_OP];
        int               r_got_reply;
        int               r_linger;
 
@@ -174,6 +175,8 @@ struct ceph_osd_request {
        unsigned long     r_stamp;            /* send OR check time */
 
        struct ceph_snap_context *r_snapc;    /* snap context for writes */
+
+       struct ceph_osd_req_op r_ops[];
 };
 
 struct ceph_request_redirect {
@@ -263,6 +266,8 @@ extern void osd_req_op_extent_init(struct ceph_osd_request *osd_req,
                                        u64 truncate_size, u32 truncate_seq);
 extern void osd_req_op_extent_update(struct ceph_osd_request *osd_req,
                                        unsigned int which, u64 length);
+extern void osd_req_op_extent_dup_last(struct ceph_osd_request *osd_req,
+                                      unsigned int which, u64 offset_inc);
 
 extern struct ceph_osd_data *osd_req_op_extent_osd_data(
                                        struct ceph_osd_request *osd_req,
index d1e49d5..de17999 100644 (file)
@@ -10,3 +10,8 @@
 #undef uninitialized_var
 #define uninitialized_var(x) x = *(&(x))
 #endif
+
+/* same as gcc, this was present in clang-2.6 so we can assume it works
+ * with any version that can compile the kernel
+ */
+#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
index 532108e..3fe90d4 100644 (file)
@@ -94,7 +94,7 @@ struct dma_buf_ops {
        void (*release)(struct dma_buf *);
 
        int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction);
-       void (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);
+       int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);
        void *(*kmap_atomic)(struct dma_buf *, unsigned long);
        void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *);
        void *(*kmap)(struct dma_buf *, unsigned long);
@@ -224,8 +224,8 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
                                enum dma_data_direction);
 int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
                             enum dma_data_direction dir);
-void dma_buf_end_cpu_access(struct dma_buf *dma_buf,
-                           enum dma_data_direction dir);
+int dma_buf_end_cpu_access(struct dma_buf *dma_buf,
+                          enum dma_data_direction dir);
 void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
 void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
 void *dma_buf_kmap(struct dma_buf *, unsigned long);
index 605bd88..2b17698 100644 (file)
@@ -294,7 +294,7 @@ static inline bool fence_is_later(struct fence *f1, struct fence *f2)
        if (WARN_ON(f1->context != f2->context))
                return false;
 
-       return f1->seqno - f2->seqno < INT_MAX;
+       return (int)(f1->seqno - f2->seqno) > 0;
 }
 
 /**
index 6d9df3f..dea12a6 100644 (file)
@@ -811,16 +811,6 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
  */
 #define __notrace_funcgraph            notrace
 
-/*
- * We want to which function is an entrypoint of a hardirq.
- * That will help us to put a signal on output.
- */
-#define __irq_entry             __attribute__((__section__(".irqentry.text")))
-
-/* Limits of hardirq entrypoints */
-extern char __irqentry_text_start[];
-extern char __irqentry_text_end[];
-
 #define FTRACE_NOTRACE_DEPTH 65536
 #define FTRACE_RETFUNC_DEPTH 50
 #define FTRACE_RETSTACK_ALLOC_SIZE 32
@@ -857,7 +847,6 @@ static inline void unpause_graph_tracing(void)
 #else /* !CONFIG_FUNCTION_GRAPH_TRACER */
 
 #define __notrace_funcgraph
-#define __irq_entry
 #define INIT_FTRACE_GRAPH
 
 static inline void ftrace_graph_init_task(struct task_struct *t) { }
index 79b0ef6..7008623 100644 (file)
@@ -127,7 +127,7 @@ static inline spinlock_t *pmd_trans_huge_lock(pmd_t *pmd,
        if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd))
                return __pmd_trans_huge_lock(pmd, vma);
        else
-               return false;
+               return NULL;
 }
 static inline int hpage_nr_pages(struct page *page)
 {
index 358076e..9fcabeb 100644 (file)
@@ -683,4 +683,24 @@ extern int early_irq_init(void);
 extern int arch_probe_nr_irqs(void);
 extern int arch_early_irq_init(void);
 
+#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
+/*
+ * We want to know which function is an entrypoint of a hardirq or a softirq.
+ */
+#define __irq_entry             __attribute__((__section__(".irqentry.text")))
+#define __softirq_entry  \
+       __attribute__((__section__(".softirqentry.text")))
+
+/* Limits of hardirq entrypoints */
+extern char __irqentry_text_start[];
+extern char __irqentry_text_end[];
+/* Limits of softirq entrypoints */
+extern char __softirqentry_text_start[];
+extern char __softirqentry_text_end[];
+
+#else
+#define __irq_entry
+#define __softirq_entry
+#endif
+
 #endif
index 0fdc798..737371b 100644 (file)
@@ -48,19 +48,28 @@ void kasan_unpoison_task_stack(struct task_struct *task);
 void kasan_alloc_pages(struct page *page, unsigned int order);
 void kasan_free_pages(struct page *page, unsigned int order);
 
+void kasan_cache_create(struct kmem_cache *cache, size_t *size,
+                       unsigned long *flags);
+
 void kasan_poison_slab(struct page *page);
 void kasan_unpoison_object_data(struct kmem_cache *cache, void *object);
 void kasan_poison_object_data(struct kmem_cache *cache, void *object);
 
-void kasan_kmalloc_large(const void *ptr, size_t size);
+void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags);
 void kasan_kfree_large(const void *ptr);
 void kasan_kfree(void *ptr);
-void kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size);
-void kasan_krealloc(const void *object, size_t new_size);
+void kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size,
+                 gfp_t flags);
+void kasan_krealloc(const void *object, size_t new_size, gfp_t flags);
 
-void kasan_slab_alloc(struct kmem_cache *s, void *object);
+void kasan_slab_alloc(struct kmem_cache *s, void *object, gfp_t flags);
 void kasan_slab_free(struct kmem_cache *s, void *object);
 
+struct kasan_cache {
+       int alloc_meta_offset;
+       int free_meta_offset;
+};
+
 int kasan_module_alloc(void *addr, size_t size);
 void kasan_free_shadow(const struct vm_struct *vm);
 
@@ -76,20 +85,26 @@ static inline void kasan_disable_current(void) {}
 static inline void kasan_alloc_pages(struct page *page, unsigned int order) {}
 static inline void kasan_free_pages(struct page *page, unsigned int order) {}
 
+static inline void kasan_cache_create(struct kmem_cache *cache,
+                                     size_t *size,
+                                     unsigned long *flags) {}
+
 static inline void kasan_poison_slab(struct page *page) {}
 static inline void kasan_unpoison_object_data(struct kmem_cache *cache,
                                        void *object) {}
 static inline void kasan_poison_object_data(struct kmem_cache *cache,
                                        void *object) {}
 
-static inline void kasan_kmalloc_large(void *ptr, size_t size) {}
+static inline void kasan_kmalloc_large(void *ptr, size_t size, gfp_t flags) {}
 static inline void kasan_kfree_large(const void *ptr) {}
 static inline void kasan_kfree(void *ptr) {}
 static inline void kasan_kmalloc(struct kmem_cache *s, const void *object,
-                               size_t size) {}
-static inline void kasan_krealloc(const void *object, size_t new_size) {}
+                               size_t size, gfp_t flags) {}
+static inline void kasan_krealloc(const void *object, size_t new_size,
+                                gfp_t flags) {}
 
-static inline void kasan_slab_alloc(struct kmem_cache *s, void *object) {}
+static inline void kasan_slab_alloc(struct kmem_cache *s, void *object,
+                                  gfp_t flags) {}
 static inline void kasan_slab_free(struct kmem_cache *s, void *object) {}
 
 static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
index c3c4318..cdcb2cc 100644 (file)
@@ -242,6 +242,7 @@ struct nvm_rq {
        uint16_t nr_pages;
        uint16_t flags;
 
+       u64 ppa_status; /* ppa media status */
        int error;
 };
 
@@ -346,6 +347,7 @@ struct nvm_dev {
        int nr_luns;
        unsigned max_pages_per_blk;
 
+       unsigned long *lun_map;
        void *ppalist_pool;
 
        struct nvm_id identity;
@@ -355,6 +357,7 @@ struct nvm_dev {
        char name[DISK_NAME_LEN];
 
        struct mutex mlock;
+       spinlock_t lock;
 };
 
 static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
@@ -465,8 +468,13 @@ typedef int (nvmm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
 typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
                                                                unsigned long);
 typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int);
+typedef int (nvmm_reserve_lun)(struct nvm_dev *, int);
+typedef void (nvmm_release_lun)(struct nvm_dev *, int);
 typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
 
+typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
+typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t);
+
 struct nvmm_type {
        const char *name;
        unsigned int version[3];
@@ -488,9 +496,15 @@ struct nvmm_type {
 
        /* Configuration management */
        nvmm_get_lun_fn *get_lun;
+       nvmm_reserve_lun *reserve_lun;
+       nvmm_release_lun *release_lun;
 
        /* Statistics */
        nvmm_lun_info_print_fn *lun_info_print;
+
+       nvmm_get_area_fn *get_area;
+       nvmm_put_area_fn *put_area;
+
        struct list_head list;
 };
 
index 450fc97..ed6407d 100644 (file)
@@ -1132,6 +1132,8 @@ struct zap_details {
        struct address_space *check_mapping;    /* Check page->mapping if set */
        pgoff_t first_index;                    /* Lowest page->index to unmap */
        pgoff_t last_index;                     /* Highest page->index to unmap */
+       bool ignore_dirty;                      /* Ignore dirty pages */
+       bool check_swap_entries;                /* Check also swap entries */
 };
 
 struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
index 36bb6a5..3bf8f95 100644 (file)
@@ -166,7 +166,6 @@ struct bbm_info {
 };
 
 /* OneNAND BBT interface */
-extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
 extern int onenand_default_bbt(struct mtd_info *mtd);
 
 #endif /* __LINUX_MTD_BBM_H */
index 02cd5f9..8255118 100644 (file)
@@ -44,7 +44,6 @@ struct INFTLrecord {
        unsigned int nb_blocks;         /* number of physical blocks */
        unsigned int nb_boot_blocks;    /* number of blocks used by the bios */
        struct erase_info instr;
-       struct nand_ecclayout oobinfo;
 };
 
 int INFTL_mount(struct INFTLrecord *s);
index 58f3ba7..5e0eb7c 100644 (file)
@@ -240,8 +240,11 @@ struct map_info {
           If there is no cache to care about this can be set to NULL. */
        void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
 
-       /* set_vpp() must handle being reentered -- enable, enable, disable
-          must leave it enabled. */
+       /* This will be called with 1 as parameter when the first map user
+        * needs VPP, and called with 0 when the last user exits. The map
+        * core maintains a reference counter, and assumes that VPP is a
+        * global resource applying to all mapped flash chips on the system.
+        */
        void (*set_vpp)(struct map_info *, int);
 
        unsigned long pfow_base;
index cc84923..7712721 100644 (file)
@@ -105,7 +105,6 @@ struct mtd_oob_ops {
 struct nand_ecclayout {
        __u32 eccbytes;
        __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
-       __u32 oobavail;
        struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
 };
 
@@ -265,6 +264,11 @@ static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
        return mtd->dev.of_node;
 }
 
+static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
+{
+       return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
+}
+
 int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
 int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
              void **virt, resource_size_t *phys);
index bdd68e2..56574ba 100644 (file)
@@ -168,6 +168,12 @@ typedef enum {
 /* Device supports subpage reads */
 #define NAND_SUBPAGE_READ      0x00001000
 
+/*
+ * Some MLC NANDs need data scrambling to limit bitflips caused by repeated
+ * patterns.
+ */
+#define NAND_NEED_SCRAMBLING   0x00002000
+
 /* Options valid for Samsung large page devices */
 #define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
 
@@ -666,7 +672,7 @@ struct nand_chip {
        void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
        void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
        void (*select_chip)(struct mtd_info *mtd, int chip);
-       int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+       int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
        int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
        void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
        int (*dev_ready)(struct mtd_info *mtd);
@@ -896,7 +902,6 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
  * @chip_delay:                R/B delay value in us
  * @options:           Option flags, e.g. 16bit buswidth
  * @bbt_options:       BBT option flags, e.g. NAND_BBT_USE_FLASH
- * @ecclayout:         ECC layout info structure
  * @part_probe_types:  NULL-terminated array of probe types
  */
 struct platform_nand_chip {
@@ -904,7 +909,6 @@ struct platform_nand_chip {
        int chip_offset;
        int nr_partitions;
        struct mtd_partition *partitions;
-       struct nand_ecclayout *ecclayout;
        int chip_delay;
        unsigned int options;
        unsigned int bbt_options;
index fb0bc34..98f20ef 100644 (file)
@@ -32,9 +32,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
 /*
  * Initialize BCH encoder/decoder
  */
-struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
-             unsigned int eccbytes, struct nand_ecclayout **ecclayout);
+struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
 /*
  * Release BCH encoder/decoder resources
  */
@@ -58,9 +56,7 @@ nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
        return -ENOTSUPP;
 }
 
-static inline struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
-             unsigned int eccbytes, struct nand_ecclayout **ecclayout)
+static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 {
        return NULL;
 }
index b059629..044daa0 100644 (file)
@@ -50,7 +50,6 @@ struct NFTLrecord {
         unsigned int nb_blocks;                /* number of physical blocks */
         unsigned int nb_boot_blocks;   /* number of blocks used by the bios */
         struct erase_info instr;
-       struct nand_ecclayout oobinfo;
 };
 
 int NFTL_mount(struct NFTLrecord *s);
index 62356d5..3c36113 100644 (file)
@@ -85,6 +85,7 @@
 #define SR_BP0                 BIT(2)  /* Block protect 0 */
 #define SR_BP1                 BIT(3)  /* Block protect 1 */
 #define SR_BP2                 BIT(4)  /* Block protect 2 */
+#define SR_TB                  BIT(5)  /* Top/Bottom protect */
 #define SR_SRWD                        BIT(7)  /* SR write protect */
 
 #define SR_QUAD_EN_MX          BIT(6)  /* Macronix Quad I/O */
@@ -116,6 +117,7 @@ enum spi_nor_ops {
 
 enum spi_nor_option_flags {
        SNOR_F_USE_FSR          = BIT(0),
+       SNOR_F_HAS_SR_TB        = BIT(1),
 };
 
 /**
index d6f9b4e..0114334 100644 (file)
@@ -529,6 +529,7 @@ enum pnfs_layouttype {
        LAYOUT_OSD2_OBJECTS = 2,
        LAYOUT_BLOCK_VOLUME = 3,
        LAYOUT_FLEX_FILES = 4,
+       LAYOUT_SCSI = 5,
        LAYOUT_TYPE_MAX
 };
 
@@ -555,6 +556,7 @@ enum pnfs_block_volume_type {
        PNFS_BLOCK_VOLUME_SLICE         = 1,
        PNFS_BLOCK_VOLUME_CONCAT        = 2,
        PNFS_BLOCK_VOLUME_STRIPE        = 3,
+       PNFS_BLOCK_VOLUME_SCSI          = 4,
 };
 
 enum pnfs_block_extent_state {
@@ -568,6 +570,23 @@ enum pnfs_block_extent_state {
 #define PNFS_BLOCK_EXTENT_SIZE \
        (7 * sizeof(__be32) + NFS4_DEVICEID4_SIZE)
 
+/* on the wire size of a scsi commit range */
+#define PNFS_SCSI_RANGE_SIZE \
+       (4 * sizeof(__be32))
+
+enum scsi_code_set {
+       PS_CODE_SET_BINARY      = 1,
+       PS_CODE_SET_ASCII       = 2,
+       PS_CODE_SET_UTF8        = 3
+};
+
+enum scsi_designator_type {
+       PS_DESIGNATOR_T10       = 1,
+       PS_DESIGNATOR_EUI64     = 2,
+       PS_DESIGNATOR_NAA       = 3,
+       PS_DESIGNATOR_NAME      = 8
+};
+
 #define NFL4_UFLG_MASK                 0x0000003F
 #define NFL4_UFLG_DENSE                        0x00000001
 #define NFL4_UFLG_COMMIT_THRU_MDS      0x00000002
index f798e2a..6f47562 100644 (file)
@@ -284,7 +284,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
                /* ops->db_read_mask                    && */
                ops->db_set_mask                        &&
                ops->db_clear_mask                      &&
-               ops->peer_db_addr                       &&
+               /* ops->peer_db_addr                    && */
                /* ops->peer_db_read                    && */
                ops->peer_db_set                        &&
                /* ops->peer_db_clear                   && */
@@ -295,7 +295,7 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
                ops->spad_count                         &&
                ops->spad_read                          &&
                ops->spad_write                         &&
-               ops->peer_spad_addr                     &&
+               /* ops->peer_spad_addr                  && */
                /* ops->peer_spad_read                  && */
                ops->peer_spad_write                    &&
                1;
@@ -757,6 +757,9 @@ static inline int ntb_peer_db_addr(struct ntb_dev *ntb,
                                   phys_addr_t *db_addr,
                                   resource_size_t *db_size)
 {
+       if (!ntb->ops->peer_db_addr)
+               return -EINVAL;
+
        return ntb->ops->peer_db_addr(ntb, db_addr, db_size);
 }
 
@@ -948,6 +951,9 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
 static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
                                     phys_addr_t *spad_addr)
 {
+       if (!ntb->ops->peer_spad_addr)
+               return -EINVAL;
+
        return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
 }
 
index 03e6257..628a432 100644 (file)
@@ -76,8 +76,6 @@ extern unsigned long oom_badness(struct task_struct *p,
                struct mem_cgroup *memcg, const nodemask_t *nodemask,
                unsigned long totalpages);
 
-extern int oom_kills_count(void);
-extern void note_oom_kill(void);
 extern void oom_kill_process(struct oom_control *oc, struct task_struct *p,
                             unsigned int points, unsigned long totalpages,
                             struct mem_cgroup *memcg, const char *message);
@@ -91,7 +89,7 @@ extern enum oom_scan_t oom_scan_process_thread(struct oom_control *oc,
 
 extern bool out_of_memory(struct oom_control *oc);
 
-extern void exit_oom_victim(void);
+extern void exit_oom_victim(struct task_struct *tsk);
 
 extern int register_oom_notifier(struct notifier_block *nb);
 extern int unregister_oom_notifier(struct notifier_block *nb);
index 36bb921..c55e42e 100644 (file)
@@ -40,7 +40,6 @@ struct s3c2410_nand_set {
        char                    *name;
        int                     *nr_map;
        struct mtd_partition    *partitions;
-       struct nand_ecclayout   *ecc_layout;
 };
 
 struct s3c2410_platform_nand {
index 25266c6..308d604 100644 (file)
@@ -42,7 +42,9 @@ extern int pm_clk_create(struct device *dev);
 extern void pm_clk_destroy(struct device *dev);
 extern int pm_clk_add(struct device *dev, const char *con_id);
 extern int pm_clk_add_clk(struct device *dev, struct clk *clk);
+extern int of_pm_clk_add_clks(struct device *dev);
 extern void pm_clk_remove(struct device *dev, const char *con_id);
+extern void pm_clk_remove_clk(struct device *dev, struct clk *clk);
 extern int pm_clk_suspend(struct device *dev);
 extern int pm_clk_resume(struct device *dev);
 #else
@@ -69,11 +71,18 @@ static inline int pm_clk_add_clk(struct device *dev, struct clk *clk)
 {
        return -EINVAL;
 }
+static inline int of_pm_clk_add_clks(struct device *dev)
+{
+       return -EINVAL;
+}
 static inline void pm_clk_remove(struct device *dev, const char *con_id)
 {
 }
 #define pm_clk_suspend NULL
 #define pm_clk_resume  NULL
+static inline void pm_clk_remove_clk(struct device *dev, struct clk *clk)
+{
+}
 #endif
 
 #ifdef CONFIG_HAVE_CLK
index 3ec5309..ac6d872 100644 (file)
@@ -42,6 +42,13 @@ static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src,
        BUG();
 }
 
+static inline int arch_memcpy_from_pmem(void *dst, const void __pmem *src,
+               size_t n)
+{
+       BUG();
+       return -EFAULT;
+}
+
 static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
                struct iov_iter *i)
 {
@@ -66,14 +73,17 @@ static inline void arch_invalidate_pmem(void __pmem *addr, size_t size)
 #endif
 
 /*
- * Architectures that define ARCH_HAS_PMEM_API must provide
- * implementations for arch_memcpy_to_pmem(), arch_wmb_pmem(),
- * arch_copy_from_iter_pmem(), arch_clear_pmem(), arch_wb_cache_pmem()
- * and arch_has_wmb_pmem().
+ * memcpy_from_pmem - read from persistent memory with error handling
+ * @dst: destination buffer
+ * @src: source buffer
+ * @size: transfer length
+ *
+ * Returns 0 on success negative error code on failure.
  */
-static inline void memcpy_from_pmem(void *dst, void __pmem const *src, size_t size)
+static inline int memcpy_from_pmem(void *dst, void __pmem const *src,
+               size_t size)
 {
-       memcpy(dst, (void __force const *) src, size);
+       return arch_memcpy_from_pmem(dst, src, size);
 }
 
 static inline bool arch_has_pmem_api(void)
index 34495d2..60bba7e 100644 (file)
@@ -426,6 +426,7 @@ extern signed long schedule_timeout(signed long timeout);
 extern signed long schedule_timeout_interruptible(signed long timeout);
 extern signed long schedule_timeout_killable(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
+extern signed long schedule_timeout_idle(signed long timeout);
 asmlinkage void schedule(void);
 extern void schedule_preempt_disabled(void);
 
@@ -1848,6 +1849,9 @@ struct task_struct {
        unsigned long   task_state_change;
 #endif
        int pagefault_disabled;
+#ifdef CONFIG_MMU
+       struct task_struct *oom_reaper_list;
+#endif
 /* CPU-specific state of this task */
        struct thread_struct thread;
 /*
@@ -2870,10 +2874,18 @@ static inline unsigned long stack_not_used(struct task_struct *p)
        unsigned long *n = end_of_stack(p);
 
        do {    /* Skip over canary */
+# ifdef CONFIG_STACK_GROWSUP
+               n--;
+# else
                n++;
+# endif
        } while (!*n);
 
+# ifdef CONFIG_STACK_GROWSUP
+       return (unsigned long)end_of_stack(p) - (unsigned long)n;
+# else
        return (unsigned long)n - (unsigned long)end_of_stack(p);
+# endif
 }
 #endif
 extern void set_task_stack_end_magic(struct task_struct *tsk);
index e4b5687..508bd82 100644 (file)
 # define SLAB_ACCOUNT          0x00000000UL
 #endif
 
+#ifdef CONFIG_KASAN
+#define SLAB_KASAN             0x08000000UL
+#else
+#define SLAB_KASAN             0x00000000UL
+#endif
+
 /* The following flags affect the page allocator grouping pages by mobility */
 #define SLAB_RECLAIM_ACCOUNT   0x00020000UL            /* Objects are reclaimable */
 #define SLAB_TEMPORARY         SLAB_RECLAIM_ACCOUNT    /* Objects are short-lived */
@@ -370,7 +376,7 @@ static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s,
 {
        void *ret = kmem_cache_alloc(s, flags);
 
-       kasan_kmalloc(s, ret, size);
+       kasan_kmalloc(s, ret, size, flags);
        return ret;
 }
 
@@ -381,7 +387,7 @@ kmem_cache_alloc_node_trace(struct kmem_cache *s,
 {
        void *ret = kmem_cache_alloc_node(s, gfpflags, node);
 
-       kasan_kmalloc(s, ret, size);
+       kasan_kmalloc(s, ret, size, gfpflags);
        return ret;
 }
 #endif /* CONFIG_TRACING */
index e878ba3..9edbbf3 100644 (file)
@@ -76,8 +76,22 @@ struct kmem_cache {
 #ifdef CONFIG_MEMCG
        struct memcg_cache_params memcg_params;
 #endif
+#ifdef CONFIG_KASAN
+       struct kasan_cache kasan_info;
+#endif
 
        struct kmem_cache_node *node[MAX_NUMNODES];
 };
 
+static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
+                               void *x) {
+       void *object = x - (x - page->s_mem) % cache->size;
+       void *last_object = page->s_mem + (cache->num - 1) * cache->size;
+
+       if (unlikely(object > last_object))
+               return last_object;
+       else
+               return object;
+}
+
 #endif /* _LINUX_SLAB_DEF_H */
index ac5143f..665cd0c 100644 (file)
@@ -130,4 +130,15 @@ static inline void *virt_to_obj(struct kmem_cache *s,
 void object_err(struct kmem_cache *s, struct page *page,
                u8 *object, char *reason);
 
+static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
+                               void *x) {
+       void *object = x - (x - page_address(page)) % cache->size;
+       void *last_object = page_address(page) +
+               (page->objects - 1) * cache->size;
+       if (unlikely(object > last_object))
+               return last_object;
+       else
+               return object;
+}
+
 #endif /* _LINUX_SLUB_DEF_H */
diff --git a/include/linux/stackdepot.h b/include/linux/stackdepot.h
new file mode 100644 (file)
index 0000000..7978b3e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * A generic stack depot implementation
+ *
+ * Author: Alexander Potapenko <glider@google.com>
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Based on code by Dmitry Chernenkov.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_STACKDEPOT_H
+#define _LINUX_STACKDEPOT_H
+
+typedef u32 depot_stack_handle_t;
+
+struct stack_trace;
+
+depot_stack_handle_t depot_save_stack(struct stack_trace *trace, gfp_t flags);
+
+void depot_fetch_stack(depot_stack_handle_t handle, struct stack_trace *trace);
+
+#endif
index 784bc2c..bf66ea6 100644 (file)
@@ -28,6 +28,7 @@
 #define SCSI_TRANSPORT_FC_H
 
 #include <linux/sched.h>
+#include <asm/unaligned.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_netlink.h>
 
@@ -797,22 +798,12 @@ fc_remote_port_chkready(struct fc_rport *rport)
 
 static inline u64 wwn_to_u64(u8 *wwn)
 {
-       return (u64)wwn[0] << 56 | (u64)wwn[1] << 48 |
-           (u64)wwn[2] << 40 | (u64)wwn[3] << 32 |
-           (u64)wwn[4] << 24 | (u64)wwn[5] << 16 |
-           (u64)wwn[6] <<  8 | (u64)wwn[7];
+       return get_unaligned_be64(wwn);
 }
 
 static inline void u64_to_wwn(u64 inm, u8 *wwn)
 {
-       wwn[0] = (inm >> 56) & 0xff;
-       wwn[1] = (inm >> 48) & 0xff;
-       wwn[2] = (inm >> 40) & 0xff;
-       wwn[3] = (inm >> 32) & 0xff;
-       wwn[4] = (inm >> 24) & 0xff;
-       wwn[5] = (inm >> 16) & 0xff;
-       wwn[6] = (inm >> 8) & 0xff;
-       wwn[7] = inm & 0xff;
+       put_unaligned_be64(inm, wwn);
 }
 
 /**
index 6fb6440..8738a78 100644 (file)
@@ -29,7 +29,7 @@ TRACE_EVENT(test_pages_isolated,
 
        TP_printk("start_pfn=0x%lx end_pfn=0x%lx fin_pfn=0x%lx ret=%s",
                __entry->start_pfn, __entry->end_pfn, __entry->fin_pfn,
-               __entry->end_pfn == __entry->fin_pfn ? "success" : "fail")
+               __entry->end_pfn <= __entry->fin_pfn ? "success" : "fail")
 );
 
 #endif /* _TRACE_PAGE_ISOLATION_H */
index e0d2616..0dfd09d 100644 (file)
@@ -272,8 +272,9 @@ config CROSS_MEMORY_ATTACH
          See the man page for more details.
 
 config FHANDLE
-       bool "open by fhandle syscalls"
+       bool "open by fhandle syscalls" if EXPERT
        select EXPORTFS
+       default y
        help
          If you say Y here, a user level program will be able to map
          file names to handle and then later use the handle for
index 953d1a1..fd90195 100644 (file)
@@ -435,7 +435,7 @@ static void exit_mm(struct task_struct *tsk)
        mm_update_next_owner(mm);
        mmput(mm);
        if (test_thread_flag(TIF_MEMDIE))
-               exit_oom_victim();
+               exit_oom_victim(tsk);
 }
 
 static struct task_struct *find_alive_thread(struct task_struct *p)
index aa0f26b..fca9254 100644 (file)
@@ -339,6 +339,7 @@ int hibernation_snapshot(int platform_mode)
        pm_message_t msg;
        int error;
 
+       pm_suspend_clear_flags();
        error = platform_begin(platform_mode);
        if (error)
                goto Close;
index 8aae49d..17caf4b 100644 (file)
@@ -227,7 +227,7 @@ static inline bool lockdep_softirq_start(void) { return false; }
 static inline void lockdep_softirq_end(bool in_hardirq) { }
 #endif
 
-asmlinkage __visible void __do_softirq(void)
+asmlinkage __visible void __softirq_entry __do_softirq(void)
 {
        unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
        unsigned long old_flags = current->flags;
index d1798fa..73164c3 100644 (file)
@@ -1566,6 +1566,17 @@ signed long __sched schedule_timeout_uninterruptible(signed long timeout)
 }
 EXPORT_SYMBOL(schedule_timeout_uninterruptible);
 
+/*
+ * Like schedule_timeout_uninterruptible(), except this task will not contribute
+ * to load average.
+ */
+signed long __sched schedule_timeout_idle(signed long timeout)
+{
+       __set_current_state(TASK_IDLE);
+       return schedule_timeout(timeout);
+}
+EXPORT_SYMBOL(schedule_timeout_idle);
+
 #ifdef CONFIG_HOTPLUG_CPU
 static void migrate_timer_list(struct tvec_base *new_base, struct hlist_head *head)
 {
index 91d6a63..3a0244f 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <linux/uaccess.h>
 #include <linux/ftrace.h>
+#include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 
index 133ebc0..3cca122 100644 (file)
@@ -536,4 +536,8 @@ config ARCH_HAS_PMEM_API
 config ARCH_HAS_MMIO_FLUSH
        bool
 
+config STACKDEPOT
+       bool
+       select STACKTRACE
+
 endmenu
index 532d4d5..1e9a607 100644 (file)
@@ -558,7 +558,7 @@ config DEBUG_KMEMLEAK_DEFAULT_OFF
 
 config DEBUG_STACK_USAGE
        bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL && !IA64 && !PARISC && !METAG
+       depends on DEBUG_KERNEL && !IA64
        help
          Enables the display of the minimum amount of free stack which each
          task has ever had available in the sysrq-T and sysrq-P debug output.
index 0fee5ac..67d8c68 100644 (file)
@@ -5,8 +5,9 @@ if HAVE_ARCH_KASAN
 
 config KASAN
        bool "KASan: runtime memory debugger"
-       depends on SLUB_DEBUG
+       depends on SLUB_DEBUG || (SLAB && !DEBUG_SLAB)
        select CONSTRUCTORS
+       select STACKDEPOT if SLAB
        help
          Enables kernel address sanitizer - runtime memory debugger,
          designed to find out-of-bounds accesses and use-after-free bugs.
@@ -16,6 +17,8 @@ config KASAN
          This feature consumes about 1/8 of available memory and brings about
          ~x3 performance slowdown.
          For better error detection enable CONFIG_STACKTRACE.
+         Currently CONFIG_KASAN doesn't work with CONFIG_DEBUG_SLAB
+         (the resulting kernel does not boot).
 
 choice
        prompt "Instrumentation type"
index a1de5b6..7bd6fd4 100644 (file)
@@ -181,6 +181,9 @@ obj-$(CONFIG_SG_SPLIT) += sg_split.o
 obj-$(CONFIG_STMP_DEVICE) += stmp_device.o
 obj-$(CONFIG_IRQ_POLL) += irq_poll.o
 
+obj-$(CONFIG_STACKDEPOT) += stackdepot.o
+KASAN_SANITIZE_stackdepot.o := n
+
 libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \
               fdt_empty_tree.o
 $(foreach file, $(libfdt_files), \
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
new file mode 100644 (file)
index 0000000..654c9d8
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Generic stack depot for storing stack traces.
+ *
+ * Some debugging tools need to save stack traces of certain events which can
+ * be later presented to the user. For example, KASAN needs to safe alloc and
+ * free stacks for each object, but storing two stack traces per object
+ * requires too much memory (e.g. SLUB_DEBUG needs 256 bytes per object for
+ * that).
+ *
+ * Instead, stack depot maintains a hashtable of unique stacktraces. Since alloc
+ * and free stacks repeat a lot, we save about 100x space.
+ * Stacks are never removed from depot, so we store them contiguously one after
+ * another in a contiguos memory allocation.
+ *
+ * Author: Alexander Potapenko <glider@google.com>
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Based on code by Dmitry Chernenkov.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/gfp.h>
+#include <linux/jhash.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/percpu.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/stacktrace.h>
+#include <linux/stackdepot.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define DEPOT_STACK_BITS (sizeof(depot_stack_handle_t) * 8)
+
+#define STACK_ALLOC_ORDER 2 /* 'Slab' size order for stack depot, 4 pages */
+#define STACK_ALLOC_SIZE (1LL << (PAGE_SHIFT + STACK_ALLOC_ORDER))
+#define STACK_ALLOC_ALIGN 4
+#define STACK_ALLOC_OFFSET_BITS (STACK_ALLOC_ORDER + PAGE_SHIFT - \
+                                       STACK_ALLOC_ALIGN)
+#define STACK_ALLOC_INDEX_BITS (DEPOT_STACK_BITS - STACK_ALLOC_OFFSET_BITS)
+#define STACK_ALLOC_SLABS_CAP 1024
+#define STACK_ALLOC_MAX_SLABS \
+       (((1LL << (STACK_ALLOC_INDEX_BITS)) < STACK_ALLOC_SLABS_CAP) ? \
+        (1LL << (STACK_ALLOC_INDEX_BITS)) : STACK_ALLOC_SLABS_CAP)
+
+/* The compact structure to store the reference to stacks. */
+union handle_parts {
+       depot_stack_handle_t handle;
+       struct {
+               u32 slabindex : STACK_ALLOC_INDEX_BITS;
+               u32 offset : STACK_ALLOC_OFFSET_BITS;
+       };
+};
+
+struct stack_record {
+       struct stack_record *next;      /* Link in the hashtable */
+       u32 hash;                       /* Hash in the hastable */
+       u32 size;                       /* Number of frames in the stack */
+       union handle_parts handle;
+       unsigned long entries[1];       /* Variable-sized array of entries. */
+};
+
+static void *stack_slabs[STACK_ALLOC_MAX_SLABS];
+
+static int depot_index;
+static int next_slab_inited;
+static size_t depot_offset;
+static DEFINE_SPINLOCK(depot_lock);
+
+static bool init_stack_slab(void **prealloc)
+{
+       if (!*prealloc)
+               return false;
+       /*
+        * This smp_load_acquire() pairs with smp_store_release() to
+        * |next_slab_inited| below and in depot_alloc_stack().
+        */
+       if (smp_load_acquire(&next_slab_inited))
+               return true;
+       if (stack_slabs[depot_index] == NULL) {
+               stack_slabs[depot_index] = *prealloc;
+       } else {
+               stack_slabs[depot_index + 1] = *prealloc;
+               /*
+                * This smp_store_release pairs with smp_load_acquire() from
+                * |next_slab_inited| above and in depot_save_stack().
+                */
+               smp_store_release(&next_slab_inited, 1);
+       }
+       *prealloc = NULL;
+       return true;
+}
+
+/* Allocation of a new stack in raw storage */
+static struct stack_record *depot_alloc_stack(unsigned long *entries, int size,
+               u32 hash, void **prealloc, gfp_t alloc_flags)
+{
+       int required_size = offsetof(struct stack_record, entries) +
+               sizeof(unsigned long) * size;
+       struct stack_record *stack;
+
+       required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
+
+       if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
+               if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
+                       WARN_ONCE(1, "Stack depot reached limit capacity");
+                       return NULL;
+               }
+               depot_index++;
+               depot_offset = 0;
+               /*
+                * smp_store_release() here pairs with smp_load_acquire() from
+                * |next_slab_inited| in depot_save_stack() and
+                * init_stack_slab().
+                */
+               if (depot_index + 1 < STACK_ALLOC_MAX_SLABS)
+                       smp_store_release(&next_slab_inited, 0);
+       }
+       init_stack_slab(prealloc);
+       if (stack_slabs[depot_index] == NULL)
+               return NULL;
+
+       stack = stack_slabs[depot_index] + depot_offset;
+
+       stack->hash = hash;
+       stack->size = size;
+       stack->handle.slabindex = depot_index;
+       stack->handle.offset = depot_offset >> STACK_ALLOC_ALIGN;
+       memcpy(stack->entries, entries, size * sizeof(unsigned long));
+       depot_offset += required_size;
+
+       return stack;
+}
+
+#define STACK_HASH_ORDER 20
+#define STACK_HASH_SIZE (1L << STACK_HASH_ORDER)
+#define STACK_HASH_MASK (STACK_HASH_SIZE - 1)
+#define STACK_HASH_SEED 0x9747b28c
+
+static struct stack_record *stack_table[STACK_HASH_SIZE] = {
+       [0 ...  STACK_HASH_SIZE - 1] = NULL
+};
+
+/* Calculate hash for a stack */
+static inline u32 hash_stack(unsigned long *entries, unsigned int size)
+{
+       return jhash2((u32 *)entries,
+                              size * sizeof(unsigned long) / sizeof(u32),
+                              STACK_HASH_SEED);
+}
+
+/* Find a stack that is equal to the one stored in entries in the hash */
+static inline struct stack_record *find_stack(struct stack_record *bucket,
+                                            unsigned long *entries, int size,
+                                            u32 hash)
+{
+       struct stack_record *found;
+
+       for (found = bucket; found; found = found->next) {
+               if (found->hash == hash &&
+                   found->size == size &&
+                   !memcmp(entries, found->entries,
+                           size * sizeof(unsigned long))) {
+                       return found;
+               }
+       }
+       return NULL;
+}
+
+void depot_fetch_stack(depot_stack_handle_t handle, struct stack_trace *trace)
+{
+       union handle_parts parts = { .handle = handle };
+       void *slab = stack_slabs[parts.slabindex];
+       size_t offset = parts.offset << STACK_ALLOC_ALIGN;
+       struct stack_record *stack = slab + offset;
+
+       trace->nr_entries = trace->max_entries = stack->size;
+       trace->entries = stack->entries;
+       trace->skip = 0;
+}
+
+/**
+ * depot_save_stack - save stack in a stack depot.
+ * @trace - the stacktrace to save.
+ * @alloc_flags - flags for allocating additional memory if required.
+ *
+ * Returns the handle of the stack struct stored in depot.
+ */
+depot_stack_handle_t depot_save_stack(struct stack_trace *trace,
+                                   gfp_t alloc_flags)
+{
+       u32 hash;
+       depot_stack_handle_t retval = 0;
+       struct stack_record *found = NULL, **bucket;
+       unsigned long flags;
+       struct page *page = NULL;
+       void *prealloc = NULL;
+
+       if (unlikely(trace->nr_entries == 0))
+               goto fast_exit;
+
+       hash = hash_stack(trace->entries, trace->nr_entries);
+       /* Bad luck, we won't store this stack. */
+       if (hash == 0)
+               goto exit;
+
+       bucket = &stack_table[hash & STACK_HASH_MASK];
+
+       /*
+        * Fast path: look the stack trace up without locking.
+        * The smp_load_acquire() here pairs with smp_store_release() to
+        * |bucket| below.
+        */
+       found = find_stack(smp_load_acquire(bucket), trace->entries,
+                          trace->nr_entries, hash);
+       if (found)
+               goto exit;
+
+       /*
+        * Check if the current or the next stack slab need to be initialized.
+        * If so, allocate the memory - we won't be able to do that under the
+        * lock.
+        *
+        * The smp_load_acquire() here pairs with smp_store_release() to
+        * |next_slab_inited| in depot_alloc_stack() and init_stack_slab().
+        */
+       if (unlikely(!smp_load_acquire(&next_slab_inited))) {
+               /*
+                * Zero out zone modifiers, as we don't have specific zone
+                * requirements. Keep the flags related to allocation in atomic
+                * contexts and I/O.
+                */
+               alloc_flags &= ~GFP_ZONEMASK;
+               alloc_flags &= (GFP_ATOMIC | GFP_KERNEL);
+               page = alloc_pages(alloc_flags, STACK_ALLOC_ORDER);
+               if (page)
+                       prealloc = page_address(page);
+       }
+
+       spin_lock_irqsave(&depot_lock, flags);
+
+       found = find_stack(*bucket, trace->entries, trace->nr_entries, hash);
+       if (!found) {
+               struct stack_record *new =
+                       depot_alloc_stack(trace->entries, trace->nr_entries,
+                                         hash, &prealloc, alloc_flags);
+               if (new) {
+                       new->next = *bucket;
+                       /*
+                        * This smp_store_release() pairs with
+                        * smp_load_acquire() from |bucket| above.
+                        */
+                       smp_store_release(bucket, new);
+                       found = new;
+               }
+       } else if (prealloc) {
+               /*
+                * We didn't need to store this stack trace, but let's keep
+                * the preallocated memory for the future.
+                */
+               WARN_ON(!init_stack_slab(&prealloc));
+       }
+
+       spin_unlock_irqrestore(&depot_lock, flags);
+exit:
+       if (prealloc) {
+               /* Nobody used this memory, ok to free it. */
+               free_pages((unsigned long)prealloc, STACK_ALLOC_ORDER);
+       }
+       if (found)
+               retval = found->handle.handle;
+fast_exit:
+       return retval;
+}
index c32f3b0..82169fb 100644 (file)
@@ -65,11 +65,34 @@ static noinline void __init kmalloc_node_oob_right(void)
        kfree(ptr);
 }
 
-static noinline void __init kmalloc_large_oob_right(void)
+#ifdef CONFIG_SLUB
+static noinline void __init kmalloc_pagealloc_oob_right(void)
 {
        char *ptr;
        size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
 
+       /* Allocate a chunk that does not fit into a SLUB cache to trigger
+        * the page allocator fallback.
+        */
+       pr_info("kmalloc pagealloc allocation: out-of-bounds to right\n");
+       ptr = kmalloc(size, GFP_KERNEL);
+       if (!ptr) {
+               pr_err("Allocation failed\n");
+               return;
+       }
+
+       ptr[size] = 0;
+       kfree(ptr);
+}
+#endif
+
+static noinline void __init kmalloc_large_oob_right(void)
+{
+       char *ptr;
+       size_t size = KMALLOC_MAX_CACHE_SIZE - 256;
+       /* Allocate a chunk that is large enough, but still fits into a slab
+        * and does not trigger the page allocator fallback in SLUB.
+        */
        pr_info("kmalloc large allocation: out-of-bounds to right\n");
        ptr = kmalloc(size, GFP_KERNEL);
        if (!ptr) {
@@ -271,6 +294,8 @@ static noinline void __init kmalloc_uaf2(void)
        }
 
        ptr1[40] = 'x';
+       if (ptr1 == ptr2)
+               pr_err("Could not detect use-after-free: ptr1 == ptr2\n");
        kfree(ptr2);
 }
 
@@ -324,6 +349,9 @@ static int __init kmalloc_tests_init(void)
        kmalloc_oob_right();
        kmalloc_oob_left();
        kmalloc_node_oob_right();
+#ifdef CONFIG_SLUB
+       kmalloc_pagealloc_oob_right();
+#endif
        kmalloc_large_oob_right();
        kmalloc_oob_krealloc_more();
        kmalloc_oob_krealloc_less();
index f5e797c..deb467e 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 KASAN_SANITIZE_slab_common.o := n
+KASAN_SANITIZE_slab.o := n
 KASAN_SANITIZE_slub.o := n
 
 # These files are disabled because they produce non-interesting and/or
index 7c00f10..a8c69c8 100644 (file)
@@ -1840,15 +1840,16 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
        ssize_t retval = 0;
        loff_t *ppos = &iocb->ki_pos;
        loff_t pos = *ppos;
+       size_t count = iov_iter_count(iter);
+
+       if (!count)
+               goto out; /* skip atime */
 
        if (iocb->ki_flags & IOCB_DIRECT) {
                struct address_space *mapping = file->f_mapping;
                struct inode *inode = mapping->host;
-               size_t count = iov_iter_count(iter);
                loff_t size;
 
-               if (!count)
-                       goto out; /* skip atime */
                size = i_size_read(inode);
                retval = filemap_write_and_wait_range(mapping, pos,
                                        pos + count - 1);
index fbfb1b8..86f9f8b 100644 (file)
@@ -2578,7 +2578,7 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
                }
                khugepaged_node_load[node]++;
                if (!PageLRU(page)) {
-                       result = SCAN_SCAN_ABORT;
+                       result = SCAN_PAGE_LRU;
                        goto out_unmap;
                }
                if (PageLocked(page)) {
index 7449392..b79abb6 100644 (file)
 void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
                unsigned long floor, unsigned long ceiling);
 
+void unmap_page_range(struct mmu_gather *tlb,
+                            struct vm_area_struct *vma,
+                            unsigned long addr, unsigned long end,
+                            struct zap_details *details);
+
 extern int __do_page_cache_readahead(struct address_space *mapping,
                struct file *filp, pgoff_t offset, unsigned long nr_to_read,
                unsigned long lookahead_size);
index 1ad20ad..38f1dd7 100644 (file)
@@ -17,7 +17,9 @@
 #define DISABLE_BRANCH_PROFILING
 
 #include <linux/export.h>
+#include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/kasan.h>
 #include <linux/kernel.h>
 #include <linux/kmemleak.h>
 #include <linux/linkage.h>
@@ -32,7 +34,6 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
-#include <linux/kasan.h>
 
 #include "kasan.h"
 #include "../slab.h"
@@ -334,6 +335,59 @@ void kasan_free_pages(struct page *page, unsigned int order)
                                KASAN_FREE_PAGE);
 }
 
+#ifdef CONFIG_SLAB
+/*
+ * Adaptive redzone policy taken from the userspace AddressSanitizer runtime.
+ * For larger allocations larger redzones are used.
+ */
+static size_t optimal_redzone(size_t object_size)
+{
+       int rz =
+               object_size <= 64        - 16   ? 16 :
+               object_size <= 128       - 32   ? 32 :
+               object_size <= 512       - 64   ? 64 :
+               object_size <= 4096      - 128  ? 128 :
+               object_size <= (1 << 14) - 256  ? 256 :
+               object_size <= (1 << 15) - 512  ? 512 :
+               object_size <= (1 << 16) - 1024 ? 1024 : 2048;
+       return rz;
+}
+
+void kasan_cache_create(struct kmem_cache *cache, size_t *size,
+                       unsigned long *flags)
+{
+       int redzone_adjust;
+       /* Make sure the adjusted size is still less than
+        * KMALLOC_MAX_CACHE_SIZE.
+        * TODO: this check is only useful for SLAB, but not SLUB. We'll need
+        * to skip it for SLUB when it starts using kasan_cache_create().
+        */
+       if (*size > KMALLOC_MAX_CACHE_SIZE -
+           sizeof(struct kasan_alloc_meta) -
+           sizeof(struct kasan_free_meta))
+               return;
+       *flags |= SLAB_KASAN;
+       /* Add alloc meta. */
+       cache->kasan_info.alloc_meta_offset = *size;
+       *size += sizeof(struct kasan_alloc_meta);
+
+       /* Add free meta. */
+       if (cache->flags & SLAB_DESTROY_BY_RCU || cache->ctor ||
+           cache->object_size < sizeof(struct kasan_free_meta)) {
+               cache->kasan_info.free_meta_offset = *size;
+               *size += sizeof(struct kasan_free_meta);
+       }
+       redzone_adjust = optimal_redzone(cache->object_size) -
+               (*size - cache->object_size);
+       if (redzone_adjust > 0)
+               *size += redzone_adjust;
+       *size = min(KMALLOC_MAX_CACHE_SIZE,
+                   max(*size,
+                       cache->object_size +
+                       optimal_redzone(cache->object_size)));
+}
+#endif
+
 void kasan_poison_slab(struct page *page)
 {
        kasan_poison_shadow(page_address(page),
@@ -351,11 +405,81 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object)
        kasan_poison_shadow(object,
                        round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE),
                        KASAN_KMALLOC_REDZONE);
+#ifdef CONFIG_SLAB
+       if (cache->flags & SLAB_KASAN) {
+               struct kasan_alloc_meta *alloc_info =
+                       get_alloc_info(cache, object);
+               alloc_info->state = KASAN_STATE_INIT;
+       }
+#endif
 }
 
-void kasan_slab_alloc(struct kmem_cache *cache, void *object)
+#ifdef CONFIG_SLAB
+static inline int in_irqentry_text(unsigned long ptr)
 {
-       kasan_kmalloc(cache, object, cache->object_size);
+       return (ptr >= (unsigned long)&__irqentry_text_start &&
+               ptr < (unsigned long)&__irqentry_text_end) ||
+               (ptr >= (unsigned long)&__softirqentry_text_start &&
+                ptr < (unsigned long)&__softirqentry_text_end);
+}
+
+static inline void filter_irq_stacks(struct stack_trace *trace)
+{
+       int i;
+
+       if (!trace->nr_entries)
+               return;
+       for (i = 0; i < trace->nr_entries; i++)
+               if (in_irqentry_text(trace->entries[i])) {
+                       /* Include the irqentry function into the stack. */
+                       trace->nr_entries = i + 1;
+                       break;
+               }
+}
+
+static inline depot_stack_handle_t save_stack(gfp_t flags)
+{
+       unsigned long entries[KASAN_STACK_DEPTH];
+       struct stack_trace trace = {
+               .nr_entries = 0,
+               .entries = entries,
+               .max_entries = KASAN_STACK_DEPTH,
+               .skip = 0
+       };
+
+       save_stack_trace(&trace);
+       filter_irq_stacks(&trace);
+       if (trace.nr_entries != 0 &&
+           trace.entries[trace.nr_entries-1] == ULONG_MAX)
+               trace.nr_entries--;
+
+       return depot_save_stack(&trace, flags);
+}
+
+static inline void set_track(struct kasan_track *track, gfp_t flags)
+{
+       track->pid = current->pid;
+       track->stack = save_stack(flags);
+}
+
+struct kasan_alloc_meta *get_alloc_info(struct kmem_cache *cache,
+                                       const void *object)
+{
+       BUILD_BUG_ON(sizeof(struct kasan_alloc_meta) > 32);
+       return (void *)object + cache->kasan_info.alloc_meta_offset;
+}
+
+struct kasan_free_meta *get_free_info(struct kmem_cache *cache,
+                                     const void *object)
+{
+       BUILD_BUG_ON(sizeof(struct kasan_free_meta) > 32);
+       return (void *)object + cache->kasan_info.free_meta_offset;
+}
+#endif
+
+void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags)
+{
+       kasan_kmalloc(cache, object, cache->object_size, flags);
 }
 
 void kasan_slab_free(struct kmem_cache *cache, void *object)
@@ -367,10 +491,22 @@ void kasan_slab_free(struct kmem_cache *cache, void *object)
        if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU))
                return;
 
+#ifdef CONFIG_SLAB
+       if (cache->flags & SLAB_KASAN) {
+               struct kasan_free_meta *free_info =
+                       get_free_info(cache, object);
+               struct kasan_alloc_meta *alloc_info =
+                       get_alloc_info(cache, object);
+               alloc_info->state = KASAN_STATE_FREE;
+               set_track(&free_info->track, GFP_NOWAIT);
+       }
+#endif
+
        kasan_poison_shadow(object, rounded_up_size, KASAN_KMALLOC_FREE);
 }
 
-void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size)
+void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
+                  gfp_t flags)
 {
        unsigned long redzone_start;
        unsigned long redzone_end;
@@ -386,10 +522,20 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size)
        kasan_unpoison_shadow(object, size);
        kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start,
                KASAN_KMALLOC_REDZONE);
+#ifdef CONFIG_SLAB
+       if (cache->flags & SLAB_KASAN) {
+               struct kasan_alloc_meta *alloc_info =
+                       get_alloc_info(cache, object);
+
+               alloc_info->state = KASAN_STATE_ALLOC;
+               alloc_info->alloc_size = size;
+               set_track(&alloc_info->track, flags);
+       }
+#endif
 }
 EXPORT_SYMBOL(kasan_kmalloc);
 
-void kasan_kmalloc_large(const void *ptr, size_t size)
+void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags)
 {
        struct page *page;
        unsigned long redzone_start;
@@ -408,7 +554,7 @@ void kasan_kmalloc_large(const void *ptr, size_t size)
                KASAN_PAGE_REDZONE);
 }
 
-void kasan_krealloc(const void *object, size_t size)
+void kasan_krealloc(const void *object, size_t size, gfp_t flags)
 {
        struct page *page;
 
@@ -418,9 +564,9 @@ void kasan_krealloc(const void *object, size_t size)
        page = virt_to_head_page(object);
 
        if (unlikely(!PageSlab(page)))
-               kasan_kmalloc_large(object, size);
+               kasan_kmalloc_large(object, size, flags);
        else
-               kasan_kmalloc(page->slab_cache, object, size);
+               kasan_kmalloc(page->slab_cache, object, size, flags);
 }
 
 void kasan_kfree(void *ptr)
index 4f6c62e..30a2f0b 100644 (file)
@@ -2,6 +2,7 @@
 #define __MM_KASAN_KASAN_H
 
 #include <linux/kasan.h>
+#include <linux/stackdepot.h>
 
 #define KASAN_SHADOW_SCALE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT)
 #define KASAN_SHADOW_MASK       (KASAN_SHADOW_SCALE_SIZE - 1)
@@ -54,6 +55,42 @@ struct kasan_global {
 #endif
 };
 
+/**
+ * Structures to keep alloc and free tracks *
+ */
+
+enum kasan_state {
+       KASAN_STATE_INIT,
+       KASAN_STATE_ALLOC,
+       KASAN_STATE_FREE
+};
+
+#define KASAN_STACK_DEPTH 64
+
+struct kasan_track {
+       u32 pid;
+       depot_stack_handle_t stack;
+};
+
+struct kasan_alloc_meta {
+       struct kasan_track track;
+       u32 state : 2;  /* enum kasan_state */
+       u32 alloc_size : 30;
+       u32 reserved;
+};
+
+struct kasan_free_meta {
+       /* Allocator freelist pointer, unused by KASAN. */
+       void **freelist;
+       struct kasan_track track;
+};
+
+struct kasan_alloc_meta *get_alloc_info(struct kmem_cache *cache,
+                                       const void *object);
+struct kasan_free_meta *get_free_info(struct kmem_cache *cache,
+                                       const void *object);
+
+
 static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
 {
        return (void *)(((unsigned long)shadow_addr - KASAN_SHADOW_OFFSET)
index 745aa8f..60869a5 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/printk.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/stackdepot.h>
 #include <linux/stacktrace.h>
 #include <linux/string.h>
 #include <linux/types.h>
@@ -115,6 +116,53 @@ static inline bool init_task_stack_addr(const void *addr)
                        sizeof(init_thread_union.stack));
 }
 
+#ifdef CONFIG_SLAB
+static void print_track(struct kasan_track *track)
+{
+       pr_err("PID = %u\n", track->pid);
+       if (track->stack) {
+               struct stack_trace trace;
+
+               depot_fetch_stack(track->stack, &trace);
+               print_stack_trace(&trace, 0);
+       } else {
+               pr_err("(stack is not available)\n");
+       }
+}
+
+static void object_err(struct kmem_cache *cache, struct page *page,
+                       void *object, char *unused_reason)
+{
+       struct kasan_alloc_meta *alloc_info = get_alloc_info(cache, object);
+       struct kasan_free_meta *free_info;
+
+       dump_stack();
+       pr_err("Object at %p, in cache %s\n", object, cache->name);
+       if (!(cache->flags & SLAB_KASAN))
+               return;
+       switch (alloc_info->state) {
+       case KASAN_STATE_INIT:
+               pr_err("Object not allocated yet\n");
+               break;
+       case KASAN_STATE_ALLOC:
+               pr_err("Object allocated with size %u bytes.\n",
+                      alloc_info->alloc_size);
+               pr_err("Allocation:\n");
+               print_track(&alloc_info->track);
+               break;
+       case KASAN_STATE_FREE:
+               pr_err("Object freed, allocated with size %u bytes\n",
+                      alloc_info->alloc_size);
+               free_info = get_free_info(cache, object);
+               pr_err("Allocation:\n");
+               print_track(&alloc_info->track);
+               pr_err("Deallocation:\n");
+               print_track(&free_info->track);
+               break;
+       }
+}
+#endif
+
 static void print_address_description(struct kasan_access_info *info)
 {
        const void *addr = info->access_addr;
@@ -126,17 +174,10 @@ static void print_address_description(struct kasan_access_info *info)
                if (PageSlab(page)) {
                        void *object;
                        struct kmem_cache *cache = page->slab_cache;
-                       void *last_object;
-
-                       object = virt_to_obj(cache, page_address(page), addr);
-                       last_object = page_address(page) +
-                               page->objects * cache->size;
-
-                       if (unlikely(object > last_object))
-                               object = last_object; /* we hit into padding */
-
+                       object = nearest_obj(cache, page,
+                                               (void *)info->access_addr);
                        object_err(cache, page, object,
-                               "kasan: bad access detected");
+                                       "kasan: bad access detected");
                        return;
                }
                dump_page(page, "kasan: bad access detected");
@@ -146,7 +187,6 @@ static void print_address_description(struct kasan_access_info *info)
                if (!init_task_stack_addr(addr))
                        pr_err("Address belongs to variable %pS\n", addr);
        }
-
        dump_stack();
 }
 
index 81dca00..098f00d 100644 (file)
@@ -1102,6 +1102,12 @@ again:
 
                        if (!PageAnon(page)) {
                                if (pte_dirty(ptent)) {
+                                       /*
+                                        * oom_reaper cannot tear down dirty
+                                        * pages
+                                        */
+                                       if (unlikely(details && details->ignore_dirty))
+                                               continue;
                                        force_flush = 1;
                                        set_page_dirty(page);
                                }
@@ -1120,8 +1126,8 @@ again:
                        }
                        continue;
                }
-               /* If details->check_mapping, we leave swap entries. */
-               if (unlikely(details))
+               /* only check swap_entries if explicitly asked for in details */
+               if (unlikely(details && !details->check_swap_entries))
                        continue;
 
                entry = pte_to_swp_entry(ptent);
@@ -1226,7 +1232,7 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
        return addr;
 }
 
-static void unmap_page_range(struct mmu_gather *tlb,
+void unmap_page_range(struct mmu_gather *tlb,
                             struct vm_area_struct *vma,
                             unsigned long addr, unsigned long end,
                             struct zap_details *details)
@@ -1234,9 +1240,6 @@ static void unmap_page_range(struct mmu_gather *tlb,
        pgd_t *pgd;
        unsigned long next;
 
-       if (details && !details->check_mapping)
-               details = NULL;
-
        BUG_ON(addr >= end);
        tlb_start_vma(tlb, vma);
        pgd = pgd_offset(vma->vm_mm, addr);
@@ -2432,7 +2435,7 @@ static inline void unmap_mapping_range_tree(struct rb_root *root,
 void unmap_mapping_range(struct address_space *mapping,
                loff_t const holebegin, loff_t const holelen, int even_cows)
 {
-       struct zap_details details;
+       struct zap_details details = { };
        pgoff_t hba = holebegin >> PAGE_SHIFT;
        pgoff_t hlen = (holelen + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
index 07c383d..9b7a14a 100644 (file)
@@ -112,12 +112,12 @@ static void kasan_poison_element(mempool_t *pool, void *element)
                kasan_free_pages(element, (unsigned long)pool->pool_data);
 }
 
-static void kasan_unpoison_element(mempool_t *pool, void *element)
+static void kasan_unpoison_element(mempool_t *pool, void *element, gfp_t flags)
 {
        if (pool->alloc == mempool_alloc_slab)
-               kasan_slab_alloc(pool->pool_data, element);
+               kasan_slab_alloc(pool->pool_data, element, flags);
        if (pool->alloc == mempool_kmalloc)
-               kasan_krealloc(element, (size_t)pool->pool_data);
+               kasan_krealloc(element, (size_t)pool->pool_data, flags);
        if (pool->alloc == mempool_alloc_pages)
                kasan_alloc_pages(element, (unsigned long)pool->pool_data);
 }
@@ -130,12 +130,12 @@ static void add_element(mempool_t *pool, void *element)
        pool->elements[pool->curr_nr++] = element;
 }
 
-static void *remove_element(mempool_t *pool)
+static void *remove_element(mempool_t *pool, gfp_t flags)
 {
        void *element = pool->elements[--pool->curr_nr];
 
        BUG_ON(pool->curr_nr < 0);
-       kasan_unpoison_element(pool, element);
+       kasan_unpoison_element(pool, element, flags);
        check_element(pool, element);
        return element;
 }
@@ -154,7 +154,7 @@ void mempool_destroy(mempool_t *pool)
                return;
 
        while (pool->curr_nr) {
-               void *element = remove_element(pool);
+               void *element = remove_element(pool, GFP_KERNEL);
                pool->free(element, pool->pool_data);
        }
        kfree(pool->elements);
@@ -250,7 +250,7 @@ int mempool_resize(mempool_t *pool, int new_min_nr)
        spin_lock_irqsave(&pool->lock, flags);
        if (new_min_nr <= pool->min_nr) {
                while (new_min_nr < pool->curr_nr) {
-                       element = remove_element(pool);
+                       element = remove_element(pool, GFP_KERNEL);
                        spin_unlock_irqrestore(&pool->lock, flags);
                        pool->free(element, pool->pool_data);
                        spin_lock_irqsave(&pool->lock, flags);
@@ -347,7 +347,7 @@ repeat_alloc:
 
        spin_lock_irqsave(&pool->lock, flags);
        if (likely(pool->curr_nr)) {
-               element = remove_element(pool);
+               element = remove_element(pool, gfp_temp);
                spin_unlock_irqrestore(&pool->lock, flags);
                /* paired with rmb in mempool_free(), read comment there */
                smp_wmb();
index 06f7e17..8634958 100644 (file)
 #include <linux/freezer.h>
 #include <linux/ftrace.h>
 #include <linux/ratelimit.h>
+#include <linux/kthread.h>
+#include <linux/init.h>
+
+#include <asm/tlb.h>
+#include "internal.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/oom.h>
@@ -405,6 +410,176 @@ static DECLARE_WAIT_QUEUE_HEAD(oom_victims_wait);
 
 bool oom_killer_disabled __read_mostly;
 
+#define K(x) ((x) << (PAGE_SHIFT-10))
+
+#ifdef CONFIG_MMU
+/*
+ * OOM Reaper kernel thread which tries to reap the memory used by the OOM
+ * victim (if that is possible) to help the OOM killer to move on.
+ */
+static struct task_struct *oom_reaper_th;
+static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait);
+static struct task_struct *oom_reaper_list;
+static DEFINE_SPINLOCK(oom_reaper_lock);
+
+
+static bool __oom_reap_task(struct task_struct *tsk)
+{
+       struct mmu_gather tlb;
+       struct vm_area_struct *vma;
+       struct mm_struct *mm;
+       struct task_struct *p;
+       struct zap_details details = {.check_swap_entries = true,
+                                     .ignore_dirty = true};
+       bool ret = true;
+
+       /*
+        * Make sure we find the associated mm_struct even when the particular
+        * thread has already terminated and cleared its mm.
+        * We might have race with exit path so consider our work done if there
+        * is no mm.
+        */
+       p = find_lock_task_mm(tsk);
+       if (!p)
+               return true;
+
+       mm = p->mm;
+       if (!atomic_inc_not_zero(&mm->mm_users)) {
+               task_unlock(p);
+               return true;
+       }
+
+       task_unlock(p);
+
+       if (!down_read_trylock(&mm->mmap_sem)) {
+               ret = false;
+               goto out;
+       }
+
+       tlb_gather_mmu(&tlb, mm, 0, -1);
+       for (vma = mm->mmap ; vma; vma = vma->vm_next) {
+               if (is_vm_hugetlb_page(vma))
+                       continue;
+
+               /*
+                * mlocked VMAs require explicit munlocking before unmap.
+                * Let's keep it simple here and skip such VMAs.
+                */
+               if (vma->vm_flags & VM_LOCKED)
+                       continue;
+
+               /*
+                * Only anonymous pages have a good chance to be dropped
+                * without additional steps which we cannot afford as we
+                * are OOM already.
+                *
+                * We do not even care about fs backed pages because all
+                * which are reclaimable have already been reclaimed and
+                * we do not want to block exit_mmap by keeping mm ref
+                * count elevated without a good reason.
+                */
+               if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED))
+                       unmap_page_range(&tlb, vma, vma->vm_start, vma->vm_end,
+                                        &details);
+       }
+       tlb_finish_mmu(&tlb, 0, -1);
+       pr_info("oom_reaper: reaped process %d (%s), now anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
+                       task_pid_nr(tsk), tsk->comm,
+                       K(get_mm_counter(mm, MM_ANONPAGES)),
+                       K(get_mm_counter(mm, MM_FILEPAGES)),
+                       K(get_mm_counter(mm, MM_SHMEMPAGES)));
+       up_read(&mm->mmap_sem);
+
+       /*
+        * Clear TIF_MEMDIE because the task shouldn't be sitting on a
+        * reasonably reclaimable memory anymore. OOM killer can continue
+        * by selecting other victim if unmapping hasn't led to any
+        * improvements. This also means that selecting this task doesn't
+        * make any sense.
+        */
+       tsk->signal->oom_score_adj = OOM_SCORE_ADJ_MIN;
+       exit_oom_victim(tsk);
+out:
+       mmput(mm);
+       return ret;
+}
+
+#define MAX_OOM_REAP_RETRIES 10
+static void oom_reap_task(struct task_struct *tsk)
+{
+       int attempts = 0;
+
+       /* Retry the down_read_trylock(mmap_sem) a few times */
+       while (attempts++ < MAX_OOM_REAP_RETRIES && !__oom_reap_task(tsk))
+               schedule_timeout_idle(HZ/10);
+
+       if (attempts > MAX_OOM_REAP_RETRIES) {
+               pr_info("oom_reaper: unable to reap pid:%d (%s)\n",
+                               task_pid_nr(tsk), tsk->comm);
+               debug_show_all_locks();
+       }
+
+       /* Drop a reference taken by wake_oom_reaper */
+       put_task_struct(tsk);
+}
+
+static int oom_reaper(void *unused)
+{
+       set_freezable();
+
+       while (true) {
+               struct task_struct *tsk = NULL;
+
+               wait_event_freezable(oom_reaper_wait, oom_reaper_list != NULL);
+               spin_lock(&oom_reaper_lock);
+               if (oom_reaper_list != NULL) {
+                       tsk = oom_reaper_list;
+                       oom_reaper_list = tsk->oom_reaper_list;
+               }
+               spin_unlock(&oom_reaper_lock);
+
+               if (tsk)
+                       oom_reap_task(tsk);
+       }
+
+       return 0;
+}
+
+static void wake_oom_reaper(struct task_struct *tsk)
+{
+       if (!oom_reaper_th)
+               return;
+
+       /* tsk is already queued? */
+       if (tsk == oom_reaper_list || tsk->oom_reaper_list)
+               return;
+
+       get_task_struct(tsk);
+
+       spin_lock(&oom_reaper_lock);
+       tsk->oom_reaper_list = oom_reaper_list;
+       oom_reaper_list = tsk;
+       spin_unlock(&oom_reaper_lock);
+       wake_up(&oom_reaper_wait);
+}
+
+static int __init oom_init(void)
+{
+       oom_reaper_th = kthread_run(oom_reaper, NULL, "oom_reaper");
+       if (IS_ERR(oom_reaper_th)) {
+               pr_err("Unable to start OOM reaper %ld. Continuing regardless\n",
+                               PTR_ERR(oom_reaper_th));
+               oom_reaper_th = NULL;
+       }
+       return 0;
+}
+subsys_initcall(oom_init)
+#else
+static void wake_oom_reaper(struct task_struct *tsk)
+{
+}
+#endif
+
 /**
  * mark_oom_victim - mark the given task as OOM victim
  * @tsk: task to mark
@@ -431,9 +606,10 @@ void mark_oom_victim(struct task_struct *tsk)
 /**
  * exit_oom_victim - note the exit of an OOM victim
  */
-void exit_oom_victim(void)
+void exit_oom_victim(struct task_struct *tsk)
 {
-       clear_thread_flag(TIF_MEMDIE);
+       if (!test_and_clear_tsk_thread_flag(tsk, TIF_MEMDIE))
+               return;
 
        if (!atomic_dec_return(&oom_victims))
                wake_up_all(&oom_victims_wait);
@@ -494,7 +670,6 @@ static bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
        return false;
 }
 
-#define K(x) ((x) << (PAGE_SHIFT-10))
 /*
  * Must be called while holding a reference to p, which will be released upon
  * returning.
@@ -510,6 +685,7 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
        unsigned int victim_points = 0;
        static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
                                              DEFAULT_RATELIMIT_BURST);
+       bool can_oom_reap = true;
 
        /*
         * If the task is already exiting, don't alarm the sysadmin or kill
@@ -600,17 +776,23 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
                        continue;
                if (same_thread_group(p, victim))
                        continue;
-               if (unlikely(p->flags & PF_KTHREAD))
-                       continue;
-               if (is_global_init(p))
-                       continue;
-               if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+               if (unlikely(p->flags & PF_KTHREAD) || is_global_init(p) ||
+                   p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+                       /*
+                        * We cannot use oom_reaper for the mm shared by this
+                        * process because it wouldn't get killed and so the
+                        * memory might be still used.
+                        */
+                       can_oom_reap = false;
                        continue;
-
+               }
                do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);
        }
        rcu_read_unlock();
 
+       if (can_oom_reap)
+               wake_oom_reaper(victim);
+
        mmdrop(mm);
        put_task_struct(victim);
 }
index a762be5..59de90d 100644 (file)
@@ -692,34 +692,28 @@ static inline void __free_one_page(struct page *page,
        unsigned long combined_idx;
        unsigned long uninitialized_var(buddy_idx);
        struct page *buddy;
-       unsigned int max_order = MAX_ORDER;
+       unsigned int max_order;
+
+       max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
 
        VM_BUG_ON(!zone_is_initialized(zone));
        VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page);
 
        VM_BUG_ON(migratetype == -1);
-       if (is_migrate_isolate(migratetype)) {
-               /*
-                * We restrict max order of merging to prevent merge
-                * between freepages on isolate pageblock and normal
-                * pageblock. Without this, pageblock isolation
-                * could cause incorrect freepage accounting.
-                */
-               max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
-       } else {
+       if (likely(!is_migrate_isolate(migratetype)))
                __mod_zone_freepage_state(zone, 1 << order, migratetype);
-       }
 
-       page_idx = pfn & ((1 << max_order) - 1);
+       page_idx = pfn & ((1 << MAX_ORDER) - 1);
 
        VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page);
        VM_BUG_ON_PAGE(bad_range(zone, page), page);
 
+continue_merging:
        while (order < max_order - 1) {
                buddy_idx = __find_buddy_index(page_idx, order);
                buddy = page + (buddy_idx - page_idx);
                if (!page_is_buddy(page, buddy, order))
-                       break;
+                       goto done_merging;
                /*
                 * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
                 * merge with it and move up one order.
@@ -736,6 +730,32 @@ static inline void __free_one_page(struct page *page,
                page_idx = combined_idx;
                order++;
        }
+       if (max_order < MAX_ORDER) {
+               /* If we are here, it means order is >= pageblock_order.
+                * We want to prevent merge between freepages on isolate
+                * pageblock and normal pageblock. Without this, pageblock
+                * isolation could cause incorrect freepage or CMA accounting.
+                *
+                * We don't want to hit this code for the more frequent
+                * low-order merging.
+                */
+               if (unlikely(has_isolate_pageblock(zone))) {
+                       int buddy_mt;
+
+                       buddy_idx = __find_buddy_index(page_idx, order);
+                       buddy = page + (buddy_idx - page_idx);
+                       buddy_mt = get_pageblock_migratetype(buddy);
+
+                       if (migratetype != buddy_mt
+                                       && (is_migrate_isolate(migratetype) ||
+                                               is_migrate_isolate(buddy_mt)))
+                               goto done_merging;
+               }
+               max_order++;
+               goto continue_merging;
+       }
+
+done_merging:
        set_page_order(page, order);
 
        /*
index 92c4c36..c4f5682 100644 (file)
@@ -215,7 +215,7 @@ int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
  * all pages in [start_pfn...end_pfn) must be in the same zone.
  * zone->lock must be held before call this.
  *
- * Returns 1 if all pages in the range are isolated.
+ * Returns the last tested pfn.
  */
 static unsigned long
 __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
@@ -289,11 +289,11 @@ struct page *alloc_migrate_target(struct page *page, unsigned long private,
         * now as a simple work-around, we use the next node for destination.
         */
        if (PageHuge(page)) {
-               nodemask_t src = nodemask_of_node(page_to_nid(page));
-               nodemask_t dst;
-               nodes_complement(dst, src);
+               int node = next_online_node(page_to_nid(page));
+               if (node == MAX_NUMNODES)
+                       node = first_online_node;
                return alloc_huge_page_node(page_hstate(compound_head(page)),
-                                           next_node(page_to_nid(page), dst));
+                                           node);
        }
 
        if (PageHighMem(page))
index c399a0d..395e314 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -569,19 +569,6 @@ void page_unlock_anon_vma_read(struct anon_vma *anon_vma)
 }
 
 #ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
-static void percpu_flush_tlb_batch_pages(void *data)
-{
-       /*
-        * All TLB entries are flushed on the assumption that it is
-        * cheaper to flush all TLBs and let them be refilled than
-        * flushing individual PFNs. Note that we do not track mm's
-        * to flush as that might simply be multiple full TLB flushes
-        * for no gain.
-        */
-       count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
-       flush_tlb_local();
-}
-
 /*
  * Flush TLB entries for recently unmapped pages from remote CPUs. It is
  * important if a PTE was dirty when it was unmapped that it's flushed
@@ -598,15 +585,14 @@ void try_to_unmap_flush(void)
 
        cpu = get_cpu();
 
-       trace_tlb_flush(TLB_REMOTE_SHOOTDOWN, -1UL);
-
-       if (cpumask_test_cpu(cpu, &tlb_ubc->cpumask))
-               percpu_flush_tlb_batch_pages(&tlb_ubc->cpumask);
-
-       if (cpumask_any_but(&tlb_ubc->cpumask, cpu) < nr_cpu_ids) {
-               smp_call_function_many(&tlb_ubc->cpumask,
-                       percpu_flush_tlb_batch_pages, (void *)tlb_ubc, true);
+       if (cpumask_test_cpu(cpu, &tlb_ubc->cpumask)) {
+               count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
+               local_flush_tlb();
+               trace_tlb_flush(TLB_LOCAL_SHOOTDOWN, TLB_FLUSH_ALL);
        }
+
+       if (cpumask_any_but(&tlb_ubc->cpumask, cpu) < nr_cpu_ids)
+               flush_tlb_others(&tlb_ubc->cpumask, NULL, 0, TLB_FLUSH_ALL);
        cpumask_clear(&tlb_ubc->cpumask);
        tlb_ubc->flush_required = false;
        tlb_ubc->writable = false;
index e719a5c..17e2848 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2086,6 +2086,8 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
        }
 #endif
 
+       kasan_cache_create(cachep, &size, &flags);
+
        size = ALIGN(size, cachep->align);
        /*
         * We should restrict the number of objects in a slab to implement
@@ -2387,8 +2389,13 @@ static void cache_init_objs_debug(struct kmem_cache *cachep, struct page *page)
                 * cache which they are a constructor for.  Otherwise, deadlock.
                 * They must also be threaded.
                 */
-               if (cachep->ctor && !(cachep->flags & SLAB_POISON))
+               if (cachep->ctor && !(cachep->flags & SLAB_POISON)) {
+                       kasan_unpoison_object_data(cachep,
+                                                  objp + obj_offset(cachep));
                        cachep->ctor(objp + obj_offset(cachep));
+                       kasan_poison_object_data(
+                               cachep, objp + obj_offset(cachep));
+               }
 
                if (cachep->flags & SLAB_RED_ZONE) {
                        if (*dbg_redzone2(cachep, objp) != RED_INACTIVE)
@@ -2409,6 +2416,7 @@ static void cache_init_objs(struct kmem_cache *cachep,
                            struct page *page)
 {
        int i;
+       void *objp;
 
        cache_init_objs_debug(cachep, page);
 
@@ -2419,8 +2427,12 @@ static void cache_init_objs(struct kmem_cache *cachep,
 
        for (i = 0; i < cachep->num; i++) {
                /* constructor could break poison info */
-               if (DEBUG == 0 && cachep->ctor)
-                       cachep->ctor(index_to_obj(cachep, page, i));
+               if (DEBUG == 0 && cachep->ctor) {
+                       objp = index_to_obj(cachep, page, i);
+                       kasan_unpoison_object_data(cachep, objp);
+                       cachep->ctor(objp);
+                       kasan_poison_object_data(cachep, objp);
+               }
 
                set_free_obj(page, i, i);
        }
@@ -2550,6 +2562,7 @@ static int cache_grow(struct kmem_cache *cachep,
 
        slab_map_pages(cachep, page, freelist);
 
+       kasan_poison_slab(page);
        cache_init_objs(cachep, page);
 
        if (gfpflags_allow_blocking(local_flags))
@@ -3316,6 +3329,8 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp,
 {
        struct array_cache *ac = cpu_cache_get(cachep);
 
+       kasan_slab_free(cachep, objp);
+
        check_irq_off();
        kmemleak_free_recursive(objp, cachep->flags);
        objp = cache_free_debugcheck(cachep, objp, caller);
@@ -3363,6 +3378,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
 {
        void *ret = slab_alloc(cachep, flags, _RET_IP_);
 
+       kasan_slab_alloc(cachep, ret, flags);
        trace_kmem_cache_alloc(_RET_IP_, ret,
                               cachep->object_size, cachep->size, flags);
 
@@ -3428,6 +3444,7 @@ kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size)
 
        ret = slab_alloc(cachep, flags, _RET_IP_);
 
+       kasan_kmalloc(cachep, ret, size, flags);
        trace_kmalloc(_RET_IP_, ret,
                      size, cachep->size, flags);
        return ret;
@@ -3451,6 +3468,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
 {
        void *ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_);
 
+       kasan_slab_alloc(cachep, ret, flags);
        trace_kmem_cache_alloc_node(_RET_IP_, ret,
                                    cachep->object_size, cachep->size,
                                    flags, nodeid);
@@ -3469,6 +3487,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep,
 
        ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_);
 
+       kasan_kmalloc(cachep, ret, size, flags);
        trace_kmalloc_node(_RET_IP_, ret,
                           size, cachep->size,
                           flags, nodeid);
@@ -3481,11 +3500,15 @@ static __always_inline void *
 __do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller)
 {
        struct kmem_cache *cachep;
+       void *ret;
 
        cachep = kmalloc_slab(size, flags);
        if (unlikely(ZERO_OR_NULL_PTR(cachep)))
                return cachep;
-       return kmem_cache_alloc_node_trace(cachep, flags, node, size);
+       ret = kmem_cache_alloc_node_trace(cachep, flags, node, size);
+       kasan_kmalloc(cachep, ret, size, flags);
+
+       return ret;
 }
 
 void *__kmalloc_node(size_t size, gfp_t flags, int node)
@@ -3519,6 +3542,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
                return cachep;
        ret = slab_alloc(cachep, flags, caller);
 
+       kasan_kmalloc(cachep, ret, size, flags);
        trace_kmalloc(caller, ret,
                      size, cachep->size, flags);
 
@@ -4290,10 +4314,18 @@ module_init(slab_proc_init);
  */
 size_t ksize(const void *objp)
 {
+       size_t size;
+
        BUG_ON(!objp);
        if (unlikely(objp == ZERO_SIZE_PTR))
                return 0;
 
-       return virt_to_cache(objp)->object_size;
+       size = virt_to_cache(objp)->object_size;
+       /* We assume that ksize callers could use the whole allocated area,
+        * so we need to unpoison this area.
+        */
+       kasan_krealloc(objp, size, GFP_NOWAIT);
+
+       return size;
 }
 EXPORT_SYMBOL(ksize);
index ff39a8f..5969769 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -405,7 +405,7 @@ static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
                kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
                kmemleak_alloc_recursive(object, s->object_size, 1,
                                         s->flags, flags);
-               kasan_slab_alloc(s, object);
+               kasan_slab_alloc(s, object, flags);
        }
        memcg_kmem_put_cache(s);
 }
index b2e3796..3239bfd 100644 (file)
@@ -35,7 +35,7 @@ struct kmem_cache *kmem_cache;
  */
 #define SLAB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
                SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \
-               SLAB_FAILSLAB)
+               SLAB_FAILSLAB | SLAB_KASAN)
 
 #define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | \
                         SLAB_NOTRACK | SLAB_ACCOUNT)
@@ -1013,7 +1013,7 @@ void *kmalloc_order(size_t size, gfp_t flags, unsigned int order)
        page = alloc_kmem_pages(flags, order);
        ret = page ? page_address(page) : NULL;
        kmemleak_alloc(ret, size, 1, flags);
-       kasan_kmalloc_large(ret, size);
+       kasan_kmalloc_large(ret, size, flags);
        return ret;
 }
 EXPORT_SYMBOL(kmalloc_order);
@@ -1192,7 +1192,7 @@ static __always_inline void *__do_krealloc(const void *p, size_t new_size,
                ks = ksize(p);
 
        if (ks >= new_size) {
-               kasan_krealloc((void *)p, new_size);
+               kasan_krealloc((void *)p, new_size, flags);
                return (void *)p;
        }
 
index 7277413..4dbb109 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1313,7 +1313,7 @@ static inline void dec_slabs_node(struct kmem_cache *s, int node,
 static inline void kmalloc_large_node_hook(void *ptr, size_t size, gfp_t flags)
 {
        kmemleak_alloc(ptr, size, 1, flags);
-       kasan_kmalloc_large(ptr, size);
+       kasan_kmalloc_large(ptr, size, flags);
 }
 
 static inline void kfree_hook(const void *x)
@@ -2596,7 +2596,7 @@ void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
 {
        void *ret = slab_alloc(s, gfpflags, _RET_IP_);
        trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags);
-       kasan_kmalloc(s, ret, size);
+       kasan_kmalloc(s, ret, size, gfpflags);
        return ret;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_trace);
@@ -2624,7 +2624,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
        trace_kmalloc_node(_RET_IP_, ret,
                           size, s->size, gfpflags, node);
 
-       kasan_kmalloc(s, ret, size);
+       kasan_kmalloc(s, ret, size, gfpflags);
        return ret;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
@@ -3182,7 +3182,8 @@ static void early_kmem_cache_node_alloc(int node)
        init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
        init_tracking(kmem_cache_node, n);
 #endif
-       kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node));
+       kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node),
+                     GFP_KERNEL);
        init_kmem_cache_node(n);
        inc_slabs_node(kmem_cache_node, node, page->objects);
 
@@ -3561,7 +3562,7 @@ void *__kmalloc(size_t size, gfp_t flags)
 
        trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
 
-       kasan_kmalloc(s, ret, size);
+       kasan_kmalloc(s, ret, size, flags);
 
        return ret;
 }
@@ -3606,7 +3607,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
 
        trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node);
 
-       kasan_kmalloc(s, ret, size);
+       kasan_kmalloc(s, ret, size, flags);
 
        return ret;
 }
@@ -3635,7 +3636,7 @@ size_t ksize(const void *object)
        size_t size = __ksize(object);
        /* We assume that ksize callers could use whole allocated area,
           so we need unpoison this area. */
-       kasan_krealloc(object, size);
+       kasan_krealloc(object, size, GFP_NOWAIT);
        return size;
 }
 EXPORT_SYMBOL(ksize);
index bcbec33..dcc18c6 100644 (file)
@@ -361,7 +361,6 @@ ceph_parse_options(char *options, const char *dev_name,
        opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
        opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT;
        opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;
-       opt->monc_ping_timeout = CEPH_MONC_PING_TIMEOUT_DEFAULT;
 
        /* get mon ip(s) */
        /* ip1[:port1][,ip2[:port2]...] */
@@ -686,6 +685,9 @@ int __ceph_open_session(struct ceph_client *client, unsigned long started)
                        return client->auth_err;
        }
 
+       pr_info("client%llu fsid %pU\n", ceph_client_id(client), &client->fsid);
+       ceph_debugfs_client_init(client);
+
        return 0;
 }
 EXPORT_SYMBOL(__ceph_open_session);
index 593dc2e..b902fbc 100644 (file)
@@ -112,15 +112,20 @@ static int monc_show(struct seq_file *s, void *p)
        struct ceph_mon_generic_request *req;
        struct ceph_mon_client *monc = &client->monc;
        struct rb_node *rp;
+       int i;
 
        mutex_lock(&monc->mutex);
 
-       if (monc->have_mdsmap)
-               seq_printf(s, "have mdsmap %u\n", (unsigned int)monc->have_mdsmap);
-       if (monc->have_osdmap)
-               seq_printf(s, "have osdmap %u\n", (unsigned int)monc->have_osdmap);
-       if (monc->want_next_osdmap)
-               seq_printf(s, "want next osdmap\n");
+       for (i = 0; i < ARRAY_SIZE(monc->subs); i++) {
+               seq_printf(s, "have %s %u", ceph_sub_str[i],
+                          monc->subs[i].have);
+               if (monc->subs[i].want)
+                       seq_printf(s, " want %llu%s",
+                                  le64_to_cpu(monc->subs[i].item.start),
+                                  (monc->subs[i].item.flags &
+                                       CEPH_SUBSCRIBE_ONETIME ?  "" : "+"));
+               seq_putc(s, '\n');
+       }
 
        for (rp = rb_first(&monc->generic_request_tree); rp; rp = rb_next(rp)) {
                __u16 op;
index 9382619..1831f63 100644 (file)
@@ -235,18 +235,12 @@ static struct workqueue_struct *ceph_msgr_wq;
 static int ceph_msgr_slab_init(void)
 {
        BUG_ON(ceph_msg_cache);
-       ceph_msg_cache = kmem_cache_create("ceph_msg",
-                                       sizeof (struct ceph_msg),
-                                       __alignof__(struct ceph_msg), 0, NULL);
-
+       ceph_msg_cache = KMEM_CACHE(ceph_msg, 0);
        if (!ceph_msg_cache)
                return -ENOMEM;
 
        BUG_ON(ceph_msg_data_cache);
-       ceph_msg_data_cache = kmem_cache_create("ceph_msg_data",
-                                       sizeof (struct ceph_msg_data),
-                                       __alignof__(struct ceph_msg_data),
-                                       0, NULL);
+       ceph_msg_data_cache = KMEM_CACHE(ceph_msg_data, 0);
        if (ceph_msg_data_cache)
                return 0;
 
@@ -1221,25 +1215,19 @@ static void prepare_message_data(struct ceph_msg *msg, u32 data_len)
 static void prepare_write_message_footer(struct ceph_connection *con)
 {
        struct ceph_msg *m = con->out_msg;
-       int v = con->out_kvec_left;
 
        m->footer.flags |= CEPH_MSG_FOOTER_COMPLETE;
 
        dout("prepare_write_message_footer %p\n", con);
-       con->out_kvec[v].iov_base = &m->footer;
+       con_out_kvec_add(con, sizeof_footer(con), &m->footer);
        if (con->peer_features & CEPH_FEATURE_MSG_AUTH) {
                if (con->ops->sign_message)
                        con->ops->sign_message(m);
                else
                        m->footer.sig = 0;
-               con->out_kvec[v].iov_len = sizeof(m->footer);
-               con->out_kvec_bytes += sizeof(m->footer);
        } else {
                m->old_footer.flags = m->footer.flags;
-               con->out_kvec[v].iov_len = sizeof(m->old_footer);
-               con->out_kvec_bytes += sizeof(m->old_footer);
        }
-       con->out_kvec_left++;
        con->out_more = m->more_to_follow;
        con->out_msg_done = true;
 }
@@ -2409,11 +2397,7 @@ static int read_partial_message(struct ceph_connection *con)
        }
 
        /* footer */
-       if (need_sign)
-               size = sizeof(m->footer);
-       else
-               size = sizeof(m->old_footer);
-
+       size = sizeof_footer(con);
        end += size;
        ret = read_partial(con, end, size, &m->footer);
        if (ret <= 0)
@@ -3089,10 +3073,7 @@ void ceph_msg_revoke(struct ceph_msg *msg)
                        con->out_skip += con_out_kvec_skip(con);
                } else {
                        BUG_ON(!msg->data_length);
-                       if (con->peer_features & CEPH_FEATURE_MSG_AUTH)
-                               con->out_skip += sizeof(msg->footer);
-                       else
-                               con->out_skip += sizeof(msg->old_footer);
+                       con->out_skip += sizeof_footer(con);
                }
                /* data, middle, front */
                if (msg->data_length)
index de85ddd..cf638c0 100644 (file)
@@ -122,51 +122,91 @@ static void __close_session(struct ceph_mon_client *monc)
        ceph_msg_revoke(monc->m_subscribe);
        ceph_msg_revoke_incoming(monc->m_subscribe_ack);
        ceph_con_close(&monc->con);
-       monc->cur_mon = -1;
+
        monc->pending_auth = 0;
        ceph_auth_reset(monc->auth);
 }
 
 /*
- * Open a session with a (new) monitor.
+ * Pick a new monitor at random and set cur_mon.  If we are repicking
+ * (i.e. cur_mon is already set), be sure to pick a different one.
  */
-static int __open_session(struct ceph_mon_client *monc)
+static void pick_new_mon(struct ceph_mon_client *monc)
 {
-       char r;
-       int ret;
+       int old_mon = monc->cur_mon;
 
-       if (monc->cur_mon < 0) {
-               get_random_bytes(&r, 1);
-               monc->cur_mon = r % monc->monmap->num_mon;
-               dout("open_session num=%d r=%d -> mon%d\n",
-                    monc->monmap->num_mon, r, monc->cur_mon);
-               monc->sub_sent = 0;
-               monc->sub_renew_after = jiffies;  /* i.e., expired */
-               monc->want_next_osdmap = !!monc->want_next_osdmap;
-
-               dout("open_session mon%d opening\n", monc->cur_mon);
-               ceph_con_open(&monc->con,
-                             CEPH_ENTITY_TYPE_MON, monc->cur_mon,
-                             &monc->monmap->mon_inst[monc->cur_mon].addr);
-
-               /* send an initial keepalive to ensure our timestamp is
-                * valid by the time we are in an OPENED state */
-               ceph_con_keepalive(&monc->con);
-
-               /* initiatiate authentication handshake */
-               ret = ceph_auth_build_hello(monc->auth,
-                                           monc->m_auth->front.iov_base,
-                                           monc->m_auth->front_alloc_len);
-               __send_prepared_auth_request(monc, ret);
+       BUG_ON(monc->monmap->num_mon < 1);
+
+       if (monc->monmap->num_mon == 1) {
+               monc->cur_mon = 0;
        } else {
-               dout("open_session mon%d already open\n", monc->cur_mon);
+               int max = monc->monmap->num_mon;
+               int o = -1;
+               int n;
+
+               if (monc->cur_mon >= 0) {
+                       if (monc->cur_mon < monc->monmap->num_mon)
+                               o = monc->cur_mon;
+                       if (o >= 0)
+                               max--;
+               }
+
+               n = prandom_u32() % max;
+               if (o >= 0 && n >= o)
+                       n++;
+
+               monc->cur_mon = n;
        }
-       return 0;
+
+       dout("%s mon%d -> mon%d out of %d mons\n", __func__, old_mon,
+            monc->cur_mon, monc->monmap->num_mon);
+}
+
+/*
+ * Open a session with a new monitor.
+ */
+static void __open_session(struct ceph_mon_client *monc)
+{
+       int ret;
+
+       pick_new_mon(monc);
+
+       monc->hunting = true;
+       if (monc->had_a_connection) {
+               monc->hunt_mult *= CEPH_MONC_HUNT_BACKOFF;
+               if (monc->hunt_mult > CEPH_MONC_HUNT_MAX_MULT)
+                       monc->hunt_mult = CEPH_MONC_HUNT_MAX_MULT;
+       }
+
+       monc->sub_renew_after = jiffies; /* i.e., expired */
+       monc->sub_renew_sent = 0;
+
+       dout("%s opening mon%d\n", __func__, monc->cur_mon);
+       ceph_con_open(&monc->con, CEPH_ENTITY_TYPE_MON, monc->cur_mon,
+                     &monc->monmap->mon_inst[monc->cur_mon].addr);
+
+       /*
+        * send an initial keepalive to ensure our timestamp is valid
+        * by the time we are in an OPENED state
+        */
+       ceph_con_keepalive(&monc->con);
+
+       /* initiate authentication handshake */
+       ret = ceph_auth_build_hello(monc->auth,
+                                   monc->m_auth->front.iov_base,
+                                   monc->m_auth->front_alloc_len);
+       BUG_ON(ret <= 0);
+       __send_prepared_auth_request(monc, ret);
 }
 
-static bool __sub_expired(struct ceph_mon_client *monc)
+static void reopen_session(struct ceph_mon_client *monc)
 {
-       return time_after_eq(jiffies, monc->sub_renew_after);
+       if (!monc->hunting)
+               pr_info("mon%d %s session lost, hunting for new mon\n",
+                   monc->cur_mon, ceph_pr_addr(&monc->con.peer_addr.in_addr));
+
+       __close_session(monc);
+       __open_session(monc);
 }
 
 /*
@@ -174,74 +214,70 @@ static bool __sub_expired(struct ceph_mon_client *monc)
  */
 static void __schedule_delayed(struct ceph_mon_client *monc)
 {
-       struct ceph_options *opt = monc->client->options;
        unsigned long delay;
 
-       if (monc->cur_mon < 0 || __sub_expired(monc)) {
-               delay = 10 * HZ;
-       } else {
-               delay = 20 * HZ;
-               if (opt->monc_ping_timeout > 0)
-                       delay = min(delay, opt->monc_ping_timeout / 3);
-       }
+       if (monc->hunting)
+               delay = CEPH_MONC_HUNT_INTERVAL * monc->hunt_mult;
+       else
+               delay = CEPH_MONC_PING_INTERVAL;
+
        dout("__schedule_delayed after %lu\n", delay);
-       schedule_delayed_work(&monc->delayed_work,
-                             round_jiffies_relative(delay));
+       mod_delayed_work(system_wq, &monc->delayed_work,
+                        round_jiffies_relative(delay));
 }
 
+const char *ceph_sub_str[] = {
+       [CEPH_SUB_MDSMAP] = "mdsmap",
+       [CEPH_SUB_MONMAP] = "monmap",
+       [CEPH_SUB_OSDMAP] = "osdmap",
+};
+
 /*
- * Send subscribe request for mdsmap and/or osdmap.
+ * Send subscribe request for one or more maps, according to
+ * monc->subs.
  */
 static void __send_subscribe(struct ceph_mon_client *monc)
 {
-       dout("__send_subscribe sub_sent=%u exp=%u want_osd=%d\n",
-            (unsigned int)monc->sub_sent, __sub_expired(monc),
-            monc->want_next_osdmap);
-       if ((__sub_expired(monc) && !monc->sub_sent) ||
-           monc->want_next_osdmap == 1) {
-               struct ceph_msg *msg = monc->m_subscribe;
-               struct ceph_mon_subscribe_item *i;
-               void *p, *end;
-               int num;
-
-               p = msg->front.iov_base;
-               end = p + msg->front_alloc_len;
-
-               num = 1 + !!monc->want_next_osdmap + !!monc->want_mdsmap;
-               ceph_encode_32(&p, num);
-
-               if (monc->want_next_osdmap) {
-                       dout("__send_subscribe to 'osdmap' %u\n",
-                            (unsigned int)monc->have_osdmap);
-                       ceph_encode_string(&p, end, "osdmap", 6);
-                       i = p;
-                       i->have = cpu_to_le64(monc->have_osdmap);
-                       i->onetime = 1;
-                       p += sizeof(*i);
-                       monc->want_next_osdmap = 2;  /* requested */
-               }
-               if (monc->want_mdsmap) {
-                       dout("__send_subscribe to 'mdsmap' %u+\n",
-                            (unsigned int)monc->have_mdsmap);
-                       ceph_encode_string(&p, end, "mdsmap", 6);
-                       i = p;
-                       i->have = cpu_to_le64(monc->have_mdsmap);
-                       i->onetime = 0;
-                       p += sizeof(*i);
-               }
-               ceph_encode_string(&p, end, "monmap", 6);
-               i = p;
-               i->have = 0;
-               i->onetime = 0;
-               p += sizeof(*i);
-
-               msg->front.iov_len = p - msg->front.iov_base;
-               msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
-               ceph_msg_revoke(msg);
-               ceph_con_send(&monc->con, ceph_msg_get(msg));
-
-               monc->sub_sent = jiffies | 1;  /* never 0 */
+       struct ceph_msg *msg = monc->m_subscribe;
+       void *p = msg->front.iov_base;
+       void *const end = p + msg->front_alloc_len;
+       int num = 0;
+       int i;
+
+       dout("%s sent %lu\n", __func__, monc->sub_renew_sent);
+
+       BUG_ON(monc->cur_mon < 0);
+
+       if (!monc->sub_renew_sent)
+               monc->sub_renew_sent = jiffies | 1; /* never 0 */
+
+       msg->hdr.version = cpu_to_le16(2);
+
+       for (i = 0; i < ARRAY_SIZE(monc->subs); i++) {
+               if (monc->subs[i].want)
+                       num++;
        }
+       BUG_ON(num < 1); /* monmap sub is always there */
+       ceph_encode_32(&p, num);
+       for (i = 0; i < ARRAY_SIZE(monc->subs); i++) {
+               const char *s = ceph_sub_str[i];
+
+               if (!monc->subs[i].want)
+                       continue;
+
+               dout("%s %s start %llu flags 0x%x\n", __func__, s,
+                    le64_to_cpu(monc->subs[i].item.start),
+                    monc->subs[i].item.flags);
+               ceph_encode_string(&p, end, s, strlen(s));
+               memcpy(p, &monc->subs[i].item, sizeof(monc->subs[i].item));
+               p += sizeof(monc->subs[i].item);
+       }
+
+       BUG_ON(p != (end - 35 - (ARRAY_SIZE(monc->subs) - num) * 19));
+       msg->front.iov_len = p - msg->front.iov_base;
+       msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
+       ceph_msg_revoke(msg);
+       ceph_con_send(&monc->con, ceph_msg_get(msg));
 }
 
 static void handle_subscribe_ack(struct ceph_mon_client *monc,
@@ -255,15 +291,16 @@ static void handle_subscribe_ack(struct ceph_mon_client *monc,
        seconds = le32_to_cpu(h->duration);
 
        mutex_lock(&monc->mutex);
-       if (monc->hunting) {
-               pr_info("mon%d %s session established\n",
-                       monc->cur_mon,
-                       ceph_pr_addr(&monc->con.peer_addr.in_addr));
-               monc->hunting = false;
+       if (monc->sub_renew_sent) {
+               monc->sub_renew_after = monc->sub_renew_sent +
+                                           (seconds >> 1) * HZ - 1;
+               dout("%s sent %lu duration %d renew after %lu\n", __func__,
+                    monc->sub_renew_sent, seconds, monc->sub_renew_after);
+               monc->sub_renew_sent = 0;
+       } else {
+               dout("%s sent %lu renew after %lu, ignoring\n", __func__,
+                    monc->sub_renew_sent, monc->sub_renew_after);
        }
-       dout("handle_subscribe_ack after %d seconds\n", seconds);
-       monc->sub_renew_after = monc->sub_sent + (seconds >> 1)*HZ - 1;
-       monc->sub_sent = 0;
        mutex_unlock(&monc->mutex);
        return;
 bad:
@@ -272,36 +309,82 @@ bad:
 }
 
 /*
- * Keep track of which maps we have
+ * Register interest in a map
+ *
+ * @sub: one of CEPH_SUB_*
+ * @epoch: X for "every map since X", or 0 for "just the latest"
  */
-int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 got)
+static bool __ceph_monc_want_map(struct ceph_mon_client *monc, int sub,
+                                u32 epoch, bool continuous)
+{
+       __le64 start = cpu_to_le64(epoch);
+       u8 flags = !continuous ? CEPH_SUBSCRIBE_ONETIME : 0;
+
+       dout("%s %s epoch %u continuous %d\n", __func__, ceph_sub_str[sub],
+            epoch, continuous);
+
+       if (monc->subs[sub].want &&
+           monc->subs[sub].item.start == start &&
+           monc->subs[sub].item.flags == flags)
+               return false;
+
+       monc->subs[sub].item.start = start;
+       monc->subs[sub].item.flags = flags;
+       monc->subs[sub].want = true;
+
+       return true;
+}
+
+bool ceph_monc_want_map(struct ceph_mon_client *monc, int sub, u32 epoch,
+                       bool continuous)
 {
+       bool need_request;
+
        mutex_lock(&monc->mutex);
-       monc->have_mdsmap = got;
+       need_request = __ceph_monc_want_map(monc, sub, epoch, continuous);
        mutex_unlock(&monc->mutex);
-       return 0;
+
+       return need_request;
 }
-EXPORT_SYMBOL(ceph_monc_got_mdsmap);
+EXPORT_SYMBOL(ceph_monc_want_map);
 
-int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 got)
+/*
+ * Keep track of which maps we have
+ *
+ * @sub: one of CEPH_SUB_*
+ */
+static void __ceph_monc_got_map(struct ceph_mon_client *monc, int sub,
+                               u32 epoch)
+{
+       dout("%s %s epoch %u\n", __func__, ceph_sub_str[sub], epoch);
+
+       if (monc->subs[sub].want) {
+               if (monc->subs[sub].item.flags & CEPH_SUBSCRIBE_ONETIME)
+                       monc->subs[sub].want = false;
+               else
+                       monc->subs[sub].item.start = cpu_to_le64(epoch + 1);
+       }
+
+       monc->subs[sub].have = epoch;
+}
+
+void ceph_monc_got_map(struct ceph_mon_client *monc, int sub, u32 epoch)
 {
        mutex_lock(&monc->mutex);
-       monc->have_osdmap = got;
-       monc->want_next_osdmap = 0;
+       __ceph_monc_got_map(monc, sub, epoch);
        mutex_unlock(&monc->mutex);
-       return 0;
 }
+EXPORT_SYMBOL(ceph_monc_got_map);
 
 /*
  * Register interest in the next osdmap
  */
 void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc)
 {
-       dout("request_next_osdmap have %u\n", monc->have_osdmap);
+       dout("%s have %u\n", __func__, monc->subs[CEPH_SUB_OSDMAP].have);
        mutex_lock(&monc->mutex);
-       if (!monc->want_next_osdmap)
-               monc->want_next_osdmap = 1;
-       if (monc->want_next_osdmap < 2)
+       if (__ceph_monc_want_map(monc, CEPH_SUB_OSDMAP,
+                                monc->subs[CEPH_SUB_OSDMAP].have + 1, false))
                __send_subscribe(monc);
        mutex_unlock(&monc->mutex);
 }
@@ -320,15 +403,15 @@ int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch,
        long ret;
 
        mutex_lock(&monc->mutex);
-       while (monc->have_osdmap < epoch) {
+       while (monc->subs[CEPH_SUB_OSDMAP].have < epoch) {
                mutex_unlock(&monc->mutex);
 
                if (timeout && time_after_eq(jiffies, started + timeout))
                        return -ETIMEDOUT;
 
                ret = wait_event_interruptible_timeout(monc->client->auth_wq,
-                                               monc->have_osdmap >= epoch,
-                                               ceph_timeout_jiffies(timeout));
+                                    monc->subs[CEPH_SUB_OSDMAP].have >= epoch,
+                                    ceph_timeout_jiffies(timeout));
                if (ret < 0)
                        return ret;
 
@@ -341,11 +424,14 @@ int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch,
 EXPORT_SYMBOL(ceph_monc_wait_osdmap);
 
 /*
- *
+ * Open a session with a random monitor.  Request monmap and osdmap,
+ * which are waited upon in __ceph_open_session().
  */
 int ceph_monc_open_session(struct ceph_mon_client *monc)
 {
        mutex_lock(&monc->mutex);
+       __ceph_monc_want_map(monc, CEPH_SUB_MONMAP, 0, true);
+       __ceph_monc_want_map(monc, CEPH_SUB_OSDMAP, 0, false);
        __open_session(monc);
        __schedule_delayed(monc);
        mutex_unlock(&monc->mutex);
@@ -353,29 +439,15 @@ int ceph_monc_open_session(struct ceph_mon_client *monc)
 }
 EXPORT_SYMBOL(ceph_monc_open_session);
 
-/*
- * We require the fsid and global_id in order to initialize our
- * debugfs dir.
- */
-static bool have_debugfs_info(struct ceph_mon_client *monc)
-{
-       dout("have_debugfs_info fsid %d globalid %lld\n",
-            (int)monc->client->have_fsid, monc->auth->global_id);
-       return monc->client->have_fsid && monc->auth->global_id > 0;
-}
-
 static void ceph_monc_handle_map(struct ceph_mon_client *monc,
                                 struct ceph_msg *msg)
 {
        struct ceph_client *client = monc->client;
        struct ceph_monmap *monmap = NULL, *old = monc->monmap;
        void *p, *end;
-       int had_debugfs_info, init_debugfs = 0;
 
        mutex_lock(&monc->mutex);
 
-       had_debugfs_info = have_debugfs_info(monc);
-
        dout("handle_monmap\n");
        p = msg->front.iov_base;
        end = p + msg->front.iov_len;
@@ -395,29 +467,11 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc,
        client->monc.monmap = monmap;
        kfree(old);
 
-       if (!client->have_fsid) {
-               client->have_fsid = true;
-               if (!had_debugfs_info && have_debugfs_info(monc)) {
-                       pr_info("client%lld fsid %pU\n",
-                               ceph_client_id(monc->client),
-                               &monc->client->fsid);
-                       init_debugfs = 1;
-               }
-               mutex_unlock(&monc->mutex);
-
-               if (init_debugfs) {
-                       /*
-                        * do debugfs initialization without mutex to avoid
-                        * creating a locking dependency
-                        */
-                       ceph_debugfs_client_init(monc->client);
-               }
+       __ceph_monc_got_map(monc, CEPH_SUB_MONMAP, monc->monmap->epoch);
+       client->have_fsid = true;
 
-               goto out_unlocked;
-       }
 out:
        mutex_unlock(&monc->mutex);
-out_unlocked:
        wake_up_all(&client->auth_wq);
 }
 
@@ -745,18 +799,15 @@ static void delayed_work(struct work_struct *work)
        dout("monc delayed_work\n");
        mutex_lock(&monc->mutex);
        if (monc->hunting) {
-               __close_session(monc);
-               __open_session(monc);  /* continue hunting */
+               dout("%s continuing hunt\n", __func__);
+               reopen_session(monc);
        } else {
-               struct ceph_options *opt = monc->client->options;
                int is_auth = ceph_auth_is_authenticated(monc->auth);
                if (ceph_con_keepalive_expired(&monc->con,
-                                              opt->monc_ping_timeout)) {
+                                              CEPH_MONC_PING_TIMEOUT)) {
                        dout("monc keepalive timeout\n");
                        is_auth = 0;
-                       __close_session(monc);
-                       monc->hunting = true;
-                       __open_session(monc);
+                       reopen_session(monc);
                }
 
                if (!monc->hunting) {
@@ -764,8 +815,14 @@ static void delayed_work(struct work_struct *work)
                        __validate_auth(monc);
                }
 
-               if (is_auth)
-                       __send_subscribe(monc);
+               if (is_auth) {
+                       unsigned long now = jiffies;
+
+                       dout("%s renew subs? now %lu renew after %lu\n",
+                            __func__, now, monc->sub_renew_after);
+                       if (time_after_eq(now, monc->sub_renew_after))
+                               __send_subscribe(monc);
+               }
        }
        __schedule_delayed(monc);
        mutex_unlock(&monc->mutex);
@@ -852,18 +909,14 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
                      &monc->client->msgr);
 
        monc->cur_mon = -1;
-       monc->hunting = true;
-       monc->sub_renew_after = jiffies;
-       monc->sub_sent = 0;
+       monc->had_a_connection = false;
+       monc->hunt_mult = 1;
 
        INIT_DELAYED_WORK(&monc->delayed_work, delayed_work);
        monc->generic_request_tree = RB_ROOT;
        monc->num_generic_requests = 0;
        monc->last_tid = 0;
 
-       monc->have_mdsmap = 0;
-       monc->have_osdmap = 0;
-       monc->want_next_osdmap = 1;
        return 0;
 
 out_auth_reply:
@@ -888,7 +941,7 @@ void ceph_monc_stop(struct ceph_mon_client *monc)
 
        mutex_lock(&monc->mutex);
        __close_session(monc);
-
+       monc->cur_mon = -1;
        mutex_unlock(&monc->mutex);
 
        /*
@@ -910,26 +963,40 @@ void ceph_monc_stop(struct ceph_mon_client *monc)
 }
 EXPORT_SYMBOL(ceph_monc_stop);
 
+static void finish_hunting(struct ceph_mon_client *monc)
+{
+       if (monc->hunting) {
+               dout("%s found mon%d\n", __func__, monc->cur_mon);
+               monc->hunting = false;
+               monc->had_a_connection = true;
+               monc->hunt_mult /= 2; /* reduce by 50% */
+               if (monc->hunt_mult < 1)
+                       monc->hunt_mult = 1;
+       }
+}
+
 static void handle_auth_reply(struct ceph_mon_client *monc,
                              struct ceph_msg *msg)
 {
        int ret;
        int was_auth = 0;
-       int had_debugfs_info, init_debugfs = 0;
 
        mutex_lock(&monc->mutex);
-       had_debugfs_info = have_debugfs_info(monc);
        was_auth = ceph_auth_is_authenticated(monc->auth);
        monc->pending_auth = 0;
        ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base,
                                     msg->front.iov_len,
                                     monc->m_auth->front.iov_base,
                                     monc->m_auth->front_alloc_len);
+       if (ret > 0) {
+               __send_prepared_auth_request(monc, ret);
+               goto out;
+       }
+
+       finish_hunting(monc);
+
        if (ret < 0) {
                monc->client->auth_err = ret;
-               wake_up_all(&monc->client->auth_wq);
-       } else if (ret > 0) {
-               __send_prepared_auth_request(monc, ret);
        } else if (!was_auth && ceph_auth_is_authenticated(monc->auth)) {
                dout("authenticated, starting session\n");
 
@@ -939,23 +1006,15 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
 
                __send_subscribe(monc);
                __resend_generic_request(monc);
-       }
 
-       if (!had_debugfs_info && have_debugfs_info(monc)) {
-               pr_info("client%lld fsid %pU\n",
-                       ceph_client_id(monc->client),
-                       &monc->client->fsid);
-               init_debugfs = 1;
+               pr_info("mon%d %s session established\n", monc->cur_mon,
+                       ceph_pr_addr(&monc->con.peer_addr.in_addr));
        }
-       mutex_unlock(&monc->mutex);
 
-       if (init_debugfs) {
-               /*
-                * do debugfs initialization without mutex to avoid
-                * creating a locking dependency
-                */
-               ceph_debugfs_client_init(monc->client);
-       }
+out:
+       mutex_unlock(&monc->mutex);
+       if (monc->client->auth_err < 0)
+               wake_up_all(&monc->client->auth_wq);
 }
 
 static int __validate_auth(struct ceph_mon_client *monc)
@@ -1096,29 +1155,17 @@ static void mon_fault(struct ceph_connection *con)
 {
        struct ceph_mon_client *monc = con->private;
 
-       if (!monc)
-               return;
-
-       dout("mon_fault\n");
        mutex_lock(&monc->mutex);
-       if (!con->private)
-               goto out;
-
-       if (!monc->hunting)
-               pr_info("mon%d %s session lost, "
-                       "hunting for new mon\n", monc->cur_mon,
-                       ceph_pr_addr(&monc->con.peer_addr.in_addr));
-
-       __close_session(monc);
-       if (!monc->hunting) {
-               /* start hunting */
-               monc->hunting = true;
-               __open_session(monc);
-       } else {
-               /* already hunting, let's wait a bit */
-               __schedule_delayed(monc);
+       dout("%s mon%d\n", __func__, monc->cur_mon);
+       if (monc->cur_mon >= 0) {
+               if (!monc->hunting) {
+                       dout("%s hunting for new mon\n", __func__);
+                       reopen_session(monc);
+                       __schedule_delayed(monc);
+               } else {
+                       dout("%s already hunting\n", __func__);
+               }
        }
-out:
        mutex_unlock(&monc->mutex);
 }
 
index 5bc0537..32355d9 100644 (file)
@@ -338,9 +338,10 @@ static void ceph_osdc_release_request(struct kref *kref)
        ceph_put_snap_context(req->r_snapc);
        if (req->r_mempool)
                mempool_free(req, req->r_osdc->req_mempool);
-       else
+       else if (req->r_num_ops <= CEPH_OSD_SLAB_OPS)
                kmem_cache_free(ceph_osd_request_cache, req);
-
+       else
+               kfree(req);
 }
 
 void ceph_osdc_get_request(struct ceph_osd_request *req)
@@ -369,28 +370,22 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
        struct ceph_msg *msg;
        size_t msg_size;
 
-       BUILD_BUG_ON(CEPH_OSD_MAX_OP > U16_MAX);
-       BUG_ON(num_ops > CEPH_OSD_MAX_OP);
-
-       msg_size = 4 + 4 + 8 + 8 + 4+8;
-       msg_size += 2 + 4 + 8 + 4 + 4; /* oloc */
-       msg_size += 1 + 8 + 4 + 4;     /* pg_t */
-       msg_size += 4 + CEPH_MAX_OID_NAME_LEN; /* oid */
-       msg_size += 2 + num_ops*sizeof(struct ceph_osd_op);
-       msg_size += 8;  /* snapid */
-       msg_size += 8;  /* snap_seq */
-       msg_size += 8 * (snapc ? snapc->num_snaps : 0);  /* snaps */
-       msg_size += 4;
-
        if (use_mempool) {
+               BUG_ON(num_ops > CEPH_OSD_SLAB_OPS);
                req = mempool_alloc(osdc->req_mempool, gfp_flags);
-               memset(req, 0, sizeof(*req));
+       } else if (num_ops <= CEPH_OSD_SLAB_OPS) {
+               req = kmem_cache_alloc(ceph_osd_request_cache, gfp_flags);
        } else {
-               req = kmem_cache_zalloc(ceph_osd_request_cache, gfp_flags);
+               BUG_ON(num_ops > CEPH_OSD_MAX_OPS);
+               req = kmalloc(sizeof(*req) + num_ops * sizeof(req->r_ops[0]),
+                             gfp_flags);
        }
-       if (req == NULL)
+       if (unlikely(!req))
                return NULL;
 
+       /* req only, each op is zeroed in _osd_req_op_init() */
+       memset(req, 0, sizeof(*req));
+
        req->r_osdc = osdc;
        req->r_mempool = use_mempool;
        req->r_num_ops = num_ops;
@@ -408,18 +403,36 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
        req->r_base_oloc.pool = -1;
        req->r_target_oloc.pool = -1;
 
+       msg_size = OSD_OPREPLY_FRONT_LEN;
+       if (num_ops > CEPH_OSD_SLAB_OPS) {
+               /* ceph_osd_op and rval */
+               msg_size += (num_ops - CEPH_OSD_SLAB_OPS) *
+                           (sizeof(struct ceph_osd_op) + 4);
+       }
+
        /* create reply message */
        if (use_mempool)
                msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0);
        else
-               msg = ceph_msg_new(CEPH_MSG_OSD_OPREPLY,
-                                  OSD_OPREPLY_FRONT_LEN, gfp_flags, true);
+               msg = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, msg_size,
+                                  gfp_flags, true);
        if (!msg) {
                ceph_osdc_put_request(req);
                return NULL;
        }
        req->r_reply = msg;
 
+       msg_size = 4 + 4 + 4; /* client_inc, osdmap_epoch, flags */
+       msg_size += 4 + 4 + 4 + 8; /* mtime, reassert_version */
+       msg_size += 2 + 4 + 8 + 4 + 4; /* oloc */
+       msg_size += 1 + 8 + 4 + 4; /* pgid */
+       msg_size += 4 + CEPH_MAX_OID_NAME_LEN; /* oid */
+       msg_size += 2 + num_ops * sizeof(struct ceph_osd_op);
+       msg_size += 8; /* snapid */
+       msg_size += 8; /* snap_seq */
+       msg_size += 4 + 8 * (snapc ? snapc->num_snaps : 0); /* snaps */
+       msg_size += 4; /* retry_attempt */
+
        /* create request message; allow space for oid */
        if (use_mempool)
                msg = ceph_msgpool_get(&osdc->msgpool_op, 0);
@@ -498,7 +511,7 @@ void osd_req_op_extent_init(struct ceph_osd_request *osd_req,
        if (opcode == CEPH_OSD_OP_WRITE || opcode == CEPH_OSD_OP_WRITEFULL)
                payload_len += length;
 
-       op->payload_len = payload_len;
+       op->indata_len = payload_len;
 }
 EXPORT_SYMBOL(osd_req_op_extent_init);
 
@@ -517,10 +530,32 @@ void osd_req_op_extent_update(struct ceph_osd_request *osd_req,
        BUG_ON(length > previous);
 
        op->extent.length = length;
-       op->payload_len -= previous - length;
+       op->indata_len -= previous - length;
 }
 EXPORT_SYMBOL(osd_req_op_extent_update);
 
+void osd_req_op_extent_dup_last(struct ceph_osd_request *osd_req,
+                               unsigned int which, u64 offset_inc)
+{
+       struct ceph_osd_req_op *op, *prev_op;
+
+       BUG_ON(which + 1 >= osd_req->r_num_ops);
+
+       prev_op = &osd_req->r_ops[which];
+       op = _osd_req_op_init(osd_req, which + 1, prev_op->op, prev_op->flags);
+       /* dup previous one */
+       op->indata_len = prev_op->indata_len;
+       op->outdata_len = prev_op->outdata_len;
+       op->extent = prev_op->extent;
+       /* adjust offset */
+       op->extent.offset += offset_inc;
+       op->extent.length -= offset_inc;
+
+       if (op->op == CEPH_OSD_OP_WRITE || op->op == CEPH_OSD_OP_WRITEFULL)
+               op->indata_len -= offset_inc;
+}
+EXPORT_SYMBOL(osd_req_op_extent_dup_last);
+
 void osd_req_op_cls_init(struct ceph_osd_request *osd_req, unsigned int which,
                        u16 opcode, const char *class, const char *method)
 {
@@ -554,7 +589,7 @@ void osd_req_op_cls_init(struct ceph_osd_request *osd_req, unsigned int which,
 
        op->cls.argc = 0;       /* currently unused */
 
-       op->payload_len = payload_len;
+       op->indata_len = payload_len;
 }
 EXPORT_SYMBOL(osd_req_op_cls_init);
 
@@ -587,7 +622,7 @@ int osd_req_op_xattr_init(struct ceph_osd_request *osd_req, unsigned int which,
        op->xattr.cmp_mode = cmp_mode;
 
        ceph_osd_data_pagelist_init(&op->xattr.osd_data, pagelist);
-       op->payload_len = payload_len;
+       op->indata_len = payload_len;
        return 0;
 }
 EXPORT_SYMBOL(osd_req_op_xattr_init);
@@ -707,7 +742,7 @@ static u64 osd_req_encode_op(struct ceph_osd_request *req,
                        BUG_ON(osd_data->type == CEPH_OSD_DATA_TYPE_NONE);
                        dst->cls.indata_len = cpu_to_le32(data_length);
                        ceph_osdc_msg_data_add(req->r_request, osd_data);
-                       src->payload_len += data_length;
+                       src->indata_len += data_length;
                        request_data_len += data_length;
                }
                osd_data = &src->cls.response_data;
@@ -750,7 +785,7 @@ static u64 osd_req_encode_op(struct ceph_osd_request *req,
 
        dst->op = cpu_to_le16(src->op);
        dst->flags = cpu_to_le32(src->flags);
-       dst->payload_len = cpu_to_le32(src->payload_len);
+       dst->payload_len = cpu_to_le32(src->indata_len);
 
        return request_data_len;
 }
@@ -1810,7 +1845,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg)
 
        ceph_decode_need(&p, end, 4, bad_put);
        numops = ceph_decode_32(&p);
-       if (numops > CEPH_OSD_MAX_OP)
+       if (numops > CEPH_OSD_MAX_OPS)
                goto bad_put;
        if (numops != req->r_num_ops)
                goto bad_put;
@@ -1821,7 +1856,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                int len;
 
                len = le32_to_cpu(op->payload_len);
-               req->r_reply_op_len[i] = len;
+               req->r_ops[i].outdata_len = len;
                dout(" op %d has %d bytes\n", i, len);
                payload_len += len;
                p += sizeof(*op);
@@ -1836,7 +1871,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg)
        ceph_decode_need(&p, end, 4 + numops * 4, bad_put);
        retry_attempt = ceph_decode_32(&p);
        for (i = 0; i < numops; i++)
-               req->r_reply_op_result[i] = ceph_decode_32(&p);
+               req->r_ops[i].rval = ceph_decode_32(&p);
 
        if (le16_to_cpu(msg->hdr.version) >= 6) {
                p += 8 + 4; /* skip replay_version */
@@ -2187,7 +2222,8 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                goto bad;
 done:
        downgrade_write(&osdc->map_sem);
-       ceph_monc_got_osdmap(&osdc->client->monc, osdc->osdmap->epoch);
+       ceph_monc_got_map(&osdc->client->monc, CEPH_SUB_OSDMAP,
+                         osdc->osdmap->epoch);
 
        /*
         * subscribe to subsequent osdmap updates if full to ensure
@@ -2646,8 +2682,8 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
            round_jiffies_relative(osdc->client->options->osd_idle_ttl));
 
        err = -ENOMEM;
-       osdc->req_mempool = mempool_create_kmalloc_pool(10,
-                                       sizeof(struct ceph_osd_request));
+       osdc->req_mempool = mempool_create_slab_pool(10,
+                                                    ceph_osd_request_cache);
        if (!osdc->req_mempool)
                goto out;
 
@@ -2782,11 +2818,12 @@ EXPORT_SYMBOL(ceph_osdc_writepages);
 
 int ceph_osdc_setup(void)
 {
+       size_t size = sizeof(struct ceph_osd_request) +
+           CEPH_OSD_SLAB_OPS * sizeof(struct ceph_osd_req_op);
+
        BUG_ON(ceph_osd_request_cache);
-       ceph_osd_request_cache = kmem_cache_create("ceph_osd_request",
-                                       sizeof (struct ceph_osd_request),
-                                       __alignof__(struct ceph_osd_request),
-                                       0, NULL);
+       ceph_osd_request_cache = kmem_cache_create("ceph_osd_request", size,
+                                                  0, 0, NULL);
 
        return ceph_osd_request_cache ? 0 : -ENOMEM;
 }
index 1db6d73..b2ab2a9 100644 (file)
@@ -251,7 +251,7 @@ any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
 if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
        @set -e;                                                             \
        $(echo-cmd) $(cmd_$(1));                                             \
-       printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
+       printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
 
 # Execute the command and also postprocess generated .d dependencies file.
 if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
@@ -259,14 +259,14 @@ if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
        $(echo-cmd) $(cmd_$(1));                                             \
        scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
        rm -f $(depfile);                                                    \
-       mv -f $(dot-target).tmp $(dot-target).cmd)
+       mv -f $(dot-target).tmp $(dot-target).cmd, @:)
 
 # Usage: $(call if_changed_rule,foo)
 # Will check if $(cmd_foo) or any of the prerequisites changed,
 # and if so will execute $(rule_foo).
 if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 \
        @set -e;                                                             \
-       $(rule_$(1)))
+       $(rule_$(1)), @:)
 
 ###
 # why - tell why a a target got build
index 1c15717..a1be75d 100644 (file)
@@ -23,8 +23,6 @@ include $(src)/Makefile
 PHONY += __dtbs_install_prep
 __dtbs_install_prep:
 ifeq ("$(dtbinst-root)", "$(obj)")
-       $(Q)if [ -d $(INSTALL_DTBS_PATH).old ]; then rm -rf $(INSTALL_DTBS_PATH).old; fi
-       $(Q)if [ -d $(INSTALL_DTBS_PATH) ]; then mv $(INSTALL_DTBS_PATH) $(INSTALL_DTBS_PATH).old; fi
        $(Q)mkdir -p $(INSTALL_DTBS_PATH)
 endif
 
index 5b327c6..caef815 100644 (file)
@@ -274,7 +274,11 @@ static void do_config_file(const char *filename)
                perror(filename);
                exit(2);
        }
-       fstat(fd, &st);
+       if (fstat(fd, &st) < 0) {
+               fprintf(stderr, "fixdep: error fstat'ing config file: ");
+               perror(filename);
+               exit(2);
+       }
        if (st.st_size == 0) {
                close(fd);
                return;
index b7042d0..89b98a2 100644 (file)
@@ -78,7 +78,7 @@ ret = pm_runtime_api(...);
 //  For org and report mode
 //----------------------------------------------------------
 
-@r depends on runtime_bad_err_handle exists@
+@r depends on runtime_bad_err_handle && (org || report) exists@
 position p1, p2;
 identifier pm_runtime_api;
 expression ret;
diff --git a/scripts/coccinelle/api/setup_timer.cocci b/scripts/coccinelle/api/setup_timer.cocci
new file mode 100644 (file)
index 0000000..8ee0ac3
--- /dev/null
@@ -0,0 +1,199 @@
+/// Use setup_timer function instead of initializing timer with the function
+/// and data fields
+// Confidence: High
+// Copyright: (C) 2016 Vaishali Thakkar, Oracle. GPLv2
+// Options: --no-includes --include-headers
+// Keywords: init_timer, setup_timer
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@match_immediate_function_data_after_init_timer
+depends on patch && !context && !org && !report@
+expression e, func, da;
+@@
+
+-init_timer (&e);
++setup_timer (&e, func, da);
+
+(
+-e.function = func;
+-e.data = da;
+|
+-e.data = da;
+-e.function = func;
+)
+
+@match_function_and_data_after_init_timer
+depends on patch && !context && !org && !report@
+expression e1, e2, e3, e4, e5, a, b;
+@@
+
+-init_timer (&e1);
++setup_timer (&e1, a, b);
+
+... when != a = e2
+    when != b = e3
+(
+-e1.function = a;
+... when != b = e4
+-e1.data = b;
+|
+-e1.data = b;
+... when != a = e5
+-e1.function = a;
+)
+
+@r1 exists@
+identifier f;
+position p;
+@@
+
+f(...) { ... when any
+  init_timer@p(...)
+  ... when any
+}
+
+@r2 exists@
+identifier g != r1.f;
+struct timer_list t;
+expression e8;
+@@
+
+g(...) { ... when any
+  t.data = e8
+  ... when any
+}
+
+// It is dangerous to use setup_timer if data field is initialized
+// in another function.
+
+@script:python depends on r2@
+p << r1.p;
+@@
+
+cocci.include_match(False)
+
+@r3 depends on patch && !context && !org && !report@
+expression e6, e7, c;
+position r1.p;
+@@
+
+-init_timer@p (&e6);
++setup_timer (&e6, c, 0UL);
+... when != c = e7
+-e6.function = c;
+
+// ----------------------------------------------------------------------------
+
+@match_immediate_function_data_after_init_timer_context
+depends on !patch && (context || org || report)@
+expression da, e, func;
+position j0, j1, j2;
+@@
+
+* init_timer@j0 (&e);
+(
+* e@j1.function = func;
+* e@j2.data = da;
+|
+* e@j1.data = da;
+* e@j2.function = func;
+)
+
+@match_function_and_data_after_init_timer_context
+depends on !patch &&
+!match_immediate_function_data_after_init_timer_context &&
+(context || org || report)@
+expression a, b, e1, e2, e3, e4, e5;
+position j0, j1, j2;
+@@
+
+* init_timer@j0 (&e1);
+... when != a = e2
+    when != b = e3
+(
+* e1@j1.function = a;
+... when != b = e4
+* e1@j2.data = b;
+|
+* e1@j1.data = b;
+... when != a = e5
+* e1@j2.function = a;
+)
+
+@r3_context depends on !patch &&
+!match_immediate_function_data_after_init_timer_context &&
+!match_function_and_data_after_init_timer_context &&
+(context || org || report)@
+expression c, e6, e7;
+position r1.p;
+position j0, j1;
+@@
+
+* init_timer@j0@p (&e6);
+... when != c = e7
+* e6@j1.function = c;
+
+// ----------------------------------------------------------------------------
+
+@script:python match_immediate_function_data_after_init_timer_org
+depends on org@
+j0 << match_immediate_function_data_after_init_timer_context.j0;
+j1 << match_immediate_function_data_after_init_timer_context.j1;
+j2 << match_immediate_function_data_after_init_timer_context.j2;
+@@
+
+msg = "Use setup_timer function."
+coccilib.org.print_todo(j0[0], msg)
+coccilib.org.print_link(j1[0], "")
+coccilib.org.print_link(j2[0], "")
+
+@script:python match_function_and_data_after_init_timer_org depends on org@
+j0 << match_function_and_data_after_init_timer_context.j0;
+j1 << match_function_and_data_after_init_timer_context.j1;
+j2 << match_function_and_data_after_init_timer_context.j2;
+@@
+
+msg = "Use setup_timer function."
+coccilib.org.print_todo(j0[0], msg)
+coccilib.org.print_link(j1[0], "")
+coccilib.org.print_link(j2[0], "")
+
+@script:python r3_org depends on org@
+j0 << r3_context.j0;
+j1 << r3_context.j1;
+@@
+
+msg = "Use setup_timer function."
+coccilib.org.print_todo(j0[0], msg)
+coccilib.org.print_link(j1[0], "")
+
+// ----------------------------------------------------------------------------
+
+@script:python match_immediate_function_data_after_init_timer_report
+depends on report@
+j0 << match_immediate_function_data_after_init_timer_context.j0;
+j1 << match_immediate_function_data_after_init_timer_context.j1;
+@@
+
+msg = "Use setup_timer function for function on line %s." % (j1[0].line)
+coccilib.report.print_report(j0[0], msg)
+
+@script:python match_function_and_data_after_init_timer_report depends on report@
+j0 << match_function_and_data_after_init_timer_context.j0;
+j1 << match_function_and_data_after_init_timer_context.j1;
+@@
+
+msg = "Use setup_timer function for function on line %s." % (j1[0].line)
+coccilib.report.print_report(j0[0], msg)
+
+@script:python r3_report depends on report@
+j0 << r3_context.j0;
+j1 << r3_context.j1;
+@@
+
+msg = "Use setup_timer function for function on line %s." % (j1[0].line)
+coccilib.report.print_report(j0[0], msg)
index f085f59..ce8cc9c 100644 (file)
@@ -123,7 +123,7 @@ list_remove_head(x,c,...)
 |
 sizeof(<+...c...+>)
 |
-&c->member
+ &c->member
 |
 c = E
 |
index 81e279c..6ec0571 100644 (file)
@@ -59,7 +59,7 @@ T[] E;
 //  For org and report mode
 //----------------------------------------------------------
 
-@r@
+@r depends on (org || report)@
 type T;
 T[] E;
 position p;
index 2fc06fc..481cf30 100644 (file)
@@ -50,7 +50,7 @@ T **x;
 //  For org and report mode
 //----------------------------------------------------------
 
-@r disable sizeof_type_expr@
+@r depends on (org || report) disable sizeof_type_expr@
 type T;
 T **x;
 position p;
index 27c97f1..7415860 100644 (file)
@@ -40,7 +40,7 @@ expression e;
 //  For org and report mode
 //----------------------------------------------------------
 
-@r@
+@r depends on (org || report)@
 expression e;
 position p;
 @@
index d79cba4..ebced77 100644 (file)
@@ -96,13 +96,15 @@ savedefconfig: $(obj)/conf
 defconfig: $(obj)/conf
 ifeq ($(KBUILD_DEFCONFIG),)
        $< $(silent) --defconfig $(Kconfig)
-else ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
+else
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
        @$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
        $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
 else
        @$(kecho) "*** Default configuration is based on target '$(KBUILD_DEFCONFIG)'"
        $(Q)$(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG)
 endif
+endif
 
 %_defconfig: $(obj)/conf
        $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
index 0b7dc2f..dd243d2 100644 (file)
@@ -267,10 +267,8 @@ int conf_read_simple(const char *name, int def)
                if (in)
                        goto load;
                sym_add_change_count(1);
-               if (!sym_defconfig_list) {
-                       sym_calc_value(modules_sym);
+               if (!sym_defconfig_list)
                        return 1;
-               }
 
                for_all_defaults(sym_defconfig_list, prop) {
                        if (expr_calc_value(prop->visible.expr) == no ||
@@ -403,7 +401,6 @@ setsym:
        }
        free(line);
        fclose(in);
-       sym_calc_value(modules_sym);
        return 0;
 }
 
@@ -414,8 +411,12 @@ int conf_read(const char *name)
 
        sym_set_change_count(0);
 
-       if (conf_read_simple(name, S_DEF_USER))
+       if (conf_read_simple(name, S_DEF_USER)) {
+               sym_calc_value(modules_sym);
                return 1;
+       }
+
+       sym_calc_value(modules_sym);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
@@ -846,6 +847,7 @@ static int conf_split_config(void)
 
        name = conf_get_autoconfig_name();
        conf_read_simple(name, S_DEF_AUTO);
+       sym_calc_value(modules_sym);
 
        if (chdir("include/config"))
                return 1;
index 453ede9..49d61ad 100755 (executable)
@@ -97,9 +97,10 @@ kallsyms()
        local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
                      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
 
-       ${NM} -n ${1} | \
-               scripts/kallsyms ${kallsymopt} | \
-               ${CC} ${aflags} -c -o ${2} -x assembler-with-cpp -
+       local afile="`basename ${2} .o`.S"
+
+       ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${afile}
+       ${CC} ${aflags} -c -o ${2} ${afile}
 }
 
 # Create map file with all symbols from ${1}
index 71004da..b6de63c 100755 (executable)
@@ -131,11 +131,16 @@ echo 'rm -rf $RPM_BUILD_ROOT'
 echo ""
 echo "%post"
 echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then"
-echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm"
-echo "cp /boot/System.map-$KERNELRELEASE /boot/System.map-$KERNELRELEASE-rpm"
+echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm"
+echo "cp /boot/System.map-$KERNELRELEASE /boot/.System.map-$KERNELRELEASE-rpm"
 echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE"
-echo "/sbin/installkernel $KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm"
-echo "rm -f /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm"
+echo "/sbin/installkernel $KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm"
+echo "rm -f /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm"
+echo "fi"
+echo ""
+echo "%preun"
+echo "if [ -x /sbin/new-kernel-pkg ]; then"
+echo "new-kernel-pkg --remove $KERNELRELEASE --rminitrd --initrdfile=/boot/initramfs-$KERNELRELEASE.img"
 echo "fi"
 echo ""
 echo "%files"
index 62a1822..f453b7c 100644 (file)
@@ -315,6 +315,7 @@ do_file(char const *const fname)
 
        case EM_S390:
        case EM_AARCH64:
+       case EM_PARISC:
                custom_sort = sort_relative_table;
                break;
        case EM_ARCOMPACT:
index 23ba1c6..f72f48f 100755 (executable)
@@ -163,6 +163,8 @@ regex_c=(
        '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
        '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1/'
        '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
+       '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/get_\1_slot/'
+       '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/free_\1_slot/'
        '/^PAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
        '/^PAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
        '/^PAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
index aa1b15c..6469bed 100644 (file)
@@ -1019,8 +1019,8 @@ static int snd_timer_s_start(struct snd_timer * timer)
                njiff += timer->sticks - priv->correction;
                priv->correction = 0;
        }
-       priv->last_expires = priv->tlist.expires = njiff;
-       add_timer(&priv->tlist);
+       priv->last_expires = njiff;
+       mod_timer(&priv->tlist, njiff);
        return 0;
 }
 
@@ -1502,17 +1502,13 @@ static int snd_timer_user_ginfo(struct file *file,
        return err;
 }
 
-static int snd_timer_user_gparams(struct file *file,
-                                 struct snd_timer_gparams __user *_gparams)
+static int timer_set_gparams(struct snd_timer_gparams *gparams)
 {
-       struct snd_timer_gparams gparams;
        struct snd_timer *t;
        int err;
 
-       if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
-               return -EFAULT;
        mutex_lock(&register_mutex);
-       t = snd_timer_find(&gparams.tid);
+       t = snd_timer_find(&gparams->tid);
        if (!t) {
                err = -ENODEV;
                goto _error;
@@ -1525,12 +1521,22 @@ static int snd_timer_user_gparams(struct file *file,
                err = -ENOSYS;
                goto _error;
        }
-       err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
+       err = t->hw.set_period(t, gparams->period_num, gparams->period_den);
 _error:
        mutex_unlock(&register_mutex);
        return err;
 }
 
+static int snd_timer_user_gparams(struct file *file,
+                                 struct snd_timer_gparams __user *_gparams)
+{
+       struct snd_timer_gparams gparams;
+
+       if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
+               return -EFAULT;
+       return timer_set_gparams(&gparams);
+}
+
 static int snd_timer_user_gstatus(struct file *file,
                                  struct snd_timer_gstatus __user *_gstatus)
 {
index 2e90822..6a437eb 100644 (file)
 
 #include <linux/compat.h>
 
+/*
+ * ILP32/LP64 has different size for 'long' type. Additionally, the size
+ * of storage alignment differs depending on architectures. Here, '__packed'
+ * qualifier is used so that the size of this structure is multiple of 4 and
+ * it fits to any architectures with 32 bit storage alignment.
+ */
+struct snd_timer_gparams32 {
+       struct snd_timer_id tid;
+       u32 period_num;
+       u32 period_den;
+       unsigned char reserved[32];
+} __packed;
+
 struct snd_timer_info32 {
        u32 flags;
        s32 card;
@@ -32,6 +45,19 @@ struct snd_timer_info32 {
        unsigned char reserved[64];
 };
 
+static int snd_timer_user_gparams_compat(struct file *file,
+                                       struct snd_timer_gparams32 __user *user)
+{
+       struct snd_timer_gparams gparams;
+
+       if (copy_from_user(&gparams.tid, &user->tid, sizeof(gparams.tid)) ||
+           get_user(gparams.period_num, &user->period_num) ||
+           get_user(gparams.period_den, &user->period_den))
+               return -EFAULT;
+
+       return timer_set_gparams(&gparams);
+}
+
 static int snd_timer_user_info_compat(struct file *file,
                                      struct snd_timer_info32 __user *_info)
 {
@@ -99,6 +125,7 @@ static int snd_timer_user_status_compat(struct file *file,
  */
 
 enum {
+       SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32),
        SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
        SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32),
 #ifdef CONFIG_X86_X32
@@ -114,7 +141,6 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
        case SNDRV_TIMER_IOCTL_PVERSION:
        case SNDRV_TIMER_IOCTL_TREAD:
        case SNDRV_TIMER_IOCTL_GINFO:
-       case SNDRV_TIMER_IOCTL_GPARAMS:
        case SNDRV_TIMER_IOCTL_GSTATUS:
        case SNDRV_TIMER_IOCTL_SELECT:
        case SNDRV_TIMER_IOCTL_PARAMS:
@@ -128,6 +154,8 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
        case SNDRV_TIMER_IOCTL_PAUSE_OLD:
        case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
                return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
+       case SNDRV_TIMER_IOCTL_GPARAMS32:
+               return snd_timer_user_gparams_compat(file, argp);
        case SNDRV_TIMER_IOCTL_INFO32:
                return snd_timer_user_info_compat(file, argp);
        case SNDRV_TIMER_IOCTL_STATUS32:
index 845d5e5..ec4db3a 100644 (file)
@@ -446,18 +446,12 @@ end:
 
 void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 {
-       struct reg_params tx_params, rx_params;
-
-       snd_dice_transaction_clear_enable(dice);
+       unsigned int i;
 
-       if (get_register_params(dice, &tx_params, &rx_params) == 0) {
-               stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
-               stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
+       for (i = 0; i < MAX_STREAMS; i++) {
+               destroy_stream(dice, AMDTP_IN_STREAM, i);
+               destroy_stream(dice, AMDTP_OUT_STREAM, i);
        }
-
-       release_resources(dice);
-
-       dice->substreams_counter = 0;
 }
 
 void snd_dice_stream_update_duplex(struct snd_dice *dice)
index 2624cfe..b680be0 100644 (file)
@@ -2361,6 +2361,10 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0xaae8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaae0),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaaf0),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        /* VIA VT8251/VT8237A */
        { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
        /* VIA GFX VT7122/VX900 */
index 4f5ca0b..fefe83f 100644 (file)
@@ -4759,6 +4759,7 @@ enum {
        ALC255_FIXUP_DELL_SPK_NOISE,
        ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
        ALC280_FIXUP_HP_HEADSET_MIC,
+       ALC221_FIXUP_HP_FRONT_MIC,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5401,6 +5402,13 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MIC,
        },
+       [ALC221_FIXUP_HP_FRONT_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x02a19020 }, /* Front Mic */
+                       { }
+               },
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5506,6 +5514,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -6406,6 +6415,7 @@ enum {
        ALC668_FIXUP_AUTO_MUTE,
        ALC668_FIXUP_DELL_DISABLE_AAMIX,
        ALC668_FIXUP_DELL_XPS13,
+       ALC662_FIXUP_ASUS_Nx50,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -6646,6 +6656,12 @@ static const struct hda_fixup alc662_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_bass_chmap,
        },
+       [ALC662_FIXUP_ASUS_Nx50] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_auto_mute_via_amp,
+               .chained = true,
+               .chain_id = ALC662_FIXUP_BASS_1A
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -6668,8 +6684,9 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
-       SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A),
+       SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
        SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
+       SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
        SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
        SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
        SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
index fb62bce..6178bb5 100644 (file)
@@ -150,6 +150,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
                usb_audio_err(chip, "cannot memdup\n");
                return -ENOMEM;
        }
+       INIT_LIST_HEAD(&fp->list);
        if (fp->nr_rates > MAX_NR_RATES) {
                kfree(fp);
                return -EINVAL;
@@ -193,6 +194,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
        return 0;
 
  error:
+       list_del(&fp->list); /* unlink for avoiding double-free */
        kfree(fp);
        kfree(rate_table);
        return err;
@@ -469,6 +471,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
        fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
        fp->datainterval = 0;
        fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+       INIT_LIST_HEAD(&fp->list);
 
        switch (fp->maxpacksize) {
        case 0x120:
@@ -492,6 +495,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
                ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
        err = snd_usb_add_audio_stream(chip, stream, fp);
        if (err < 0) {
+               list_del(&fp->list); /* unlink for avoiding double-free */
                kfree(fp);
                return err;
        }
index 51258a1..6fe7f21 100644 (file)
@@ -316,7 +316,9 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
 /*
  * add this endpoint to the chip instance.
  * if a stream with the same endpoint already exists, append to it.
- * if not, create a new pcm stream.
+ * if not, create a new pcm stream. note, fp is added to the substream
+ * fmt_list and will be freed on the chip instance release. do not free
+ * fp or do remove it from the substream fmt_list to avoid double-free.
  */
 int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                             int stream,
@@ -677,6 +679,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                                        * (fp->maxpacksize & 0x7ff);
                fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
                fp->clock = clock;
+               INIT_LIST_HEAD(&fp->list);
 
                /* some quirks for attributes here */
 
@@ -725,6 +728,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
                err = snd_usb_add_audio_stream(chip, stream, fp);
                if (err < 0) {
+                       list_del(&fp->list); /* unlink for avoiding double-free */
                        kfree(fp->rate_table);
                        kfree(fp->chmap);
                        kfree(fp);