]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 20 Dec 2016 23:19:55 +0000 (15:19 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 20 Dec 2016 23:19:55 +0000 (15:19 -0800)
Pull i2c fixes from Wolfram Sang.

* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: mux: mlxcpld: fix i2c mux selection caching
  i2c: designware: fix wrong Tx/Rx FIFO for ACPI
  i2c: xgene: Fix missing code of DTB support
  i2c: mux: pca954x: fix i2c mux selection caching
  i2c: octeon: thunderx: Limit register access retries

528 files changed:
Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration
Documentation/DocBook/Makefile
Documentation/DocBook/crypto-API.tmpl [deleted file]
Documentation/crypto/api-aead.rst [new file with mode: 0644]
Documentation/crypto/api-akcipher.rst [new file with mode: 0644]
Documentation/crypto/api-digest.rst [new file with mode: 0644]
Documentation/crypto/api-kpp.rst [new file with mode: 0644]
Documentation/crypto/api-rng.rst [new file with mode: 0644]
Documentation/crypto/api-samples.rst [new file with mode: 0644]
Documentation/crypto/api-skcipher.rst [new file with mode: 0644]
Documentation/crypto/api.rst [new file with mode: 0644]
Documentation/crypto/architecture.rst [new file with mode: 0644]
Documentation/crypto/devel-algos.rst [new file with mode: 0644]
Documentation/crypto/index.rst [new file with mode: 0644]
Documentation/crypto/intro.rst [new file with mode: 0644]
Documentation/crypto/userspace-if.rst [new file with mode: 0644]
Documentation/devicetree/bindings/input/da9062-onkey.txt
Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt
Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
Documentation/devicetree/bindings/mfd/altera-a10sr.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt
Documentation/devicetree/bindings/mfd/rn5t618.txt
Documentation/devicetree/bindings/mtd/oxnas-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/tango-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/tps65218.txt
Documentation/devicetree/bindings/rtc/epson,rtc7301.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/twl-rtc.txt
Documentation/features/io/dma-api-debug/arch-support.txt
Documentation/features/io/dma-contiguous/arch-support.txt
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
Documentation/index.rst
Documentation/sphinx/rstFlatTable.py
Documentation/virtual/kvm/locking.txt
MAINTAINERS
arch/arm/mach-s3c24xx/common-smdk.c
arch/arm/mach-s3c24xx/mach-anubis.c
arch/arm/mach-s3c24xx/mach-at2440evb.c
arch/arm/mach-s3c24xx/mach-bast.c
arch/arm/mach-s3c24xx/mach-gta02.c
arch/arm/mach-s3c24xx/mach-jive.c
arch/arm/mach-s3c24xx/mach-mini2440.c
arch/arm/mach-s3c24xx/mach-osiris.c
arch/arm/mach-s3c24xx/mach-qt2410.c
arch/arm/mach-s3c24xx/mach-rx1950.c
arch/arm/mach-s3c24xx/mach-rx3715.c
arch/arm/mach-s3c24xx/mach-vstms.c
arch/arm/mach-s3c64xx/mach-hmt.c
arch/arm/mach-s3c64xx/mach-mini6410.c
arch/arm/mach-s3c64xx/mach-real6410.c
arch/arm64/include/asm/numa.h
arch/arm64/mm/numa.c
arch/ia64/include/asm/numa.h
arch/microblaze/include/asm/unistd.h
arch/microblaze/include/uapi/asm/unistd.h
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/syscall_table.S
arch/microblaze/kernel/timer.c
arch/mips/boot/dts/ingenic/jz4740.dtsi
arch/mips/boot/dts/ingenic/qi_lb60.dts
arch/mips/include/asm/mach-jz4740/platform.h
arch/mips/jz4740/board-qi_lb60.c
arch/mips/jz4740/platform.c
arch/mips/jz4740/reset.c
arch/powerpc/oprofile/cell/spu_task_sync.c
arch/tile/include/asm/cache.h
arch/tile/include/asm/sections.h
arch/tile/kernel/module.c
arch/tile/kernel/pci.c
arch/tile/kernel/pci_gx.c
arch/tile/kernel/setup.c
arch/tile/kernel/smp.c
arch/tile/kernel/time.c
arch/tile/kernel/unaligned.c
arch/tile/lib/cacheflush.c
arch/tile/mm/extable.c
arch/tile/mm/fault.c
arch/tile/mm/homecache.c
arch/tile/mm/init.c
arch/x86/Kconfig
arch/x86/include/asm/asm-prototypes.h [new file with mode: 0644]
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/floppy.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mmu.h
arch/x86/include/asm/mpx.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/tsc.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/head_64.S
arch/x86/kernel/process.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tsc.c
arch/x86/kernel/tsc_msr.c
arch/x86/kernel/tsc_sync.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/hyperv.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/fault.c
arch/x86/mm/init_64.c
arch/x86/mm/mpx.c
arch/x86/mm/numa.c
arch/x86/platform/Makefile
arch/x86/platform/intel-mid/mfld.c
arch/x86/platform/intel-mid/mrfld.c
arch/x86/platform/mellanox/Makefile [deleted file]
arch/x86/platform/mellanox/mlx-platform.c [deleted file]
arch/x86/power/cpu.c
arch/x86/xen/smp.c
arch/xtensa/Kconfig
arch/xtensa/boot/dts/kc705.dts
arch/xtensa/include/asm/Kbuild
arch/xtensa/kernel/Makefile
arch/xtensa/kernel/pci-dma.c
arch/xtensa/kernel/s32c1i_selftest.c [new file with mode: 0644]
arch/xtensa/kernel/setup.c
arch/xtensa/mm/init.c
crypto/algif_aead.c
drivers/acpi/numa.c
drivers/dax/dax.c
drivers/dax/pmem.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-tps65218.c
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/gvt/Makefile
drivers/gpu/drm/i915/gvt/gvt.h
drivers/gpu/drm/i915/gvt/kvmgt.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/lpc32xx-keys.c
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/keyboard/tca8418_keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/bma150.c
drivers/input/misc/da9063_onkey.c
drivers/input/misc/drv260x.c
drivers/input/misc/drv2665.c
drivers/input/misc/drv2667.c
drivers/input/misc/soc_button_array.c
drivers/input/misc/tps65218-pwrbutton.c
drivers/input/mouse/alps.c
drivers/input/mouse/alps.h
drivers/input/mouse/elan_i2c_core.c
drivers/input/rmi4/Kconfig
drivers/input/rmi4/Makefile
drivers/input/rmi4/rmi_2d_sensor.c
drivers/input/rmi4/rmi_2d_sensor.h
drivers/input/rmi4/rmi_bus.c
drivers/input/rmi4/rmi_bus.h
drivers/input/rmi4/rmi_driver.c
drivers/input/rmi4/rmi_driver.h
drivers/input/rmi4/rmi_f01.c
drivers/input/rmi4/rmi_f03.c [new file with mode: 0644]
drivers/input/rmi4/rmi_f11.c
drivers/input/rmi4/rmi_f12.c
drivers/input/rmi4/rmi_f30.c
drivers/input/rmi4/rmi_f34.c [new file with mode: 0644]
drivers/input/rmi4/rmi_f34.h [new file with mode: 0644]
drivers/input/rmi4/rmi_f34v7.c [new file with mode: 0644]
drivers/input/rmi4/rmi_f54.c
drivers/input/rmi4/rmi_f55.c [new file with mode: 0644]
drivers/input/rmi4/rmi_i2c.c
drivers/input/rmi4/rmi_smbus.c [new file with mode: 0644]
drivers/input/rmi4/rmi_spi.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/touchscreen/fsl-imx25-tcq.c
drivers/input/touchscreen/imx6ul_tsc.c
drivers/input/touchscreen/melfas_mip4.c
drivers/input/touchscreen/raydium_i2c_ts.c
drivers/input/touchscreen/silead.c
drivers/isdn/gigaset/bas-gigaset.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/gigaset/usb-gigaset.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/hisax.h
drivers/isdn/i4l/isdn_concap.c
drivers/isdn/i4l/isdn_x25iface.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab3100-core.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-sysctrl.c
drivers/mfd/abx500-core.c
drivers/mfd/arizona-core.c
drivers/mfd/arizona-irq.c
drivers/mfd/axp20x-i2c.c
drivers/mfd/axp20x.c
drivers/mfd/bcm590xx.c
drivers/mfd/cs47l24-tables.c
drivers/mfd/davinci_voicecodec.c
drivers/mfd/fsl-imx25-tsadc.c
drivers/mfd/hi655x-pmic.c
drivers/mfd/intel-lpss-pci.c
drivers/mfd/intel_soc_pmic_bxtwc.c
drivers/mfd/lpc_ich.c
drivers/mfd/palmas.c
drivers/mfd/qcom-pm8xxx.c
drivers/mfd/rk808.c
drivers/mfd/rn5t618.c
drivers/mfd/si476x-i2c.c
drivers/mfd/sun4i-gpadc.c [new file with mode: 0644]
drivers/mfd/tc3589x.c
drivers/mfd/tps65217.c
drivers/mfd/tps65218.c
drivers/mfd/tps65912-core.c
drivers/mfd/wm5102-tables.c
drivers/mfd/wm8994-core.c
drivers/mtd/bcm47xxpart.c
drivers/mtd/devices/bcm47xxsflash.c
drivers/mtd/maps/sc520cdp.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdswap.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/cmx270_nand.c
drivers/mtd/nand/cs553x_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c
drivers/mtd/nand/denali_pci.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/hisi504_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mtk_nand.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nand_timings.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/oxnas_nand.c [new file with mode: 0644]
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/socrates_nand.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/tango_nand.c [new file with mode: 0644]
drivers/mtd/nand/tmio_nand.c
drivers/mtd/nand/vf610_nfc.c
drivers/mtd/spi-nor/cadence-quadspi.c
drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/spi-nor.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/ethernet/3com/3c515.c
drivers/net/ethernet/brocade/bna/bna_enet.c
drivers/net/ethernet/cadence/Kconfig
drivers/net/ethernet/cadence/Makefile
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb_pci.c [new file with mode: 0644]
drivers/net/ethernet/chelsio/cxgb/cxgb2.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/cirrus/ep93xx_eth.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/freescale/dpaa/Kconfig
drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
drivers/net/ethernet/hisilicon/hip04_eth.c
drivers/net/ethernet/hisilicon/hisi_femac.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/microchip/encx24j600-regmap.c
drivers/net/ethernet/microchip/encx24j600.c
drivers/net/ethernet/qlogic/qed/qed_iscsi.c
drivers/net/ethernet/qualcomm/emac/emac.c
drivers/net/ethernet/rdc/r6040.c
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/mcdi_port.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/gtp.c
drivers/net/irda/w83977af_ir.c
drivers/net/virtio_net.c
drivers/net/vrf.c
drivers/net/wan/lmc/lmc_media.c
drivers/nvdimm/claim.c
drivers/nvdimm/core.c
drivers/nvdimm/dimm.c
drivers/nvdimm/dimm_devs.c
drivers/nvdimm/e820.c
drivers/nvdimm/label.c
drivers/nvdimm/namespace_devs.c
drivers/nvdimm/nd.h
drivers/nvdimm/pfn_devs.c
drivers/nvdimm/pmem.c
drivers/nvdimm/region_devs.c
drivers/oprofile/buffer_sync.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_bxtwc_tmu.c [new file with mode: 0644]
drivers/platform/x86/mlx-platform.c [new file with mode: 0644]
drivers/platform/x86/surface3-wmi.c [new file with mode: 0644]
drivers/platform/x86/surface3_button.c [new file with mode: 0644]
drivers/regulator/tps65218-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-imxdi.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-lib.c
drivers/rtc/rtc-mcp795.c
drivers/rtc/rtc-pcf85063.c
drivers/rtc/rtc-r7301.c [new file with mode: 0644]
drivers/rtc/rtc-starfire.c
drivers/rtc/rtc-sun4v.c
drivers/rtc/rtc-twl.c
drivers/staging/lustre/lustre/llite/symlink.c
fs/9p/vfs_addr.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/affs/symlink.c
fs/autofs4/autofs_i.h
fs/autofs4/dev-ioctl.c
fs/autofs4/expire.c
fs/autofs4/root.c
fs/autofs4/symlink.c
fs/autofs4/waitq.c
fs/bad_inode.c
fs/btrfs/ctree.h
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/ceph/addr.c
fs/ceph/inode.c
fs/cifs/cifsfs.c
fs/coda/cnode.c
fs/configfs/symlink.c
fs/dcache.c
fs/dcookies.c
fs/ecryptfs/inode.c
fs/exofs/inode.c
fs/ext2/inode.c
fs/ext2/symlink.c
fs/ext4/super.c
fs/ext4/symlink.c
fs/f2fs/namei.c
fs/file_table.c
fs/fuse/dir.c
fs/gfs2/aops.c
fs/gfs2/inode.c
fs/hostfs/hostfs_kern.c
fs/internal.h
fs/jffs2/symlink.c
fs/jfs/symlink.c
fs/kernfs/symlink.c
fs/libfs.c
fs/minix/inode.c
fs/mount.h
fs/namei.c
fs/namespace.c
fs/ncpfs/inode.c
fs/nfs/file.c
fs/nfs/symlink.c
fs/nfsd/nfs4xdr.c
fs/nfsd/vfs.c
fs/nilfs2/namei.c
fs/notify/dnotify/dnotify.c
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify.h
fs/notify/fsnotify.c
fs/notify/inode_mark.c
fs/notify/inotify/inotify.h
fs/notify/inotify/inotify_fsnotify.c
fs/ocfs2/alloc.c
fs/ocfs2/aops.c
fs/ocfs2/file.c
fs/ocfs2/file.h
fs/ocfs2/inode.h
fs/ocfs2/move_extents.c
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/ocfs2/refcounttree.c
fs/ocfs2/refcounttree.h
fs/ocfs2/super.c
fs/ocfs2/symlink.c
fs/ocfs2/xattr.c
fs/orangefs/symlink.c
fs/overlayfs/inode.c
fs/proc/inode.c
fs/proc/self.c
fs/proc/thread_self.c
fs/quota/dquot.c
fs/quota/quota.c
fs/read_write.c
fs/reiserfs/namei.c
fs/reiserfs/super.c
fs/squashfs/symlink.c
fs/stat.c
fs/statfs.c
fs/super.c
fs/sysv/inode.c
fs/ubifs/file.c
fs/utimes.c
fs/xfs/xfs_file.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_reflink.c
include/asm-generic/asm-prototypes.h [new file with mode: 0644]
include/asm-generic/vmlinux.lds.h
include/crypto/aead.h
include/crypto/dh.h
include/crypto/ecdh.h
include/crypto/hash.h
include/crypto/kpp.h
include/crypto/skcipher.h
include/linux/audit.h
include/linux/bpf-cgroup.h
include/linux/bpf.h
include/linux/cpuhotplug.h
include/linux/cpumask.h
include/linux/crypto.h
include/linux/dcache.h
include/linux/dcookies.h
include/linux/file.h
include/linux/filter.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/fsnotify_backend.h
include/linux/gpio_keys.h
include/linux/mfd/axp20x.h
include/linux/mfd/davinci_voicecodec.h
include/linux/mfd/intel_soc_pmic.h
include/linux/mfd/rk808.h
include/linux/mfd/rn5t618.h
include/linux/mfd/sun4i-gpadc.h [new file with mode: 0644]
include/linux/mfd/tps65217.h
include/linux/mfd/tps65218.h
include/linux/mfd/tps65912.h
include/linux/miscdevice.h
include/linux/mm_types.h
include/linux/mount.h
include/linux/mtd/nand.h
include/linux/platform_data/drv260x-pdata.h [deleted file]
include/linux/platform_data/macb.h
include/linux/platform_data/mtd-nand-s3c2410.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/rmi.h
include/net/inet6_connection_sock.h
include/net/inet_connection_sock.h
include/net/netlink.h
init/Kconfig
kernel/audit.c
kernel/audit.h
kernel/audit_fsnotify.c
kernel/audit_tree.c
kernel/audit_watch.c
kernel/bpf/core.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cpu.c
kernel/irq/affinity.c
kernel/time/tick-broadcast.c
mm/shmem.c
net/atm/lec.c
net/atm/mpoa_caches.c
net/core/filter.c
net/decnet/dn_dev.c
net/ipv4/inet_connection_sock.c
net/ipv6/inet6_connection_sock.c
net/ipv6/route.c
net/irda/irnet/irnet.h
net/irda/irnet/irnet_ppp.h
net/irda/irproc.c
net/mac80211/key.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/sched/cls_flower.c
net/sctp/endpointola.c
net/sctp/socket.c
net/vmw_vsock/vmci_transport_notify.c
net/vmw_vsock/vmci_transport_notify_qstate.c
net/x25/sysctl_net_x25.c
samples/bpf/Makefile
samples/connector/Makefile
scripts/Makefile.build
scripts/adjust_autoksyms.sh
scripts/coccinelle/misc/boolconv.cocci [new file with mode: 0644]
scripts/coccinelle/misc/irqf_oneshot.cocci
scripts/genksyms/keywords.gperf
scripts/genksyms/keywords.hash.c_shipped
scripts/genksyms/parse.tab.c_shipped
scripts/genksyms/parse.tab.h_shipped
scripts/genksyms/parse.y
scripts/kallsyms.c
scripts/kconfig/nconf.c
scripts/kconfig/nconf.gui.c
scripts/kconfig/qconf.cc
scripts/link-vmlinux.sh
scripts/mod/modpost.c
scripts/package/builddeb
scripts/package/mkspec
tools/build/Makefile
tools/gpio/Makefile
tools/lib/api/Makefile
tools/lib/bpf/Makefile
tools/lib/lockdep/Makefile
tools/lib/subcmd/Makefile
tools/lib/traceevent/Makefile
tools/objtool/Makefile
tools/perf/Makefile.perf
tools/perf/tests/make
tools/power/cpupower/Makefile
tools/power/cpupower/debug/kernel/Makefile
tools/testing/nvdimm/test/nfit.c
tools/testing/selftests/bpf/test_verifier.c

index 4cf1e72222d9c449464c1f3cd07f2ac7508d9349..ec950c93e5c6998daf2ee497732f732a2182ec25 100644 (file)
@@ -1,8 +1,9 @@
-What:           Attribute for calibrating ST-Ericsson AB8500 Real Time Clock
+What:           /sys/class/rtc/rtc0/device/rtc_calibration
 Date:           Oct 2011
 KernelVersion:  3.0
 Contact:        Mark Godfrey <mark.godfrey@stericsson.com>
-Description:    The rtc_calibration attribute allows the userspace to
+Description:    Attribute for calibrating ST-Ericsson AB8500 Real Time Clock
+               The rtc_calibration attribute allows the userspace to
                 calibrate the AB8500.s 32KHz Real Time Clock.
                 Every 60 seconds the AB8500 will correct the RTC's value
                 by adding to it the value of this attribute.
index caab9039362f650bd77d66f8092cd8010b73405b..c75e5d6b8fa8d48b787eed2a0f926bc36fe0a930 100644 (file)
@@ -13,7 +13,7 @@ DOCBOOKS := z8530book.xml  \
            gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
            80211.xml sh.xml regulator.xml w1.xml \
-           writing_musb_glue_layer.xml crypto-API.xml iio.xml
+           writing_musb_glue_layer.xml iio.xml
 
 ifeq ($(DOCBOOKS),)
 
diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl
deleted file mode 100644 (file)
index 088b79c..0000000
+++ /dev/null
@@ -1,2092 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
-
-<book id="KernelCryptoAPI">
- <bookinfo>
-  <title>Linux Kernel Crypto API</title>
-
-  <authorgroup>
-   <author>
-    <firstname>Stephan</firstname>
-    <surname>Mueller</surname>
-    <affiliation>
-     <address>
-      <email>smueller@chronox.de</email>
-     </address>
-    </affiliation>
-   </author>
-   <author>
-    <firstname>Marek</firstname>
-    <surname>Vasut</surname>
-    <affiliation>
-     <address>
-      <email>marek@denx.de</email>
-     </address>
-    </affiliation>
-   </author>
-  </authorgroup>
-
-  <copyright>
-   <year>2014</year>
-   <holder>Stephan Mueller</holder>
-  </copyright>
-
-
-  <legalnotice>
-   <para>
-     This documentation 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.
-   </para>
-
-   <para>
-     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.
-   </para>
-
-   <para>
-     You should have received a copy of the GNU General Public
-     License along with this program; if not, write to the Free
-     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-     MA 02111-1307 USA
-   </para>
-
-   <para>
-     For more details see the file COPYING in the source
-     distribution of Linux.
-   </para>
-  </legalnotice>
- </bookinfo>
-
- <toc></toc>
-
- <chapter id="Intro">
-  <title>Kernel Crypto API Interface Specification</title>
-
-   <sect1><title>Introduction</title>
-
-    <para>
-     The kernel crypto API offers a rich set of cryptographic ciphers as
-     well as other data transformation mechanisms and methods to invoke
-     these. This document contains a description of the API and provides
-     example code.
-    </para>
-
-    <para>
-     To understand and properly use the kernel crypto API a brief
-     explanation of its structure is given. Based on the architecture,
-     the API can be separated into different components. Following the
-     architecture specification, hints to developers of ciphers are
-     provided. Pointers to the API function call  documentation are
-     given at the end.
-    </para>
-
-    <para>
-     The kernel crypto API refers to all algorithms as "transformations".
-     Therefore, a cipher handle variable usually has the name "tfm".
-     Besides cryptographic operations, the kernel crypto API also knows
-     compression transformations and handles them the same way as ciphers.
-    </para>
-
-    <para>
-     The kernel crypto API serves the following entity types:
-
-     <itemizedlist>
-      <listitem>
-       <para>consumers requesting cryptographic services</para>
-      </listitem>
-      <listitem>
-      <para>data transformation implementations (typically ciphers)
-       that can be called by consumers using the kernel crypto
-       API</para>
-      </listitem>
-     </itemizedlist>
-    </para>
-
-    <para>
-     This specification is intended for consumers of the kernel crypto
-     API as well as for developers implementing ciphers. This API
-     specification, however, does not discuss all API calls available
-     to data transformation implementations (i.e. implementations of
-     ciphers and other transformations (such as CRC or even compression
-     algorithms) that can register with the kernel crypto API).
-    </para>
-
-    <para>
-     Note: The terms "transformation" and cipher algorithm are used
-     interchangeably.
-    </para>
-   </sect1>
-
-   <sect1><title>Terminology</title>
-    <para>
-     The transformation implementation is an actual code or interface
-     to hardware which implements a certain transformation with precisely
-     defined behavior.
-    </para>
-
-    <para>
-     The transformation object (TFM) is an instance of a transformation
-     implementation. There can be multiple transformation objects
-     associated with a single transformation implementation. Each of
-     those transformation objects is held by a crypto API consumer or
-     another transformation. Transformation object is allocated when a
-     crypto API consumer requests a transformation implementation.
-     The consumer is then provided with a structure, which contains
-     a transformation object (TFM).
-    </para>
-
-    <para>
-     The structure that contains transformation objects may also be
-     referred to as a "cipher handle". Such a cipher handle is always
-     subject to the following phases that are reflected in the API calls
-     applicable to such a cipher handle:
-    </para>
-
-    <orderedlist>
-     <listitem>
-      <para>Initialization of a cipher handle.</para>
-     </listitem>
-     <listitem>
-      <para>Execution of all intended cipher operations applicable
-      for the handle where the cipher handle must be furnished to
-      every API call.</para>
-     </listitem>
-     <listitem>
-      <para>Destruction of a cipher handle.</para>
-     </listitem>
-    </orderedlist>
-
-    <para>
-     When using the initialization API calls, a cipher handle is
-     created and returned to the consumer. Therefore, please refer
-     to all initialization API calls that refer to the data
-     structure type a consumer is expected to receive and subsequently
-     to use. The initialization API calls have all the same naming
-     conventions of crypto_alloc_*.
-    </para>
-
-    <para>
-     The transformation context is private data associated with
-     the transformation object.
-    </para>
-   </sect1>
-  </chapter>
-
-  <chapter id="Architecture"><title>Kernel Crypto API Architecture</title>
-   <sect1><title>Cipher algorithm types</title>
-    <para>
-     The kernel crypto API provides different API calls for the
-     following cipher types:
-
-     <itemizedlist>
-      <listitem><para>Symmetric ciphers</para></listitem>
-      <listitem><para>AEAD ciphers</para></listitem>
-      <listitem><para>Message digest, including keyed message digest</para></listitem>
-      <listitem><para>Random number generation</para></listitem>
-      <listitem><para>User space interface</para></listitem>
-     </itemizedlist>
-    </para>
-   </sect1>
-
-   <sect1><title>Ciphers And Templates</title>
-    <para>
-     The kernel crypto API provides implementations of single block
-     ciphers and message digests. In addition, the kernel crypto API
-     provides numerous "templates" that can be used in conjunction
-     with the single block ciphers and message digests. Templates
-     include all types of block chaining mode, the HMAC mechanism, etc.
-    </para>
-
-    <para>
-     Single block ciphers and message digests can either be directly
-     used by a caller or invoked together with a template to form
-     multi-block ciphers or keyed message digests.
-    </para>
-
-    <para>
-     A single block cipher may even be called with multiple templates.
-     However, templates cannot be used without a single cipher.
-    </para>
-
-    <para>
-     See /proc/crypto and search for "name". For example:
-
-     <itemizedlist>
-      <listitem><para>aes</para></listitem>
-      <listitem><para>ecb(aes)</para></listitem>
-      <listitem><para>cmac(aes)</para></listitem>
-      <listitem><para>ccm(aes)</para></listitem>
-      <listitem><para>rfc4106(gcm(aes))</para></listitem>
-      <listitem><para>sha1</para></listitem>
-      <listitem><para>hmac(sha1)</para></listitem>
-      <listitem><para>authenc(hmac(sha1),cbc(aes))</para></listitem>
-     </itemizedlist>
-    </para>
-
-    <para>
-     In these examples, "aes" and "sha1" are the ciphers and all
-     others are the templates.
-    </para>
-   </sect1>
-
-   <sect1><title>Synchronous And Asynchronous Operation</title>
-    <para>
-     The kernel crypto API provides synchronous and asynchronous
-     API operations.
-    </para>
-
-    <para>
-     When using the synchronous API operation, the caller invokes
-     a cipher operation which is performed synchronously by the
-     kernel crypto API. That means, the caller waits until the
-     cipher operation completes. Therefore, the kernel crypto API
-     calls work like regular function calls. For synchronous
-     operation, the set of API calls is small and conceptually
-     similar to any other crypto library.
-    </para>
-
-    <para>
-     Asynchronous operation is provided by the kernel crypto API
-     which implies that the invocation of a cipher operation will
-     complete almost instantly. That invocation triggers the
-     cipher operation but it does not signal its completion. Before
-     invoking a cipher operation, the caller must provide a callback
-     function the kernel crypto API can invoke to signal the
-     completion of the cipher operation. Furthermore, the caller
-     must ensure it can handle such asynchronous events by applying
-     appropriate locking around its data. The kernel crypto API
-     does not perform any special serialization operation to protect
-     the caller's data integrity.
-    </para>
-   </sect1>
-
-   <sect1><title>Crypto API Cipher References And Priority</title>
-    <para>
-     A cipher is referenced by the caller with a string. That string
-     has the following semantics:
-
-     <programlisting>
-       template(single block cipher)
-     </programlisting>
-
-     where "template" and "single block cipher" is the aforementioned
-     template and single block cipher, respectively. If applicable,
-     additional templates may enclose other templates, such as
-
-      <programlisting>
-       template1(template2(single block cipher)))
-      </programlisting>
-    </para>
-
-    <para>
-     The kernel crypto API may provide multiple implementations of a
-     template or a single block cipher. For example, AES on newer
-     Intel hardware has the following implementations: AES-NI,
-     assembler implementation, or straight C. Now, when using the
-     string "aes" with the kernel crypto API, which cipher
-     implementation is used? The answer to that question is the
-     priority number assigned to each cipher implementation by the
-     kernel crypto API. When a caller uses the string to refer to a
-     cipher during initialization of a cipher handle, the kernel
-     crypto API looks up all implementations providing an
-     implementation with that name and selects the implementation
-     with the highest priority.
-    </para>
-
-    <para>
-     Now, a caller may have the need to refer to a specific cipher
-     implementation and thus does not want to rely on the
-     priority-based selection. To accommodate this scenario, the
-     kernel crypto API allows the cipher implementation to register
-     a unique name in addition to common names. When using that
-     unique name, a caller is therefore always sure to refer to
-     the intended cipher implementation.
-    </para>
-
-    <para>
-     The list of available ciphers is given in /proc/crypto. However,
-     that list does not specify all possible permutations of
-     templates and ciphers. Each block listed in /proc/crypto may
-     contain the following information -- if one of the components
-     listed as follows are not applicable to a cipher, it is not
-     displayed:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>name: the generic name of the cipher that is subject
-       to the priority-based selection -- this name can be used by
-       the cipher allocation API calls (all names listed above are
-       examples for such generic names)</para>
-     </listitem>
-     <listitem>
-      <para>driver: the unique name of the cipher -- this name can
-       be used by the cipher allocation API calls</para>
-     </listitem>
-     <listitem>
-      <para>module: the kernel module providing the cipher
-       implementation (or "kernel" for statically linked ciphers)</para>
-     </listitem>
-     <listitem>
-      <para>priority: the priority value of the cipher implementation</para>
-     </listitem>
-     <listitem>
-      <para>refcnt: the reference count of the respective cipher
-       (i.e. the number of current consumers of this cipher)</para>
-     </listitem>
-     <listitem>
-      <para>selftest: specification whether the self test for the
-       cipher passed</para>
-     </listitem>
-     <listitem>
-      <para>type:
-       <itemizedlist>
-        <listitem>
-         <para>skcipher for symmetric key ciphers</para>
-        </listitem>
-        <listitem>
-         <para>cipher for single block ciphers that may be used with
-          an additional template</para>
-        </listitem>
-        <listitem>
-         <para>shash for synchronous message digest</para>
-        </listitem>
-        <listitem>
-         <para>ahash for asynchronous message digest</para>
-        </listitem>
-        <listitem>
-         <para>aead for AEAD cipher type</para>
-        </listitem>
-        <listitem>
-         <para>compression for compression type transformations</para>
-        </listitem>
-        <listitem>
-         <para>rng for random number generator</para>
-        </listitem>
-        <listitem>
-         <para>givcipher for cipher with associated IV generator
-          (see the geniv entry below for the specification of the
-          IV generator type used by the cipher implementation)</para>
-        </listitem>
-       </itemizedlist>
-      </para>
-     </listitem>
-     <listitem>
-      <para>blocksize: blocksize of cipher in bytes</para>
-     </listitem>
-     <listitem>
-      <para>keysize: key size in bytes</para>
-     </listitem>
-     <listitem>
-      <para>ivsize: IV size in bytes</para>
-     </listitem>
-     <listitem>
-      <para>seedsize: required size of seed data for random number
-       generator</para>
-     </listitem>
-     <listitem>
-      <para>digestsize: output size of the message digest</para>
-     </listitem>
-     <listitem>
-      <para>geniv: IV generation type:
-       <itemizedlist>
-        <listitem>
-         <para>eseqiv for encrypted sequence number based IV
-          generation</para>
-        </listitem>
-        <listitem>
-         <para>seqiv for sequence number based IV generation</para>
-        </listitem>
-        <listitem>
-         <para>chainiv for chain iv generation</para>
-        </listitem>
-        <listitem>
-         <para>&lt;builtin&gt; is a marker that the cipher implements
-          IV generation and handling as it is specific to the given
-          cipher</para>
-        </listitem>
-       </itemizedlist>
-      </para>
-     </listitem>
-    </itemizedlist>
-   </sect1>
-
-   <sect1><title>Key Sizes</title>
-    <para>
-     When allocating a cipher handle, the caller only specifies the
-     cipher type. Symmetric ciphers, however, typically support
-     multiple key sizes (e.g. AES-128 vs. AES-192 vs. AES-256).
-     These key sizes are determined with the length of the provided
-     key. Thus, the kernel crypto API does not provide a separate
-     way to select the particular symmetric cipher key size.
-    </para>
-   </sect1>
-
-   <sect1><title>Cipher Allocation Type And Masks</title>
-    <para>
-     The different cipher handle allocation functions allow the
-     specification of a type and mask flag. Both parameters have
-     the following meaning (and are therefore not covered in the
-     subsequent sections).
-    </para>
-
-    <para>
-     The type flag specifies the type of the cipher algorithm.
-     The caller usually provides a 0 when the caller wants the
-     default handling. Otherwise, the caller may provide the
-     following selections which match the aforementioned cipher
-     types:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_CIPHER Single block cipher</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_COMPRESS Compression</para>
-     </listitem>
-     <listitem>
-     <para>CRYPTO_ALG_TYPE_AEAD Authenticated Encryption with
-      Associated Data (MAC)</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_BLKCIPHER Synchronous multi-block cipher</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_ABLKCIPHER Asynchronous multi-block cipher</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_GIVCIPHER Asynchronous multi-block
-       cipher packed together with an IV generator (see geniv field
-       in the /proc/crypto listing for the known IV generators)</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_DIGEST Raw message digest</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_HASH Alias for CRYPTO_ALG_TYPE_DIGEST</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_SHASH Synchronous multi-block hash</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_AHASH Asynchronous multi-block hash</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_RNG Random Number Generation</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_AKCIPHER Asymmetric cipher</para>
-     </listitem>
-     <listitem>
-      <para>CRYPTO_ALG_TYPE_PCOMPRESS Enhanced version of
-       CRYPTO_ALG_TYPE_COMPRESS allowing for segmented compression /
-       decompression instead of performing the operation on one
-       segment only. CRYPTO_ALG_TYPE_PCOMPRESS is intended to replace
-       CRYPTO_ALG_TYPE_COMPRESS once existing consumers are converted.</para>
-     </listitem>
-    </itemizedlist>
-
-    <para>
-     The mask flag restricts the type of cipher. The only allowed
-     flag is CRYPTO_ALG_ASYNC to restrict the cipher lookup function
-     to asynchronous ciphers. Usually, a caller provides a 0 for the
-     mask flag.
-    </para>
-
-    <para>
-     When the caller provides a mask and type specification, the
-     caller limits the search the kernel crypto API can perform for
-     a suitable cipher implementation for the given cipher name.
-     That means, even when a caller uses a cipher name that exists
-     during its initialization call, the kernel crypto API may not
-     select it due to the used type and mask field.
-    </para>
-   </sect1>
-
-   <sect1><title>Internal Structure of Kernel Crypto API</title>
-
-    <para>
-     The kernel crypto API has an internal structure where a cipher
-     implementation may use many layers and indirections. This section
-     shall help to clarify how the kernel crypto API uses
-     various components to implement the complete cipher.
-    </para>
-
-    <para>
-     The following subsections explain the internal structure based
-     on existing cipher implementations. The first section addresses
-     the most complex scenario where all other scenarios form a logical
-     subset.
-    </para>
-
-    <sect2><title>Generic AEAD Cipher Structure</title>
-
-     <para>
-      The following ASCII art decomposes the kernel crypto API layers
-      when using the AEAD cipher with the automated IV generation. The
-      shown example is used by the IPSEC layer.
-     </para>
-
-     <para>
-      For other use cases of AEAD ciphers, the ASCII art applies as
-      well, but the caller may not use the AEAD cipher with a separate
-      IV generator. In this case, the caller must generate the IV.
-     </para>
-
-     <para>
-      The depicted example decomposes the AEAD cipher of GCM(AES) based
-      on the generic C implementations (gcm.c, aes-generic.c, ctr.c,
-      ghash-generic.c, seqiv.c). The generic implementation serves as an
-      example showing the complete logic of the kernel crypto API.
-     </para>
-
-     <para>
-      It is possible that some streamlined cipher implementations (like
-      AES-NI) provide implementations merging aspects which in the view
-      of the kernel crypto API cannot be decomposed into layers any more.
-      In case of the AES-NI implementation, the CTR mode, the GHASH
-      implementation and the AES cipher are all merged into one cipher
-      implementation registered with the kernel crypto API. In this case,
-      the concept described by the following ASCII art applies too. However,
-      the decomposition of GCM into the individual sub-components
-      by the kernel crypto API is not done any more.
-     </para>
-
-     <para>
-      Each block in the following ASCII art is an independent cipher
-      instance obtained from the kernel crypto API. Each block
-      is accessed by the caller or by other blocks using the API functions
-      defined by the kernel crypto API for the cipher implementation type.
-     </para>
-
-     <para>
-      The blocks below indicate the cipher type as well as the specific
-      logic implemented in the cipher.
-     </para>
-
-     <para>
-      The ASCII art picture also indicates the call structure, i.e. who
-      calls which component. The arrows point to the invoked block
-      where the caller uses the API applicable to the cipher type
-      specified for the block.
-     </para>
-
-     <programlisting>
-<![CDATA[
-kernel crypto API                                |   IPSEC Layer
-                                                 |
-+-----------+                                    |
-|           |            (1)
-|   aead    | <-----------------------------------  esp_output
-|  (seqiv)  | ---+
-+-----------+    |
-                 | (2)
-+-----------+    |
-|           | <--+                (2)
-|   aead    | <-----------------------------------  esp_input
-|   (gcm)   | ------------+
-+-----------+             |
-      | (3)               | (5)
-      v                   v
-+-----------+       +-----------+
-|           |       |           |
-|  skcipher |       |   ahash   |
-|   (ctr)   | ---+  |  (ghash)  |
-+-----------+    |  +-----------+
-                 |
-+-----------+    | (4)
-|           | <--+
-|   cipher  |
-|   (aes)   |
-+-----------+
-]]>
-     </programlisting>
-
-     <para>
-      The following call sequence is applicable when the IPSEC layer
-      triggers an encryption operation with the esp_output function. During
-      configuration, the administrator set up the use of rfc4106(gcm(aes)) as
-      the cipher for ESP. The following call sequence is now depicted in the
-      ASCII art above:
-     </para>
-
-     <orderedlist>
-      <listitem>
-       <para>
-        esp_output() invokes crypto_aead_encrypt() to trigger an encryption
-        operation of the AEAD cipher with IV generator.
-       </para>
-
-       <para>
-        In case of GCM, the SEQIV implementation is registered as GIVCIPHER
-        in crypto_rfc4106_alloc().
-       </para>
-
-       <para>
-        The SEQIV performs its operation to generate an IV where the core
-        function is seqiv_geniv().
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Now, SEQIV uses the AEAD API function calls to invoke the associated
-        AEAD cipher. In our case, during the instantiation of SEQIV, the
-        cipher handle for GCM is provided to SEQIV. This means that SEQIV
-        invokes AEAD cipher operations with the GCM cipher handle.
-       </para>
-
-       <para>
-        During instantiation of the GCM handle, the CTR(AES) and GHASH
-        ciphers are instantiated. The cipher handles for CTR(AES) and GHASH
-        are retained for later use.
-       </para>
-
-       <para>
-        The GCM implementation is responsible to invoke the CTR mode AES and
-        the GHASH cipher in the right manner to implement the GCM
-        specification.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        The GCM AEAD cipher type implementation now invokes the SKCIPHER API
-        with the instantiated CTR(AES) cipher handle.
-       </para>
-
-       <para>
-       During instantiation of the CTR(AES) cipher, the CIPHER type
-       implementation of AES is instantiated. The cipher handle for AES is
-       retained.
-       </para>
-
-       <para>
-        That means that the SKCIPHER implementation of CTR(AES) only
-        implements the CTR block chaining mode. After performing the block
-        chaining operation, the CIPHER implementation of AES is invoked.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        The SKCIPHER of CTR(AES) now invokes the CIPHER API with the AES
-        cipher handle to encrypt one block.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        The GCM AEAD implementation also invokes the GHASH cipher
-        implementation via the AHASH API.
-       </para>
-      </listitem>
-     </orderedlist>
-
-     <para>
-      When the IPSEC layer triggers the esp_input() function, the same call
-      sequence is followed with the only difference that the operation starts
-      with step (2).
-     </para>
-    </sect2>
-
-    <sect2><title>Generic Block Cipher Structure</title>
-     <para>
-      Generic block ciphers follow the same concept as depicted with the ASCII
-      art picture above.
-     </para>
-
-     <para>
-      For example, CBC(AES) is implemented with cbc.c, and aes-generic.c. The
-      ASCII art picture above applies as well with the difference that only
-      step (4) is used and the SKCIPHER block chaining mode is CBC.
-     </para>
-    </sect2>
-
-    <sect2><title>Generic Keyed Message Digest Structure</title>
-     <para>
-      Keyed message digest implementations again follow the same concept as
-      depicted in the ASCII art picture above.
-     </para>
-
-     <para>
-      For example, HMAC(SHA256) is implemented with hmac.c and
-      sha256_generic.c. The following ASCII art illustrates the
-      implementation:
-     </para>
-
-     <programlisting>
-<![CDATA[
-kernel crypto API            |       Caller
-                             |
-+-----------+         (1)    |
-|           | <------------------  some_function
-|   ahash   |
-|   (hmac)  | ---+
-+-----------+    |
-                 | (2)
-+-----------+    |
-|           | <--+
-|   shash   |
-|  (sha256) |
-+-----------+
-]]>
-     </programlisting>
-
-     <para>
-      The following call sequence is applicable when a caller triggers
-      an HMAC operation:
-     </para>
-
-     <orderedlist>
-      <listitem>
-       <para>
-        The AHASH API functions are invoked by the caller. The HMAC
-        implementation performs its operation as needed.
-       </para>
-
-       <para>
-        During initialization of the HMAC cipher, the SHASH cipher type of
-        SHA256 is instantiated. The cipher handle for the SHA256 instance is
-        retained.
-       </para>
-
-       <para>
-        At one time, the HMAC implementation requires a SHA256 operation
-        where the SHA256 cipher handle is used.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        The HMAC instance now invokes the SHASH API with the SHA256
-        cipher handle to calculate the message digest.
-       </para>
-      </listitem>
-     </orderedlist>
-    </sect2>
-   </sect1>
-  </chapter>
-
-  <chapter id="Development"><title>Developing Cipher Algorithms</title>
-   <sect1><title>Registering And Unregistering Transformation</title>
-    <para>
-     There are three distinct types of registration functions in
-     the Crypto API. One is used to register a generic cryptographic
-     transformation, while the other two are specific to HASH
-     transformations and COMPRESSion. We will discuss the latter
-     two in a separate chapter, here we will only look at the
-     generic ones.
-    </para>
-
-    <para>
-     Before discussing the register functions, the data structure
-     to be filled with each, struct crypto_alg, must be considered
-     -- see below for a description of this data structure.
-    </para>
-
-    <para>
-     The generic registration functions can be found in
-     include/linux/crypto.h and their definition can be seen below.
-     The former function registers a single transformation, while
-     the latter works on an array of transformation descriptions.
-     The latter is useful when registering transformations in bulk,
-     for example when a driver implements multiple transformations.
-    </para>
-
-    <programlisting>
-   int crypto_register_alg(struct crypto_alg *alg);
-   int crypto_register_algs(struct crypto_alg *algs, int count);
-    </programlisting>
-
-    <para>
-     The counterparts to those functions are listed below.
-    </para>
-
-    <programlisting>
-   int crypto_unregister_alg(struct crypto_alg *alg);
-   int crypto_unregister_algs(struct crypto_alg *algs, int count);
-    </programlisting>
-
-    <para>
-     Notice that both registration and unregistration functions
-     do return a value, so make sure to handle errors. A return
-     code of zero implies success. Any return code &lt; 0 implies
-     an error.
-    </para>
-
-    <para>
-     The bulk registration/unregistration functions
-     register/unregister each transformation in the given array of
-     length count.  They handle errors as follows:
-    </para>
-    <itemizedlist>
-     <listitem>
-      <para>
-       crypto_register_algs() succeeds if and only if it
-       successfully registers all the given transformations. If an
-       error occurs partway through, then it rolls back successful
-       registrations before returning the error code. Note that if
-       a driver needs to handle registration errors for individual
-       transformations, then it will need to use the non-bulk
-       function crypto_register_alg() instead.
-      </para>
-     </listitem>
-     <listitem>
-      <para>
-       crypto_unregister_algs() tries to unregister all the given
-       transformations, continuing on error. It logs errors and
-       always returns zero.
-      </para>
-     </listitem>
-    </itemizedlist>
-
-   </sect1>
-
-   <sect1><title>Single-Block Symmetric Ciphers [CIPHER]</title>
-    <para>
-     Example of transformations: aes, arc4, ...
-    </para>
-
-    <para>
-     This section describes the simplest of all transformation
-     implementations, that being the CIPHER type used for symmetric
-     ciphers. The CIPHER type is used for transformations which
-     operate on exactly one block at a time and there are no
-     dependencies between blocks at all.
-    </para>
-
-    <sect2><title>Registration specifics</title>
-     <para>
-      The registration of [CIPHER] algorithm is specific in that
-      struct crypto_alg field .cra_type is empty. The .cra_u.cipher
-      has to be filled in with proper callbacks to implement this
-      transformation.
-     </para>
-
-     <para>
-      See struct cipher_alg below.
-     </para>
-    </sect2>
-
-    <sect2><title>Cipher Definition With struct cipher_alg</title>
-     <para>
-      Struct cipher_alg defines a single block cipher.
-     </para>
-
-     <para>
-      Here are schematics of how these functions are called when
-      operated from other part of the kernel. Note that the
-      .cia_setkey() call might happen before or after any of these
-      schematics happen, but must not happen during any of these
-      are in-flight.
-     </para>
-
-     <para>
-      <programlisting>
-         KEY ---.    PLAINTEXT ---.
-                v                 v
-          .cia_setkey() -&gt; .cia_encrypt()
-                                  |
-                                  '-----&gt; CIPHERTEXT
-      </programlisting>
-     </para>
-
-     <para>
-      Please note that a pattern where .cia_setkey() is called
-      multiple times is also valid:
-     </para>
-
-     <para>
-      <programlisting>
-
-  KEY1 --.    PLAINTEXT1 --.         KEY2 --.    PLAINTEXT2 --.
-         v                 v                v                 v
-   .cia_setkey() -&gt; .cia_encrypt() -&gt; .cia_setkey() -&gt; .cia_encrypt()
-                           |                                  |
-                           '---&gt; CIPHERTEXT1                  '---&gt; CIPHERTEXT2
-      </programlisting>
-     </para>
-
-    </sect2>
-   </sect1>
-
-   <sect1><title>Multi-Block Ciphers</title>
-    <para>
-     Example of transformations: cbc(aes), ecb(arc4), ...
-    </para>
-
-    <para>
-     This section describes the multi-block cipher transformation
-     implementations. The multi-block ciphers are
-     used for transformations which operate on scatterlists of
-     data supplied to the transformation functions. They output
-     the result into a scatterlist of data as well.
-    </para>
-
-    <sect2><title>Registration Specifics</title>
-
-     <para>
-      The registration of multi-block cipher algorithms
-      is one of the most standard procedures throughout the crypto API.
-     </para>
-
-     <para>
-      Note, if a cipher implementation requires a proper alignment
-      of data, the caller should use the functions of
-      crypto_skcipher_alignmask() to identify a memory alignment mask.
-      The kernel crypto API is able to process requests that are unaligned.
-      This implies, however, additional overhead as the kernel
-      crypto API needs to perform the realignment of the data which
-      may imply moving of data.
-     </para>
-    </sect2>
-
-    <sect2><title>Cipher Definition With struct blkcipher_alg and ablkcipher_alg</title>
-     <para>
-      Struct blkcipher_alg defines a synchronous block cipher whereas
-      struct ablkcipher_alg defines an asynchronous block cipher.
-     </para>
-
-     <para>
-      Please refer to the single block cipher description for schematics
-      of the block cipher usage.
-     </para>
-    </sect2>
-
-    <sect2><title>Specifics Of Asynchronous Multi-Block Cipher</title>
-     <para>
-      There are a couple of specifics to the asynchronous interface.
-     </para>
-
-     <para>
-      First of all, some of the drivers will want to use the
-      Generic ScatterWalk in case the hardware needs to be fed
-      separate chunks of the scatterlist which contains the
-      plaintext and will contain the ciphertext. Please refer
-      to the ScatterWalk interface offered by the Linux kernel
-      scatter / gather list implementation.
-     </para>
-    </sect2>
-   </sect1>
-
-   <sect1><title>Hashing [HASH]</title>
-
-    <para>
-     Example of transformations: crc32, md5, sha1, sha256,...
-    </para>
-
-    <sect2><title>Registering And Unregistering The Transformation</title>
-
-     <para>
-      There are multiple ways to register a HASH transformation,
-      depending on whether the transformation is synchronous [SHASH]
-      or asynchronous [AHASH] and the amount of HASH transformations
-      we are registering. You can find the prototypes defined in
-      include/crypto/internal/hash.h:
-     </para>
-
-     <programlisting>
-   int crypto_register_ahash(struct ahash_alg *alg);
-
-   int crypto_register_shash(struct shash_alg *alg);
-   int crypto_register_shashes(struct shash_alg *algs, int count);
-     </programlisting>
-
-     <para>
-      The respective counterparts for unregistering the HASH
-      transformation are as follows:
-     </para>
-
-     <programlisting>
-   int crypto_unregister_ahash(struct ahash_alg *alg);
-
-   int crypto_unregister_shash(struct shash_alg *alg);
-   int crypto_unregister_shashes(struct shash_alg *algs, int count);
-     </programlisting>
-    </sect2>
-
-    <sect2><title>Cipher Definition With struct shash_alg and ahash_alg</title>
-     <para>
-      Here are schematics of how these functions are called when
-      operated from other part of the kernel. Note that the .setkey()
-      call might happen before or after any of these schematics happen,
-      but must not happen during any of these are in-flight. Please note
-      that calling .init() followed immediately by .finish() is also a
-      perfectly valid transformation.
-     </para>
-
-     <programlisting>
-   I)   DATA -----------.
-                        v
-         .init() -&gt; .update() -&gt; .final()      ! .update() might not be called
-                     ^    |         |            at all in this scenario.
-                     '----'         '---&gt; HASH
-
-   II)  DATA -----------.-----------.
-                        v           v
-         .init() -&gt; .update() -&gt; .finup()      ! .update() may not be called
-                     ^    |         |            at all in this scenario.
-                     '----'         '---&gt; HASH
-
-   III) DATA -----------.
-                        v
-                    .digest()                  ! The entire process is handled
-                        |                        by the .digest() call.
-                        '---------------&gt; HASH
-     </programlisting>
-
-     <para>
-      Here is a schematic of how the .export()/.import() functions are
-      called when used from another part of the kernel.
-     </para>
-
-     <programlisting>
-   KEY--.                 DATA--.
-        v                       v                  ! .update() may not be called
-    .setkey() -&gt; .init() -&gt; .update() -&gt; .export()   at all in this scenario.
-                             ^     |         |
-                             '-----'         '--&gt; PARTIAL_HASH
-
-   ----------- other transformations happen here -----------
-
-   PARTIAL_HASH--.   DATA1--.
-                 v          v
-             .import -&gt; .update() -&gt; .final()     ! .update() may not be called
-                         ^    |         |           at all in this scenario.
-                         '----'         '--&gt; HASH1
-
-   PARTIAL_HASH--.   DATA2-.
-                 v         v
-             .import -&gt; .finup()
-                           |
-                           '---------------&gt; HASH2
-     </programlisting>
-    </sect2>
-
-    <sect2><title>Specifics Of Asynchronous HASH Transformation</title>
-     <para>
-      Some of the drivers will want to use the Generic ScatterWalk
-      in case the implementation needs to be fed separate chunks of the
-      scatterlist which contains the input data. The buffer containing
-      the resulting hash will always be properly aligned to
-      .cra_alignmask so there is no need to worry about this.
-     </para>
-    </sect2>
-   </sect1>
-  </chapter>
-
-  <chapter id="User"><title>User Space Interface</title>
-   <sect1><title>Introduction</title>
-    <para>
-     The concepts of the kernel crypto API visible to kernel space is fully
-     applicable to the user space interface as well. Therefore, the kernel
-     crypto API high level discussion for the in-kernel use cases applies
-     here as well.
-    </para>
-
-    <para>
-     The major difference, however, is that user space can only act as a
-     consumer and never as a provider of a transformation or cipher algorithm.
-    </para>
-
-    <para>
-     The following covers the user space interface exported by the kernel
-     crypto API. A working example of this description is libkcapi that
-     can be obtained from [1]. That library can be used by user space
-     applications that require cryptographic services from the kernel.
-    </para>
-
-    <para>
-     Some details of the in-kernel kernel crypto API aspects do not
-     apply to user space, however. This includes the difference between
-     synchronous and asynchronous invocations. The user space API call
-     is fully synchronous.
-    </para>
-
-    <para>
-     [1] <ulink url="http://www.chronox.de/libkcapi.html">http://www.chronox.de/libkcapi.html</ulink>
-    </para>
-
-   </sect1>
-
-   <sect1><title>User Space API General Remarks</title>
-    <para>
-     The kernel crypto API is accessible from user space. Currently,
-     the following ciphers are accessible:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>Message digest including keyed message digest (HMAC, CMAC)</para>
-     </listitem>
-
-     <listitem>
-      <para>Symmetric ciphers</para>
-     </listitem>
-
-     <listitem>
-      <para>AEAD ciphers</para>
-     </listitem>
-
-     <listitem>
-      <para>Random Number Generators</para>
-     </listitem>
-    </itemizedlist>
-
-    <para>
-     The interface is provided via socket type using the type AF_ALG.
-     In addition, the setsockopt option type is SOL_ALG. In case the
-     user space header files do not export these flags yet, use the
-     following macros:
-    </para>
-
-    <programlisting>
-#ifndef AF_ALG
-#define AF_ALG 38
-#endif
-#ifndef SOL_ALG
-#define SOL_ALG 279
-#endif
-    </programlisting>
-
-    <para>
-     A cipher is accessed with the same name as done for the in-kernel
-     API calls. This includes the generic vs. unique naming schema for
-     ciphers as well as the enforcement of priorities for generic names.
-    </para>
-
-    <para>
-     To interact with the kernel crypto API, a socket must be
-     created by the user space application. User space invokes the cipher
-     operation with the send()/write() system call family. The result of the
-     cipher operation is obtained with the read()/recv() system call family.
-    </para>
-
-    <para>
-     The following API calls assume that the socket descriptor
-     is already opened by the user space application and discusses only
-     the kernel crypto API specific invocations.
-    </para>
-
-    <para>
-     To initialize the socket interface, the following sequence has to
-     be performed by the consumer:
-    </para>
-
-    <orderedlist>
-     <listitem>
-      <para>
-       Create a socket of type AF_ALG with the struct sockaddr_alg
-       parameter specified below for the different cipher types.
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Invoke bind with the socket descriptor
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Invoke accept with the socket descriptor. The accept system call
-       returns a new file descriptor that is to be used to interact with
-       the particular cipher instance. When invoking send/write or recv/read
-       system calls to send data to the kernel or obtain data from the
-       kernel, the file descriptor returned by accept must be used.
-      </para>
-     </listitem>
-    </orderedlist>
-   </sect1>
-
-   <sect1><title>In-place Cipher operation</title>
-    <para>
-     Just like the in-kernel operation of the kernel crypto API, the user
-     space interface allows the cipher operation in-place. That means that
-     the input buffer used for the send/write system call and the output
-     buffer used by the read/recv system call may be one and the same.
-     This is of particular interest for symmetric cipher operations where a
-     copying of the output data to its final destination can be avoided.
-    </para>
-
-    <para>
-     If a consumer on the other hand wants to maintain the plaintext and
-     the ciphertext in different memory locations, all a consumer needs
-     to do is to provide different memory pointers for the encryption and
-     decryption operation.
-    </para>
-   </sect1>
-
-   <sect1><title>Message Digest API</title>
-    <para>
-     The message digest type to be used for the cipher operation is
-     selected when invoking the bind syscall. bind requires the caller
-     to provide a filled struct sockaddr data structure. This data
-     structure must be filled as follows:
-    </para>
-
-    <programlisting>
-struct sockaddr_alg sa = {
-       .salg_family = AF_ALG,
-       .salg_type = "hash", /* this selects the hash logic in the kernel */
-       .salg_name = "sha1" /* this is the cipher name */
-};
-    </programlisting>
-
-    <para>
-     The salg_type value "hash" applies to message digests and keyed
-     message digests. Though, a keyed message digest is referenced by
-     the appropriate salg_name. Please see below for the setsockopt
-     interface that explains how the key can be set for a keyed message
-     digest.
-    </para>
-
-    <para>
-     Using the send() system call, the application provides the data that
-     should be processed with the message digest. The send system call
-     allows the following flags to be specified:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>
-       MSG_MORE: If this flag is set, the send system call acts like a
-       message digest update function where the final hash is not
-       yet calculated. If the flag is not set, the send system call
-       calculates the final message digest immediately.
-      </para>
-     </listitem>
-    </itemizedlist>
-
-    <para>
-     With the recv() system call, the application can read the message
-     digest from the kernel crypto API. If the buffer is too small for the
-     message digest, the flag MSG_TRUNC is set by the kernel.
-    </para>
-
-    <para>
-     In order to set a message digest key, the calling application must use
-     the setsockopt() option of ALG_SET_KEY. If the key is not set the HMAC
-     operation is performed without the initial HMAC state change caused by
-     the key.
-    </para>
-   </sect1>
-
-   <sect1><title>Symmetric Cipher API</title>
-    <para>
-     The operation is very similar to the message digest discussion.
-     During initialization, the struct sockaddr data structure must be
-     filled as follows:
-    </para>
-
-    <programlisting>
-struct sockaddr_alg sa = {
-       .salg_family = AF_ALG,
-       .salg_type = "skcipher", /* this selects the symmetric cipher */
-       .salg_name = "cbc(aes)" /* this is the cipher name */
-};
-    </programlisting>
-
-    <para>
-     Before data can be sent to the kernel using the write/send system
-     call family, the consumer must set the key. The key setting is
-     described with the setsockopt invocation below.
-    </para>
-
-    <para>
-     Using the sendmsg() system call, the application provides the data that should be processed for encryption or decryption. In addition, the IV is
-     specified with the data structure provided by the sendmsg() system call.
-    </para>
-
-    <para>
-     The sendmsg system call parameter of struct msghdr is embedded into the
-     struct cmsghdr data structure. See recv(2) and cmsg(3) for more
-     information on how the cmsghdr data structure is used together with the
-     send/recv system call family. That cmsghdr data structure holds the
-     following information specified with a separate header instances:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>
-       specification of the cipher operation type with one of these flags:
-      </para>
-      <itemizedlist>
-       <listitem>
-        <para>ALG_OP_ENCRYPT - encryption of data</para>
-       </listitem>
-       <listitem>
-        <para>ALG_OP_DECRYPT - decryption of data</para>
-       </listitem>
-      </itemizedlist>
-     </listitem>
-
-     <listitem>
-      <para>
-       specification of the IV information marked with the flag ALG_SET_IV
-      </para>
-     </listitem>
-    </itemizedlist>
-
-    <para>
-     The send system call family allows the following flag to be specified:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>
-       MSG_MORE: If this flag is set, the send system call acts like a
-       cipher update function where more input data is expected
-       with a subsequent invocation of the send system call.
-      </para>
-     </listitem>
-    </itemizedlist>
-
-    <para>
-     Note: The kernel reports -EINVAL for any unexpected data. The caller
-     must make sure that all data matches the constraints given in
-     /proc/crypto for the selected cipher.
-    </para>
-
-    <para>
-     With the recv() system call, the application can read the result of
-     the cipher operation from the kernel crypto API. The output buffer
-     must be at least as large as to hold all blocks of the encrypted or
-     decrypted data. If the output data size is smaller, only as many
-     blocks are returned that fit into that output buffer size.
-    </para>
-   </sect1>
-
-   <sect1><title>AEAD Cipher API</title>
-    <para>
-     The operation is very similar to the symmetric cipher discussion.
-     During initialization, the struct sockaddr data structure must be
-     filled as follows:
-    </para>
-
-    <programlisting>
-struct sockaddr_alg sa = {
-       .salg_family = AF_ALG,
-       .salg_type = "aead", /* this selects the symmetric cipher */
-       .salg_name = "gcm(aes)" /* this is the cipher name */
-};
-    </programlisting>
-
-    <para>
-     Before data can be sent to the kernel using the write/send system
-     call family, the consumer must set the key. The key setting is
-     described with the setsockopt invocation below.
-    </para>
-
-    <para>
-     In addition, before data can be sent to the kernel using the
-     write/send system call family, the consumer must set the authentication
-     tag size. To set the authentication tag size, the caller must use the
-     setsockopt invocation described below.
-    </para>
-
-    <para>
-     Using the sendmsg() system call, the application provides the data that should be processed for encryption or decryption. In addition, the IV is
-     specified with the data structure provided by the sendmsg() system call.
-    </para>
-
-    <para>
-     The sendmsg system call parameter of struct msghdr is embedded into the
-     struct cmsghdr data structure. See recv(2) and cmsg(3) for more
-     information on how the cmsghdr data structure is used together with the
-     send/recv system call family. That cmsghdr data structure holds the
-     following information specified with a separate header instances:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>
-       specification of the cipher operation type with one of these flags:
-      </para>
-      <itemizedlist>
-       <listitem>
-        <para>ALG_OP_ENCRYPT - encryption of data</para>
-       </listitem>
-       <listitem>
-        <para>ALG_OP_DECRYPT - decryption of data</para>
-       </listitem>
-      </itemizedlist>
-     </listitem>
-
-     <listitem>
-      <para>
-       specification of the IV information marked with the flag ALG_SET_IV
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       specification of the associated authentication data (AAD) with the
-       flag ALG_SET_AEAD_ASSOCLEN. The AAD is sent to the kernel together
-       with the plaintext / ciphertext. See below for the memory structure.
-      </para>
-     </listitem>
-    </itemizedlist>
-
-    <para>
-     The send system call family allows the following flag to be specified:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>
-       MSG_MORE: If this flag is set, the send system call acts like a
-       cipher update function where more input data is expected
-       with a subsequent invocation of the send system call.
-      </para>
-     </listitem>
-    </itemizedlist>
-
-    <para>
-     Note: The kernel reports -EINVAL for any unexpected data. The caller
-     must make sure that all data matches the constraints given in
-     /proc/crypto for the selected cipher.
-    </para>
-
-    <para>
-     With the recv() system call, the application can read the result of
-     the cipher operation from the kernel crypto API. The output buffer
-     must be at least as large as defined with the memory structure below.
-     If the output data size is smaller, the cipher operation is not performed.
-    </para>
-
-    <para>
-     The authenticated decryption operation may indicate an integrity error.
-     Such breach in integrity is marked with the -EBADMSG error code.
-    </para>
-
-    <sect2><title>AEAD Memory Structure</title>
-     <para>
-      The AEAD cipher operates with the following information that
-      is communicated between user and kernel space as one data stream:
-     </para>
-
-     <itemizedlist>
-      <listitem>
-       <para>plaintext or ciphertext</para>
-      </listitem>
-
-      <listitem>
-       <para>associated authentication data (AAD)</para>
-      </listitem>
-
-      <listitem>
-       <para>authentication tag</para>
-      </listitem>
-     </itemizedlist>
-
-     <para>
-      The sizes of the AAD and the authentication tag are provided with
-      the sendmsg and setsockopt calls (see there). As the kernel knows
-      the size of the entire data stream, the kernel is now able to
-      calculate the right offsets of the data components in the data
-      stream.
-     </para>
-
-     <para>
-      The user space caller must arrange the aforementioned information
-      in the following order:
-     </para>
-
-     <itemizedlist>
-      <listitem>
-       <para>
-        AEAD encryption input: AAD || plaintext
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        AEAD decryption input: AAD || ciphertext || authentication tag
-       </para>
-      </listitem>
-     </itemizedlist>
-
-     <para>
-      The output buffer the user space caller provides must be at least as
-      large to hold the following data:
-     </para>
-
-     <itemizedlist>
-      <listitem>
-       <para>
-        AEAD encryption output: ciphertext || authentication tag
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        AEAD decryption output: plaintext
-       </para>
-      </listitem>
-     </itemizedlist>
-    </sect2>
-   </sect1>
-
-   <sect1><title>Random Number Generator API</title>
-    <para>
-     Again, the operation is very similar to the other APIs.
-     During initialization, the struct sockaddr data structure must be
-     filled as follows:
-    </para>
-
-    <programlisting>
-struct sockaddr_alg sa = {
-       .salg_family = AF_ALG,
-       .salg_type = "rng", /* this selects the symmetric cipher */
-       .salg_name = "drbg_nopr_sha256" /* this is the cipher name */
-};
-    </programlisting>
-
-    <para>
-     Depending on the RNG type, the RNG must be seeded. The seed is provided
-     using the setsockopt interface to set the key. For example, the
-     ansi_cprng requires a seed. The DRBGs do not require a seed, but
-     may be seeded.
-    </para>
-
-    <para>
-     Using the read()/recvmsg() system calls, random numbers can be obtained.
-     The kernel generates at most 128 bytes in one call. If user space
-     requires more data, multiple calls to read()/recvmsg() must be made.
-    </para>
-
-    <para>
-     WARNING: The user space caller may invoke the initially mentioned
-     accept system call multiple times. In this case, the returned file
-     descriptors have the same state.
-    </para>
-
-   </sect1>
-
-   <sect1><title>Zero-Copy Interface</title>
-    <para>
-     In addition to the send/write/read/recv system call family, the AF_ALG
-     interface can be accessed with the zero-copy interface of splice/vmsplice.
-     As the name indicates, the kernel tries to avoid a copy operation into
-     kernel space.
-    </para>
-
-    <para>
-     The zero-copy operation requires data to be aligned at the page boundary.
-     Non-aligned data can be used as well, but may require more operations of
-     the kernel which would defeat the speed gains obtained from the zero-copy
-     interface.
-    </para>
-
-    <para>
-     The system-interent limit for the size of one zero-copy operation is
-     16 pages. If more data is to be sent to AF_ALG, user space must slice
-     the input into segments with a maximum size of 16 pages.
-    </para>
-
-    <para>
-     Zero-copy can be used with the following code example (a complete working
-     example is provided with libkcapi):
-    </para>
-
-    <programlisting>
-int pipes[2];
-
-pipe(pipes);
-/* input data in iov */
-vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT);
-/* opfd is the file descriptor returned from accept() system call */
-splice(pipes[0], NULL, opfd, NULL, ret, 0);
-read(opfd, out, outlen);
-    </programlisting>
-
-   </sect1>
-
-   <sect1><title>Setsockopt Interface</title>
-    <para>
-     In addition to the read/recv and send/write system call handling
-     to send and retrieve data subject to the cipher operation, a consumer
-     also needs to set the additional information for the cipher operation.
-     This additional information is set using the setsockopt system call
-     that must be invoked with the file descriptor of the open cipher
-     (i.e. the file descriptor returned by the accept system call).
-    </para>
-
-    <para>
-     Each setsockopt invocation must use the level SOL_ALG.
-    </para>
-
-    <para>
-     The setsockopt interface allows setting the following data using
-     the mentioned optname:
-    </para>
-
-    <itemizedlist>
-     <listitem>
-      <para>
-       ALG_SET_KEY -- Setting the key. Key setting is applicable to:
-      </para>
-      <itemizedlist>
-       <listitem>
-        <para>the skcipher cipher type (symmetric ciphers)</para>
-       </listitem>
-       <listitem>
-        <para>the hash cipher type (keyed message digests)</para>
-       </listitem>
-       <listitem>
-        <para>the AEAD cipher type</para>
-       </listitem>
-       <listitem>
-        <para>the RNG cipher type to provide the seed</para>
-       </listitem>
-      </itemizedlist>
-     </listitem>
-
-     <listitem>
-      <para>
-       ALG_SET_AEAD_AUTHSIZE -- Setting the authentication tag size
-       for AEAD ciphers. For a encryption operation, the authentication
-       tag of the given size will be generated. For a decryption operation,
-       the provided ciphertext is assumed to contain an authentication tag
-       of the given size (see section about AEAD memory layout below).
-      </para>
-     </listitem>
-    </itemizedlist>
-
-   </sect1>
-
-   <sect1><title>User space API example</title>
-    <para>
-     Please see [1] for libkcapi which provides an easy-to-use wrapper
-     around the aforementioned Netlink kernel interface. [1] also contains
-     a test application that invokes all libkcapi API calls.
-    </para>
-
-    <para>
-     [1] <ulink url="http://www.chronox.de/libkcapi.html">http://www.chronox.de/libkcapi.html</ulink>
-    </para>
-
-   </sect1>
-
-  </chapter>
-
-  <chapter id="API"><title>Programming Interface</title>
-   <para>
-    Please note that the kernel crypto API contains the AEAD givcrypt
-    API (crypto_aead_giv* and aead_givcrypt_* function calls in
-    include/crypto/aead.h). This API is obsolete and will be removed
-    in the future. To obtain the functionality of an AEAD cipher with
-    internal IV generation, use the IV generator as a regular cipher.
-    For example, rfc4106(gcm(aes)) is the AEAD cipher with external
-    IV generation and seqniv(rfc4106(gcm(aes))) implies that the kernel
-    crypto API generates the IV. Different IV generators are available.
-   </para>
-   <sect1><title>Block Cipher Context Data Structures</title>
-!Pinclude/linux/crypto.h Block Cipher Context Data Structures
-!Finclude/crypto/aead.h aead_request
-   </sect1>
-   <sect1><title>Block Cipher Algorithm Definitions</title>
-!Pinclude/linux/crypto.h Block Cipher Algorithm Definitions
-!Finclude/linux/crypto.h crypto_alg
-!Finclude/linux/crypto.h ablkcipher_alg
-!Finclude/crypto/aead.h aead_alg
-!Finclude/linux/crypto.h blkcipher_alg
-!Finclude/linux/crypto.h cipher_alg
-!Finclude/crypto/rng.h rng_alg
-   </sect1>
-   <sect1><title>Symmetric Key Cipher API</title>
-!Pinclude/crypto/skcipher.h Symmetric Key Cipher API
-!Finclude/crypto/skcipher.h crypto_alloc_skcipher
-!Finclude/crypto/skcipher.h crypto_free_skcipher
-!Finclude/crypto/skcipher.h crypto_has_skcipher
-!Finclude/crypto/skcipher.h crypto_skcipher_ivsize
-!Finclude/crypto/skcipher.h crypto_skcipher_blocksize
-!Finclude/crypto/skcipher.h crypto_skcipher_setkey
-!Finclude/crypto/skcipher.h crypto_skcipher_reqtfm
-!Finclude/crypto/skcipher.h crypto_skcipher_encrypt
-!Finclude/crypto/skcipher.h crypto_skcipher_decrypt
-   </sect1>
-   <sect1><title>Symmetric Key Cipher Request Handle</title>
-!Pinclude/crypto/skcipher.h Symmetric Key Cipher Request Handle
-!Finclude/crypto/skcipher.h crypto_skcipher_reqsize
-!Finclude/crypto/skcipher.h skcipher_request_set_tfm
-!Finclude/crypto/skcipher.h skcipher_request_alloc
-!Finclude/crypto/skcipher.h skcipher_request_free
-!Finclude/crypto/skcipher.h skcipher_request_set_callback
-!Finclude/crypto/skcipher.h skcipher_request_set_crypt
-   </sect1>
-   <sect1><title>Asynchronous Block Cipher API - Deprecated</title>
-!Pinclude/linux/crypto.h Asynchronous Block Cipher API
-!Finclude/linux/crypto.h crypto_alloc_ablkcipher
-!Finclude/linux/crypto.h crypto_free_ablkcipher
-!Finclude/linux/crypto.h crypto_has_ablkcipher
-!Finclude/linux/crypto.h crypto_ablkcipher_ivsize
-!Finclude/linux/crypto.h crypto_ablkcipher_blocksize
-!Finclude/linux/crypto.h crypto_ablkcipher_setkey
-!Finclude/linux/crypto.h crypto_ablkcipher_reqtfm
-!Finclude/linux/crypto.h crypto_ablkcipher_encrypt
-!Finclude/linux/crypto.h crypto_ablkcipher_decrypt
-   </sect1>
-   <sect1><title>Asynchronous Cipher Request Handle - Deprecated</title>
-!Pinclude/linux/crypto.h Asynchronous Cipher Request Handle
-!Finclude/linux/crypto.h crypto_ablkcipher_reqsize
-!Finclude/linux/crypto.h ablkcipher_request_set_tfm
-!Finclude/linux/crypto.h ablkcipher_request_alloc
-!Finclude/linux/crypto.h ablkcipher_request_free
-!Finclude/linux/crypto.h ablkcipher_request_set_callback
-!Finclude/linux/crypto.h ablkcipher_request_set_crypt
-   </sect1>
-   <sect1><title>Authenticated Encryption With Associated Data (AEAD) Cipher API</title>
-!Pinclude/crypto/aead.h Authenticated Encryption With Associated Data (AEAD) Cipher API
-!Finclude/crypto/aead.h crypto_alloc_aead
-!Finclude/crypto/aead.h crypto_free_aead
-!Finclude/crypto/aead.h crypto_aead_ivsize
-!Finclude/crypto/aead.h crypto_aead_authsize
-!Finclude/crypto/aead.h crypto_aead_blocksize
-!Finclude/crypto/aead.h crypto_aead_setkey
-!Finclude/crypto/aead.h crypto_aead_setauthsize
-!Finclude/crypto/aead.h crypto_aead_encrypt
-!Finclude/crypto/aead.h crypto_aead_decrypt
-   </sect1>
-   <sect1><title>Asynchronous AEAD Request Handle</title>
-!Pinclude/crypto/aead.h Asynchronous AEAD Request Handle
-!Finclude/crypto/aead.h crypto_aead_reqsize
-!Finclude/crypto/aead.h aead_request_set_tfm
-!Finclude/crypto/aead.h aead_request_alloc
-!Finclude/crypto/aead.h aead_request_free
-!Finclude/crypto/aead.h aead_request_set_callback
-!Finclude/crypto/aead.h aead_request_set_crypt
-!Finclude/crypto/aead.h aead_request_set_ad
-   </sect1>
-   <sect1><title>Synchronous Block Cipher API - Deprecated</title>
-!Pinclude/linux/crypto.h Synchronous Block Cipher API
-!Finclude/linux/crypto.h crypto_alloc_blkcipher
-!Finclude/linux/crypto.h crypto_free_blkcipher
-!Finclude/linux/crypto.h crypto_has_blkcipher
-!Finclude/linux/crypto.h crypto_blkcipher_name
-!Finclude/linux/crypto.h crypto_blkcipher_ivsize
-!Finclude/linux/crypto.h crypto_blkcipher_blocksize
-!Finclude/linux/crypto.h crypto_blkcipher_setkey
-!Finclude/linux/crypto.h crypto_blkcipher_encrypt
-!Finclude/linux/crypto.h crypto_blkcipher_encrypt_iv
-!Finclude/linux/crypto.h crypto_blkcipher_decrypt
-!Finclude/linux/crypto.h crypto_blkcipher_decrypt_iv
-!Finclude/linux/crypto.h crypto_blkcipher_set_iv
-!Finclude/linux/crypto.h crypto_blkcipher_get_iv
-   </sect1>
-   <sect1><title>Single Block Cipher API</title>
-!Pinclude/linux/crypto.h Single Block Cipher API
-!Finclude/linux/crypto.h crypto_alloc_cipher
-!Finclude/linux/crypto.h crypto_free_cipher
-!Finclude/linux/crypto.h crypto_has_cipher
-!Finclude/linux/crypto.h crypto_cipher_blocksize
-!Finclude/linux/crypto.h crypto_cipher_setkey
-!Finclude/linux/crypto.h crypto_cipher_encrypt_one
-!Finclude/linux/crypto.h crypto_cipher_decrypt_one
-   </sect1>
-   <sect1><title>Message Digest Algorithm Definitions</title>
-!Pinclude/crypto/hash.h Message Digest Algorithm Definitions
-!Finclude/crypto/hash.h hash_alg_common
-!Finclude/crypto/hash.h ahash_alg
-!Finclude/crypto/hash.h shash_alg
-   </sect1>
-   <sect1><title>Asynchronous Message Digest API</title>
-!Pinclude/crypto/hash.h Asynchronous Message Digest API
-!Finclude/crypto/hash.h crypto_alloc_ahash
-!Finclude/crypto/hash.h crypto_free_ahash
-!Finclude/crypto/hash.h crypto_ahash_init
-!Finclude/crypto/hash.h crypto_ahash_digestsize
-!Finclude/crypto/hash.h crypto_ahash_reqtfm
-!Finclude/crypto/hash.h crypto_ahash_reqsize
-!Finclude/crypto/hash.h crypto_ahash_setkey
-!Finclude/crypto/hash.h crypto_ahash_finup
-!Finclude/crypto/hash.h crypto_ahash_final
-!Finclude/crypto/hash.h crypto_ahash_digest
-!Finclude/crypto/hash.h crypto_ahash_export
-!Finclude/crypto/hash.h crypto_ahash_import
-   </sect1>
-   <sect1><title>Asynchronous Hash Request Handle</title>
-!Pinclude/crypto/hash.h Asynchronous Hash Request Handle
-!Finclude/crypto/hash.h ahash_request_set_tfm
-!Finclude/crypto/hash.h ahash_request_alloc
-!Finclude/crypto/hash.h ahash_request_free
-!Finclude/crypto/hash.h ahash_request_set_callback
-!Finclude/crypto/hash.h ahash_request_set_crypt
-   </sect1>
-   <sect1><title>Synchronous Message Digest API</title>
-!Pinclude/crypto/hash.h Synchronous Message Digest API
-!Finclude/crypto/hash.h crypto_alloc_shash
-!Finclude/crypto/hash.h crypto_free_shash
-!Finclude/crypto/hash.h crypto_shash_blocksize
-!Finclude/crypto/hash.h crypto_shash_digestsize
-!Finclude/crypto/hash.h crypto_shash_descsize
-!Finclude/crypto/hash.h crypto_shash_setkey
-!Finclude/crypto/hash.h crypto_shash_digest
-!Finclude/crypto/hash.h crypto_shash_export
-!Finclude/crypto/hash.h crypto_shash_import
-!Finclude/crypto/hash.h crypto_shash_init
-!Finclude/crypto/hash.h crypto_shash_update
-!Finclude/crypto/hash.h crypto_shash_final
-!Finclude/crypto/hash.h crypto_shash_finup
-   </sect1>
-   <sect1><title>Crypto API Random Number API</title>
-!Pinclude/crypto/rng.h Random number generator API
-!Finclude/crypto/rng.h crypto_alloc_rng
-!Finclude/crypto/rng.h crypto_rng_alg
-!Finclude/crypto/rng.h crypto_free_rng
-!Finclude/crypto/rng.h crypto_rng_generate
-!Finclude/crypto/rng.h crypto_rng_get_bytes
-!Finclude/crypto/rng.h crypto_rng_reset
-!Finclude/crypto/rng.h crypto_rng_seedsize
-!Cinclude/crypto/rng.h
-   </sect1>
-   <sect1><title>Asymmetric Cipher API</title>
-!Pinclude/crypto/akcipher.h Generic Public Key API
-!Finclude/crypto/akcipher.h akcipher_alg
-!Finclude/crypto/akcipher.h akcipher_request
-!Finclude/crypto/akcipher.h crypto_alloc_akcipher
-!Finclude/crypto/akcipher.h crypto_free_akcipher
-!Finclude/crypto/akcipher.h crypto_akcipher_set_pub_key
-!Finclude/crypto/akcipher.h crypto_akcipher_set_priv_key
-   </sect1>
-   <sect1><title>Asymmetric Cipher Request Handle</title>
-!Finclude/crypto/akcipher.h akcipher_request_alloc
-!Finclude/crypto/akcipher.h akcipher_request_free
-!Finclude/crypto/akcipher.h akcipher_request_set_callback
-!Finclude/crypto/akcipher.h akcipher_request_set_crypt
-!Finclude/crypto/akcipher.h crypto_akcipher_maxsize
-!Finclude/crypto/akcipher.h crypto_akcipher_encrypt
-!Finclude/crypto/akcipher.h crypto_akcipher_decrypt
-!Finclude/crypto/akcipher.h crypto_akcipher_sign
-!Finclude/crypto/akcipher.h crypto_akcipher_verify
-   </sect1>
-  </chapter>
-
-  <chapter id="Code"><title>Code Examples</title>
-   <sect1><title>Code Example For Symmetric Key Cipher Operation</title>
-    <programlisting>
-
-struct tcrypt_result {
-       struct completion completion;
-       int err;
-};
-
-/* tie all data structures together */
-struct skcipher_def {
-       struct scatterlist sg;
-       struct crypto_skcipher *tfm;
-       struct skcipher_request *req;
-       struct tcrypt_result result;
-};
-
-/* Callback function */
-static void test_skcipher_cb(struct crypto_async_request *req, int error)
-{
-       struct tcrypt_result *result = req-&gt;data;
-
-       if (error == -EINPROGRESS)
-               return;
-       result-&gt;err = error;
-       complete(&amp;result-&gt;completion);
-       pr_info("Encryption finished successfully\n");
-}
-
-/* Perform cipher operation */
-static unsigned int test_skcipher_encdec(struct skcipher_def *sk,
-                                        int enc)
-{
-       int rc = 0;
-
-       if (enc)
-               rc = crypto_skcipher_encrypt(sk-&gt;req);
-       else
-               rc = crypto_skcipher_decrypt(sk-&gt;req);
-
-       switch (rc) {
-       case 0:
-               break;
-       case -EINPROGRESS:
-       case -EBUSY:
-               rc = wait_for_completion_interruptible(
-                       &amp;sk-&gt;result.completion);
-               if (!rc &amp;&amp; !sk-&gt;result.err) {
-                       reinit_completion(&amp;sk-&gt;result.completion);
-                       break;
-               }
-       default:
-               pr_info("skcipher encrypt returned with %d result %d\n",
-                       rc, sk-&gt;result.err);
-               break;
-       }
-       init_completion(&amp;sk-&gt;result.completion);
-
-       return rc;
-}
-
-/* Initialize and trigger cipher operation */
-static int test_skcipher(void)
-{
-       struct skcipher_def sk;
-       struct crypto_skcipher *skcipher = NULL;
-       struct skcipher_request *req = NULL;
-       char *scratchpad = NULL;
-       char *ivdata = NULL;
-       unsigned char key[32];
-       int ret = -EFAULT;
-
-       skcipher = crypto_alloc_skcipher("cbc-aes-aesni", 0, 0);
-       if (IS_ERR(skcipher)) {
-               pr_info("could not allocate skcipher handle\n");
-               return PTR_ERR(skcipher);
-       }
-
-       req = skcipher_request_alloc(skcipher, GFP_KERNEL);
-       if (!req) {
-               pr_info("could not allocate skcipher request\n");
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-                                     test_skcipher_cb,
-                                     &amp;sk.result);
-
-       /* AES 256 with random key */
-       get_random_bytes(&amp;key, 32);
-       if (crypto_skcipher_setkey(skcipher, key, 32)) {
-               pr_info("key could not be set\n");
-               ret = -EAGAIN;
-               goto out;
-       }
-
-       /* IV will be random */
-       ivdata = kmalloc(16, GFP_KERNEL);
-       if (!ivdata) {
-               pr_info("could not allocate ivdata\n");
-               goto out;
-       }
-       get_random_bytes(ivdata, 16);
-
-       /* Input data will be random */
-       scratchpad = kmalloc(16, GFP_KERNEL);
-       if (!scratchpad) {
-               pr_info("could not allocate scratchpad\n");
-               goto out;
-       }
-       get_random_bytes(scratchpad, 16);
-
-       sk.tfm = skcipher;
-       sk.req = req;
-
-       /* We encrypt one block */
-       sg_init_one(&amp;sk.sg, scratchpad, 16);
-       skcipher_request_set_crypt(req, &amp;sk.sg, &amp;sk.sg, 16, ivdata);
-       init_completion(&amp;sk.result.completion);
-
-       /* encrypt data */
-       ret = test_skcipher_encdec(&amp;sk, 1);
-       if (ret)
-               goto out;
-
-       pr_info("Encryption triggered successfully\n");
-
-out:
-       if (skcipher)
-               crypto_free_skcipher(skcipher);
-       if (req)
-               skcipher_request_free(req);
-       if (ivdata)
-               kfree(ivdata);
-       if (scratchpad)
-               kfree(scratchpad);
-       return ret;
-}
-    </programlisting>
-   </sect1>
-
-   <sect1><title>Code Example For Use of Operational State Memory With SHASH</title>
-    <programlisting>
-
-struct sdesc {
-       struct shash_desc shash;
-       char ctx[];
-};
-
-static struct sdescinit_sdesc(struct crypto_shash *alg)
-{
-       struct sdescsdesc;
-       int size;
-
-       size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
-       sdesc = kmalloc(size, GFP_KERNEL);
-       if (!sdesc)
-               return ERR_PTR(-ENOMEM);
-       sdesc-&gt;shash.tfm = alg;
-       sdesc-&gt;shash.flags = 0x0;
-       return sdesc;
-}
-
-static int calc_hash(struct crypto_shashalg,
-                    const unsigned chardata, unsigned int datalen,
-                    unsigned chardigest) {
-       struct sdescsdesc;
-       int ret;
-
-       sdesc = init_sdesc(alg);
-       if (IS_ERR(sdesc)) {
-               pr_info("trusted_key: can't alloc %s\n", hash_alg);
-               return PTR_ERR(sdesc);
-       }
-
-       ret = crypto_shash_digest(&amp;sdesc-&gt;shash, data, datalen, digest);
-       kfree(sdesc);
-       return ret;
-}
-    </programlisting>
-   </sect1>
-
-   <sect1><title>Code Example For Random Number Generator Usage</title>
-    <programlisting>
-
-static int get_random_numbers(u8 *buf, unsigned int len)
-{
-       struct crypto_rngrng = NULL;
-       chardrbg = "drbg_nopr_sha256"; /* Hash DRBG with SHA-256, no PR */
-       int ret;
-
-       if (!buf || !len) {
-               pr_debug("No output buffer provided\n");
-               return -EINVAL;
-       }
-
-       rng = crypto_alloc_rng(drbg, 0, 0);
-       if (IS_ERR(rng)) {
-               pr_debug("could not allocate RNG handle for %s\n", drbg);
-               return -PTR_ERR(rng);
-       }
-
-       ret = crypto_rng_get_bytes(rng, buf, len);
-       if (ret &lt; 0)
-               pr_debug("generation of random numbers failed\n");
-       else if (ret == 0)
-               pr_debug("RNG returned no data");
-       else
-               pr_debug("RNG returned %d bytes of data\n", ret);
-
-out:
-       crypto_free_rng(rng);
-       return ret;
-}
-    </programlisting>
-   </sect1>
-  </chapter>
- </book>
diff --git a/Documentation/crypto/api-aead.rst b/Documentation/crypto/api-aead.rst
new file mode 100644 (file)
index 0000000..d15256f
--- /dev/null
@@ -0,0 +1,23 @@
+Authenticated Encryption With Associated Data (AEAD) Algorithm Definitions
+--------------------------------------------------------------------------
+
+.. kernel-doc:: include/crypto/aead.h
+   :doc: Authenticated Encryption With Associated Data (AEAD) Cipher API
+
+.. kernel-doc:: include/crypto/aead.h
+   :functions: aead_request aead_alg
+
+Authenticated Encryption With Associated Data (AEAD) Cipher API
+---------------------------------------------------------------
+
+.. kernel-doc:: include/crypto/aead.h
+   :functions: crypto_alloc_aead crypto_free_aead crypto_aead_ivsize crypto_aead_authsize crypto_aead_blocksize crypto_aead_setkey crypto_aead_setauthsize crypto_aead_encrypt crypto_aead_decrypt
+
+Asynchronous AEAD Request Handle
+--------------------------------
+
+.. kernel-doc:: include/crypto/aead.h
+   :doc: Asynchronous AEAD Request Handle
+
+.. kernel-doc:: include/crypto/aead.h
+   :functions: crypto_aead_reqsize aead_request_set_tfm aead_request_alloc aead_request_free aead_request_set_callback aead_request_set_crypt aead_request_set_ad
diff --git a/Documentation/crypto/api-akcipher.rst b/Documentation/crypto/api-akcipher.rst
new file mode 100644 (file)
index 0000000..40aa874
--- /dev/null
@@ -0,0 +1,20 @@
+Asymmetric Cipher Algorithm Definitions
+---------------------------------------
+
+.. kernel-doc:: include/crypto/akcipher.h
+   :functions: akcipher_alg akcipher_request
+
+Asymmetric Cipher API
+---------------------
+
+.. kernel-doc:: include/crypto/akcipher.h
+   :doc: Generic Public Key API
+
+.. kernel-doc:: include/crypto/akcipher.h
+   :functions: crypto_alloc_akcipher crypto_free_akcipher crypto_akcipher_set_pub_key crypto_akcipher_set_priv_key crypto_akcipher_maxsize crypto_akcipher_encrypt crypto_akcipher_decrypt crypto_akcipher_sign crypto_akcipher_verify
+
+Asymmetric Cipher Request Handle
+--------------------------------
+
+.. kernel-doc:: include/crypto/akcipher.h
+   :functions: akcipher_request_alloc akcipher_request_free akcipher_request_set_callback akcipher_request_set_crypt
diff --git a/Documentation/crypto/api-digest.rst b/Documentation/crypto/api-digest.rst
new file mode 100644 (file)
index 0000000..07356fa
--- /dev/null
@@ -0,0 +1,35 @@
+Message Digest Algorithm Definitions
+------------------------------------
+
+.. kernel-doc:: include/crypto/hash.h
+   :doc: Message Digest Algorithm Definitions
+
+.. kernel-doc:: include/crypto/hash.h
+   :functions: hash_alg_common ahash_alg shash_alg
+
+Asynchronous Message Digest API
+-------------------------------
+
+.. kernel-doc:: include/crypto/hash.h
+   :doc: Asynchronous Message Digest API
+
+.. kernel-doc:: include/crypto/hash.h
+   :functions: crypto_alloc_ahash crypto_free_ahash crypto_ahash_init crypto_ahash_digestsize crypto_ahash_reqtfm crypto_ahash_reqsize crypto_ahash_setkey crypto_ahash_finup crypto_ahash_final crypto_ahash_digest crypto_ahash_export crypto_ahash_import
+
+Asynchronous Hash Request Handle
+--------------------------------
+
+.. kernel-doc:: include/crypto/hash.h
+   :doc: Asynchronous Hash Request Handle
+
+.. kernel-doc:: include/crypto/hash.h
+   :functions: ahash_request_set_tfm ahash_request_alloc ahash_request_free ahash_request_set_callback ahash_request_set_crypt
+
+Synchronous Message Digest API
+------------------------------
+
+.. kernel-doc:: include/crypto/hash.h
+   :doc: Synchronous Message Digest API
+
+.. kernel-doc:: include/crypto/hash.h
+   :functions: crypto_alloc_shash crypto_free_shash crypto_shash_blocksize crypto_shash_digestsize crypto_shash_descsize crypto_shash_setkey crypto_shash_digest crypto_shash_export crypto_shash_import crypto_shash_init crypto_shash_update crypto_shash_final crypto_shash_finup
diff --git a/Documentation/crypto/api-kpp.rst b/Documentation/crypto/api-kpp.rst
new file mode 100644 (file)
index 0000000..7d86ab9
--- /dev/null
@@ -0,0 +1,38 @@
+Key-agreement Protocol Primitives (KPP) Cipher Algorithm Definitions
+--------------------------------------------------------------------
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_request crypto_kpp kpp_alg kpp_secret
+
+Key-agreement Protocol Primitives (KPP) Cipher API
+--------------------------------------------------
+
+.. kernel-doc:: include/crypto/kpp.h
+   :doc: Generic Key-agreement Protocol Primitives API
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: crypto_alloc_kpp crypto_free_kpp crypto_kpp_set_secret crypto_kpp_generate_public_key crypto_kpp_compute_shared_secret crypto_kpp_maxsize
+
+Key-agreement Protocol Primitives (KPP) Cipher Request Handle
+-------------------------------------------------------------
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_request_alloc kpp_request_free kpp_request_set_callback kpp_request_set_input kpp_request_set_output
+
+ECDH Helper Functions
+---------------------
+
+.. kernel-doc:: include/crypto/ecdh.h
+   :doc: ECDH Helper Functions
+
+.. kernel-doc:: include/crypto/ecdh.h
+   :functions: ecdh crypto_ecdh_key_len crypto_ecdh_encode_key crypto_ecdh_decode_key
+
+DH Helper Functions
+-------------------
+
+.. kernel-doc:: include/crypto/dh.h
+   :doc: DH Helper Functions
+
+.. kernel-doc:: include/crypto/dh.h
+   :functions: dh crypto_dh_key_len crypto_dh_encode_key crypto_dh_decode_key
diff --git a/Documentation/crypto/api-rng.rst b/Documentation/crypto/api-rng.rst
new file mode 100644 (file)
index 0000000..10ba743
--- /dev/null
@@ -0,0 +1,14 @@
+Random Number Algorithm Definitions
+-----------------------------------
+
+.. kernel-doc:: include/crypto/rng.h
+   :functions: rng_alg
+
+Crypto API Random Number API
+----------------------------
+
+.. kernel-doc:: include/crypto/rng.h
+   :doc: Random number generator API
+
+.. kernel-doc:: include/crypto/rng.h
+   :functions: crypto_alloc_rng crypto_rng_alg crypto_free_rng crypto_rng_generate crypto_rng_get_bytes crypto_rng_reset crypto_rng_seedsize
diff --git a/Documentation/crypto/api-samples.rst b/Documentation/crypto/api-samples.rst
new file mode 100644 (file)
index 0000000..0a10819
--- /dev/null
@@ -0,0 +1,224 @@
+Code Examples
+=============
+
+Code Example For Symmetric Key Cipher Operation
+-----------------------------------------------
+
+::
+
+
+    struct tcrypt_result {
+        struct completion completion;
+        int err;
+    };
+
+    /* tie all data structures together */
+    struct skcipher_def {
+        struct scatterlist sg;
+        struct crypto_skcipher *tfm;
+        struct skcipher_request *req;
+        struct tcrypt_result result;
+    };
+
+    /* Callback function */
+    static void test_skcipher_cb(struct crypto_async_request *req, int error)
+    {
+        struct tcrypt_result *result = req->data;
+
+        if (error == -EINPROGRESS)
+            return;
+        result->err = error;
+        complete(&result->completion);
+        pr_info("Encryption finished successfully\n");
+    }
+
+    /* Perform cipher operation */
+    static unsigned int test_skcipher_encdec(struct skcipher_def *sk,
+                         int enc)
+    {
+        int rc = 0;
+
+        if (enc)
+            rc = crypto_skcipher_encrypt(sk->req);
+        else
+            rc = crypto_skcipher_decrypt(sk->req);
+
+        switch (rc) {
+        case 0:
+            break;
+        case -EINPROGRESS:
+        case -EBUSY:
+            rc = wait_for_completion_interruptible(
+                &sk->result.completion);
+            if (!rc && !sk->result.err) {
+                reinit_completion(&sk->result.completion);
+                break;
+            }
+        default:
+            pr_info("skcipher encrypt returned with %d result %d\n",
+                rc, sk->result.err);
+            break;
+        }
+        init_completion(&sk->result.completion);
+
+        return rc;
+    }
+
+    /* Initialize and trigger cipher operation */
+    static int test_skcipher(void)
+    {
+        struct skcipher_def sk;
+        struct crypto_skcipher *skcipher = NULL;
+        struct skcipher_request *req = NULL;
+        char *scratchpad = NULL;
+        char *ivdata = NULL;
+        unsigned char key[32];
+        int ret = -EFAULT;
+
+        skcipher = crypto_alloc_skcipher("cbc-aes-aesni", 0, 0);
+        if (IS_ERR(skcipher)) {
+            pr_info("could not allocate skcipher handle\n");
+            return PTR_ERR(skcipher);
+        }
+
+        req = skcipher_request_alloc(skcipher, GFP_KERNEL);
+        if (!req) {
+            pr_info("could not allocate skcipher request\n");
+            ret = -ENOMEM;
+            goto out;
+        }
+
+        skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                          test_skcipher_cb,
+                          &sk.result);
+
+        /* AES 256 with random key */
+        get_random_bytes(&key, 32);
+        if (crypto_skcipher_setkey(skcipher, key, 32)) {
+            pr_info("key could not be set\n");
+            ret = -EAGAIN;
+            goto out;
+        }
+
+        /* IV will be random */
+        ivdata = kmalloc(16, GFP_KERNEL);
+        if (!ivdata) {
+            pr_info("could not allocate ivdata\n");
+            goto out;
+        }
+        get_random_bytes(ivdata, 16);
+
+        /* Input data will be random */
+        scratchpad = kmalloc(16, GFP_KERNEL);
+        if (!scratchpad) {
+            pr_info("could not allocate scratchpad\n");
+            goto out;
+        }
+        get_random_bytes(scratchpad, 16);
+
+        sk.tfm = skcipher;
+        sk.req = req;
+
+        /* We encrypt one block */
+        sg_init_one(&sk.sg, scratchpad, 16);
+        skcipher_request_set_crypt(req, &sk.sg, &sk.sg, 16, ivdata);
+        init_completion(&sk.result.completion);
+
+        /* encrypt data */
+        ret = test_skcipher_encdec(&sk, 1);
+        if (ret)
+            goto out;
+
+        pr_info("Encryption triggered successfully\n");
+
+    out:
+        if (skcipher)
+            crypto_free_skcipher(skcipher);
+        if (req)
+            skcipher_request_free(req);
+        if (ivdata)
+            kfree(ivdata);
+        if (scratchpad)
+            kfree(scratchpad);
+        return ret;
+    }
+
+
+Code Example For Use of Operational State Memory With SHASH
+-----------------------------------------------------------
+
+::
+
+
+    struct sdesc {
+        struct shash_desc shash;
+        char ctx[];
+    };
+
+    static struct sdescinit_sdesc(struct crypto_shash *alg)
+    {
+        struct sdescsdesc;
+        int size;
+
+        size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
+        sdesc = kmalloc(size, GFP_KERNEL);
+        if (!sdesc)
+            return ERR_PTR(-ENOMEM);
+        sdesc->shash.tfm = alg;
+        sdesc->shash.flags = 0x0;
+        return sdesc;
+    }
+
+    static int calc_hash(struct crypto_shashalg,
+                 const unsigned chardata, unsigned int datalen,
+                 unsigned chardigest) {
+        struct sdescsdesc;
+        int ret;
+
+        sdesc = init_sdesc(alg);
+        if (IS_ERR(sdesc)) {
+            pr_info("trusted_key: can't alloc %s\n", hash_alg);
+            return PTR_ERR(sdesc);
+        }
+
+        ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
+        kfree(sdesc);
+        return ret;
+    }
+
+
+Code Example For Random Number Generator Usage
+----------------------------------------------
+
+::
+
+
+    static int get_random_numbers(u8 *buf, unsigned int len)
+    {
+        struct crypto_rngrng = NULL;
+        chardrbg = "drbg_nopr_sha256"; /* Hash DRBG with SHA-256, no PR */
+        int ret;
+
+        if (!buf || !len) {
+            pr_debug("No output buffer provided\n");
+            return -EINVAL;
+        }
+
+        rng = crypto_alloc_rng(drbg, 0, 0);
+        if (IS_ERR(rng)) {
+            pr_debug("could not allocate RNG handle for %s\n", drbg);
+            return -PTR_ERR(rng);
+        }
+
+        ret = crypto_rng_get_bytes(rng, buf, len);
+        if (ret < 0)
+            pr_debug("generation of random numbers failed\n");
+        else if (ret == 0)
+            pr_debug("RNG returned no data");
+        else
+            pr_debug("RNG returned %d bytes of data\n", ret);
+
+    out:
+        crypto_free_rng(rng);
+        return ret;
+    }
diff --git a/Documentation/crypto/api-skcipher.rst b/Documentation/crypto/api-skcipher.rst
new file mode 100644 (file)
index 0000000..b20028a
--- /dev/null
@@ -0,0 +1,62 @@
+Block Cipher Algorithm Definitions
+----------------------------------
+
+.. kernel-doc:: include/linux/crypto.h
+   :doc: Block Cipher Algorithm Definitions
+
+.. kernel-doc:: include/linux/crypto.h
+   :functions: crypto_alg ablkcipher_alg blkcipher_alg cipher_alg
+
+Symmetric Key Cipher API
+------------------------
+
+.. kernel-doc:: include/crypto/skcipher.h
+   :doc: Symmetric Key Cipher API
+
+.. kernel-doc:: include/crypto/skcipher.h
+   :functions: crypto_alloc_skcipher crypto_free_skcipher crypto_has_skcipher crypto_skcipher_ivsize crypto_skcipher_blocksize crypto_skcipher_setkey crypto_skcipher_reqtfm crypto_skcipher_encrypt crypto_skcipher_decrypt
+
+Symmetric Key Cipher Request Handle
+-----------------------------------
+
+.. kernel-doc:: include/crypto/skcipher.h
+   :doc: Symmetric Key Cipher Request Handle
+
+.. kernel-doc:: include/crypto/skcipher.h
+   :functions: crypto_skcipher_reqsize skcipher_request_set_tfm skcipher_request_alloc skcipher_request_free skcipher_request_set_callback skcipher_request_set_crypt
+
+Single Block Cipher API
+-----------------------
+
+.. kernel-doc:: include/linux/crypto.h
+   :doc: Single Block Cipher API
+
+.. kernel-doc:: include/linux/crypto.h
+   :functions: crypto_alloc_cipher crypto_free_cipher crypto_has_cipher crypto_cipher_blocksize crypto_cipher_setkey crypto_cipher_encrypt_one crypto_cipher_decrypt_one
+
+Asynchronous Block Cipher API - Deprecated
+------------------------------------------
+
+.. kernel-doc:: include/linux/crypto.h
+   :doc: Asynchronous Block Cipher API
+
+.. kernel-doc:: include/linux/crypto.h
+   :functions: crypto_free_ablkcipher crypto_has_ablkcipher crypto_ablkcipher_ivsize crypto_ablkcipher_blocksize crypto_ablkcipher_setkey crypto_ablkcipher_reqtfm crypto_ablkcipher_encrypt crypto_ablkcipher_decrypt
+
+Asynchronous Cipher Request Handle - Deprecated
+-----------------------------------------------
+
+.. kernel-doc:: include/linux/crypto.h
+   :doc: Asynchronous Cipher Request Handle
+
+.. kernel-doc:: include/linux/crypto.h
+   :functions: crypto_ablkcipher_reqsize ablkcipher_request_set_tfm ablkcipher_request_alloc ablkcipher_request_free ablkcipher_request_set_callback ablkcipher_request_set_crypt
+
+Synchronous Block Cipher API - Deprecated
+-----------------------------------------
+
+.. kernel-doc:: include/linux/crypto.h
+   :doc: Synchronous Block Cipher API
+
+.. kernel-doc:: include/linux/crypto.h
+   :functions: crypto_alloc_blkcipher rypto_free_blkcipher crypto_has_blkcipher crypto_blkcipher_name crypto_blkcipher_ivsize crypto_blkcipher_blocksize crypto_blkcipher_setkey crypto_blkcipher_encrypt crypto_blkcipher_encrypt_iv crypto_blkcipher_decrypt crypto_blkcipher_decrypt_iv crypto_blkcipher_set_iv crypto_blkcipher_get_iv
diff --git a/Documentation/crypto/api.rst b/Documentation/crypto/api.rst
new file mode 100644 (file)
index 0000000..2e51919
--- /dev/null
@@ -0,0 +1,25 @@
+Programming Interface
+=====================
+
+Please note that the kernel crypto API contains the AEAD givcrypt API
+(crypto_aead_giv\* and aead_givcrypt\* function calls in
+include/crypto/aead.h). This API is obsolete and will be removed in the
+future. To obtain the functionality of an AEAD cipher with internal IV
+generation, use the IV generator as a regular cipher. For example,
+rfc4106(gcm(aes)) is the AEAD cipher with external IV generation and
+seqniv(rfc4106(gcm(aes))) implies that the kernel crypto API generates
+the IV. Different IV generators are available.
+
+.. class:: toc-title
+
+          Table of contents
+
+.. toctree::
+   :maxdepth: 2
+
+   api-skcipher
+   api-aead
+   api-digest
+   api-rng
+   api-akcipher
+   api-kpp
diff --git a/Documentation/crypto/architecture.rst b/Documentation/crypto/architecture.rst
new file mode 100644 (file)
index 0000000..ca2d09b
--- /dev/null
@@ -0,0 +1,441 @@
+Kernel Crypto API Architecture
+==============================
+
+Cipher algorithm types
+----------------------
+
+The kernel crypto API provides different API calls for the following
+cipher types:
+
+-  Symmetric ciphers
+
+-  AEAD ciphers
+
+-  Message digest, including keyed message digest
+
+-  Random number generation
+
+-  User space interface
+
+Ciphers And Templates
+---------------------
+
+The kernel crypto API provides implementations of single block ciphers
+and message digests. In addition, the kernel crypto API provides
+numerous "templates" that can be used in conjunction with the single
+block ciphers and message digests. Templates include all types of block
+chaining mode, the HMAC mechanism, etc.
+
+Single block ciphers and message digests can either be directly used by
+a caller or invoked together with a template to form multi-block ciphers
+or keyed message digests.
+
+A single block cipher may even be called with multiple templates.
+However, templates cannot be used without a single cipher.
+
+See /proc/crypto and search for "name". For example:
+
+-  aes
+
+-  ecb(aes)
+
+-  cmac(aes)
+
+-  ccm(aes)
+
+-  rfc4106(gcm(aes))
+
+-  sha1
+
+-  hmac(sha1)
+
+-  authenc(hmac(sha1),cbc(aes))
+
+In these examples, "aes" and "sha1" are the ciphers and all others are
+the templates.
+
+Synchronous And Asynchronous Operation
+--------------------------------------
+
+The kernel crypto API provides synchronous and asynchronous API
+operations.
+
+When using the synchronous API operation, the caller invokes a cipher
+operation which is performed synchronously by the kernel crypto API.
+That means, the caller waits until the cipher operation completes.
+Therefore, the kernel crypto API calls work like regular function calls.
+For synchronous operation, the set of API calls is small and
+conceptually similar to any other crypto library.
+
+Asynchronous operation is provided by the kernel crypto API which
+implies that the invocation of a cipher operation will complete almost
+instantly. That invocation triggers the cipher operation but it does not
+signal its completion. Before invoking a cipher operation, the caller
+must provide a callback function the kernel crypto API can invoke to
+signal the completion of the cipher operation. Furthermore, the caller
+must ensure it can handle such asynchronous events by applying
+appropriate locking around its data. The kernel crypto API does not
+perform any special serialization operation to protect the caller's data
+integrity.
+
+Crypto API Cipher References And Priority
+-----------------------------------------
+
+A cipher is referenced by the caller with a string. That string has the
+following semantics:
+
+::
+
+        template(single block cipher)
+
+
+where "template" and "single block cipher" is the aforementioned
+template and single block cipher, respectively. If applicable,
+additional templates may enclose other templates, such as
+
+::
+
+        template1(template2(single block cipher)))
+
+
+The kernel crypto API may provide multiple implementations of a template
+or a single block cipher. For example, AES on newer Intel hardware has
+the following implementations: AES-NI, assembler implementation, or
+straight C. Now, when using the string "aes" with the kernel crypto API,
+which cipher implementation is used? The answer to that question is the
+priority number assigned to each cipher implementation by the kernel
+crypto API. When a caller uses the string to refer to a cipher during
+initialization of a cipher handle, the kernel crypto API looks up all
+implementations providing an implementation with that name and selects
+the implementation with the highest priority.
+
+Now, a caller may have the need to refer to a specific cipher
+implementation and thus does not want to rely on the priority-based
+selection. To accommodate this scenario, the kernel crypto API allows
+the cipher implementation to register a unique name in addition to
+common names. When using that unique name, a caller is therefore always
+sure to refer to the intended cipher implementation.
+
+The list of available ciphers is given in /proc/crypto. However, that
+list does not specify all possible permutations of templates and
+ciphers. Each block listed in /proc/crypto may contain the following
+information -- if one of the components listed as follows are not
+applicable to a cipher, it is not displayed:
+
+-  name: the generic name of the cipher that is subject to the
+   priority-based selection -- this name can be used by the cipher
+   allocation API calls (all names listed above are examples for such
+   generic names)
+
+-  driver: the unique name of the cipher -- this name can be used by the
+   cipher allocation API calls
+
+-  module: the kernel module providing the cipher implementation (or
+   "kernel" for statically linked ciphers)
+
+-  priority: the priority value of the cipher implementation
+
+-  refcnt: the reference count of the respective cipher (i.e. the number
+   of current consumers of this cipher)
+
+-  selftest: specification whether the self test for the cipher passed
+
+-  type:
+
+   -  skcipher for symmetric key ciphers
+
+   -  cipher for single block ciphers that may be used with an
+      additional template
+
+   -  shash for synchronous message digest
+
+   -  ahash for asynchronous message digest
+
+   -  aead for AEAD cipher type
+
+   -  compression for compression type transformations
+
+   -  rng for random number generator
+
+   -  givcipher for cipher with associated IV generator (see the geniv
+      entry below for the specification of the IV generator type used by
+      the cipher implementation)
+
+   -  kpp for a Key-agreement Protocol Primitive (KPP) cipher such as
+      an ECDH or DH implementation
+
+-  blocksize: blocksize of cipher in bytes
+
+-  keysize: key size in bytes
+
+-  ivsize: IV size in bytes
+
+-  seedsize: required size of seed data for random number generator
+
+-  digestsize: output size of the message digest
+
+-  geniv: IV generation type:
+
+   -  eseqiv for encrypted sequence number based IV generation
+
+   -  seqiv for sequence number based IV generation
+
+   -  chainiv for chain iv generation
+
+   -  <builtin> is a marker that the cipher implements IV generation and
+      handling as it is specific to the given cipher
+
+Key Sizes
+---------
+
+When allocating a cipher handle, the caller only specifies the cipher
+type. Symmetric ciphers, however, typically support multiple key sizes
+(e.g. AES-128 vs. AES-192 vs. AES-256). These key sizes are determined
+with the length of the provided key. Thus, the kernel crypto API does
+not provide a separate way to select the particular symmetric cipher key
+size.
+
+Cipher Allocation Type And Masks
+--------------------------------
+
+The different cipher handle allocation functions allow the specification
+of a type and mask flag. Both parameters have the following meaning (and
+are therefore not covered in the subsequent sections).
+
+The type flag specifies the type of the cipher algorithm. The caller
+usually provides a 0 when the caller wants the default handling.
+Otherwise, the caller may provide the following selections which match
+the aforementioned cipher types:
+
+-  CRYPTO_ALG_TYPE_CIPHER Single block cipher
+
+-  CRYPTO_ALG_TYPE_COMPRESS Compression
+
+-  CRYPTO_ALG_TYPE_AEAD Authenticated Encryption with Associated Data
+   (MAC)
+
+-  CRYPTO_ALG_TYPE_BLKCIPHER Synchronous multi-block cipher
+
+-  CRYPTO_ALG_TYPE_ABLKCIPHER Asynchronous multi-block cipher
+
+-  CRYPTO_ALG_TYPE_GIVCIPHER Asynchronous multi-block cipher packed
+   together with an IV generator (see geniv field in the /proc/crypto
+   listing for the known IV generators)
+
+-  CRYPTO_ALG_TYPE_KPP Key-agreement Protocol Primitive (KPP) such as
+   an ECDH or DH implementation
+
+-  CRYPTO_ALG_TYPE_DIGEST Raw message digest
+
+-  CRYPTO_ALG_TYPE_HASH Alias for CRYPTO_ALG_TYPE_DIGEST
+
+-  CRYPTO_ALG_TYPE_SHASH Synchronous multi-block hash
+
+-  CRYPTO_ALG_TYPE_AHASH Asynchronous multi-block hash
+
+-  CRYPTO_ALG_TYPE_RNG Random Number Generation
+
+-  CRYPTO_ALG_TYPE_AKCIPHER Asymmetric cipher
+
+-  CRYPTO_ALG_TYPE_PCOMPRESS Enhanced version of
+   CRYPTO_ALG_TYPE_COMPRESS allowing for segmented compression /
+   decompression instead of performing the operation on one segment
+   only. CRYPTO_ALG_TYPE_PCOMPRESS is intended to replace
+   CRYPTO_ALG_TYPE_COMPRESS once existing consumers are converted.
+
+The mask flag restricts the type of cipher. The only allowed flag is
+CRYPTO_ALG_ASYNC to restrict the cipher lookup function to
+asynchronous ciphers. Usually, a caller provides a 0 for the mask flag.
+
+When the caller provides a mask and type specification, the caller
+limits the search the kernel crypto API can perform for a suitable
+cipher implementation for the given cipher name. That means, even when a
+caller uses a cipher name that exists during its initialization call,
+the kernel crypto API may not select it due to the used type and mask
+field.
+
+Internal Structure of Kernel Crypto API
+---------------------------------------
+
+The kernel crypto API has an internal structure where a cipher
+implementation may use many layers and indirections. This section shall
+help to clarify how the kernel crypto API uses various components to
+implement the complete cipher.
+
+The following subsections explain the internal structure based on
+existing cipher implementations. The first section addresses the most
+complex scenario where all other scenarios form a logical subset.
+
+Generic AEAD Cipher Structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ASCII art decomposes the kernel crypto API layers when
+using the AEAD cipher with the automated IV generation. The shown
+example is used by the IPSEC layer.
+
+For other use cases of AEAD ciphers, the ASCII art applies as well, but
+the caller may not use the AEAD cipher with a separate IV generator. In
+this case, the caller must generate the IV.
+
+The depicted example decomposes the AEAD cipher of GCM(AES) based on the
+generic C implementations (gcm.c, aes-generic.c, ctr.c, ghash-generic.c,
+seqiv.c). The generic implementation serves as an example showing the
+complete logic of the kernel crypto API.
+
+It is possible that some streamlined cipher implementations (like
+AES-NI) provide implementations merging aspects which in the view of the
+kernel crypto API cannot be decomposed into layers any more. In case of
+the AES-NI implementation, the CTR mode, the GHASH implementation and
+the AES cipher are all merged into one cipher implementation registered
+with the kernel crypto API. In this case, the concept described by the
+following ASCII art applies too. However, the decomposition of GCM into
+the individual sub-components by the kernel crypto API is not done any
+more.
+
+Each block in the following ASCII art is an independent cipher instance
+obtained from the kernel crypto API. Each block is accessed by the
+caller or by other blocks using the API functions defined by the kernel
+crypto API for the cipher implementation type.
+
+The blocks below indicate the cipher type as well as the specific logic
+implemented in the cipher.
+
+The ASCII art picture also indicates the call structure, i.e. who calls
+which component. The arrows point to the invoked block where the caller
+uses the API applicable to the cipher type specified for the block.
+
+::
+
+
+    kernel crypto API                                |   IPSEC Layer
+                                                     |
+    +-----------+                                    |
+    |           |            (1)
+    |   aead    | <-----------------------------------  esp_output
+    |  (seqiv)  | ---+
+    +-----------+    |
+                     | (2)
+    +-----------+    |
+    |           | <--+                (2)
+    |   aead    | <-----------------------------------  esp_input
+    |   (gcm)   | ------------+
+    +-----------+             |
+          | (3)               | (5)
+          v                   v
+    +-----------+       +-----------+
+    |           |       |           |
+    |  skcipher |       |   ahash   |
+    |   (ctr)   | ---+  |  (ghash)  |
+    +-----------+    |  +-----------+
+                     |
+    +-----------+    | (4)
+    |           | <--+
+    |   cipher  |
+    |   (aes)   |
+    +-----------+
+
+
+
+The following call sequence is applicable when the IPSEC layer triggers
+an encryption operation with the esp_output function. During
+configuration, the administrator set up the use of rfc4106(gcm(aes)) as
+the cipher for ESP. The following call sequence is now depicted in the
+ASCII art above:
+
+1. esp_output() invokes crypto_aead_encrypt() to trigger an
+   encryption operation of the AEAD cipher with IV generator.
+
+   In case of GCM, the SEQIV implementation is registered as GIVCIPHER
+   in crypto_rfc4106_alloc().
+
+   The SEQIV performs its operation to generate an IV where the core
+   function is seqiv_geniv().
+
+2. Now, SEQIV uses the AEAD API function calls to invoke the associated
+   AEAD cipher. In our case, during the instantiation of SEQIV, the
+   cipher handle for GCM is provided to SEQIV. This means that SEQIV
+   invokes AEAD cipher operations with the GCM cipher handle.
+
+   During instantiation of the GCM handle, the CTR(AES) and GHASH
+   ciphers are instantiated. The cipher handles for CTR(AES) and GHASH
+   are retained for later use.
+
+   The GCM implementation is responsible to invoke the CTR mode AES and
+   the GHASH cipher in the right manner to implement the GCM
+   specification.
+
+3. The GCM AEAD cipher type implementation now invokes the SKCIPHER API
+   with the instantiated CTR(AES) cipher handle.
+
+   During instantiation of the CTR(AES) cipher, the CIPHER type
+   implementation of AES is instantiated. The cipher handle for AES is
+   retained.
+
+   That means that the SKCIPHER implementation of CTR(AES) only
+   implements the CTR block chaining mode. After performing the block
+   chaining operation, the CIPHER implementation of AES is invoked.
+
+4. The SKCIPHER of CTR(AES) now invokes the CIPHER API with the AES
+   cipher handle to encrypt one block.
+
+5. The GCM AEAD implementation also invokes the GHASH cipher
+   implementation via the AHASH API.
+
+When the IPSEC layer triggers the esp_input() function, the same call
+sequence is followed with the only difference that the operation starts
+with step (2).
+
+Generic Block Cipher Structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generic block ciphers follow the same concept as depicted with the ASCII
+art picture above.
+
+For example, CBC(AES) is implemented with cbc.c, and aes-generic.c. The
+ASCII art picture above applies as well with the difference that only
+step (4) is used and the SKCIPHER block chaining mode is CBC.
+
+Generic Keyed Message Digest Structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Keyed message digest implementations again follow the same concept as
+depicted in the ASCII art picture above.
+
+For example, HMAC(SHA256) is implemented with hmac.c and
+sha256_generic.c. The following ASCII art illustrates the
+implementation:
+
+::
+
+
+    kernel crypto API            |       Caller
+                                 |
+    +-----------+         (1)    |
+    |           | <------------------  some_function
+    |   ahash   |
+    |   (hmac)  | ---+
+    +-----------+    |
+                     | (2)
+    +-----------+    |
+    |           | <--+
+    |   shash   |
+    |  (sha256) |
+    +-----------+
+
+
+
+The following call sequence is applicable when a caller triggers an HMAC
+operation:
+
+1. The AHASH API functions are invoked by the caller. The HMAC
+   implementation performs its operation as needed.
+
+   During initialization of the HMAC cipher, the SHASH cipher type of
+   SHA256 is instantiated. The cipher handle for the SHA256 instance is
+   retained.
+
+   At one time, the HMAC implementation requires a SHA256 operation
+   where the SHA256 cipher handle is used.
+
+2. The HMAC instance now invokes the SHASH API with the SHA256 cipher
+   handle to calculate the message digest.
diff --git a/Documentation/crypto/devel-algos.rst b/Documentation/crypto/devel-algos.rst
new file mode 100644 (file)
index 0000000..66f50d3
--- /dev/null
@@ -0,0 +1,247 @@
+Developing Cipher Algorithms
+============================
+
+Registering And Unregistering Transformation
+--------------------------------------------
+
+There are three distinct types of registration functions in the Crypto
+API. One is used to register a generic cryptographic transformation,
+while the other two are specific to HASH transformations and
+COMPRESSion. We will discuss the latter two in a separate chapter, here
+we will only look at the generic ones.
+
+Before discussing the register functions, the data structure to be
+filled with each, struct crypto_alg, must be considered -- see below
+for a description of this data structure.
+
+The generic registration functions can be found in
+include/linux/crypto.h and their definition can be seen below. The
+former function registers a single transformation, while the latter
+works on an array of transformation descriptions. The latter is useful
+when registering transformations in bulk, for example when a driver
+implements multiple transformations.
+
+::
+
+       int crypto_register_alg(struct crypto_alg *alg);
+       int crypto_register_algs(struct crypto_alg *algs, int count);
+
+
+The counterparts to those functions are listed below.
+
+::
+
+       int crypto_unregister_alg(struct crypto_alg *alg);
+       int crypto_unregister_algs(struct crypto_alg *algs, int count);
+
+
+Notice that both registration and unregistration functions do return a
+value, so make sure to handle errors. A return code of zero implies
+success. Any return code < 0 implies an error.
+
+The bulk registration/unregistration functions register/unregister each
+transformation in the given array of length count. They handle errors as
+follows:
+
+-  crypto_register_algs() succeeds if and only if it successfully
+   registers all the given transformations. If an error occurs partway
+   through, then it rolls back successful registrations before returning
+   the error code. Note that if a driver needs to handle registration
+   errors for individual transformations, then it will need to use the
+   non-bulk function crypto_register_alg() instead.
+
+-  crypto_unregister_algs() tries to unregister all the given
+   transformations, continuing on error. It logs errors and always
+   returns zero.
+
+Single-Block Symmetric Ciphers [CIPHER]
+---------------------------------------
+
+Example of transformations: aes, arc4, ...
+
+This section describes the simplest of all transformation
+implementations, that being the CIPHER type used for symmetric ciphers.
+The CIPHER type is used for transformations which operate on exactly one
+block at a time and there are no dependencies between blocks at all.
+
+Registration specifics
+~~~~~~~~~~~~~~~~~~~~~~
+
+The registration of [CIPHER] algorithm is specific in that struct
+crypto_alg field .cra_type is empty. The .cra_u.cipher has to be
+filled in with proper callbacks to implement this transformation.
+
+See struct cipher_alg below.
+
+Cipher Definition With struct cipher_alg
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Struct cipher_alg defines a single block cipher.
+
+Here are schematics of how these functions are called when operated from
+other part of the kernel. Note that the .cia_setkey() call might happen
+before or after any of these schematics happen, but must not happen
+during any of these are in-flight.
+
+::
+
+             KEY ---.    PLAINTEXT ---.
+                    v                 v
+              .cia_setkey() -> .cia_encrypt()
+                                      |
+                                      '-----> CIPHERTEXT
+
+
+Please note that a pattern where .cia_setkey() is called multiple times
+is also valid:
+
+::
+
+
+      KEY1 --.    PLAINTEXT1 --.         KEY2 --.    PLAINTEXT2 --.
+             v                 v                v                 v
+       .cia_setkey() -> .cia_encrypt() -> .cia_setkey() -> .cia_encrypt()
+                               |                                  |
+                               '---> CIPHERTEXT1                  '---> CIPHERTEXT2
+
+
+Multi-Block Ciphers
+-------------------
+
+Example of transformations: cbc(aes), ecb(arc4), ...
+
+This section describes the multi-block cipher transformation
+implementations. The multi-block ciphers are used for transformations
+which operate on scatterlists of data supplied to the transformation
+functions. They output the result into a scatterlist of data as well.
+
+Registration Specifics
+~~~~~~~~~~~~~~~~~~~~~~
+
+The registration of multi-block cipher algorithms is one of the most
+standard procedures throughout the crypto API.
+
+Note, if a cipher implementation requires a proper alignment of data,
+the caller should use the functions of crypto_skcipher_alignmask() to
+identify a memory alignment mask. The kernel crypto API is able to
+process requests that are unaligned. This implies, however, additional
+overhead as the kernel crypto API needs to perform the realignment of
+the data which may imply moving of data.
+
+Cipher Definition With struct blkcipher_alg and ablkcipher_alg
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Struct blkcipher_alg defines a synchronous block cipher whereas struct
+ablkcipher_alg defines an asynchronous block cipher.
+
+Please refer to the single block cipher description for schematics of
+the block cipher usage.
+
+Specifics Of Asynchronous Multi-Block Cipher
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are a couple of specifics to the asynchronous interface.
+
+First of all, some of the drivers will want to use the Generic
+ScatterWalk in case the hardware needs to be fed separate chunks of the
+scatterlist which contains the plaintext and will contain the
+ciphertext. Please refer to the ScatterWalk interface offered by the
+Linux kernel scatter / gather list implementation.
+
+Hashing [HASH]
+--------------
+
+Example of transformations: crc32, md5, sha1, sha256,...
+
+Registering And Unregistering The Transformation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are multiple ways to register a HASH transformation, depending on
+whether the transformation is synchronous [SHASH] or asynchronous
+[AHASH] and the amount of HASH transformations we are registering. You
+can find the prototypes defined in include/crypto/internal/hash.h:
+
+::
+
+       int crypto_register_ahash(struct ahash_alg *alg);
+
+       int crypto_register_shash(struct shash_alg *alg);
+       int crypto_register_shashes(struct shash_alg *algs, int count);
+
+
+The respective counterparts for unregistering the HASH transformation
+are as follows:
+
+::
+
+       int crypto_unregister_ahash(struct ahash_alg *alg);
+
+       int crypto_unregister_shash(struct shash_alg *alg);
+       int crypto_unregister_shashes(struct shash_alg *algs, int count);
+
+
+Cipher Definition With struct shash_alg and ahash_alg
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here are schematics of how these functions are called when operated from
+other part of the kernel. Note that the .setkey() call might happen
+before or after any of these schematics happen, but must not happen
+during any of these are in-flight. Please note that calling .init()
+followed immediately by .finish() is also a perfectly valid
+transformation.
+
+::
+
+       I)   DATA -----------.
+                            v
+             .init() -> .update() -> .final()      ! .update() might not be called
+                         ^    |         |            at all in this scenario.
+                         '----'         '---> HASH
+
+       II)  DATA -----------.-----------.
+                            v           v
+             .init() -> .update() -> .finup()      ! .update() may not be called
+                         ^    |         |            at all in this scenario.
+                         '----'         '---> HASH
+
+       III) DATA -----------.
+                            v
+                        .digest()                  ! The entire process is handled
+                            |                        by the .digest() call.
+                            '---------------> HASH
+
+
+Here is a schematic of how the .export()/.import() functions are called
+when used from another part of the kernel.
+
+::
+
+       KEY--.                 DATA--.
+            v                       v                  ! .update() may not be called
+        .setkey() -> .init() -> .update() -> .export()   at all in this scenario.
+                                 ^     |         |
+                                 '-----'         '--> PARTIAL_HASH
+
+       ----------- other transformations happen here -----------
+
+       PARTIAL_HASH--.   DATA1--.
+                     v          v
+                 .import -> .update() -> .final()     ! .update() may not be called
+                             ^    |         |           at all in this scenario.
+                             '----'         '--> HASH1
+
+       PARTIAL_HASH--.   DATA2-.
+                     v         v
+                 .import -> .finup()
+                               |
+                               '---------------> HASH2
+
+
+Specifics Of Asynchronous HASH Transformation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some of the drivers will want to use the Generic ScatterWalk in case the
+implementation needs to be fed separate chunks of the scatterlist which
+contains the input data. The buffer containing the resulting hash will
+always be properly aligned to .cra_alignmask so there is no need to
+worry about this.
diff --git a/Documentation/crypto/index.rst b/Documentation/crypto/index.rst
new file mode 100644 (file)
index 0000000..94c4786
--- /dev/null
@@ -0,0 +1,24 @@
+=======================
+Linux Kernel Crypto API
+=======================
+
+:Author: Stephan Mueller
+:Author: Marek Vasut
+
+This documentation outlines the Linux kernel crypto API with its
+concepts, details about developing cipher implementations, employment of the API
+for cryptographic use cases, as well as programming examples.
+
+.. class:: toc-title
+
+          Table of contents
+
+.. toctree::
+   :maxdepth: 2
+
+   intro
+   architecture
+   devel-algos
+   userspace-if
+   api
+   api-samples
diff --git a/Documentation/crypto/intro.rst b/Documentation/crypto/intro.rst
new file mode 100644 (file)
index 0000000..9aa89eb
--- /dev/null
@@ -0,0 +1,74 @@
+Kernel Crypto API Interface Specification
+=========================================
+
+Introduction
+------------
+
+The kernel crypto API offers a rich set of cryptographic ciphers as well
+as other data transformation mechanisms and methods to invoke these.
+This document contains a description of the API and provides example
+code.
+
+To understand and properly use the kernel crypto API a brief explanation
+of its structure is given. Based on the architecture, the API can be
+separated into different components. Following the architecture
+specification, hints to developers of ciphers are provided. Pointers to
+the API function call documentation are given at the end.
+
+The kernel crypto API refers to all algorithms as "transformations".
+Therefore, a cipher handle variable usually has the name "tfm". Besides
+cryptographic operations, the kernel crypto API also knows compression
+transformations and handles them the same way as ciphers.
+
+The kernel crypto API serves the following entity types:
+
+-  consumers requesting cryptographic services
+
+-  data transformation implementations (typically ciphers) that can be
+   called by consumers using the kernel crypto API
+
+This specification is intended for consumers of the kernel crypto API as
+well as for developers implementing ciphers. This API specification,
+however, does not discuss all API calls available to data transformation
+implementations (i.e. implementations of ciphers and other
+transformations (such as CRC or even compression algorithms) that can
+register with the kernel crypto API).
+
+Note: The terms "transformation" and cipher algorithm are used
+interchangeably.
+
+Terminology
+-----------
+
+The transformation implementation is an actual code or interface to
+hardware which implements a certain transformation with precisely
+defined behavior.
+
+The transformation object (TFM) is an instance of a transformation
+implementation. There can be multiple transformation objects associated
+with a single transformation implementation. Each of those
+transformation objects is held by a crypto API consumer or another
+transformation. Transformation object is allocated when a crypto API
+consumer requests a transformation implementation. The consumer is then
+provided with a structure, which contains a transformation object (TFM).
+
+The structure that contains transformation objects may also be referred
+to as a "cipher handle". Such a cipher handle is always subject to the
+following phases that are reflected in the API calls applicable to such
+a cipher handle:
+
+1. Initialization of a cipher handle.
+
+2. Execution of all intended cipher operations applicable for the handle
+   where the cipher handle must be furnished to every API call.
+
+3. Destruction of a cipher handle.
+
+When using the initialization API calls, a cipher handle is created and
+returned to the consumer. Therefore, please refer to all initialization
+API calls that refer to the data structure type a consumer is expected
+to receive and subsequently to use. The initialization API calls have
+all the same naming conventions of crypto_alloc\*.
+
+The transformation context is private data associated with the
+transformation object.
diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
new file mode 100644 (file)
index 0000000..de5a72e
--- /dev/null
@@ -0,0 +1,387 @@
+User Space Interface
+====================
+
+Introduction
+------------
+
+The concepts of the kernel crypto API visible to kernel space is fully
+applicable to the user space interface as well. Therefore, the kernel
+crypto API high level discussion for the in-kernel use cases applies
+here as well.
+
+The major difference, however, is that user space can only act as a
+consumer and never as a provider of a transformation or cipher
+algorithm.
+
+The following covers the user space interface exported by the kernel
+crypto API. A working example of this description is libkcapi that can
+be obtained from [1]. That library can be used by user space
+applications that require cryptographic services from the kernel.
+
+Some details of the in-kernel kernel crypto API aspects do not apply to
+user space, however. This includes the difference between synchronous
+and asynchronous invocations. The user space API call is fully
+synchronous.
+
+[1] http://www.chronox.de/libkcapi.html
+
+User Space API General Remarks
+------------------------------
+
+The kernel crypto API is accessible from user space. Currently, the
+following ciphers are accessible:
+
+-  Message digest including keyed message digest (HMAC, CMAC)
+
+-  Symmetric ciphers
+
+-  AEAD ciphers
+
+-  Random Number Generators
+
+The interface is provided via socket type using the type AF_ALG. In
+addition, the setsockopt option type is SOL_ALG. In case the user space
+header files do not export these flags yet, use the following macros:
+
+::
+
+    #ifndef AF_ALG
+    #define AF_ALG 38
+    #endif
+    #ifndef SOL_ALG
+    #define SOL_ALG 279
+    #endif
+
+
+A cipher is accessed with the same name as done for the in-kernel API
+calls. This includes the generic vs. unique naming schema for ciphers as
+well as the enforcement of priorities for generic names.
+
+To interact with the kernel crypto API, a socket must be created by the
+user space application. User space invokes the cipher operation with the
+send()/write() system call family. The result of the cipher operation is
+obtained with the read()/recv() system call family.
+
+The following API calls assume that the socket descriptor is already
+opened by the user space application and discusses only the kernel
+crypto API specific invocations.
+
+To initialize the socket interface, the following sequence has to be
+performed by the consumer:
+
+1. Create a socket of type AF_ALG with the struct sockaddr_alg
+   parameter specified below for the different cipher types.
+
+2. Invoke bind with the socket descriptor
+
+3. Invoke accept with the socket descriptor. The accept system call
+   returns a new file descriptor that is to be used to interact with the
+   particular cipher instance. When invoking send/write or recv/read
+   system calls to send data to the kernel or obtain data from the
+   kernel, the file descriptor returned by accept must be used.
+
+In-place Cipher operation
+-------------------------
+
+Just like the in-kernel operation of the kernel crypto API, the user
+space interface allows the cipher operation in-place. That means that
+the input buffer used for the send/write system call and the output
+buffer used by the read/recv system call may be one and the same. This
+is of particular interest for symmetric cipher operations where a
+copying of the output data to its final destination can be avoided.
+
+If a consumer on the other hand wants to maintain the plaintext and the
+ciphertext in different memory locations, all a consumer needs to do is
+to provide different memory pointers for the encryption and decryption
+operation.
+
+Message Digest API
+------------------
+
+The message digest type to be used for the cipher operation is selected
+when invoking the bind syscall. bind requires the caller to provide a
+filled struct sockaddr data structure. This data structure must be
+filled as follows:
+
+::
+
+    struct sockaddr_alg sa = {
+        .salg_family = AF_ALG,
+        .salg_type = "hash", /* this selects the hash logic in the kernel */
+        .salg_name = "sha1" /* this is the cipher name */
+    };
+
+
+The salg_type value "hash" applies to message digests and keyed message
+digests. Though, a keyed message digest is referenced by the appropriate
+salg_name. Please see below for the setsockopt interface that explains
+how the key can be set for a keyed message digest.
+
+Using the send() system call, the application provides the data that
+should be processed with the message digest. The send system call allows
+the following flags to be specified:
+
+-  MSG_MORE: If this flag is set, the send system call acts like a
+   message digest update function where the final hash is not yet
+   calculated. If the flag is not set, the send system call calculates
+   the final message digest immediately.
+
+With the recv() system call, the application can read the message digest
+from the kernel crypto API. If the buffer is too small for the message
+digest, the flag MSG_TRUNC is set by the kernel.
+
+In order to set a message digest key, the calling application must use
+the setsockopt() option of ALG_SET_KEY. If the key is not set the HMAC
+operation is performed without the initial HMAC state change caused by
+the key.
+
+Symmetric Cipher API
+--------------------
+
+The operation is very similar to the message digest discussion. During
+initialization, the struct sockaddr data structure must be filled as
+follows:
+
+::
+
+    struct sockaddr_alg sa = {
+        .salg_family = AF_ALG,
+        .salg_type = "skcipher", /* this selects the symmetric cipher */
+        .salg_name = "cbc(aes)" /* this is the cipher name */
+    };
+
+
+Before data can be sent to the kernel using the write/send system call
+family, the consumer must set the key. The key setting is described with
+the setsockopt invocation below.
+
+Using the sendmsg() system call, the application provides the data that
+should be processed for encryption or decryption. In addition, the IV is
+specified with the data structure provided by the sendmsg() system call.
+
+The sendmsg system call parameter of struct msghdr is embedded into the
+struct cmsghdr data structure. See recv(2) and cmsg(3) for more
+information on how the cmsghdr data structure is used together with the
+send/recv system call family. That cmsghdr data structure holds the
+following information specified with a separate header instances:
+
+-  specification of the cipher operation type with one of these flags:
+
+   -  ALG_OP_ENCRYPT - encryption of data
+
+   -  ALG_OP_DECRYPT - decryption of data
+
+-  specification of the IV information marked with the flag ALG_SET_IV
+
+The send system call family allows the following flag to be specified:
+
+-  MSG_MORE: If this flag is set, the send system call acts like a
+   cipher update function where more input data is expected with a
+   subsequent invocation of the send system call.
+
+Note: The kernel reports -EINVAL for any unexpected data. The caller
+must make sure that all data matches the constraints given in
+/proc/crypto for the selected cipher.
+
+With the recv() system call, the application can read the result of the
+cipher operation from the kernel crypto API. The output buffer must be
+at least as large as to hold all blocks of the encrypted or decrypted
+data. If the output data size is smaller, only as many blocks are
+returned that fit into that output buffer size.
+
+AEAD Cipher API
+---------------
+
+The operation is very similar to the symmetric cipher discussion. During
+initialization, the struct sockaddr data structure must be filled as
+follows:
+
+::
+
+    struct sockaddr_alg sa = {
+        .salg_family = AF_ALG,
+        .salg_type = "aead", /* this selects the symmetric cipher */
+        .salg_name = "gcm(aes)" /* this is the cipher name */
+    };
+
+
+Before data can be sent to the kernel using the write/send system call
+family, the consumer must set the key. The key setting is described with
+the setsockopt invocation below.
+
+In addition, before data can be sent to the kernel using the write/send
+system call family, the consumer must set the authentication tag size.
+To set the authentication tag size, the caller must use the setsockopt
+invocation described below.
+
+Using the sendmsg() system call, the application provides the data that
+should be processed for encryption or decryption. In addition, the IV is
+specified with the data structure provided by the sendmsg() system call.
+
+The sendmsg system call parameter of struct msghdr is embedded into the
+struct cmsghdr data structure. See recv(2) and cmsg(3) for more
+information on how the cmsghdr data structure is used together with the
+send/recv system call family. That cmsghdr data structure holds the
+following information specified with a separate header instances:
+
+-  specification of the cipher operation type with one of these flags:
+
+   -  ALG_OP_ENCRYPT - encryption of data
+
+   -  ALG_OP_DECRYPT - decryption of data
+
+-  specification of the IV information marked with the flag ALG_SET_IV
+
+-  specification of the associated authentication data (AAD) with the
+   flag ALG_SET_AEAD_ASSOCLEN. The AAD is sent to the kernel together
+   with the plaintext / ciphertext. See below for the memory structure.
+
+The send system call family allows the following flag to be specified:
+
+-  MSG_MORE: If this flag is set, the send system call acts like a
+   cipher update function where more input data is expected with a
+   subsequent invocation of the send system call.
+
+Note: The kernel reports -EINVAL for any unexpected data. The caller
+must make sure that all data matches the constraints given in
+/proc/crypto for the selected cipher.
+
+With the recv() system call, the application can read the result of the
+cipher operation from the kernel crypto API. The output buffer must be
+at least as large as defined with the memory structure below. If the
+output data size is smaller, the cipher operation is not performed.
+
+The authenticated decryption operation may indicate an integrity error.
+Such breach in integrity is marked with the -EBADMSG error code.
+
+AEAD Memory Structure
+~~~~~~~~~~~~~~~~~~~~~
+
+The AEAD cipher operates with the following information that is
+communicated between user and kernel space as one data stream:
+
+-  plaintext or ciphertext
+
+-  associated authentication data (AAD)
+
+-  authentication tag
+
+The sizes of the AAD and the authentication tag are provided with the
+sendmsg and setsockopt calls (see there). As the kernel knows the size
+of the entire data stream, the kernel is now able to calculate the right
+offsets of the data components in the data stream.
+
+The user space caller must arrange the aforementioned information in the
+following order:
+
+-  AEAD encryption input: AAD \|\| plaintext
+
+-  AEAD decryption input: AAD \|\| ciphertext \|\| authentication tag
+
+The output buffer the user space caller provides must be at least as
+large to hold the following data:
+
+-  AEAD encryption output: ciphertext \|\| authentication tag
+
+-  AEAD decryption output: plaintext
+
+Random Number Generator API
+---------------------------
+
+Again, the operation is very similar to the other APIs. During
+initialization, the struct sockaddr data structure must be filled as
+follows:
+
+::
+
+    struct sockaddr_alg sa = {
+        .salg_family = AF_ALG,
+        .salg_type = "rng", /* this selects the symmetric cipher */
+        .salg_name = "drbg_nopr_sha256" /* this is the cipher name */
+    };
+
+
+Depending on the RNG type, the RNG must be seeded. The seed is provided
+using the setsockopt interface to set the key. For example, the
+ansi_cprng requires a seed. The DRBGs do not require a seed, but may be
+seeded.
+
+Using the read()/recvmsg() system calls, random numbers can be obtained.
+The kernel generates at most 128 bytes in one call. If user space
+requires more data, multiple calls to read()/recvmsg() must be made.
+
+WARNING: The user space caller may invoke the initially mentioned accept
+system call multiple times. In this case, the returned file descriptors
+have the same state.
+
+Zero-Copy Interface
+-------------------
+
+In addition to the send/write/read/recv system call family, the AF_ALG
+interface can be accessed with the zero-copy interface of
+splice/vmsplice. As the name indicates, the kernel tries to avoid a copy
+operation into kernel space.
+
+The zero-copy operation requires data to be aligned at the page
+boundary. Non-aligned data can be used as well, but may require more
+operations of the kernel which would defeat the speed gains obtained
+from the zero-copy interface.
+
+The system-interent limit for the size of one zero-copy operation is 16
+pages. If more data is to be sent to AF_ALG, user space must slice the
+input into segments with a maximum size of 16 pages.
+
+Zero-copy can be used with the following code example (a complete
+working example is provided with libkcapi):
+
+::
+
+    int pipes[2];
+
+    pipe(pipes);
+    /* input data in iov */
+    vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT);
+    /* opfd is the file descriptor returned from accept() system call */
+    splice(pipes[0], NULL, opfd, NULL, ret, 0);
+    read(opfd, out, outlen);
+
+
+Setsockopt Interface
+--------------------
+
+In addition to the read/recv and send/write system call handling to send
+and retrieve data subject to the cipher operation, a consumer also needs
+to set the additional information for the cipher operation. This
+additional information is set using the setsockopt system call that must
+be invoked with the file descriptor of the open cipher (i.e. the file
+descriptor returned by the accept system call).
+
+Each setsockopt invocation must use the level SOL_ALG.
+
+The setsockopt interface allows setting the following data using the
+mentioned optname:
+
+-  ALG_SET_KEY -- Setting the key. Key setting is applicable to:
+
+   -  the skcipher cipher type (symmetric ciphers)
+
+   -  the hash cipher type (keyed message digests)
+
+   -  the AEAD cipher type
+
+   -  the RNG cipher type to provide the seed
+
+-  ALG_SET_AEAD_AUTHSIZE -- Setting the authentication tag size for
+   AEAD ciphers. For a encryption operation, the authentication tag of
+   the given size will be generated. For a decryption operation, the
+   provided ciphertext is assumed to contain an authentication tag of
+   the given size (see section about AEAD memory layout below).
+
+User space API example
+----------------------
+
+Please see [1] for libkcapi which provides an easy-to-use wrapper around
+the aforementioned Netlink kernel interface. [1] also contains a test
+application that invokes all libkcapi API calls.
+
+[1] http://www.chronox.de/libkcapi.html
index ab0e0488fe928ffe618fc69a10870ec291ed5b84..5f9fbc68e58a45bd95af3ea2a5998d581a328b52 100644 (file)
@@ -1,32 +1,47 @@
-* Dialog DA9062/63 OnKey Module
+* Dialog DA9061/62/63 OnKey Module
 
-This module is part of the DA9062/DA9063. For more details about entire
-chips see Documentation/devicetree/bindings/mfd/da9062.txt and
-Documentation/devicetree/bindings/mfd/da9063.txt
+This module is part of the DA9061/DA9062/DA9063. For more details about entire
+DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
+For DA9063 see Documentation/devicetree/bindings/mfd/da9063.txt
 
-This module provides KEY_POWER, KEY_SLEEP and events.
+This module provides the KEY_POWER event.
 
 Required properties:
 
-- compatible: should be one of:
-       dlg,da9062-onkey
-       dlg,da9063-onkey
+- compatible: should be one of the following valid compatible string lines:
+       "dlg,da9061-onkey", "dlg,da9062-onkey"
+       "dlg,da9062-onkey"
+       "dlg,da9063-onkey"
 
 Optional properties:
 
-  - dlg,disable-key-power : Disable power-down using a long key-press. If this
+- dlg,disable-key-power : Disable power-down using a long key-press. If this
     entry exists the OnKey driver will remove support for the KEY_POWER key
-    press. If this entry does not exist then by default the key-press
-    triggered power down is enabled and the OnKey will support both KEY_POWER
-    and KEY_SLEEP.
+    press when triggered using a long press of the OnKey.
 
-Example:
-
-       pmic0: da9062@58 {
+Example: DA9063
 
+       pmic0: da9063@58 {
                onkey {
                        compatible = "dlg,da9063-onkey";
                        dlg,disable-key-power;
                };
+       };
+
+Example: DA9062
+
+       pmic0: da9062@58 {
+               onkey {
+                       compatible = "dlg,da9062-onkey";
+                       dlg,disable-key-power;
+               };
+       };
+
+Example: DA9061 using a fall-back compatible for the DA9062 onkey driver
 
+       pmic0: da9061@58 {
+               onkey {
+                       compatible = "dlg,da9061-onkey", "dlg,da9062-onkey";
+                       dlg,disable-key-power;
+               };
        };
index 853dff96dd9f7650f6d6b9787266d001a9ded047..d4927c202aef271554022e5fd84451f1febe9212 100644 (file)
@@ -17,6 +17,8 @@ Optional properties:
   This value depends on the touch screen.
 - pre-charge-time: the touch screen need some time to precharge.
   This value depends on the touch screen.
+- touchscreen-average-samples: Number of data samples which are averaged for
+  each read. Valid values are 1, 4, 8, 16 and 32.
 
 Example:
        tsc: tsc@02040000 {
@@ -32,5 +34,6 @@ Example:
                xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
                measure-delay-time = <0xfff>;
                pre-charge-time = <0xffff>;
+               touchscreen-average-samples = <32>;
                status = "okay";
        };
index 820fee4b77b601e7f4c5521e854a06d2dd78408b..ce85ee508238f27514172ecf9559e04a8710f908 100644 (file)
@@ -18,6 +18,8 @@ Optional properties:
 - touchscreen-inverted-y  : See touchscreen.txt
 - touchscreen-swapped-x-y : See touchscreen.txt
 - silead,max-fingers     : maximum number of fingers the touchscreen can detect
+- vddio-supply           : regulator phandle for controller VDDIO
+- avdd-supply            : regulator phandle for controller AVDD
 
 Example:
 
index bccaa4e7304530b559c411afc2fab9cbccd068b3..537643e86f6186dc3189bb15213ba70ad1b8b336 100644 (file)
@@ -14,6 +14,9 @@ Optional properties for Touchscreens:
  - touchscreen-fuzz-pressure   : pressure noise value of the absolute input
                                  device (arbitrary range dependent on the
                                  controller)
+ - touchscreen-average-samples : Number of data samples which are averaged
+                                 for each read (valid values dependent on the
+                                 controller)
  - touchscreen-inverted-x      : X axis is inverted (boolean)
  - touchscreen-inverted-y      : Y axis is inverted (boolean)
  - touchscreen-swapped-x-y     : X and Y axis are swapped (boolean)
diff --git a/Documentation/devicetree/bindings/mfd/altera-a10sr.txt b/Documentation/devicetree/bindings/mfd/altera-a10sr.txt
new file mode 100644 (file)
index 0000000..ea151f2
--- /dev/null
@@ -0,0 +1,46 @@
+* Altera Arria10 Development Kit System Resource Chip
+
+Required parent device properties:
+- compatible           : "altr,a10sr"
+- spi-max-frequency    : Maximum SPI frequency.
+- reg                  : The SPI Chip Select address for the Arria10
+                         System Resource chip
+- interrupt-parent     : The parent interrupt controller.
+- interrupts           : The interrupt line the device is connected to.
+- interrupt-controller : Marks the device node as an interrupt controller.
+- #interrupt-cells     : The number of cells to describe an IRQ, should be 2.
+                           The first cell is the IRQ number.
+                           The second cell is the flags, encoded as trigger
+                           masks from ../interrupt-controller/interrupts.txt.
+
+The A10SR consists of these sub-devices:
+
+Device                   Description
+------                   ----------
+a10sr_gpio               GPIO Controller
+
+Arria10 GPIO
+Required Properties:
+- compatible        : Should be "altr,a10sr-gpio"
+- gpio-controller   : Marks the device node as a GPIO Controller.
+- #gpio-cells       : Should be two.  The first cell is the pin number and
+                      the second cell is used to specify flags.
+                      See ../gpio/gpio.txt for more information.
+
+Example:
+
+        resource-manager@0 {
+               compatible = "altr,a10sr";
+               reg = <0>;
+               spi-max-frequency = <100000>;
+               interrupt-parent = <&portb>;
+               interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+
+               a10sr_gpio: gpio-controller {
+                       compatible = "altr,a10sr-gpio";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+       };
index 37a088f9a648ec94e9d9f2046251d3993ff09ed7..9e5eba4a4f0d0ab8387c103007079702a6d278bd 100644 (file)
@@ -10,6 +10,7 @@ voltages and other various functionality to Qualcomm SoCs.
        Value type: <string>
        Definition: must be one of:
                    "qcom,pm8058"
+                   "qcom,pm8821"
                    "qcom,pm8921"
 
 - #address-cells:
index 9e6770b105c935f8932ba39fd3351f9f4628155f..65c23263cc5418db378215612f152f8d887613f7 100644 (file)
@@ -1,21 +1,25 @@
 * Ricoh RN5T567/RN5T618 PMIC
 
-Ricoh RN5T567/RN5T618 is a power management IC family which integrates
-3 to 4 step-down DCDC converters, 7 low-dropout regulators, GPIOs and
-a watchdog timer. The RN5T618 provides additionally a Li-ion battery
-charger, fuel gauge and an ADC. It can be controlled through an I2C
-interface.
+Ricoh RN5T567/RN5T618/RC5T619 is a power management IC family which
+integrates 3 to 5 step-down DCDC converters, 7 to 10 low-dropout regulators,
+GPIOs, and a watchdog timer. It can be controlled through an I2C interface.
+The RN5T618/RC5T619 provides additionally a Li-ion battery charger,
+fuel gauge, and an ADC.
+The RC5T619 additionnally includes USB charger detection and an RTC.
 
 Required properties:
  - compatible: must be one of
                "ricoh,rn5t567"
                "ricoh,rn5t618"
+               "ricoh,rc5t619"
  - reg: the I2C slave address of the device
 
 Sub-nodes:
  - regulators: the node is required if the regulator functionality is
    needed. The valid regulator names are: DCDC1, DCDC2, DCDC3, DCDC4
-   (RN5T567), LDO1, LDO2, LDO3, LDO4, LDO5, LDORTC1 and LDORTC2.
+   (RN5T567/RC5T619), LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, LDO8,
+   LDO9, LDO10, LDORTC1 and LDORTC2.
+   LDO7-10 are specific to RC5T619.
    The common bindings for each individual regulator can be found in:
    Documentation/devicetree/bindings/regulator/regulator.txt
 
diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
new file mode 100644 (file)
index 0000000..56d5c19
--- /dev/null
@@ -0,0 +1,41 @@
+* Oxford Semiconductor OXNAS NAND Controller
+
+Please refer to nand.txt for generic information regarding MTD NAND bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox820-nand"
+ - reg: Base address and length for NAND mapped memory.
+
+Optional Properties:
+ - clocks: phandle to the NAND gate clock if needed.
+ - resets: phandle to the NAND reset control if needed.
+
+Example:
+
+nandc: nand-controller@41000000 {
+       compatible = "oxsemi,ox820-nand";
+       reg = <0x41000000 0x100000>;
+       clocks = <&stdclk CLK_820_NAND>;
+       resets = <&reset RESET_NAND>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       nand@0 {
+               reg = <0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               nand-ecc-mode = "soft";
+               nand-ecc-algo = "hamming";
+
+               partition@0 {
+                       label = "boot";
+                       reg = <0x00000000 0x00e00000>;
+                       read-only;
+               };
+
+               partition@e00000 {
+                       label = "ubi";
+                       reg = <0x00e00000 0x07200000>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
new file mode 100644 (file)
index 0000000..0040eb8
--- /dev/null
@@ -0,0 +1,56 @@
+* Samsung S3C2410 and compatible NAND flash controller
+
+Required properties:
+- compatible : The possible values are:
+       "samsung,s3c2410-nand"
+       "samsung,s3c2412-nand"
+       "samsung,s3c2440-nand"
+- reg : register's location and length.
+- #address-cells, #size-cells : see nand.txt
+- clocks : phandle to the nand controller clock
+- clock-names : must contain "nand"
+
+Optional child nodes:
+Child nodes representing the available nand chips.
+
+Optional child properties:
+- nand-ecc-mode : see nand.txt
+- nand-on-flash-bbt : see nand.txt
+
+Each child 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-controller@4e000000 {
+       compatible = "samsung,s3c2440-nand";
+       reg = <0x4e000000 0x40>;
+
+       #address-cells = <1>;
+        #size-cells = <0>;
+
+       clocks = <&clocks HCLK_NAND>;
+       clock-names = "nand";
+
+       nand {
+               nand-ecc-mode = "soft";
+               nand-on-flash-bbt;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "u-boot";
+                               reg = <0 0x040000>;
+                       };
+
+                       partition@40000 {
+                               label = "kernel";
+                               reg = <0x040000 0x500000>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/tango-nand.txt b/Documentation/devicetree/bindings/mtd/tango-nand.txt
new file mode 100644 (file)
index 0000000..ad5a02f
--- /dev/null
@@ -0,0 +1,38 @@
+Sigma Designs Tango4 NAND Flash Controller (NFC)
+
+Required properties:
+
+- compatible: "sigma,smp8758-nand"
+- reg: address/size of nfc_reg, nfc_mem, and pbus_reg
+- dmas: reference to the DMA channel used by the controller
+- dma-names: "nfc_sbox"
+- clocks: reference to the system clock
+- #address-cells: <1>
+- #size-cells: <0>
+
+Children nodes represent the available NAND chips.
+See Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
+
+Example:
+
+       nandc: nand-controller@2c000 {
+               compatible = "sigma,smp8758-nand";
+               reg = <0x2c000 0x30 0x2d000 0x800 0x20000 0x1000>;
+               dmas = <&dma0 3>;
+               dma-names = "nfc_sbox";
+               clocks = <&clkgen SYS_CLK>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               nand@0 {
+                       reg = <0>; /* CS0 */
+                       nand-ecc-strength = <14>;
+                       nand-ecc-step-size = <1024>;
+               };
+
+               nand@1 {
+                       reg = <1>; /* CS1 */
+                       nand-ecc-strength = <14>;
+                       nand-ecc-step-size = <1024>;
+               };
+       };
index fccc1d24af58a51e5da9bfb3ec08d21ffab18b02..02f0e9bbfbf8a43a447ddb67d96924789dcd7618 100644 (file)
@@ -1,23 +1,78 @@
 TPS65218 family of regulators
 
 Required properties:
-For tps65218 regulators/LDOs
-- compatible:
-  - "ti,tps65218-dcdc1" for DCDC1
-  - "ti,tps65218-dcdc2" for DCDC2
-  - "ti,tps65218-dcdc3" for DCDC3
-  - "ti,tps65218-dcdc4" for DCDC4
-  - "ti,tps65218-dcdc5" for DCDC5
-  - "ti,tps65218-dcdc6" for DCDC6
-  - "ti,tps65218-ldo1" for LDO1
-
-Optional properties:
-- Any optional property defined in bindings/regulator/regulator.txt
+- compatible: "ti,tps65218"
+- reg: I2C slave address
+
+- List of regulators provided by this controller, must be named
+  after their hardware counterparts: dcdc[1-6] and ldo1
+- This is the list of child nodes that specify the regulator
+  initialization data for defined regulators. Not all regulators for the given
+  device need to be present. The definition for each of these nodes is defined
+  using the standard binding for regulators found at ./regulator.txt.
+
+  The valid names for regulators are:
+  tps65217: regulator-dcdc1, regulator-dcdc2, regulator-dcdc3, regulator-dcdc4,
+  regulator-dcdc5, regulator-dcdc6, regulator-ldo1, regulator-ls3.
+  Each regulator is defined using the standard binding for regulators.
 
 Example:
+tps65218: tps65218@24 {
+       reg = <0x24>;
+       compatible = "ti,tps65218";
+       interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */
+       interrupt-controller;
+       #interrupt-cells = <2>;
+
+       dcdc1: regulator-dcdc1 {
+               regulator-name = "vdd_core";
+               regulator-min-microvolt = <912000>;
+               regulator-max-microvolt = <1144000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       dcdc2: regulator-dcdc2 {
+               regulator-name = "vdd_mpu";
+               regulator-min-microvolt = <912000>;
+               regulator-max-microvolt = <1378000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       dcdc3: regulator-dcdc3 {
+               regulator-name = "vdcdc3";
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       dcdc5: regulator-dcdc5 {
+               regulator-name = "v1_0bat";
+               regulator-min-microvolt = <1000000>;
+               regulator-max-microvolt = <1000000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       dcdc6: regulator-dcdc6 {
+               regulator-name = "v1_8bat";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       ldo1: regulator-ldo1 {
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
 
-       xyz: regulator@0 {
-               compatible = "ti,tps65218-dcdc1";
-               regulator-min-microvolt  = <1000000>;
-               regulator-max-microvolt  = <3000000>;
+       ls3: regulator-ls3 {
+               regulator-min-microvolt = <100000>;
+               regulator-max-microvolt = <1000000>;
        };
+};
diff --git a/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt b/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt
new file mode 100644 (file)
index 0000000..5f9df3f
--- /dev/null
@@ -0,0 +1,16 @@
+EPSON TOYOCOM RTC-7301SF/DG
+
+Required properties:
+
+- compatible: Should be "epson,rtc7301sf" or "epson,rtc7301dg"
+- reg: Specifies base physical address and size of the registers.
+- interrupts: A single interrupt specifier.
+
+Example:
+
+rtc: rtc@44a00000 {
+       compatible = "epson,rtc7301dg";
+       reg = <0x44a00000 0x10000>;
+       interrupt-parent = <&axi_intc_0>;
+       interrupts = <3 2>;
+};
diff --git a/Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt b/Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt
new file mode 100644 (file)
index 0000000..41c7ae1
--- /dev/null
@@ -0,0 +1,37 @@
+JZ4740 and similar SoCs real-time clock driver
+
+Required properties:
+
+- compatible: One of:
+  - "ingenic,jz4740-rtc" - for use with the JZ4740 SoC
+  - "ingenic,jz4780-rtc" - for use with the JZ4780 SoC
+- reg: Address range of rtc register set
+- interrupts: IRQ number for the alarm interrupt
+- clocks: phandle to the "rtc" clock
+- clock-names: must be "rtc"
+
+Optional properties:
+- system-power-controller: To use this component as the
+  system power controller
+- reset-pin-assert-time-ms: Reset pin low-level assertion
+  time after wakeup (default 60ms; range 0-125ms if RTC clock
+  at 32 kHz)
+- min-wakeup-pin-assert-time-ms: Minimum wakeup pin assertion
+  time (default 100ms; range 0-2s if RTC clock at 32 kHz)
+
+Example:
+
+rtc@10003000 {
+       compatible = "ingenic,jz4740-rtc";
+       reg = <0x10003000 0x40>;
+
+       interrupt-parent = <&intc>;
+       interrupts = <32>;
+
+       clocks = <&rtc_clock>;
+       clock-names = "rtc";
+
+       system-power-controller;
+       reset-pin-assert-time-ms = <60>;
+       min-wakeup-pin-assert-time-ms = <100>;
+};
index 596e0c97be7aa318a5d2268e5d464b9b147dd7bf..8f9a94f2f8969911e4490b744563c180a413426b 100644 (file)
@@ -1,12 +1,11 @@
-* TI twl RTC
-
-The TWL family (twl4030/6030) contains a RTC.
+* Texas Instruments TWL4030/6030 RTC
 
 Required properties:
-- compatible : Should be twl4030-rtc
-
-Examples:
-
-rtc@0 {
-    compatible = "ti,twl4030-rtc";
-};
+- compatible : Should be "ti,twl4030-rtc"
+- interrupts : Should be the interrupt number.
+
+Example:
+       rtc {
+               compatible = "ti,twl4030-rtc";
+               interrupts = <11>;
+       };
index 4f4a3443b114c6ecd5a41856c86559daca0d51b6..ffa522a9bdfdcc34b017bc9a3e70be8fe2d87082 100644 (file)
@@ -36,5 +36,5 @@
     |          um: | TODO |
     |   unicore32: | TODO |
     |         x86: |  ok  |
-    |      xtensa: | TODO |
+    |      xtensa: |  ok  |
     -----------------------
index a97e8e3f4ebbed8d2467e19d6e736ef21f8f9991..83d2cf989ea3494dc825fc9e4da3b1ed09491646 100644 (file)
@@ -36,5 +36,5 @@
     |          um: | TODO |
     |   unicore32: | TODO |
     |         x86: |  ok  |
-    |      xtensa: | TODO |
+    |      xtensa: |  ok  |
     -----------------------
index 69e2387ca27838b5fbbc1e3f40d1d75ee36d0170..ace63cd7af8c0d26783f272a5fa9e39be647df3a 100644 (file)
@@ -20,7 +20,7 @@ prototypes:
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
        struct vfsmount *(*d_automount)(struct path *path);
-       int (*d_manage)(struct dentry *, bool);
+       int (*d_manage)(const struct path *, bool);
        struct dentry *(*d_real)(struct dentry *, const struct inode *,
                                 unsigned int);
 
index bdd025ceb763b112a01ff18dc6d04d866e7240e7..95280079c0b3af0c217270e6838b723eb818cbcd 100644 (file)
@@ -596,3 +596,7 @@ in your dentry operations instead.
 [mandatory]
        ->rename() has an added flags argument.  Any flags not handled by the
         filesystem should result in EINVAL being returned.
+--
+[recommended]
+       ->readlink is optional for symlinks.  Don't set, unless filesystem needs
+       to fake something for readlink(2).
index b5039a00caafae44660514da3829994436a35e84..b968084eeac14bbc4f8f51dbf7fc3484f61da496 100644 (file)
@@ -451,9 +451,6 @@ otherwise noted.
        exist; this is checked by the VFS.  Unlike plain rename,
        source and target may be of different type.
 
-  readlink: called by the readlink(2) system call. Only required if
-       you want to support reading symbolic links
-
   get_link: called by the VFS to follow a symbolic link to the
        inode it points to.  Only required if you want to support
        symbolic links.  This method returns the symlink body
@@ -468,6 +465,12 @@ otherwise noted.
        argument.  If request can't be handled without leaving RCU mode,
        have it return ERR_PTR(-ECHILD).
 
+  readlink: this is now just an override for use by readlink(2) for the
+       cases when ->get_link uses nd_jump_link() or object is not in
+       fact a symlink.  Normally filesystems should only implement
+       ->get_link for symlinks and readlink(2) will automatically use
+       that.
+
   permission: called by the VFS to check for access rights on a POSIX-like
        filesystem.
 
@@ -948,7 +951,7 @@ struct dentry_operations {
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)(struct dentry *, char *, int);
        struct vfsmount *(*d_automount)(struct path *);
-       int (*d_manage)(struct dentry *, bool);
+       int (*d_manage)(const struct path *, bool);
        struct dentry *(*d_real)(struct dentry *, const struct inode *,
                                 unsigned int);
 };
index 2bd8fdc9207c6678c233279cb52e0ac2750bb363..cb5d77699c60b97a09c0cdaf6bd751249e81c017 100644 (file)
@@ -58,6 +58,7 @@ needed).
    gpu/index
    security/index
    sound/index
+   crypto/index
 
 Korean translations
 -------------------
index 55f27579302830c4e07634c6b17e56f6fa14e227..25feb0d35e7abc7f6ff7797faf02e9e79321e644 100755 (executable)
@@ -157,6 +157,11 @@ class ListTableBuilder(object):
     def buildTableNode(self):
 
         colwidths    = self.directive.get_column_widths(self.max_cols)
+        if isinstance(colwidths, tuple):
+            # Since docutils 0.13, get_column_widths returns a (widths,
+            # colwidths) tuple, where widths is a string (i.e. 'auto').
+            # See https://sourceforge.net/p/docutils/patches/120/.
+            colwidths = colwidths[1]
         stub_columns = self.directive.options.get('stub-columns', 0)
         header_rows  = self.directive.options.get('header-rows', 0)
 
index e5dd9f4d61008ad6431e067b900608788e573020..fd013bf4115be70bafdb6489dc4caedf61e7600d 100644 (file)
@@ -13,8 +13,12 @@ The acquisition orders for mutexes are as follows:
 - kvm->slots_lock is taken outside kvm->irq_lock, though acquiring
   them together is quite rare.
 
-For spinlocks, kvm_lock is taken outside kvm->mmu_lock.  Everything
-else is a leaf: no other lock is taken inside the critical sections.
+On x86, vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock.
+
+For spinlocks, kvm_lock is taken outside kvm->mmu_lock.
+
+Everything else is a leaf: no other lock is taken inside the critical
+sections.
 
 2: Exception
 ------------
index bf8690d0a1e190f64fbd5e6beffbdc1ad91fad3c..f6eb97b35e0fd58fe353cefce963ce7ff162491f 100644 (file)
@@ -5163,6 +5163,12 @@ S:       Maintained
 F:     drivers/net/ethernet/freescale/fman
 F:     Documentation/devicetree/bindings/powerpc/fsl/fman.txt
 
+FREESCALE QORIQ DPAA ETHERNET DRIVER
+M:     Madalin Bucur <madalin.bucur@nxp.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/freescale/dpaa
+
 FREESCALE SOC DRIVERS
 M:     Scott Wood <oss@buserror.net>
 L:     linuxppc-dev@lists.ozlabs.org
@@ -8064,7 +8070,7 @@ MELLANOX PLATFORM DRIVER
 M:      Vadim Pasternak <vadimp@mellanox.com>
 L:      platform-driver-x86@vger.kernel.org
 S:      Supported
-F:      arch/x86/platform/mellanox/mlx-platform.c
+F:      drivers/platform/x86/mlx-platform.c
 
 MELLANOX MLX CPLD HOTPLUG DRIVER
 M:     Vadim Pasternak <vadimp@mellanox.com>
index e9fbcc91c5c0214811b41cd73c54cc41d18964ab..9e0bc46e90ecf54ad7ee0c42ea2326eec3992b3a 100644 (file)
@@ -171,6 +171,7 @@ static struct s3c2410_platform_nand smdk_nand_info = {
        .twrph1         = 20,
        .nr_sets        = ARRAY_SIZE(smdk_nand_sets),
        .sets           = smdk_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* devices we initialise */
index d03df0df01fa204cea8f172e6cf681984d3b664d..029ef1b58925499bbe657c267dab534a657e2d0b 100644 (file)
@@ -223,6 +223,7 @@ static struct s3c2410_platform_nand __initdata anubis_nand_info = {
        .nr_sets        = ARRAY_SIZE(anubis_nand_sets),
        .sets           = anubis_nand_sets,
        .select_chip    = anubis_nand_select,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* IDE channels */
index 9ae170fef2a7b89ca53c60f4ca3b2c48e5975c29..7b28eb623fc1ff745baf5d88fc138179c174855c 100644 (file)
@@ -114,6 +114,7 @@ static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
        .twrph1         = 40,
        .nr_sets        = ARRAY_SIZE(at2440evb_nand_sets),
        .sets           = at2440evb_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
index ed07cf392d4bb9e2d6321a6c2c85ce0d91c52a3a..5185036765db2d096ee057774dbeadaafff11304 100644 (file)
@@ -299,6 +299,7 @@ static struct s3c2410_platform_nand __initdata bast_nand_info = {
        .nr_sets        = ARRAY_SIZE(bast_nand_sets),
        .sets           = bast_nand_sets,
        .select_chip    = bast_nand_select,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000 */
index 27ae6877550f7b8972c288ee32fa43a7e9a3a07c..b0ed401da3a3aaa4a901c92159cfe585cf054284 100644 (file)
@@ -443,6 +443,7 @@ static struct s3c2410_platform_nand __initdata gta02_nand_info = {
        .twrph1         = 15,
        .nr_sets        = ARRAY_SIZE(gta02_nand_sets),
        .sets           = gta02_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 
index 7d99fe8f6157612767b667d8a2360178d4c065ab..895aca225952d62f137aae798f603fa2006fc60e 100644 (file)
@@ -232,6 +232,7 @@ static struct s3c2410_platform_nand __initdata jive_nand_info = {
        .twrph1         = 40,
        .sets           = jive_nand_sets,
        .nr_sets        = ARRAY_SIZE(jive_nand_sets),
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 static int __init jive_mtdset(char *options)
index ec60bd4a1646f094edead1037483b5ed3aea3fba..71af8d2fd3201ffd95fa8588a440905d6a44abad 100644 (file)
@@ -287,6 +287,7 @@ static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
        .nr_sets        = ARRAY_SIZE(mini2440_nand_sets),
        .sets           = mini2440_nand_sets,
        .ignore_unset_ecc = 1,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
index 2f6fdc32683524b45933f3173ee3fd7d6aacbda1..70b0eb7d31347f8fbb6371148bbcc8de89a2aae0 100644 (file)
@@ -238,6 +238,7 @@ static struct s3c2410_platform_nand __initdata osiris_nand_info = {
        .nr_sets        = ARRAY_SIZE(osiris_nand_sets),
        .sets           = osiris_nand_sets,
        .select_chip    = osiris_nand_select,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* PCMCIA control and configuration */
index 984516e8307aa599272cdc3bee33142567e0069a..868c8208740396f649163882c238469e6a45ee7a 100644 (file)
@@ -284,6 +284,7 @@ static struct s3c2410_platform_nand __initdata qt2410_nand_info = {
        .twrph1         = 20,
        .nr_sets        = ARRAY_SIZE(qt2410_nand_sets),
        .sets           = qt2410_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 /* UDC */
index 25a139bb9826dadfafd327bb1f2e1e4163993566..e86ad6a68a0b8f3f7c22e5ae6a5a595a611bec0e 100644 (file)
@@ -611,6 +611,7 @@ static struct s3c2410_platform_nand rx1950_nand_info = {
        .twrph1 = 15,
        .nr_sets = ARRAY_SIZE(rx1950_nand_sets),
        .sets = rx1950_nand_sets,
+       .ecc_mode = NAND_ECC_SOFT,
 };
 
 static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
index cf55196f89ca34ae4139ede777bc6a35af05fead..a39fb9780dd30649aaf7a9890c46083914f0e6ba 100644 (file)
@@ -164,6 +164,7 @@ static struct s3c2410_platform_nand __initdata rx3715_nand_info = {
        .twrph1         = 15,
        .nr_sets        = ARRAY_SIZE(rx3715_nand_sets),
        .sets           = rx3715_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *rx3715_devices[] __initdata = {
index b4460d5f70112354e702ad799929db0d87d47aa3..f5e6322145fa9343d2a04d8d9aa9a088423054c0 100644 (file)
@@ -117,6 +117,7 @@ static struct s3c2410_platform_nand __initdata vstms_nand_info = {
        .twrph1         = 20,
        .nr_sets        = ARRAY_SIZE(vstms_nand_sets),
        .sets           = vstms_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *vstms_devices[] __initdata = {
index bc7dc1fcbf7dca8874e63a2bbbb9c24782f9bda1..59b5531f198743363eed55b3a316744eaae6d491 100644 (file)
@@ -204,6 +204,7 @@ static struct s3c2410_platform_nand hmt_nand_info = {
        .twrph1         = 40,
        .nr_sets        = ARRAY_SIZE(hmt_nand_sets),
        .sets           = hmt_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct gpio_led hmt_leds[] = {
index ae999fb3fe6df564083391ba6f5a69f97bf7edb2..a3e3e25728b41f10e9c8e92908f60bda3c6b47fc 100644 (file)
@@ -142,6 +142,7 @@ static struct s3c2410_platform_nand mini6410_nand_info = {
        .twrph1         = 40,
        .nr_sets        = ARRAY_SIZE(mini6410_nand_sets),
        .sets           = mini6410_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
index 4e240ffa7ac7fbf3227141019141edf23c85ab72..d6b3ffd7704bdf7c18d48a42b6f67969dc755a8f 100644 (file)
@@ -194,6 +194,7 @@ static struct s3c2410_platform_nand real6410_nand_info = {
        .twrph1         = 40,
        .nr_sets        = ARRAY_SIZE(real6410_nand_sets),
        .sets           = real6410_nand_sets,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct platform_device *real6410_devices[] __initdata = {
index 600887e491fdf2af4ad30dcc0d1601908fcca087..bf466d1876e3f27d6cd2b6e7edced71c0ae32f7b 100644 (file)
@@ -15,6 +15,8 @@ int __node_distance(int from, int to);
 
 extern nodemask_t numa_nodes_parsed __initdata;
 
+extern bool numa_off;
+
 /* Mappings between node number and cpus on that node. */
 extern cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
 void numa_clear_node(unsigned int cpu);
index 4b32168cf91a0e3b99e1d899960d47fddf38ba06..b388a99fea7b783e5ab8edcad004f8a7457ee40e 100644 (file)
@@ -35,7 +35,7 @@ static int cpu_to_node_map[NR_CPUS] = { [0 ... NR_CPUS-1] = NUMA_NO_NODE };
 
 static int numa_distance_cnt;
 static u8 *numa_distance;
-static bool numa_off;
+bool numa_off;
 
 static __init int numa_parse_early_param(char *opt)
 {
index 2db0a6c6daa5f13840bed1ede72c224e6dd5cf6a..ebef7f40aabbe26a5fa384294bf05819f949dd30 100644 (file)
@@ -65,6 +65,8 @@ extern int paddr_to_nid(unsigned long paddr);
 
 #define local_nodeid (cpu_to_node_map[smp_processor_id()])
 
+#define numa_off     0
+
 extern void map_cpu_to_node(int cpu, int nid);
 extern void unmap_cpu_from_node(int cpu, int nid);
 extern void numa_clear_node(int cpu);
index 805ae5d712e8baa63095199f1601ce548c26d606..032fed71223f54358a467d5df14d0b5fe176667a 100644 (file)
@@ -38,6 +38,6 @@
 
 #endif /* __ASSEMBLY__ */
 
-#define __NR_syscalls         392
+#define __NR_syscalls         398
 
 #endif /* _ASM_MICROBLAZE_UNISTD_H */
index a8bd3fa28bc7f4e97158fff49d25443524647b0d..d8086159d996dfdec4503fa95cf1638637f8932e 100644 (file)
 #define __NR_userfaultfd       389
 #define __NR_membarrier                390
 #define __NR_mlock2            391
+#define __NR_copy_file_range   392
+#define __NR_preadv2           393
+#define __NR_pwritev2          394
+#define __NR_pkey_mprotect     395
+#define __NR_pkey_alloc                396
+#define __NR_pkey_free         397
 
 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */
index b70bb538f00165df2d46ec87c27217577ec4b95a..96b3f26d16beeb56b815da8d87661223e2beae91 100644 (file)
@@ -49,6 +49,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
        {"9.3", 0x20},
        {"9.4", 0x21},
        {"9.5", 0x22},
+       {"9.6", 0x23},
+       {"10.0", 0x24},
        {NULL, 0},
 };
 
@@ -75,6 +77,10 @@ const struct family_string_key family_string_lookup[] = {
        {"zynq7000", 0x12},
        {"UltraScale Virtex", 0x13},
        {"UltraScale Kintex", 0x14},
+       {"UltraScale+ Zynq", 0x15},
+       {"UltraScale+ Virtex", 0x16},
+       {"UltraScale+ Kintex", 0x17},
+       {"Spartan7", 0x18},
        {NULL, 0},
 };
 
index 6b3dd99126d753a22a9ed270ec92761c2f936e27..6841c2df14d9acdfe30133baac0833111bf645d5 100644 (file)
@@ -392,3 +392,9 @@ ENTRY(sys_call_table)
        .long sys_userfaultfd
        .long sys_membarrier            /* 390 */
        .long sys_mlock2
+       .long sys_copy_file_range
+       .long sys_preadv2
+       .long sys_pwritev2
+       .long sys_pkey_mprotect         /* 395 */
+       .long sys_pkey_alloc
+       .long sys_pkey_free
index 5bbf38b916ef36839396c01cfd5bc105245ae934..9e954959f60504cd7cf04d1c8c58f897bf6cea76 100644 (file)
@@ -259,7 +259,7 @@ static int __init xilinx_timer_init(struct device_node *timer)
        int ret;
 
        if (initialized)
-               return;
+               return -EINVAL;
 
        initialized = 1;
 
index f6ae6ed9c4b1a3849ab078c273c0afa199734d45..3e1587f1f77a37e712f28e6fa61011dea25fc306 100644 (file)
                #clock-cells = <1>;
        };
 
+       rtc_dev: rtc@10003000 {
+               compatible = "ingenic,jz4740-rtc";
+               reg = <0x10003000 0x40>;
+
+               interrupt-parent = <&intc>;
+               interrupts = <15>;
+
+               clocks = <&cgu JZ4740_CLK_RTC>;
+               clock-names = "rtc";
+       };
+
        uart0: serial@10030000 {
                compatible = "ingenic,jz4740-uart";
                reg = <0x10030000 0x100>;
index 2414d63ae81898d35766c184862ad2bd6e27f41b..be1a7d3a3e1b5aa8819f702d6507c44116a1e1c7 100644 (file)
@@ -13,3 +13,7 @@
 &ext {
        clock-frequency = <12000000>;
 };
+
+&rtc_dev {
+       system-power-controller;
+};
index 073b8bfbb3b3f16525df19d9802b2d32897a9bcd..3645974b7f6595ed1f5d6729621b3763b4399e87 100644 (file)
@@ -22,7 +22,6 @@
 extern struct platform_device jz4740_udc_device;
 extern struct platform_device jz4740_udc_xceiv_device;
 extern struct platform_device jz4740_mmc_device;
-extern struct platform_device jz4740_rtc_device;
 extern struct platform_device jz4740_i2c_device;
 extern struct platform_device jz4740_nand_device;
 extern struct platform_device jz4740_framebuffer_device;
index 258fd03c9ef5aa98145cb69b699f39f5dd92e81a..a5bd94b952635fb9ebb9b23e115625d4db8c6da1 100644 (file)
@@ -438,7 +438,6 @@ static struct platform_device *jz_platform_devices[] __initdata = {
        &jz4740_pcm_device,
        &jz4740_i2s_device,
        &jz4740_codec_device,
-       &jz4740_rtc_device,
        &jz4740_adc_device,
        &jz4740_pwm_device,
        &jz4740_dma_device,
index 2f1dab35c061831263073707d6ee6e4c07816c4f..5b7cdd67a9d95b624d52d780ab736f779e551904 100644 (file)
@@ -88,27 +88,6 @@ struct platform_device jz4740_mmc_device = {
        .resource       = jz4740_mmc_resources,
 };
 
-/* RTC controller */
-static struct resource jz4740_rtc_resources[] = {
-       {
-               .start  = JZ4740_RTC_BASE_ADDR,
-               .end    = JZ4740_RTC_BASE_ADDR + 0x38 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = JZ4740_IRQ_RTC,
-               .end    = JZ4740_IRQ_RTC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device jz4740_rtc_device = {
-       .name           = "jz4740-rtc",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(jz4740_rtc_resources),
-       .resource       = jz4740_rtc_resources,
-};
-
 /* I2C controller */
 static struct resource jz4740_i2c_resources[] = {
        {
index 954e669c9e6bc5d2b47f30a796e602a155dc5495..67780c4b65730597e6d66d08e238b44669456823 100644 (file)
@@ -57,71 +57,8 @@ static void jz4740_restart(char *command)
        jz4740_halt();
 }
 
-#define JZ_REG_RTC_CTRL                        0x00
-#define JZ_REG_RTC_HIBERNATE           0x20
-#define JZ_REG_RTC_WAKEUP_FILTER       0x24
-#define JZ_REG_RTC_RESET_COUNTER       0x28
-
-#define JZ_RTC_CTRL_WRDY               BIT(7)
-#define JZ_RTC_WAKEUP_FILTER_MASK      0x0000FFE0
-#define JZ_RTC_RESET_COUNTER_MASK      0x00000FE0
-
-static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base)
-{
-       uint32_t ctrl;
-
-       do {
-               ctrl = readl(rtc_base + JZ_REG_RTC_CTRL);
-       } while (!(ctrl & JZ_RTC_CTRL_WRDY));
-}
-
-static void jz4740_power_off(void)
-{
-       void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38);
-       unsigned long wakeup_filter_ticks;
-       unsigned long reset_counter_ticks;
-       struct clk *rtc_clk;
-       unsigned long rtc_rate;
-
-       rtc_clk = clk_get(NULL, "rtc");
-       if (IS_ERR(rtc_clk))
-               panic("unable to get RTC clock");
-       rtc_rate = clk_get_rate(rtc_clk);
-       clk_put(rtc_clk);
-
-       /*
-        * Set minimum wakeup pin assertion time: 100 ms.
-        * Range is 0 to 2 sec if RTC is clocked at 32 kHz.
-        */
-       wakeup_filter_ticks = (100 * rtc_rate) / 1000;
-       if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
-               wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
-       else
-               wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
-       jz4740_rtc_wait_ready(rtc_base);
-       writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER);
-
-       /*
-        * Set reset pin low-level assertion time after wakeup: 60 ms.
-        * Range is 0 to 125 ms if RTC is clocked at 32 kHz.
-        */
-       reset_counter_ticks = (60 * rtc_rate) / 1000;
-       if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
-               reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
-       else
-               reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
-       jz4740_rtc_wait_ready(rtc_base);
-       writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER);
-
-       jz4740_rtc_wait_ready(rtc_base);
-       writel(1, rtc_base + JZ_REG_RTC_HIBERNATE);
-
-       jz4740_halt();
-}
-
 void jz4740_reset_init(void)
 {
        _machine_restart = jz4740_restart;
        _machine_halt = jz4740_halt;
-       pm_power_off = jz4740_power_off;
 }
index 83d2b4ef7f0de61297fcd1dbc5b37bf2dc9478e1..44d67b167e0b18eeb512e3c059817c31fcc0f2cc 100644 (file)
@@ -295,7 +295,7 @@ out:
  * dcookie user still being registered (namely, the reader
  * of the event buffer).
  */
-static inline unsigned long fast_get_dcookie(struct path *path)
+static inline unsigned long fast_get_dcookie(const struct path *path)
 {
        unsigned long cookie;
 
index 4810e48dbbbf57cc8d77ff4ce7bcb8356b142341..7d6aaa128e8bf0d51dd5f8515f4edf8cd9fae815 100644 (file)
 
 /*
  * Originally we used small TLB pages for kernel data and grouped some
- * things together as "write once", enforcing the property at the end
+ * things together as ro-after-init, enforcing the property at the end
  * of initialization by making those pages read-only and non-coherent.
  * This allowed better cache utilization since cache inclusion did not
  * need to be maintained.  However, to do this requires an extra TLB
  * entry, which on balance is more of a performance hit than the
  * non-coherence is a performance gain, so we now just make "read
- * mostly" and "write once" be synonyms.  We keep the attribute
+ * mostly" and "ro-after-init" be synonyms.  We keep the attribute
  * separate in case we change our minds at a future date.
  */
-#define __write_once __read_mostly
-
-/* __ro_after_init is the generic name for the tile arch __write_once. */
 #define __ro_after_init __read_mostly
 
 #endif /* _ASM_TILE_CACHE_H */
index 86a746243dc83500803de2f6fa2a79b0898e1442..50343bfe7936e8b87997bbdca50423ff119b1a4b 100644 (file)
@@ -19,9 +19,6 @@
 
 #include <asm-generic/sections.h>
 
-/* Write-once data is writable only till the end of initialization. */
-extern char __w1data_begin[], __w1data_end[];
-
 extern char vdso_start[], vdso_end[];
 #ifdef CONFIG_COMPAT
 extern char vdso32_start[], vdso32_end[];
index 2305084c9b93b72df9f5fba6f6302037d0fb43a7..09233fbe78017f41f646366bc8af5f3d8ac33736 100644 (file)
@@ -43,29 +43,28 @@ void *module_alloc(unsigned long size)
        int npages;
 
        npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
-       pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
+       pages = kmalloc_array(npages, sizeof(*pages), GFP_KERNEL);
        if (pages == NULL)
                return NULL;
        for (; i < npages; ++i) {
                pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
                if (!pages[i])
-                       goto error;
+                       goto free_pages;
        }
 
        area = __get_vm_area(size, VM_ALLOC, MEM_MODULE_START, MEM_MODULE_END);
        if (!area)
-               goto error;
+               goto free_pages;
        area->nr_pages = npages;
        area->pages = pages;
 
        if (map_vm_area(area, prot_rwx, pages)) {
                vunmap(area->addr);
-               goto error;
+               goto free_pages;
        }
 
        return area->addr;
-
-error:
+ free_pages:
        while (--i >= 0)
                __free_page(pages[i]);
        kfree(pages);
index 9475a74cd53ac9ed1711dc92339fc47d2d06796b..bc6656b5708b168f8f26c99b599b0233cf7ba5e2 100644 (file)
@@ -57,7 +57,7 @@ static int pci_probe = 1;
  * This flag tells if the platform is TILEmpower that needs
  * special configuration for the PLX switch chip.
  */
-int __write_once tile_plx_gen1;
+int __ro_after_init tile_plx_gen1;
 
 static struct pci_controller controllers[TILE_NUM_PCIE];
 static int num_controllers;
index 0e7a5d09e023820e17ee1e47958d32fee1cc9136..b554a68eea1bbeb4b65aae2b0b6fcf226ca381ec 100644 (file)
@@ -131,7 +131,7 @@ static int tile_irq_cpu(int irq)
 
        count = cpumask_weight(&intr_cpus_map);
        if (unlikely(count == 0)) {
-               pr_warn("intr_cpus_map empty, interrupts will be delievered to dataplane tiles\n");
+               pr_warn("intr_cpus_map empty, interrupts will be delivered to dataplane tiles\n");
                return irq % (smp_height * smp_width);
        }
 
index 153020abd2f5c8a7476907ac62531d70f8c6f225..443a70bccc1c862d945d3a84945c6771033b74c7 100644 (file)
@@ -49,7 +49,7 @@
 static inline int ABS(int x) { return x >= 0 ? x : -x; }
 
 /* Chip information */
-char chip_model[64] __write_once;
+char chip_model[64] __ro_after_init;
 
 #ifdef CONFIG_VT
 struct screen_info screen_info;
@@ -97,17 +97,17 @@ int node_controller[MAX_NUMNODES] = { [0 ... MAX_NUMNODES-1] = -1 };
 #ifdef CONFIG_HIGHMEM
 /* Map information from VAs to PAs */
 unsigned long pbase_map[1 << (32 - HPAGE_SHIFT)]
-  __write_once __attribute__((aligned(L2_CACHE_BYTES)));
+  __ro_after_init __attribute__((aligned(L2_CACHE_BYTES)));
 EXPORT_SYMBOL(pbase_map);
 
 /* Map information from PAs to VAs */
 void *vbase_map[NR_PA_HIGHBIT_VALUES]
-  __write_once __attribute__((aligned(L2_CACHE_BYTES)));
+  __ro_after_init __attribute__((aligned(L2_CACHE_BYTES)));
 EXPORT_SYMBOL(vbase_map);
 #endif
 
 /* Node number as a function of the high PA bits */
-int highbits_to_node[NR_PA_HIGHBIT_VALUES] __write_once;
+int highbits_to_node[NR_PA_HIGHBIT_VALUES] __ro_after_init;
 EXPORT_SYMBOL(highbits_to_node);
 
 static unsigned int __initdata maxmem_pfn = -1U;
@@ -844,11 +844,11 @@ static void __init zone_sizes_init(void)
 #ifdef CONFIG_NUMA
 
 /* which logical CPUs are on which nodes */
-struct cpumask node_2_cpu_mask[MAX_NUMNODES] __write_once;
+struct cpumask node_2_cpu_mask[MAX_NUMNODES] __ro_after_init;
 EXPORT_SYMBOL(node_2_cpu_mask);
 
 /* which node each logical CPU is on */
-char cpu_2_node[NR_CPUS] __write_once __attribute__((aligned(L2_CACHE_BYTES)));
+char cpu_2_node[NR_CPUS] __ro_after_init __attribute__((aligned(L2_CACHE_BYTES)));
 EXPORT_SYMBOL(cpu_2_node);
 
 /* Return cpu_to_node() except for cpus not yet assigned, which return -1 */
@@ -1269,7 +1269,7 @@ static void __init validate_va(void)
  * cpus plus any other cpus that are willing to share their cache.
  * It is set by hv_inquire_tiles(HV_INQ_TILES_LOTAR).
  */
-struct cpumask __write_once cpu_lotar_map;
+struct cpumask __ro_after_init cpu_lotar_map;
 EXPORT_SYMBOL(cpu_lotar_map);
 
 /*
@@ -1291,7 +1291,7 @@ EXPORT_SYMBOL(hash_for_home_map);
  * cache, those tiles will only appear in cpu_lotar_map, NOT in
  * cpu_cacheable_map, as they are a special case.
  */
-struct cpumask __write_once cpu_cacheable_map;
+struct cpumask __ro_after_init cpu_cacheable_map;
 EXPORT_SYMBOL(cpu_cacheable_map);
 
 static __initdata struct cpumask disabled_map;
@@ -1506,7 +1506,7 @@ void __init setup_arch(char **cmdline_p)
  * Set up per-cpu memory.
  */
 
-unsigned long __per_cpu_offset[NR_CPUS] __write_once;
+unsigned long __per_cpu_offset[NR_CPUS] __ro_after_init;
 EXPORT_SYMBOL(__per_cpu_offset);
 
 static size_t __initdata pfn_offset[MAX_NUMNODES] = { 0 };
index 07e3ff5cc74010170ca43f7df20acb060df2727b..94a62e1197ce8a0e3b4438e2e70ddb957a6fc5c0 100644 (file)
@@ -27,7 +27,7 @@
  * We write to width and height with a single store in head_NN.S,
  * so make the variable aligned to "long".
  */
-HV_Topology smp_topology __write_once __aligned(sizeof(long));
+HV_Topology smp_topology __ro_after_init __aligned(sizeof(long));
 EXPORT_SYMBOL(smp_topology);
 
 #if CHIP_HAS_IPI()
index ea960d6609177faa86780e6164f26e4d3ef51ac2..c9357012b1c892a838512d2df063e25e4d66930d 100644 (file)
@@ -37,7 +37,7 @@
  */
 
 /* How many cycles per second we are running at. */
-static cycles_t cycles_per_sec __write_once;
+static cycles_t cycles_per_sec __ro_after_init;
 
 cycles_t get_clock_rate(void)
 {
@@ -68,7 +68,7 @@ EXPORT_SYMBOL(get_cycles);
  */
 #define SCHED_CLOCK_SHIFT 10
 
-static unsigned long sched_clock_mult __write_once;
+static unsigned long sched_clock_mult __ro_after_init;
 
 static cycles_t clocksource_get_cycles(struct clocksource *cs)
 {
index 9772a355428233c5958461dde63f083ce1e44d84..4fe78c5b839492c1935b26fece721f32dc23d88a 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/mman.h>
 #include <linux/types.h>
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/compat.h>
 #include <linux/prctl.h>
 #include <asm/cacheflush.h>
index 9c0ec22009a5ed833fab76a6e8ee94a9c1a1685f..c1ebc1065fc167114fbcded5a22762bfea269aa8 100644 (file)
@@ -138,19 +138,13 @@ finv_buffer_remote(void *buffer, size_t size, int hfh)
        if ((unsigned long)base < (unsigned long)buffer)
                base = buffer;
 
-       /*
-        * Fire all the loads we need.  The MAF only has eight entries
-        * so we can have at most eight outstanding loads, so we
-        * unroll by that amount.
-        */
-#pragma unroll 8
+       /* Fire all the loads we need. */
        for (; p >= base; p -= step_size)
                force_load(p);
 
        /*
         * Repeat, but with finv's instead of loads, to get rid of the
         * data we just loaded into our own cache and the old home L3.
-        * No need to unroll since finv's don't target a register.
         * The finv's are guaranteed not to actually flush the data in
         * the buffer back to their home, since we just read it, so the
         * lines are clean in cache; we will only invalidate those lines.
index 4fb0acb9d154d6b97a6eccf15b41d0b2c1067865..aeaf20c7aaa4e20461a8e4eb8a9db62d01dbaff2 100644 (file)
@@ -12,7 +12,7 @@
  *   more details.
  */
 
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 
index beba986589e5851aea236163a6b6f4031d6ed5a7..709f8e9ba3e9673f784c19b4a3e42dc72d8cb50d 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>             /* For unblank_screen() */
 #include <linux/highmem.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/kprobes.h>
 #include <linux/hugetlb.h>
 #include <linux/syscalls.h>
index 40ca30a9fee33eae72ab1221e2084732be7a6006..b51cc28acd0a11e27478697c0c87dec0a62930a6 100644 (file)
@@ -47,7 +47,7 @@
  * The noallocl2 option suppresses all use of the L2 cache to cache
  * locally from a remote home.
  */
-static int __write_once noallocl2;
+static int __ro_after_init noallocl2;
 static int __init set_noallocl2(char *str)
 {
        noallocl2 = 1;
index adce25462b0dbaf6bc8147583333b7ee1863b39d..3a97e4d7205cf24b793ab76ea1cdbdb65f37a155 100644 (file)
@@ -190,9 +190,9 @@ static void __init page_table_range_init(unsigned long start,
 
 static int __initdata ktext_hash = 1;  /* .text pages */
 static int __initdata kdata_hash = 1;  /* .data and .bss pages */
-int __write_once hash_default = 1;     /* kernel allocator pages */
+int __ro_after_init hash_default = 1;     /* kernel allocator pages */
 EXPORT_SYMBOL(hash_default);
-int __write_once kstack_hash = 1;      /* if no homecaching, use h4h */
+int __ro_after_init kstack_hash = 1;      /* if no homecaching, use h4h */
 
 /*
  * CPUs to use to for striping the pages of kernel data.  If hash-for-home
@@ -203,7 +203,7 @@ int __write_once kstack_hash = 1;      /* if no homecaching, use h4h */
 static __initdata struct cpumask kdata_mask;
 static __initdata int kdata_arg_seen;
 
-int __write_once kdata_huge;       /* if no homecaching, small pages */
+int __ro_after_init kdata_huge;       /* if no homecaching, small pages */
 
 
 /* Combine a generic pgprot_t with cache home to get a cache-aware pgprot. */
@@ -896,8 +896,8 @@ void __init pgtable_cache_init(void)
                panic("pgtable_cache_init(): Cannot create pgd cache");
 }
 
-static long __write_once initfree = 1;
-static bool __write_once set_initfree_done;
+static long __ro_after_init initfree = 1;
+static bool __ro_after_init set_initfree_done;
 
 /* Select whether to free (1) or mark unusable (0) the __init pages. */
 static int __init set_initfree(char *str)
index dd47e60aabf5769a30d5944cd0811de4acdb2433..64024c9995314a9488bb83261baa1d6f7a9b5cae 100644 (file)
@@ -555,18 +555,6 @@ config X86_INTEL_QUARK
          Say Y here if you have a Quark based system such as the Arduino
          compatible Intel Galileo.
 
-config MLX_PLATFORM
-       tristate "Mellanox Technologies platform support"
-       depends on X86_64
-       depends on X86_EXTENDED_PLATFORM
-       ---help---
-         This option enables system support for the Mellanox Technologies
-         platform.
-
-         Say Y here if you are building a kernel for Mellanox system.
-
-         Otherwise, say N.
-
 config X86_INTEL_LPSS
        bool "Intel Low Power Subsystem Support"
        depends on X86 && ACPI
diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h
new file mode 100644 (file)
index 0000000..44b8762
--- /dev/null
@@ -0,0 +1,16 @@
+#include <asm/ftrace.h>
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/page.h>
+#include <asm/checksum.h>
+
+#include <asm-generic/asm-prototypes.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/special_insns.h>
+#include <asm/preempt.h>
+
+#ifndef CONFIG_X86_CMPXCHG64
+extern void cmpxchg8b_emu(void);
+#endif
index 59ac427960d4dcfdc9eb13c2a171fa33f22b79fd..6ccbf1aaa7ce1f72021757593c99b555480f78da 100644 (file)
 #define X86_FEATURE_AMD_DCM     ( 3*32+27) /* multi-node processor */
 #define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
 #define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
+#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* TSC has known frequency */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3       ( 4*32+ 0) /* "pni" SSE-3 */
index 1c7eefe3250295762c258a66af22a05d53882334..7ec59edde154c344cb5bfce7ba586360a6d32d19 100644 (file)
@@ -229,18 +229,18 @@ static struct fd_routine_l {
        int (*_dma_setup)(char *addr, unsigned long size, int mode, int io);
 } fd_routine[] = {
        {
-               request_dma,
-               free_dma,
-               get_dma_residue,
-               dma_mem_alloc,
-               hard_dma_setup
+               ._request_dma           = request_dma,
+               ._free_dma              = free_dma,
+               ._get_dma_residue       = get_dma_residue,
+               ._dma_mem_alloc         = dma_mem_alloc,
+               ._dma_setup             = hard_dma_setup
        },
        {
-               vdma_request_dma,
-               vdma_nop,
-               vdma_get_dma_residue,
-               vdma_mem_alloc,
-               vdma_dma_setup
+               ._request_dma           = vdma_request_dma,
+               ._free_dma              = vdma_nop,
+               ._get_dma_residue       = vdma_get_dma_residue,
+               ._dma_mem_alloc         = vdma_mem_alloc,
+               ._dma_setup             = vdma_dma_setup
        }
 };
 
index 7892530cbacfb38e81684b1c5e60f90662e0d872..2e25038dbd932cfec9381eccbc1f4c30fe0c7b2e 100644 (file)
@@ -704,6 +704,7 @@ struct kvm_apic_map {
 
 /* Hyper-V emulation context */
 struct kvm_hv {
+       struct mutex hv_lock;
        u64 hv_guest_os_id;
        u64 hv_hypercall;
        u64 hv_tsc_page;
index 72198c64e646d3cbb0d9831d950e4e815003cdd3..f9813b6d8b806eae92363b5c5667c94ca5c9fd24 100644 (file)
@@ -31,6 +31,10 @@ typedef struct {
        u16 pkey_allocation_map;
        s16 execute_only_pkey;
 #endif
+#ifdef CONFIG_X86_INTEL_MPX
+       /* address of the bounds directory */
+       void __user *bd_addr;
+#endif
 } mm_context_t;
 
 #ifdef CONFIG_SMP
index 7a35495275a9b7b1150bde2935757a212defde59..0b416d4cf73b690a77b866ff461b5cf5ccbc2452 100644 (file)
@@ -59,7 +59,7 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs);
 int mpx_handle_bd_fault(void);
 static inline int kernel_managing_mpx_tables(struct mm_struct *mm)
 {
-       return (mm->bd_addr != MPX_INVALID_BOUNDS_DIR);
+       return (mm->context.bd_addr != MPX_INVALID_BOUNDS_DIR);
 }
 static inline void mpx_mm_init(struct mm_struct *mm)
 {
@@ -67,7 +67,7 @@ static inline void mpx_mm_init(struct mm_struct *mm)
         * NULL is theoretically a valid place to put the bounds
         * directory, so point this at an invalid address.
         */
-       mm->bd_addr = MPX_INVALID_BOUNDS_DIR;
+       mm->context.bd_addr = MPX_INVALID_BOUNDS_DIR;
 }
 void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
                      unsigned long start, unsigned long end);
index 1cc82ece9ac1819b92ec82aca72805c0e966af97..62b775926045edb68aa935d7142067e2c00a03bd 100644 (file)
@@ -116,8 +116,7 @@ static inline void native_pgd_clear(pgd_t *pgd)
        native_set_pgd(pgd, native_make_pgd(0));
 }
 
-extern void sync_global_pgds(unsigned long start, unsigned long end,
-                            int removed);
+extern void sync_global_pgds(unsigned long start, unsigned long end);
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
index 33b6365c22fed29b7081f637fd96b0b78a5c2162..abb1fdcc545a530f59880b3e7e754cf6034bf9a2 100644 (file)
@@ -45,8 +45,17 @@ extern int tsc_clocksource_reliable;
  * Boot-time check whether the TSCs are synchronized across
  * all CPUs/cores:
  */
+#ifdef CONFIG_X86_TSC
+extern bool tsc_store_and_check_tsc_adjust(bool bootcpu);
+extern void tsc_verify_tsc_adjust(bool resume);
 extern void check_tsc_sync_source(int cpu);
 extern void check_tsc_sync_target(void);
+#else
+static inline bool tsc_store_and_check_tsc_adjust(bool bootcpu) { return false; }
+static inline void tsc_verify_tsc_adjust(bool resume) { }
+static inline void check_tsc_sync_source(int cpu) { }
+static inline void check_tsc_sync_target(void) { }
+#endif
 
 extern int notsc_setup(char *);
 extern void tsc_save_sched_clock_state(void);
index 05110c1097ae0a9ba9ddd3b7936b84ac3980def9..581386c7e42953e654ee60fda2feb0941c4e9c99 100644 (file)
@@ -75,7 +75,7 @@ apm-y                         := apm_32.o
 obj-$(CONFIG_APM)              += apm.o
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_SMP)              += smpboot.o
-obj-$(CONFIG_SMP)              += tsc_sync.o
+obj-$(CONFIG_X86_TSC)          += tsc_sync.o
 obj-$(CONFIG_SMP)              += setup_percpu.o
 obj-$(CONFIG_X86_MPPARSE)      += mpparse.o
 obj-y                          += apic/
index 4764fa56924d200c724473a1c02a9823b56b5912..6f65b0eed384c6b276d26b44aeb0c535d6b9db3e 100644 (file)
@@ -715,7 +715,7 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
        int nid;
 
        nid = acpi_get_node(handle);
-       if (nid != -1) {
+       if (nid != NUMA_NO_NODE) {
                set_apicid_to_node(physid, nid);
                numa_set_node(cpu, nid);
        }
index bb47e5eacd448e0945d08ef7349d658459c02185..5b7e43eff139b888bb757c5c7ce3172017c5158b 100644 (file)
@@ -2159,21 +2159,6 @@ int __generic_processor_info(int apicid, int version, bool enabled)
                }
        }
 
-       /*
-        * This can happen on physical hotplug. The sanity check at boot time
-        * is done from native_smp_prepare_cpus() after num_possible_cpus() is
-        * established.
-        */
-       if (topology_update_package_map(apicid, cpu) < 0) {
-               int thiscpu = max + disabled_cpus;
-
-               pr_warning("APIC: Package limit reached. Processor %d/0x%x ignored.\n",
-                          thiscpu, apicid);
-
-               disabled_cpus++;
-               return -ENOSPC;
-       }
-
        /*
         * Validate version
         */
index 729f92ba8224b5682677fcf8e7a0821e993cdb10..1f6b50a449ab92820cdb9d90661d7c63eaba30c2 100644 (file)
@@ -979,29 +979,21 @@ static void x86_init_cache_qos(struct cpuinfo_x86 *c)
 }
 
 /*
- * The physical to logical package id mapping is initialized from the
- * acpi/mptables information. Make sure that CPUID actually agrees with
- * that.
+ * Validate that ACPI/mptables have the same information about the
+ * effective APIC id and update the package map.
  */
-static void sanitize_package_id(struct cpuinfo_x86 *c)
+static void validate_apic_and_package_id(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
-       unsigned int pkg, apicid, cpu = smp_processor_id();
+       unsigned int apicid, cpu = smp_processor_id();
 
        apicid = apic->cpu_present_to_apicid(cpu);
-       pkg = apicid >> boot_cpu_data.x86_coreid_bits;
 
-       if (apicid != c->initial_apicid) {
-               pr_err(FW_BUG "CPU%u: APIC id mismatch. Firmware: %x CPUID: %x\n",
+       if (apicid != c->apicid) {
+               pr_err(FW_BUG "CPU%u: APIC id mismatch. Firmware: %x APIC: %x\n",
                       cpu, apicid, c->initial_apicid);
-               c->initial_apicid = apicid;
        }
-       if (pkg != c->phys_proc_id) {
-               pr_err(FW_BUG "CPU%u: Using firmware package id %u instead of %u\n",
-                      cpu, pkg, c->phys_proc_id);
-               c->phys_proc_id = pkg;
-       }
-       c->logical_proc_id = topology_phys_to_logical_pkg(pkg);
+       BUG_ON(topology_update_package_map(c->phys_proc_id, cpu));
 #else
        c->logical_proc_id = 0;
 #endif
@@ -1132,7 +1124,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 #ifdef CONFIG_NUMA
        numa_add_cpu(smp_processor_id());
 #endif
-       sanitize_package_id(c);
 }
 
 /*
@@ -1187,6 +1178,7 @@ void identify_secondary_cpu(struct cpuinfo_x86 *c)
        enable_sep_cpu();
 #endif
        mtrr_ap_init();
+       validate_apic_and_package_id(c);
 }
 
 static __init int setup_noclflush(char *arg)
index 90de28841242a4992f23a304e6a048293f43b9af..b467b14b03eb2108bd7097065ed55aeae8121fc6 100644 (file)
@@ -298,12 +298,13 @@ ENTRY(start_cpu)
         *      REX.W + FF /5 JMP m16:64 Jump far, absolute indirect,
         *              address given in m16:64.
         */
-       call    1f              # put return address on stack for unwinder
-1:     xorq    %rbp, %rbp      # clear frame pointer
+       pushq   $.Lafter_lret   # put return address on stack for unwinder
+       xorq    %rbp, %rbp      # clear frame pointer
        movq    initial_code(%rip), %rax
        pushq   $__KERNEL_CS    # set correct cs
        pushq   %rax            # target address in negative space
        lretq
+.Lafter_lret:
 ENDPROC(start_cpu)
 
 #include "verify_cpu.S"
index 43c36d8a6ae25b43a90610dcf3079633792f8aed..37363e46b1f0beda54e6591583256c11e56cedee 100644 (file)
@@ -235,6 +235,7 @@ static inline void play_dead(void)
 
 void arch_cpu_idle_enter(void)
 {
+       tsc_verify_tsc_adjust(false);
        local_touch_nmi();
 }
 
index 0c37d4fd01b2649d0129c4c9edecefea80ab542a..46732dc3b73cd67e874dfe99b0eeb807f816e06a 100644 (file)
@@ -103,7 +103,6 @@ static unsigned int max_physical_pkg_id __read_mostly;
 unsigned int __max_logical_packages __read_mostly;
 EXPORT_SYMBOL(__max_logical_packages);
 static unsigned int logical_packages __read_mostly;
-static bool logical_packages_frozen __read_mostly;
 
 /* Maximum number of SMT threads on any online core */
 int __max_smt_threads __read_mostly;
@@ -273,9 +272,14 @@ static void notrace start_secondary(void *unused)
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
 
-int topology_update_package_map(unsigned int apicid, unsigned int cpu)
+/**
+ * topology_update_package_map - Update the physical to logical package map
+ * @pkg:       The physical package id as retrieved via CPUID
+ * @cpu:       The cpu for which this is updated
+ */
+int topology_update_package_map(unsigned int pkg, unsigned int cpu)
 {
-       unsigned int new, pkg = apicid >> boot_cpu_data.x86_coreid_bits;
+       unsigned int new;
 
        /* Called from early boot ? */
        if (!physical_package_map)
@@ -288,16 +292,17 @@ int topology_update_package_map(unsigned int apicid, unsigned int cpu)
        if (test_and_set_bit(pkg, physical_package_map))
                goto found;
 
-       if (logical_packages_frozen) {
-               physical_to_logical_pkg[pkg] = -1;
-               pr_warn("APIC(%x) Package %u exceeds logical package max\n",
-                       apicid, pkg);
+       if (logical_packages >= __max_logical_packages) {
+               pr_warn("Package %u of CPU %u exceeds BIOS package data %u.\n",
+                       logical_packages, cpu, __max_logical_packages);
                return -ENOSPC;
        }
 
        new = logical_packages++;
-       pr_info("APIC(%x) Converting physical %u to logical package %u\n",
-               apicid, pkg, new);
+       if (new != pkg) {
+               pr_info("CPU %u Converting physical %u to logical package %u\n",
+                       cpu, pkg, new);
+       }
        physical_to_logical_pkg[pkg] = new;
 
 found:
@@ -318,9 +323,9 @@ int topology_phys_to_logical_pkg(unsigned int phys_pkg)
 }
 EXPORT_SYMBOL(topology_phys_to_logical_pkg);
 
-static void __init smp_init_package_map(void)
+static void __init smp_init_package_map(struct cpuinfo_x86 *c, unsigned int cpu)
 {
-       unsigned int ncpus, cpu;
+       unsigned int ncpus;
        size_t size;
 
        /*
@@ -365,27 +370,9 @@ static void __init smp_init_package_map(void)
        size = BITS_TO_LONGS(max_physical_pkg_id) * sizeof(unsigned long);
        physical_package_map = kzalloc(size, GFP_KERNEL);
 
-       for_each_present_cpu(cpu) {
-               unsigned int apicid = apic->cpu_present_to_apicid(cpu);
-
-               if (apicid == BAD_APICID || !apic->apic_id_valid(apicid))
-                       continue;
-               if (!topology_update_package_map(apicid, cpu))
-                       continue;
-               pr_warn("CPU %u APICId %x disabled\n", cpu, apicid);
-               per_cpu(x86_bios_cpu_apicid, cpu) = BAD_APICID;
-               set_cpu_possible(cpu, false);
-               set_cpu_present(cpu, false);
-       }
-
-       if (logical_packages > __max_logical_packages) {
-               pr_warn("Detected more packages (%u), then computed by BIOS data (%u).\n",
-                       logical_packages, __max_logical_packages);
-               logical_packages_frozen = true;
-               __max_logical_packages  = logical_packages;
-       }
-
        pr_info("Max logical packages: %u\n", __max_logical_packages);
+
+       topology_update_package_map(c->phys_proc_id, cpu);
 }
 
 void __init smp_store_boot_cpu_info(void)
@@ -395,7 +382,7 @@ void __init smp_store_boot_cpu_info(void)
 
        *c = boot_cpu_data;
        c->cpu_index = id;
-       smp_init_package_map();
+       smp_init_package_map(c, id);
 }
 
 /*
@@ -1476,15 +1463,15 @@ __init void prefill_possible_map(void)
                possible = i;
        }
 
+       nr_cpu_ids = possible;
+
        pr_info("Allowing %d CPUs, %d hotplug CPUs\n",
                possible, max_t(int, possible - num_processors, 0));
 
+       reset_cpu_possible_mask();
+
        for (i = 0; i < possible; i++)
                set_cpu_possible(i, true);
-       for (; i < NR_CPUS; i++)
-               set_cpu_possible(i, false);
-
-       nr_cpu_ids = possible;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
index 46b2f41f8b05295cb782896da635c2c4c8687507..0aed75a1e31b0e7f88d3f3f105ea4207f5bcade2 100644 (file)
@@ -702,6 +702,20 @@ unsigned long native_calibrate_tsc(void)
                }
        }
 
+       /*
+        * TSC frequency determined by CPUID is a "hardware reported"
+        * frequency and is the most accurate one so far we have. This
+        * is considered a known frequency.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+
+       /*
+        * For Atom SoCs TSC is the only reliable clocksource.
+        * Mark TSC reliable so no watchdog on it.
+        */
+       if (boot_cpu_data.x86_model == INTEL_FAM6_ATOM_GOLDMONT)
+               setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
+
        return crystal_khz * ebx_numerator / eax_denominator;
 }
 
@@ -1043,18 +1057,20 @@ static void detect_art(void)
        if (boot_cpu_data.cpuid_level < ART_CPUID_LEAF)
                return;
 
-       cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
-             &art_to_tsc_numerator, unused, unused+1);
-
-       /* Don't enable ART in a VM, non-stop TSC required */
+       /* Don't enable ART in a VM, non-stop TSC and TSC_ADJUST required */
        if (boot_cpu_has(X86_FEATURE_HYPERVISOR) ||
            !boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ||
-           art_to_tsc_denominator < ART_MIN_DENOMINATOR)
+           !boot_cpu_has(X86_FEATURE_TSC_ADJUST))
                return;
 
-       if (rdmsrl_safe(MSR_IA32_TSC_ADJUST, &art_to_tsc_offset))
+       cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
+             &art_to_tsc_numerator, unused, unused+1);
+
+       if (art_to_tsc_denominator < ART_MIN_DENOMINATOR)
                return;
 
+       rdmsrl(MSR_IA32_TSC_ADJUST, art_to_tsc_offset);
+
        /* Make this sticky over multiple CPU init calls */
        setup_force_cpu_cap(X86_FEATURE_ART);
 }
@@ -1064,6 +1080,11 @@ static void detect_art(void)
 
 static struct clocksource clocksource_tsc;
 
+static void tsc_resume(struct clocksource *cs)
+{
+       tsc_verify_tsc_adjust(true);
+}
+
 /*
  * We used to compare the TSC to the cycle_last value in the clocksource
  * structure to avoid a nasty time-warp. This can be observed in a
@@ -1096,6 +1117,7 @@ static struct clocksource clocksource_tsc = {
        .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
                                  CLOCK_SOURCE_MUST_VERIFY,
        .archdata               = { .vclock_mode = VCLOCK_TSC },
+       .resume                 = tsc_resume,
 };
 
 void mark_tsc_unstable(char *reason)
@@ -1283,10 +1305,10 @@ static int __init init_tsc_clocksource(void)
                clocksource_tsc.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
 
        /*
-        * Trust the results of the earlier calibration on systems
-        * exporting a reliable TSC.
+        * When TSC frequency is known (retrieved via MSR or CPUID), we skip
+        * the refined calibration and directly register it as a clocksource.
         */
-       if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) {
+       if (boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ)) {
                clocksource_register_khz(&clocksource_tsc, tsc_khz);
                return 0;
        }
@@ -1363,6 +1385,8 @@ void __init tsc_init(void)
 
        if (unsynchronized_tsc())
                mark_tsc_unstable("TSCs unsynchronized");
+       else
+               tsc_store_and_check_tsc_adjust(true);
 
        check_system_tsc_reliable();
 
index 0fe720d64feff2c7027280f741495f6a9cf4722c..19afdbd7d0a77c8f5511cf2de616d24c5259dbae 100644 (file)
@@ -100,5 +100,24 @@ unsigned long cpu_khz_from_msr(void)
 #ifdef CONFIG_X86_LOCAL_APIC
        lapic_timer_frequency = (freq * 1000) / HZ;
 #endif
+
+       /*
+        * TSC frequency determined by MSR is always considered "known"
+        * because it is reported by HW.
+        * Another fact is that on MSR capable platforms, PIT/HPET is
+        * generally not available so calibration won't work at all.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+
+       /*
+        * Unfortunately there is no way for hardware to tell whether the
+        * TSC is reliable.  We were told by silicon design team that TSC
+        * on Atom SoCs are always "reliable". TSC is also the only
+        * reliable clocksource on these SoCs (HPET is either not present
+        * or not functional) so mark TSC reliable which removes the
+        * requirement for a watchdog clocksource.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
+
        return res;
 }
index 78083bf23ed1abc808c7699f383b58581bc72c1e..d0db011051a54212742680d3f25c2c52fb5c8ea6 100644 (file)
  * ( The serial nature of the boot logic and the CPU hotplug lock
  *   protects against more than 2 CPUs entering this code. )
  */
+#include <linux/topology.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/nmi.h>
 #include <asm/tsc.h>
 
+struct tsc_adjust {
+       s64             bootval;
+       s64             adjusted;
+       unsigned long   nextcheck;
+       bool            warned;
+};
+
+static DEFINE_PER_CPU(struct tsc_adjust, tsc_adjust);
+
+void tsc_verify_tsc_adjust(bool resume)
+{
+       struct tsc_adjust *adj = this_cpu_ptr(&tsc_adjust);
+       s64 curval;
+
+       if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+               return;
+
+       /* Rate limit the MSR check */
+       if (!resume && time_before(jiffies, adj->nextcheck))
+               return;
+
+       adj->nextcheck = jiffies + HZ;
+
+       rdmsrl(MSR_IA32_TSC_ADJUST, curval);
+       if (adj->adjusted == curval)
+               return;
+
+       /* Restore the original value */
+       wrmsrl(MSR_IA32_TSC_ADJUST, adj->adjusted);
+
+       if (!adj->warned || resume) {
+               pr_warn(FW_BUG "TSC ADJUST differs: CPU%u %lld --> %lld. Restoring\n",
+                       smp_processor_id(), adj->adjusted, curval);
+               adj->warned = true;
+       }
+}
+
+static void tsc_sanitize_first_cpu(struct tsc_adjust *cur, s64 bootval,
+                                  unsigned int cpu, bool bootcpu)
+{
+       /*
+        * First online CPU in a package stores the boot value in the
+        * adjustment value. This value might change later via the sync
+        * mechanism. If that fails we still can yell about boot values not
+        * being consistent.
+        *
+        * On the boot cpu we just force set the ADJUST value to 0 if it's
+        * non zero. We don't do that on non boot cpus because physical
+        * hotplug should have set the ADJUST register to a value > 0 so
+        * the TSC is in sync with the already running cpus.
+        *
+        * But we always force positive ADJUST values. Otherwise the TSC
+        * deadline timer creates an interrupt storm. We also have to
+        * prevent values > 0x7FFFFFFF as those wreckage the timer as well.
+        */
+       if ((bootcpu && bootval != 0) || (!bootcpu && bootval < 0) ||
+           (bootval > 0x7FFFFFFF)) {
+               pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n", cpu,
+                       bootval);
+               wrmsrl(MSR_IA32_TSC_ADJUST, 0);
+               bootval = 0;
+       }
+       cur->adjusted = bootval;
+}
+
+#ifndef CONFIG_SMP
+bool __init tsc_store_and_check_tsc_adjust(bool bootcpu)
+{
+       struct tsc_adjust *cur = this_cpu_ptr(&tsc_adjust);
+       s64 bootval;
+
+       if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+               return false;
+
+       rdmsrl(MSR_IA32_TSC_ADJUST, bootval);
+       cur->bootval = bootval;
+       cur->nextcheck = jiffies + HZ;
+       tsc_sanitize_first_cpu(cur, bootval, smp_processor_id(), bootcpu);
+       return false;
+}
+
+#else /* !CONFIG_SMP */
+
+/*
+ * Store and check the TSC ADJUST MSR if available
+ */
+bool tsc_store_and_check_tsc_adjust(bool bootcpu)
+{
+       struct tsc_adjust *ref, *cur = this_cpu_ptr(&tsc_adjust);
+       unsigned int refcpu, cpu = smp_processor_id();
+       struct cpumask *mask;
+       s64 bootval;
+
+       if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+               return false;
+
+       rdmsrl(MSR_IA32_TSC_ADJUST, bootval);
+       cur->bootval = bootval;
+       cur->nextcheck = jiffies + HZ;
+       cur->warned = false;
+
+       /*
+        * Check whether this CPU is the first in a package to come up. In
+        * this case do not check the boot value against another package
+        * because the new package might have been physically hotplugged,
+        * where TSC_ADJUST is expected to be different. When called on the
+        * boot CPU topology_core_cpumask() might not be available yet.
+        */
+       mask = topology_core_cpumask(cpu);
+       refcpu = mask ? cpumask_any_but(mask, cpu) : nr_cpu_ids;
+
+       if (refcpu >= nr_cpu_ids) {
+               tsc_sanitize_first_cpu(cur, bootval, smp_processor_id(),
+                                      bootcpu);
+               return false;
+       }
+
+       ref = per_cpu_ptr(&tsc_adjust, refcpu);
+       /*
+        * Compare the boot value and complain if it differs in the
+        * package.
+        */
+       if (bootval != ref->bootval) {
+               pr_warn(FW_BUG "TSC ADJUST differs: Reference CPU%u: %lld CPU%u: %lld\n",
+                       refcpu, ref->bootval, cpu, bootval);
+       }
+       /*
+        * The TSC_ADJUST values in a package must be the same. If the boot
+        * value on this newly upcoming CPU differs from the adjustment
+        * value of the already online CPU in this package, set it to that
+        * adjusted value.
+        */
+       if (bootval != ref->adjusted) {
+               pr_warn("TSC ADJUST synchronize: Reference CPU%u: %lld CPU%u: %lld\n",
+                       refcpu, ref->adjusted, cpu, bootval);
+               cur->adjusted = ref->adjusted;
+               wrmsrl(MSR_IA32_TSC_ADJUST, ref->adjusted);
+       }
+       /*
+        * We have the TSCs forced to be in sync on this package. Skip sync
+        * test:
+        */
+       return true;
+}
+
 /*
  * Entry/exit counters that make sure that both CPUs
  * run the measurement code at once:
  */
 static atomic_t start_count;
 static atomic_t stop_count;
+static atomic_t skip_test;
+static atomic_t test_runs;
 
 /*
  * We use a raw spinlock in this exceptional case, because
@@ -37,15 +185,16 @@ static arch_spinlock_t sync_lock = __ARCH_SPIN_LOCK_UNLOCKED;
 static cycles_t last_tsc;
 static cycles_t max_warp;
 static int nr_warps;
+static int random_warps;
 
 /*
  * TSC-warp measurement loop running on both CPUs.  This is not called
  * if there is no TSC.
  */
-static void check_tsc_warp(unsigned int timeout)
+static cycles_t check_tsc_warp(unsigned int timeout)
 {
-       cycles_t start, now, prev, end;
-       int i;
+       cycles_t start, now, prev, end, cur_max_warp = 0;
+       int i, cur_warps = 0;
 
        start = rdtsc_ordered();
        /*
@@ -85,13 +234,22 @@ static void check_tsc_warp(unsigned int timeout)
                if (unlikely(prev > now)) {
                        arch_spin_lock(&sync_lock);
                        max_warp = max(max_warp, prev - now);
+                       cur_max_warp = max_warp;
+                       /*
+                        * Check whether this bounces back and forth. Only
+                        * one CPU should observe time going backwards.
+                        */
+                       if (cur_warps != nr_warps)
+                               random_warps++;
                        nr_warps++;
+                       cur_warps = nr_warps;
                        arch_spin_unlock(&sync_lock);
                }
        }
        WARN(!(now-start),
                "Warning: zero tsc calibration delta: %Ld [max: %Ld]\n",
                        now-start, end-start);
+       return cur_max_warp;
 }
 
 /*
@@ -136,15 +294,26 @@ void check_tsc_sync_source(int cpu)
        }
 
        /*
-        * Reset it - in case this is a second bootup:
+        * Set the maximum number of test runs to
+        *  1 if the CPU does not provide the TSC_ADJUST MSR
+        *  3 if the MSR is available, so the target can try to adjust
         */
-       atomic_set(&stop_count, 0);
-
+       if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+               atomic_set(&test_runs, 1);
+       else
+               atomic_set(&test_runs, 3);
+retry:
        /*
-        * Wait for the target to arrive:
+        * Wait for the target to start or to skip the test:
         */
-       while (atomic_read(&start_count) != cpus-1)
+       while (atomic_read(&start_count) != cpus - 1) {
+               if (atomic_read(&skip_test) > 0) {
+                       atomic_set(&skip_test, 0);
+                       return;
+               }
                cpu_relax();
+       }
+
        /*
         * Trigger the target to continue into the measurement too:
         */
@@ -155,21 +324,35 @@ void check_tsc_sync_source(int cpu)
        while (atomic_read(&stop_count) != cpus-1)
                cpu_relax();
 
-       if (nr_warps) {
+       /*
+        * If the test was successful set the number of runs to zero and
+        * stop. If not, decrement the number of runs an check if we can
+        * retry. In case of random warps no retry is attempted.
+        */
+       if (!nr_warps) {
+               atomic_set(&test_runs, 0);
+
+               pr_debug("TSC synchronization [CPU#%d -> CPU#%d]: passed\n",
+                       smp_processor_id(), cpu);
+
+       } else if (atomic_dec_and_test(&test_runs) || random_warps) {
+               /* Force it to 0 if random warps brought us here */
+               atomic_set(&test_runs, 0);
+
                pr_warning("TSC synchronization [CPU#%d -> CPU#%d]:\n",
                        smp_processor_id(), cpu);
                pr_warning("Measured %Ld cycles TSC warp between CPUs, "
                           "turning off TSC clock.\n", max_warp);
+               if (random_warps)
+                       pr_warning("TSC warped randomly between CPUs\n");
                mark_tsc_unstable("check_tsc_sync_source failed");
-       } else {
-               pr_debug("TSC synchronization [CPU#%d -> CPU#%d]: passed\n",
-                       smp_processor_id(), cpu);
        }
 
        /*
         * Reset it - just in case we boot another CPU later:
         */
        atomic_set(&start_count, 0);
+       random_warps = 0;
        nr_warps = 0;
        max_warp = 0;
        last_tsc = 0;
@@ -178,6 +361,12 @@ void check_tsc_sync_source(int cpu)
         * Let the target continue with the bootup:
         */
        atomic_inc(&stop_count);
+
+       /*
+        * Retry, if there is a chance to do so.
+        */
+       if (atomic_read(&test_runs) > 0)
+               goto retry;
 }
 
 /*
@@ -185,12 +374,25 @@ void check_tsc_sync_source(int cpu)
  */
 void check_tsc_sync_target(void)
 {
+       struct tsc_adjust *cur = this_cpu_ptr(&tsc_adjust);
+       unsigned int cpu = smp_processor_id();
+       cycles_t cur_max_warp, gbl_max_warp;
        int cpus = 2;
 
        /* Also aborts if there is no TSC. */
        if (unsynchronized_tsc() || tsc_clocksource_reliable)
                return;
 
+       /*
+        * Store, verify and sanitize the TSC adjust register. If
+        * successful skip the test.
+        */
+       if (tsc_store_and_check_tsc_adjust(false)) {
+               atomic_inc(&skip_test);
+               return;
+       }
+
+retry:
        /*
         * Register this CPU's participation and wait for the
         * source CPU to start the measurement:
@@ -199,7 +401,12 @@ void check_tsc_sync_target(void)
        while (atomic_read(&start_count) != cpus)
                cpu_relax();
 
-       check_tsc_warp(loop_timeout(smp_processor_id()));
+       cur_max_warp = check_tsc_warp(loop_timeout(cpu));
+
+       /*
+        * Store the maximum observed warp value for a potential retry:
+        */
+       gbl_max_warp = max_warp;
 
        /*
         * Ok, we are done:
@@ -211,4 +418,61 @@ void check_tsc_sync_target(void)
         */
        while (atomic_read(&stop_count) != cpus)
                cpu_relax();
+
+       /*
+        * Reset it for the next sync test:
+        */
+       atomic_set(&stop_count, 0);
+
+       /*
+        * Check the number of remaining test runs. If not zero, the test
+        * failed and a retry with adjusted TSC is possible. If zero the
+        * test was either successful or failed terminally.
+        */
+       if (!atomic_read(&test_runs))
+               return;
+
+       /*
+        * If the warp value of this CPU is 0, then the other CPU
+        * observed time going backwards so this TSC was ahead and
+        * needs to move backwards.
+        */
+       if (!cur_max_warp)
+               cur_max_warp = -gbl_max_warp;
+
+       /*
+        * Add the result to the previous adjustment value.
+        *
+        * The adjustement value is slightly off by the overhead of the
+        * sync mechanism (observed values are ~200 TSC cycles), but this
+        * really depends on CPU, node distance and frequency. So
+        * compensating for this is hard to get right. Experiments show
+        * that the warp is not longer detectable when the observed warp
+        * value is used. In the worst case the adjustment needs to go
+        * through a 3rd run for fine tuning.
+        */
+       cur->adjusted += cur_max_warp;
+
+       /*
+        * TSC deadline timer stops working or creates an interrupt storm
+        * with adjust values < 0 and > x07ffffff.
+        *
+        * To allow adjust values > 0x7FFFFFFF we need to disable the
+        * deadline timer and use the local APIC timer, but that requires
+        * more intrusive changes and we do not have any useful information
+        * from Intel about the underlying HW wreckage yet.
+        */
+       if (cur->adjusted < 0)
+               cur->adjusted = 0;
+       if (cur->adjusted > 0x7FFFFFFF)
+               cur->adjusted = 0x7FFFFFFF;
+
+       pr_warn("TSC ADJUST compensate: CPU%u observed %lld warp. Adjust: %lld\n",
+               cpu, cur_max_warp, cur->adjusted);
+
+       wrmsrl(MSR_IA32_TSC_ADJUST, cur->adjusted);
+       goto retry;
+
 }
+
+#endif /* CONFIG_SMP */
index b2d3cf1ef54ae5c1cc0bfb19c8c65b08dd6f23b4..e85f6bd7b9d526266ca5f11cfd9a23f7ce19337d 100644 (file)
@@ -373,16 +373,17 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        const u32 kvm_cpuid_7_0_ebx_x86_features =
                F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
                F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
-               F(ADX) | F(SMAP) | F(AVX512F) | F(AVX512PF) | F(AVX512ER) |
-               F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
-               F(AVX512BW) | F(AVX512VL);
+               F(ADX) | F(SMAP) | F(AVX512IFMA) | F(AVX512F) | F(AVX512PF) |
+               F(AVX512ER) | F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
+               F(SHA_NI) | F(AVX512BW) | F(AVX512VL);
 
        /* cpuid 0xD.1.eax */
        const u32 kvm_cpuid_D_1_eax_x86_features =
                F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | f_xsaves;
 
        /* cpuid 7.0.ecx*/
-       const u32 kvm_cpuid_7_0_ecx_x86_features = F(PKU) | 0 /*OSPKE*/;
+       const u32 kvm_cpuid_7_0_ecx_x86_features =
+               F(AVX512VBMI) | F(PKU) | 0 /*OSPKE*/;
 
        /* cpuid 7.0.edx*/
        const u32 kvm_cpuid_7_0_edx_x86_features =
index 99cde5220e0799fd84aca5a6774dce47e289a73c..1572c35b4f1a637b2ebb622ae88c5e7e14eafd63 100644 (file)
@@ -852,6 +852,10 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
                return;
 
+       mutex_lock(&kvm->arch.hyperv.hv_lock);
+       if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
+               goto out_unlock;
+
        gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT;
        /*
         * Because the TSC parameters only vary when there is a
@@ -859,7 +863,7 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
         */
        if (unlikely(kvm_read_guest(kvm, gfn_to_gpa(gfn),
                                    &tsc_seq, sizeof(tsc_seq))))
-               return;
+               goto out_unlock;
 
        /*
         * While we're computing and writing the parameters, force the
@@ -868,15 +872,15 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        hv->tsc_ref.tsc_sequence = 0;
        if (kvm_write_guest(kvm, gfn_to_gpa(gfn),
                            &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)))
-               return;
+               goto out_unlock;
 
        if (!compute_tsc_page_parameters(hv_clock, &hv->tsc_ref))
-               return;
+               goto out_unlock;
 
        /* Ensure sequence is zero before writing the rest of the struct.  */
        smp_wmb();
        if (kvm_write_guest(kvm, gfn_to_gpa(gfn), &hv->tsc_ref, sizeof(hv->tsc_ref)))
-               return;
+               goto out_unlock;
 
        /*
         * Now switch to the TSC page mechanism by writing the sequence.
@@ -891,6 +895,8 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        hv->tsc_ref.tsc_sequence = tsc_seq;
        kvm_write_guest(kvm, gfn_to_gpa(gfn),
                        &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence));
+out_unlock:
+       mutex_unlock(&kvm->arch.hyperv.hv_lock);
 }
 
 static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
@@ -1142,9 +1148,9 @@ int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
        if (kvm_hv_msr_partition_wide(msr)) {
                int r;
 
-               mutex_lock(&vcpu->kvm->lock);
+               mutex_lock(&vcpu->kvm->arch.hyperv.hv_lock);
                r = kvm_hv_set_msr_pw(vcpu, msr, data, host);
-               mutex_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&vcpu->kvm->arch.hyperv.hv_lock);
                return r;
        } else
                return kvm_hv_set_msr(vcpu, msr, data, host);
@@ -1155,9 +1161,9 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        if (kvm_hv_msr_partition_wide(msr)) {
                int r;
 
-               mutex_lock(&vcpu->kvm->lock);
+               mutex_lock(&vcpu->kvm->arch.hyperv.hv_lock);
                r = kvm_hv_get_msr_pw(vcpu, msr, pdata);
-               mutex_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&vcpu->kvm->arch.hyperv.hv_lock);
                return r;
        } else
                return kvm_hv_get_msr(vcpu, msr, pdata);
@@ -1165,7 +1171,7 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 
 bool kvm_hv_hypercall_enabled(struct kvm *kvm)
 {
-       return kvm->arch.hyperv.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE;
+       return READ_ONCE(kvm->arch.hyperv.hv_hypercall) & HV_X64_MSR_HYPERCALL_ENABLE;
 }
 
 static void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result)
index aae43c6f24721e748451aea69d9c138c4be58f61..24db5fb6f575af27d3b61a67b15ce9996158ed8b 100644 (file)
@@ -1389,10 +1389,10 @@ static inline bool nested_cpu_has_posted_intr(struct vmcs12 *vmcs12)
        return vmcs12->pin_based_vm_exec_control & PIN_BASED_POSTED_INTR;
 }
 
-static inline bool is_exception(u32 intr_info)
+static inline bool is_nmi(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
-               == (INTR_TYPE_HARD_EXCEPTION | INTR_INFO_VALID_MASK);
+               == (INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK);
 }
 
 static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
@@ -5728,7 +5728,7 @@ static int handle_exception(struct kvm_vcpu *vcpu)
        if (is_machine_check(intr_info))
                return handle_machine_check(vcpu);
 
-       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR)
+       if (is_nmi(intr_info))
                return 1;  /* already handled by vmx_vcpu_run() */
 
        if (is_no_device(intr_info)) {
@@ -7122,7 +7122,7 @@ static int nested_vmx_check_vmptr(struct kvm_vcpu *vcpu, int exit_reason,
 
                if (vmptr == vmx->nested.vmxon_ptr) {
                        nested_vmx_failValid(vcpu,
-                                            VMXERR_VMCLEAR_VMXON_POINTER);
+                                            VMXERR_VMPTRLD_VMXON_POINTER);
                        return kvm_skip_emulated_instruction(vcpu);
                }
                break;
@@ -8170,7 +8170,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
 
        switch (exit_reason) {
        case EXIT_REASON_EXCEPTION_NMI:
-               if (!is_exception(intr_info))
+               if (is_nmi(intr_info))
                        return false;
                else if (is_page_fault(intr_info))
                        return enable_ept;
@@ -8765,8 +8765,7 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
                kvm_machine_check();
 
        /* We need to handle NMIs before interrupts are enabled */
-       if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR &&
-           (exit_intr_info & INTR_INFO_VALID_MASK)) {
+       if (is_nmi(exit_intr_info)) {
                kvm_before_handle_nmi(&vmx->vcpu);
                asm("int $2");
                kvm_after_handle_nmi(&vmx->vcpu);
index 1f0d2383f5ee6e273751949a77882224947a7861..445c51b6cf6dc702a0da9710ee5b6eb4b996ec34 100644 (file)
@@ -2844,7 +2844,24 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
+       int idx;
+       /*
+        * Disable page faults because we're in atomic context here.
+        * kvm_write_guest_offset_cached() would call might_fault()
+        * that relies on pagefault_disable() to tell if there's a
+        * bug. NOTE: the write to guest memory may not go through if
+        * during postcopy live migration or if there's heavy guest
+        * paging.
+        */
+       pagefault_disable();
+       /*
+        * kvm_memslots() will be called by
+        * kvm_write_guest_offset_cached() so take the srcu lock.
+        */
+       idx = srcu_read_lock(&vcpu->kvm->srcu);
        kvm_steal_time_set_preempted(vcpu);
+       srcu_read_unlock(&vcpu->kvm->srcu, idx);
+       pagefault_enable();
        kvm_x86_ops->vcpu_put(vcpu);
        kvm_put_guest_fpu(vcpu);
        vcpu->arch.last_host_tsc = rdtsc();
@@ -7881,6 +7898,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
        raw_spin_lock_init(&kvm->arch.tsc_write_lock);
        mutex_init(&kvm->arch.apic_map_lock);
+       mutex_init(&kvm->arch.hyperv.hv_lock);
        spin_lock_init(&kvm->arch.pvclock_gtod_sync_lock);
 
        kvm->arch.kvmclock_offset = -ktime_get_boot_ns();
index 17c55a536fdd2ce1af8b376a319e43cea3e7d45a..e3254ca0eec4ec371d6498dcb72f140ac2164a77 100644 (file)
@@ -413,7 +413,7 @@ out:
 
 void vmalloc_sync_all(void)
 {
-       sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END, 0);
+       sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END);
 }
 
 /*
index 14b9dd71d9e864e218b28f82c95df8f011cc0c91..963895f9af7fb8d7feba7ccfba05a08bcec30f2d 100644 (file)
@@ -89,10 +89,10 @@ static int __init nonx32_setup(char *str)
 __setup("noexec32=", nonx32_setup);
 
 /*
- * When memory was added/removed make sure all the processes MM have
+ * When memory was added make sure all the processes MM have
  * suitable PGD entries in the local PGD level page.
  */
-void sync_global_pgds(unsigned long start, unsigned long end, int removed)
+void sync_global_pgds(unsigned long start, unsigned long end)
 {
        unsigned long address;
 
@@ -100,12 +100,7 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed)
                const pgd_t *pgd_ref = pgd_offset_k(address);
                struct page *page;
 
-               /*
-                * When it is called after memory hot remove, pgd_none()
-                * returns true. In this case (removed == 1), we must clear
-                * the PGD entries in the local PGD level page.
-                */
-               if (pgd_none(*pgd_ref) && !removed)
+               if (pgd_none(*pgd_ref))
                        continue;
 
                spin_lock(&pgd_lock);
@@ -122,13 +117,8 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed)
                                BUG_ON(pgd_page_vaddr(*pgd)
                                       != pgd_page_vaddr(*pgd_ref));
 
-                       if (removed) {
-                               if (pgd_none(*pgd_ref) && !pgd_none(*pgd))
-                                       pgd_clear(pgd);
-                       } else {
-                               if (pgd_none(*pgd))
-                                       set_pgd(pgd, *pgd_ref);
-                       }
+                       if (pgd_none(*pgd))
+                               set_pgd(pgd, *pgd_ref);
 
                        spin_unlock(pgt_lock);
                }
@@ -596,7 +586,7 @@ kernel_physical_mapping_init(unsigned long paddr_start,
        }
 
        if (pgd_changed)
-               sync_global_pgds(vaddr_start, vaddr_end - 1, 0);
+               sync_global_pgds(vaddr_start, vaddr_end - 1);
 
        __flush_tlb_all();
 
@@ -1239,7 +1229,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
        } else
                err = vmemmap_populate_basepages(start, end, node);
        if (!err)
-               sync_global_pgds(start, end - 1, 0);
+               sync_global_pgds(start, end - 1);
        return err;
 }
 
index e4f800999b32dc94d5ba1a1283591649a818fbb7..324e5713d386f0ed235b0394f71c0290df870fae 100644 (file)
@@ -350,12 +350,12 @@ int mpx_enable_management(void)
         * The copy_xregs_to_kernel() beneath get_xsave_field_ptr() is
         * expected to be relatively expensive. Storing the bounds
         * directory here means that we do not have to do xsave in the
-        * unmap path; we can just use mm->bd_addr instead.
+        * unmap path; we can just use mm->context.bd_addr instead.
         */
        bd_base = mpx_get_bounds_dir();
        down_write(&mm->mmap_sem);
-       mm->bd_addr = bd_base;
-       if (mm->bd_addr == MPX_INVALID_BOUNDS_DIR)
+       mm->context.bd_addr = bd_base;
+       if (mm->context.bd_addr == MPX_INVALID_BOUNDS_DIR)
                ret = -ENXIO;
 
        up_write(&mm->mmap_sem);
@@ -370,7 +370,7 @@ int mpx_disable_management(void)
                return -ENXIO;
 
        down_write(&mm->mmap_sem);
-       mm->bd_addr = MPX_INVALID_BOUNDS_DIR;
+       mm->context.bd_addr = MPX_INVALID_BOUNDS_DIR;
        up_write(&mm->mmap_sem);
        return 0;
 }
@@ -947,7 +947,7 @@ static int try_unmap_single_bt(struct mm_struct *mm,
                end = bta_end_vaddr;
        }
 
-       bde_vaddr = mm->bd_addr + mpx_get_bd_entry_offset(mm, start);
+       bde_vaddr = mm->context.bd_addr + mpx_get_bd_entry_offset(mm, start);
        ret = get_bt_addr(mm, bde_vaddr, &bt_addr);
        /*
         * No bounds table there, so nothing to unmap.
index 3f35b48d1d9de6dcef0f6a24a9a0ed377e4b8889..12dcad7297a5b70ac34a7a1ca7711aca13e9d9cc 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "numa_internal.h"
 
-int __initdata numa_off;
+int numa_off;
 nodemask_t numa_nodes_parsed __initdata;
 
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
index 3c3c19ea94df460b061e232f17cd35fd144eeef6..184842ef332e0123762c3463bd795ef4a9aaa282 100644 (file)
@@ -8,7 +8,6 @@ obj-y   += iris/
 obj-y  += intel/
 obj-y  += intel-mid/
 obj-y  += intel-quark/
-obj-y  += mellanox/
 obj-y  += olpc/
 obj-y  += scx200/
 obj-y  += sfi/
index 1eb47b6298c20fc20ae6de0c2f9f3762854286cc..e793fe509971f49fb2cfa6a12f8b365a937ae206 100644 (file)
@@ -49,8 +49,13 @@ static unsigned long __init mfld_calibrate_tsc(void)
        fast_calibrate = ratio * fsb;
        pr_debug("read penwell tsc %lu khz\n", fast_calibrate);
        lapic_timer_frequency = fsb * 1000 / HZ;
-       /* mark tsc clocksource as reliable */
-       set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
+
+       /*
+        * TSC on Intel Atom SoCs is reliable and of known frequency.
+        * See tsc_msr.c for details.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+       setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
 
        return fast_calibrate;
 }
index 59253db41bbc900d238e361b9fce339161be1753..e0607c77a1bd67a06fe49f58c50c1bfe9af9da61 100644 (file)
@@ -78,8 +78,12 @@ static unsigned long __init tangier_calibrate_tsc(void)
        pr_debug("Setting lapic_timer_frequency = %d\n",
                        lapic_timer_frequency);
 
-       /* mark tsc clocksource as reliable */
-       set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
+       /*
+        * TSC on Intel Atom SoCs is reliable and of known frequency.
+        * See tsc_msr.c for details.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+       setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
 
        return fast_calibrate;
 }
diff --git a/arch/x86/platform/mellanox/Makefile b/arch/x86/platform/mellanox/Makefile
deleted file mode 100644 (file)
index f43c931..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_MLX_PLATFORM)     += mlx-platform.o
diff --git a/arch/x86/platform/mellanox/mlx-platform.c b/arch/x86/platform/mellanox/mlx-platform.c
deleted file mode 100644 (file)
index 7dcfcca..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * arch/x86/platform/mellanox/mlx-platform.c
- * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/device.h>
-#include <linux/dmi.h>
-#include <linux/i2c.h>
-#include <linux/i2c-mux.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/i2c-mux-reg.h>
-
-#define MLX_PLAT_DEVICE_NAME           "mlxplat"
-
-/* LPC bus IO offsets */
-#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR         0x2000
-#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR         0x2500
-#define MLXPLAT_CPLD_LPC_IO_RANGE              0x100
-#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF           0xdb
-#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF           0xda
-#define MLXPLAT_CPLD_LPC_PIO_OFFSET            0x10000UL
-#define MLXPLAT_CPLD_LPC_REG1  ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
-                                 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
-                                 MLXPLAT_CPLD_LPC_PIO_OFFSET)
-#define MLXPLAT_CPLD_LPC_REG2  ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
-                                 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
-                                 MLXPLAT_CPLD_LPC_PIO_OFFSET)
-
-/* Start channel numbers */
-#define MLXPLAT_CPLD_CH1                       2
-#define MLXPLAT_CPLD_CH2                       10
-
-/* Number of LPC attached MUX platform devices */
-#define MLXPLAT_CPLD_LPC_MUX_DEVS              2
-
-/* mlxplat_priv - platform private data
- * @pdev_i2c - i2c controller platform device
- * @pdev_mux - array of mux platform devices
- */
-struct mlxplat_priv {
-       struct platform_device *pdev_i2c;
-       struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
-};
-
-/* Regions for LPC I2C controller and LPC base register space */
-static const struct resource mlxplat_lpc_resources[] = {
-       [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
-                              MLXPLAT_CPLD_LPC_IO_RANGE,
-                              "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
-       [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
-                              MLXPLAT_CPLD_LPC_IO_RANGE,
-                              "mlxplat_cpld_lpc_regs",
-                              IORESOURCE_IO),
-};
-
-/* Platform default channels */
-static const int mlxplat_default_channels[][8] = {
-       {
-               MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
-               MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
-               5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
-       },
-       {
-               MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
-               MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
-               5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
-       },
-};
-
-/* Platform channels for MSN21xx system family */
-static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
-
-/* Platform mux data */
-static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
-       {
-               .parent = 1,
-               .base_nr = MLXPLAT_CPLD_CH1,
-               .write_only = 1,
-               .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
-               .reg_size = 1,
-               .idle_in_use = 1,
-       },
-       {
-               .parent = 1,
-               .base_nr = MLXPLAT_CPLD_CH2,
-               .write_only = 1,
-               .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
-               .reg_size = 1,
-               .idle_in_use = 1,
-       },
-
-};
-
-static struct platform_device *mlxplat_dev;
-
-static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
-               mlxplat_mux_data[i].values = mlxplat_default_channels[i];
-               mlxplat_mux_data[i].n_values =
-                               ARRAY_SIZE(mlxplat_default_channels[i]);
-       }
-
-       return 1;
-};
-
-static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
-               mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
-               mlxplat_mux_data[i].n_values =
-                               ARRAY_SIZE(mlxplat_msn21xx_channels);
-       }
-
-       return 1;
-};
-
-static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
-       {
-               .callback = mlxplat_dmi_default_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
-               },
-       },
-       {
-               .callback = mlxplat_dmi_default_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
-               },
-       },
-       {
-               .callback = mlxplat_dmi_default_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
-               },
-       },
-       {
-               .callback = mlxplat_dmi_default_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
-               },
-       },
-       {
-               .callback = mlxplat_dmi_msn21xx_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
-               },
-       },
-       { }
-};
-
-static int __init mlxplat_init(void)
-{
-       struct mlxplat_priv *priv;
-       int i, err;
-
-       if (!dmi_check_system(mlxplat_dmi_table))
-               return -ENODEV;
-
-       mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
-                                       mlxplat_lpc_resources,
-                                       ARRAY_SIZE(mlxplat_lpc_resources));
-
-       if (IS_ERR(mlxplat_dev))
-               return PTR_ERR(mlxplat_dev);
-
-       priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
-                           GFP_KERNEL);
-       if (!priv) {
-               err = -ENOMEM;
-               goto fail_alloc;
-       }
-       platform_set_drvdata(mlxplat_dev, priv);
-
-       priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
-                                                        NULL, 0);
-       if (IS_ERR(priv->pdev_i2c)) {
-               err = PTR_ERR(priv->pdev_i2c);
-               goto fail_alloc;
-       };
-
-       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
-               priv->pdev_mux[i] = platform_device_register_resndata(
-                                               &mlxplat_dev->dev,
-                                               "i2c-mux-reg", i, NULL,
-                                               0, &mlxplat_mux_data[i],
-                                               sizeof(mlxplat_mux_data[i]));
-               if (IS_ERR(priv->pdev_mux[i])) {
-                       err = PTR_ERR(priv->pdev_mux[i]);
-                       goto fail_platform_mux_register;
-               }
-       }
-
-       return 0;
-
-fail_platform_mux_register:
-       for (i--; i > 0 ; i--)
-               platform_device_unregister(priv->pdev_mux[i]);
-       platform_device_unregister(priv->pdev_i2c);
-fail_alloc:
-       platform_device_unregister(mlxplat_dev);
-
-       return err;
-}
-module_init(mlxplat_init);
-
-static void __exit mlxplat_exit(void)
-{
-       struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
-       int i;
-
-       for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
-               platform_device_unregister(priv->pdev_mux[i]);
-
-       platform_device_unregister(priv->pdev_i2c);
-       platform_device_unregister(mlxplat_dev);
-}
-module_exit(mlxplat_exit);
-
-MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
-MODULE_DESCRIPTION("Mellanox platform driver");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
index 53cace2ec0e2888baa5937edce817d00bd09de64..66ade16c769363ecd1bef435eccfd4977ffd5228 100644 (file)
@@ -252,6 +252,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
        fix_processor_context();
 
        do_fpu_end();
+       tsc_verify_tsc_adjust(true);
        x86_platform.restore_sched_clock_state();
        mtrr_bp_restore();
        perf_restore_debug_store();
index 9fa27ceeecfdaea1cfdbba751e79b405d857d851..311acad7dad2abdc8501c70866674ed4f5858495 100644 (file)
@@ -87,12 +87,6 @@ static void cpu_bringup(void)
        cpu_data(cpu).x86_max_cores = 1;
        set_cpu_sibling_map(cpu);
 
-       /*
-        * identify_cpu() may have set logical_pkg_id to -1 due
-        * to incorrect phys_proc_id. Let's re-comupte it.
-        */
-       topology_update_package_map(apic->cpu_present_to_apicid(cpu), cpu);
-
        xen_setup_cpu_clockevents();
 
        notify_cpu_starting(cpu);
index f61058617ada462c6e571c7936c3ebf92621aa26..f4126cf997a469da01161244e93a320d1dd2104e 100644 (file)
@@ -15,6 +15,7 @@ config XTENSA
        select GENERIC_SCHED_CLOCK
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_API_DEBUG
+       select HAVE_DMA_CONTIGUOUS
        select HAVE_EXIT_THREAD
        select HAVE_FUNCTION_TRACER
        select HAVE_FUTEX_CMPXCHG if !MMU
index b1f4ee8c9a22371ba9abedfcc7d21fb279b585f0..6106bdc097ad2f51a257d7643770b89c8d82ab8e 100644 (file)
                device_type = "memory";
                reg = <0x00000000 0x38000000>;
        };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               /* global autoconfigured region for contiguous allocations */
+               linux,cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       size = <0x04000000>;
+                       alignment = <0x2000>;
+                       alloc-ranges = <0x00000000 0x20000000>;
+                       linux,cma-default;
+               };
+       };
 };
index 28cf4c5d65efade019dbefaf809e71d13624e37c..b7fbaa56b51a573f393ce6d6abb6ec5c1895c27e 100644 (file)
@@ -3,6 +3,7 @@ generic-y += bug.h
 generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += div64.h
+generic-y += dma-contiguous.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
index c31f5d5afc7d2d969a2a0c532e9f91a4395ba49d..264fb89c444e9fde9fd5ba9157aba6d7b06eae2f 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
 obj-$(CONFIG_SMP) += smp.o mxhead.o
 obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
+obj-$(CONFIG_S32C1I_SELFTEST) += s32c1i_selftest.o
 
 AFLAGS_head.o += -mtext-section-literals
 AFLAGS_mxhead.o += -mtext-section-literals
index 6a16decf278fa0a7dfa4dd5200e55a31258dace3..70e362e6038e80c0e802bf6f2a1ebb3360292c07 100644 (file)
@@ -15,6 +15,7 @@
  * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
  */
 
+#include <linux/dma-contiguous.h>
 #include <linux/gfp.h>
 #include <linux/highmem.h>
 #include <linux/mm.h>
@@ -146,6 +147,8 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 {
        unsigned long ret;
        unsigned long uncached = 0;
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       struct page *page = NULL;
 
        /* ignore region speicifiers */
 
@@ -153,11 +156,18 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 
        if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
                flag |= GFP_DMA;
-       ret = (unsigned long)__get_free_pages(flag, get_order(size));
 
-       if (ret == 0)
+       if (gfpflags_allow_blocking(flag))
+               page = dma_alloc_from_contiguous(dev, count, get_order(size));
+
+       if (!page)
+               page = alloc_pages(flag, get_order(size));
+
+       if (!page)
                return NULL;
 
+       ret = (unsigned long)page_address(page);
+
        /* We currently don't support coherent memory outside KSEG */
 
        BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
@@ -170,16 +180,19 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
        return (void *)uncached;
 }
 
-static void xtensa_dma_free(struct device *hwdev, size_t size, void *vaddr,
+static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr,
                            dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long addr = (unsigned long)vaddr +
                XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
+       struct page *page = virt_to_page(addr);
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
        BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR ||
               addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
 
-       free_pages(addr, get_order(size));
+       if (!dma_release_from_contiguous(dev, page, count))
+               __free_pages(page, get_order(size));
 }
 
 static dma_addr_t xtensa_map_page(struct device *dev, struct page *page,
diff --git a/arch/xtensa/kernel/s32c1i_selftest.c b/arch/xtensa/kernel/s32c1i_selftest.c
new file mode 100644 (file)
index 0000000..07e56e3
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * S32C1I selftest.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2016 Cadence Design Systems Inc.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <asm/traps.h>
+
+#if XCHAL_HAVE_S32C1I
+
+static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
+
+/*
+ * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
+ *
+ * If *v == cmp, set *v = set.  Return previous *v.
+ */
+static inline int probed_compare_swap(int *v, int cmp, int set)
+{
+       int tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %1, 1f\n"
+                       "       s32i    %1, %4, 0\n"
+                       "       wsr     %2, scompare1\n"
+                       "1:     s32c1i  %0, %3, 0\n"
+                       : "=a" (set), "=&a" (tmp)
+                       : "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
+                       : "memory"
+                       );
+       return set;
+}
+
+/* Handle probed exception */
+
+static void __init do_probed_exception(struct pt_regs *regs,
+                                      unsigned long exccause)
+{
+       if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
+               regs->pc += 3;          /* skip the s32c1i instruction */
+               rcw_exc = exccause;
+       } else {
+               do_unhandled(regs, exccause);
+       }
+}
+
+/* Simple test of S32C1I (soc bringup assist) */
+
+static int __init check_s32c1i(void)
+{
+       int n, cause1, cause2;
+       void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
+
+       rcw_probe_pc = 0;
+       handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
+                       do_probed_exception);
+       handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
+                       do_probed_exception);
+       handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
+                       do_probed_exception);
+
+       /* First try an S32C1I that does not store: */
+       rcw_exc = 0;
+       rcw_word = 1;
+       n = probed_compare_swap(&rcw_word, 0, 2);
+       cause1 = rcw_exc;
+
+       /* took exception? */
+       if (cause1 != 0) {
+               /* unclean exception? */
+               if (n != 2 || rcw_word != 1)
+                       panic("S32C1I exception error");
+       } else if (rcw_word != 1 || n != 1) {
+               panic("S32C1I compare error");
+       }
+
+       /* Then an S32C1I that stores: */
+       rcw_exc = 0;
+       rcw_word = 0x1234567;
+       n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
+       cause2 = rcw_exc;
+
+       if (cause2 != 0) {
+               /* unclean exception? */
+               if (n != 0xabcde || rcw_word != 0x1234567)
+                       panic("S32C1I exception error (b)");
+       } else if (rcw_word != 0xabcde || n != 0x1234567) {
+               panic("S32C1I store error");
+       }
+
+       /* Verify consistency of exceptions: */
+       if (cause1 || cause2) {
+               pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
+               /* If emulation of S32C1I upon bus error gets implemented,
+                * we can get rid of this panic for single core (not SMP)
+                */
+               panic("S32C1I exceptions not currently supported");
+       }
+       if (cause1 != cause2)
+               panic("inconsistent S32C1I exceptions");
+
+       trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
+       trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
+       trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
+       return 0;
+}
+
+#else /* XCHAL_HAVE_S32C1I */
+
+/* This condition should not occur with a commercially deployed processor.
+ * Display reminder for early engr test or demo chips / FPGA bitstreams
+ */
+static int __init check_s32c1i(void)
+{
+       pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
+       return 0;
+}
+
+#endif /* XCHAL_HAVE_S32C1I */
+
+early_initcall(check_s32c1i);
index 88a044af7504dd9c47d0f97d64620ac8de4b5739..848e8568fb3c4a90c2eb89783c0420f8b5526cd6 100644 (file)
 # include <linux/console.h>
 #endif
 
-#ifdef CONFIG_RTC
-# include <linux/timex.h>
-#endif
-
 #ifdef CONFIG_PROC_FS
 # include <linux/seq_file.h>
 #endif
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <asm/param.h>
-#include <asm/traps.h>
 #include <asm/smp.h>
 #include <asm/sysmem.h>
 
 #include <platform/hardware.h>
 
 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
-struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
-#endif
-
-#ifdef CONFIG_BLK_DEV_FD
-extern struct fd_ops no_fd_ops;
-struct fd_ops *fd_ops;
+struct screen_info screen_info = {
+       .orig_x = 0,
+       .orig_y = 24,
+       .orig_video_cols = 80,
+       .orig_video_lines = 24,
+       .orig_video_isVGA = 1,
+       .orig_video_points = 16,
+};
 #endif
 
-extern struct rtc_ops no_rtc_ops;
-struct rtc_ops *rtc_ops;
-
 #ifdef CONFIG_BLK_DEV_INITRD
 extern unsigned long initrd_start;
 extern unsigned long initrd_end;
@@ -77,7 +71,6 @@ extern int initrd_below_start_ok;
 void *dtb_start = __dtb_start;
 #endif
 
-unsigned char aux_device_present;
 extern unsigned long loops_per_jiffy;
 
 /* Command line specified as configuration option. */
@@ -317,120 +310,6 @@ extern char _SecondaryResetVector_text_start;
 extern char _SecondaryResetVector_text_end;
 #endif
 
-
-#ifdef CONFIG_S32C1I_SELFTEST
-#if XCHAL_HAVE_S32C1I
-
-static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
-
-/*
- * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
- *
- * If *v == cmp, set *v = set.  Return previous *v.
- */
-static inline int probed_compare_swap(int *v, int cmp, int set)
-{
-       int tmp;
-
-       __asm__ __volatile__(
-                       "       movi    %1, 1f\n"
-                       "       s32i    %1, %4, 0\n"
-                       "       wsr     %2, scompare1\n"
-                       "1:     s32c1i  %0, %3, 0\n"
-                       : "=a" (set), "=&a" (tmp)
-                       : "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
-                       : "memory"
-                       );
-       return set;
-}
-
-/* Handle probed exception */
-
-static void __init do_probed_exception(struct pt_regs *regs,
-               unsigned long exccause)
-{
-       if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
-               regs->pc += 3;          /* skip the s32c1i instruction */
-               rcw_exc = exccause;
-       } else {
-               do_unhandled(regs, exccause);
-       }
-}
-
-/* Simple test of S32C1I (soc bringup assist) */
-
-static int __init check_s32c1i(void)
-{
-       int n, cause1, cause2;
-       void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
-
-       rcw_probe_pc = 0;
-       handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
-                       do_probed_exception);
-       handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
-                       do_probed_exception);
-       handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
-                       do_probed_exception);
-
-       /* First try an S32C1I that does not store: */
-       rcw_exc = 0;
-       rcw_word = 1;
-       n = probed_compare_swap(&rcw_word, 0, 2);
-       cause1 = rcw_exc;
-
-       /* took exception? */
-       if (cause1 != 0) {
-               /* unclean exception? */
-               if (n != 2 || rcw_word != 1)
-                       panic("S32C1I exception error");
-       } else if (rcw_word != 1 || n != 1) {
-               panic("S32C1I compare error");
-       }
-
-       /* Then an S32C1I that stores: */
-       rcw_exc = 0;
-       rcw_word = 0x1234567;
-       n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
-       cause2 = rcw_exc;
-
-       if (cause2 != 0) {
-               /* unclean exception? */
-               if (n != 0xabcde || rcw_word != 0x1234567)
-                       panic("S32C1I exception error (b)");
-       } else if (rcw_word != 0xabcde || n != 0x1234567) {
-               panic("S32C1I store error");
-       }
-
-       /* Verify consistency of exceptions: */
-       if (cause1 || cause2) {
-               pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
-               /* If emulation of S32C1I upon bus error gets implemented,
-                  we can get rid of this panic for single core (not SMP) */
-               panic("S32C1I exceptions not currently supported");
-       }
-       if (cause1 != cause2)
-               panic("inconsistent S32C1I exceptions");
-
-       trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
-       trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
-       trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
-       return 0;
-}
-
-#else /* XCHAL_HAVE_S32C1I */
-
-/* This condition should not occur with a commercially deployed processor.
-   Display reminder for early engr test or demo chips / FPGA bitstreams */
-static int __init check_s32c1i(void)
-{
-       pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
-       return 0;
-}
-
-#endif /* XCHAL_HAVE_S32C1I */
-early_initcall(check_s32c1i);
-#endif /* CONFIG_S32C1I_SELFTEST */
-
 static inline int mem_reserve(unsigned long start, unsigned long end)
 {
        return memblock_reserve(start, end - start);
index 80e4cfb2471ad5af6a99433d6e8af76e16865558..720fe4e8b49712db84e4e00d5fb938c9ecb4220e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/nodemask.h>
 #include <linux/mm.h>
 #include <linux/of_fdt.h>
+#include <linux/dma-contiguous.h>
 
 #include <asm/bootparam.h>
 #include <asm/page.h>
@@ -60,6 +61,7 @@ void __init bootmem_init(void)
        max_low_pfn = min(max_pfn, MAX_LOW_PFN);
 
        memblock_set_current_limit(PFN_PHYS(max_low_pfn));
+       dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
 
        memblock_dump_all();
 }
index 668ef402c6eb5098eeeb1c2cdec58ec1dfe170d0..f849311e9fd4c94e57d81ba97279ec5fb0cb0ded 100644 (file)
@@ -556,18 +556,8 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
        lock_sock(sk);
 
        /*
-        * AEAD memory structure: For encryption, the tag is appended to the
-        * ciphertext which implies that the memory allocated for the ciphertext
-        * must be increased by the tag length. For decryption, the tag
-        * is expected to be concatenated to the ciphertext. The plaintext
-        * therefore has a memory size of the ciphertext minus the tag length.
-        *
-        * The memory structure for cipher operation has the following
-        * structure:
-        *      AEAD encryption input:  assoc data || plaintext
-        *      AEAD encryption output: cipherntext || auth tag
-        *      AEAD decryption input:  assoc data || ciphertext || auth tag
-        *      AEAD decryption output: plaintext
+        * Please see documentation of aead_request_set_crypt for the
+        * description of the AEAD memory structure expected from the caller.
         */
 
        if (ctx->more) {
index ce3a7a16f03fcc8f8bff97ec137b03df2f7986f1..edb0c79f7c64eea8b4d3cdde4467a356c20a32f8 100644 (file)
@@ -70,7 +70,7 @@ int acpi_map_pxm_to_node(int pxm)
 {
        int node;
 
-       if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
+       if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
                return NUMA_NO_NODE;
 
        node = pxm_to_node_map[pxm];
index 26ec39ddf21ffa4f58d09e62dda0fab90e46ae5f..ed758b74ddf0b74fe3fdbc84f8dde771aead4aca 100644 (file)
@@ -75,6 +75,73 @@ struct dax_dev {
        struct resource res[0];
 };
 
+static ssize_t id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dax_region *dax_region;
+       ssize_t rc = -ENXIO;
+
+       device_lock(dev);
+       dax_region = dev_get_drvdata(dev);
+       if (dax_region)
+               rc = sprintf(buf, "%d\n", dax_region->id);
+       device_unlock(dev);
+
+       return rc;
+}
+static DEVICE_ATTR_RO(id);
+
+static ssize_t region_size_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dax_region *dax_region;
+       ssize_t rc = -ENXIO;
+
+       device_lock(dev);
+       dax_region = dev_get_drvdata(dev);
+       if (dax_region)
+               rc = sprintf(buf, "%llu\n", (unsigned long long)
+                               resource_size(&dax_region->res));
+       device_unlock(dev);
+
+       return rc;
+}
+static struct device_attribute dev_attr_region_size = __ATTR(size, 0444,
+               region_size_show, NULL);
+
+static ssize_t align_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dax_region *dax_region;
+       ssize_t rc = -ENXIO;
+
+       device_lock(dev);
+       dax_region = dev_get_drvdata(dev);
+       if (dax_region)
+               rc = sprintf(buf, "%u\n", dax_region->align);
+       device_unlock(dev);
+
+       return rc;
+}
+static DEVICE_ATTR_RO(align);
+
+static struct attribute *dax_region_attributes[] = {
+       &dev_attr_region_size.attr,
+       &dev_attr_align.attr,
+       &dev_attr_id.attr,
+       NULL,
+};
+
+static const struct attribute_group dax_region_attribute_group = {
+       .name = "dax_region",
+       .attrs = dax_region_attributes,
+};
+
+static const struct attribute_group *dax_region_attribute_groups[] = {
+       &dax_region_attribute_group,
+       NULL,
+};
+
 static struct inode *dax_alloc_inode(struct super_block *sb)
 {
        return kmem_cache_alloc(dax_cache, GFP_KERNEL);
@@ -200,12 +267,31 @@ void dax_region_put(struct dax_region *dax_region)
 }
 EXPORT_SYMBOL_GPL(dax_region_put);
 
+static void dax_region_unregister(void *region)
+{
+       struct dax_region *dax_region = region;
+
+       sysfs_remove_groups(&dax_region->dev->kobj,
+                       dax_region_attribute_groups);
+       dax_region_put(dax_region);
+}
+
 struct dax_region *alloc_dax_region(struct device *parent, int region_id,
                struct resource *res, unsigned int align, void *addr,
                unsigned long pfn_flags)
 {
        struct dax_region *dax_region;
 
+       /*
+        * The DAX core assumes that it can store its private data in
+        * parent->driver_data. This WARN is a reminder / safeguard for
+        * developers of device-dax drivers.
+        */
+       if (dev_get_drvdata(parent)) {
+               dev_WARN(parent, "dax core failed to setup private data\n");
+               return NULL;
+       }
+
        if (!IS_ALIGNED(res->start, align)
                        || !IS_ALIGNED(resource_size(res), align))
                return NULL;
@@ -214,6 +300,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
        if (!dax_region)
                return NULL;
 
+       dev_set_drvdata(parent, dax_region);
        memcpy(&dax_region->res, res, sizeof(*res));
        dax_region->pfn_flags = pfn_flags;
        kref_init(&dax_region->kref);
@@ -222,7 +309,14 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
        dax_region->align = align;
        dax_region->dev = parent;
        dax_region->base = addr;
+       if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) {
+               kfree(dax_region);
+               return NULL;;
+       }
 
+       kref_get(&dax_region->kref);
+       if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region))
+               return NULL;
        return dax_region;
 }
 EXPORT_SYMBOL_GPL(alloc_dax_region);
index 73c6ce93a0d9204227818465a707db9f7d5806fb..033f49b31fdcfeeedede6a6349bbdab5115c82f6 100644 (file)
@@ -89,7 +89,8 @@ static int dax_pmem_probe(struct device *dev)
        pfn_sb = nd_pfn->pfn_sb;
 
        if (!devm_request_mem_region(dev, nsio->res.start,
-                               resource_size(&nsio->res), dev_name(dev))) {
+                               resource_size(&nsio->res),
+                               dev_name(&ndns->dev))) {
                dev_warn(dev, "could not reserve region %pR\n", &nsio->res);
                return -EBUSY;
        }
index 88bebe1968b717b4060a449ff49278cee2a84315..54be60ead08f8068c18dc9bbfd5a40e3cb26685c 100644 (file)
@@ -560,7 +560,7 @@ static int __init dmi_present(const u8 *buf)
                                        dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
                        }
                        dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
-                       printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
+                       pr_info("DMI: %s\n", dmi_ids_string);
                        return 0;
                }
        }
@@ -588,7 +588,7 @@ static int __init dmi_smbios3_present(const u8 *buf)
                                dmi_ver >> 16, (dmi_ver >> 8) & 0xFF,
                                dmi_ver & 0xFF);
                        dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
-                       pr_debug("DMI: %s\n", dmi_ids_string);
+                       pr_info("DMI: %s\n", dmi_ids_string);
                        return 0;
                }
        }
index d779307a96852b15f251c9595e035e0ee537db7e..46e6dcc089cbdd25fdf61025c53e7dc078233de3 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/errno.h>
 #include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/mfd/tps65218.h>
 
 struct tps65218_gpio {
@@ -30,7 +31,7 @@ static int tps65218_gpio_get(struct gpio_chip *gc, unsigned offset)
        unsigned int val;
        int ret;
 
-       ret = tps65218_reg_read(tps65218, TPS65218_REG_ENABLE2, &val);
+       ret = regmap_read(tps65218->regmap, TPS65218_REG_ENABLE2, &val);
        if (ret)
                return ret;
 
index 5ddde7349fbde42a0cb1101f904715e4739ead88..183f5dc1c3f228fbc29df3522cfadff18641ba9b 100644 (file)
@@ -116,6 +116,7 @@ config DRM_I915_GVT_KVMGT
        tristate "Enable KVM/VFIO support for Intel GVT-g"
        depends on DRM_I915_GVT
        depends on KVM
+       depends on VFIO_MDEV && VFIO_MDEV_DEVICE
        default n
        help
          Choose this option if you want to enable KVMGT support for
index 8a46a7f31d536005052953a82a6fdac471042d0c..b123c20e209740d4f3c3af36dd3ca6835972995e 100644 (file)
@@ -5,6 +5,4 @@ GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \
 
 ccflags-y                              += -I$(src) -I$(src)/$(GVT_DIR) -Wall
 i915-y                                 += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
-
-CFLAGS_kvmgt.o                         := -Wno-unused-function
 obj-$(CONFIG_DRM_I915_GVT_KVMGT)       += $(GVT_DIR)/kvmgt.o
index b1a7c8dd4b5fdc38b7970e35d772feba19d49c26..ad0e9364ee703a65ce2a33834321bb4a9fce34f1 100644 (file)
@@ -164,15 +164,17 @@ struct intel_vgpu {
 
 #if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT)
        struct {
-               struct device *mdev;
+               struct mdev_device *mdev;
                struct vfio_region *region;
                int num_regions;
                struct eventfd_ctx *intx_trigger;
                struct eventfd_ctx *msi_trigger;
                struct rb_root cache;
                struct mutex cache_lock;
-               void *vfio_group;
                struct notifier_block iommu_notifier;
+               struct notifier_block group_notifier;
+               struct kvm *kvm;
+               struct work_struct release_work;
        } vdev;
 #endif
 };
index dc036503315741f266223486922ca4ed67afc6de..4dd6722a733933224c269825d6f12f53525bf9c7 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/mm.h>
+#include <linux/mmu_context.h>
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <linux/uuid.h>
 #include <linux/kvm_host.h>
 #include <linux/vfio.h>
+#include <linux/mdev.h>
 
 #include "i915_drv.h"
 #include "gvt.h"
 
-static inline long kvmgt_pin_pages(struct device *dev, unsigned long *user_pfn,
-                       long npage, int prot, unsigned long *phys_pfn)
-{
-       return 0;
-}
-static inline long kvmgt_unpin_pages(struct device *dev, unsigned long *pfn,
-                       long npage)
-{
-       return 0;
-}
-
 static const struct intel_gvt_ops *intel_gvt_ops;
 
-
 /* helper macros copied from vfio-pci */
 #define VFIO_PCI_OFFSET_SHIFT   40
 #define VFIO_PCI_OFFSET_TO_INDEX(off)   (off >> VFIO_PCI_OFFSET_SHIFT)
@@ -90,6 +80,15 @@ struct gvt_dma {
        kvm_pfn_t pfn;
 };
 
+static inline bool handle_valid(unsigned long handle)
+{
+       return !!(handle & ~0xff);
+}
+
+static int kvmgt_guest_init(struct mdev_device *mdev);
+static void intel_vgpu_release_work(struct work_struct *work);
+static bool kvmgt_guest_exit(struct kvmgt_guest_info *info);
+
 static struct gvt_dma *__gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn)
 {
        struct rb_node *node = vgpu->vdev.cache.rb_node;
@@ -167,9 +166,10 @@ static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu,
 
 static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn)
 {
-       struct device *dev = vgpu->vdev.mdev;
+       struct device *dev = &vgpu->vdev.mdev->dev;
        struct gvt_dma *this;
-       unsigned long pfn;
+       unsigned long g1;
+       int rc;
 
        mutex_lock(&vgpu->vdev.cache_lock);
        this  = __gvt_cache_find(vgpu, gfn);
@@ -178,8 +178,9 @@ static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn)
                return;
        }
 
-       pfn = this->pfn;
-       WARN_ON((kvmgt_unpin_pages(dev, &pfn, 1) != 1));
+       g1 = gfn;
+       rc = vfio_unpin_pages(dev, &g1, 1);
+       WARN_ON(rc != 1);
        __gvt_cache_remove_entry(vgpu, this);
        mutex_unlock(&vgpu->vdev.cache_lock);
 }
@@ -194,15 +195,15 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu)
 {
        struct gvt_dma *dma;
        struct rb_node *node = NULL;
-       struct device *dev = vgpu->vdev.mdev;
-       unsigned long pfn;
+       struct device *dev = &vgpu->vdev.mdev->dev;
+       unsigned long gfn;
 
        mutex_lock(&vgpu->vdev.cache_lock);
        while ((node = rb_first(&vgpu->vdev.cache))) {
                dma = rb_entry(node, struct gvt_dma, node);
-               pfn = dma->pfn;
+               gfn = dma->gfn;
 
-               kvmgt_unpin_pages(dev, &pfn, 1);
+               vfio_unpin_pages(dev, &gfn, 1);
                __gvt_cache_remove_entry(vgpu, dma);
        }
        mutex_unlock(&vgpu->vdev.cache_lock);
@@ -226,7 +227,53 @@ static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt,
        return NULL;
 }
 
+static ssize_t available_instance_show(struct kobject *kobj, struct device *dev,
+               char *buf)
+{
+       struct intel_vgpu_type *type;
+       unsigned int num = 0;
+       void *gvt = kdev_to_i915(dev)->gvt;
+
+       type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
+       if (!type)
+               num = 0;
+       else
+               num = type->avail_instance;
+
+       return sprintf(buf, "%u\n", num);
+}
+
+static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
+               char *buf)
+{
+       return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
+}
+
+static ssize_t description_show(struct kobject *kobj, struct device *dev,
+               char *buf)
+{
+       struct intel_vgpu_type *type;
+       void *gvt = kdev_to_i915(dev)->gvt;
+
+       type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
+       if (!type)
+               return 0;
+
+       return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
+                               "fence: %d\n",
+                               BYTES_TO_MB(type->low_gm_size),
+                               BYTES_TO_MB(type->high_gm_size),
+                               type->fence);
+}
+
+static MDEV_TYPE_ATTR_RO(available_instance);
+static MDEV_TYPE_ATTR_RO(device_api);
+static MDEV_TYPE_ATTR_RO(description);
+
 static struct attribute *type_attrs[] = {
+       &mdev_type_attr_available_instance.attr,
+       &mdev_type_attr_device_api.attr,
+       &mdev_type_attr_description.attr,
        NULL,
 };
 
@@ -322,7 +369,7 @@ static void kvmgt_protect_table_add(struct kvmgt_guest_info *info, gfn_t gfn)
        if (kvmgt_gfn_is_write_protected(info, gfn))
                return;
 
-       p = kmalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC);
+       p = kzalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC);
        if (WARN(!p, "gfn: 0x%llx\n", gfn))
                return;
 
@@ -342,6 +389,720 @@ static void kvmgt_protect_table_del(struct kvmgt_guest_info *info,
        }
 }
 
+static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
+{
+       struct intel_vgpu *vgpu;
+       struct intel_vgpu_type *type;
+       struct device *pdev;
+       void *gvt;
+
+       pdev = mdev->parent->dev;
+       gvt = kdev_to_i915(pdev)->gvt;
+
+       type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
+       if (!type) {
+               gvt_err("failed to find type %s to create\n",
+                                               kobject_name(kobj));
+               return -EINVAL;
+       }
+
+       vgpu = intel_gvt_ops->vgpu_create(gvt, type);
+       if (IS_ERR_OR_NULL(vgpu)) {
+               gvt_err("create intel vgpu failed\n");
+               return -EINVAL;
+       }
+
+       INIT_WORK(&vgpu->vdev.release_work, intel_vgpu_release_work);
+
+       vgpu->vdev.mdev = mdev;
+       mdev_set_drvdata(mdev, vgpu);
+
+       gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n",
+                    dev_name(&mdev->dev));
+       return 0;
+}
+
+static int intel_vgpu_remove(struct mdev_device *mdev)
+{
+       struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+
+       if (handle_valid(vgpu->handle))
+               return -EBUSY;
+
+       intel_gvt_ops->vgpu_destroy(vgpu);
+       return 0;
+}
+
+static int intel_vgpu_iommu_notifier(struct notifier_block *nb,
+                                    unsigned long action, void *data)
+{
+       struct intel_vgpu *vgpu = container_of(nb,
+                                       struct intel_vgpu,
+                                       vdev.iommu_notifier);
+
+       if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
+               struct vfio_iommu_type1_dma_unmap *unmap = data;
+               unsigned long gfn, end_gfn;
+
+               gfn = unmap->iova >> PAGE_SHIFT;
+               end_gfn = gfn + unmap->size / PAGE_SIZE;
+
+               while (gfn < end_gfn)
+                       gvt_cache_remove(vgpu, gfn++);
+       }
+
+       return NOTIFY_OK;
+}
+
+static int intel_vgpu_group_notifier(struct notifier_block *nb,
+                                    unsigned long action, void *data)
+{
+       struct intel_vgpu *vgpu = container_of(nb,
+                                       struct intel_vgpu,
+                                       vdev.group_notifier);
+
+       /* the only action we care about */
+       if (action == VFIO_GROUP_NOTIFY_SET_KVM) {
+               vgpu->vdev.kvm = data;
+
+               if (!data)
+                       schedule_work(&vgpu->vdev.release_work);
+       }
+
+       return NOTIFY_OK;
+}
+
+static int intel_vgpu_open(struct mdev_device *mdev)
+{
+       struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+       unsigned long events;
+       int ret;
+
+       vgpu->vdev.iommu_notifier.notifier_call = intel_vgpu_iommu_notifier;
+       vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier;
+
+       events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+       ret = vfio_register_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, &events,
+                               &vgpu->vdev.iommu_notifier);
+       if (ret != 0) {
+               gvt_err("vfio_register_notifier for iommu failed: %d\n", ret);
+               goto out;
+       }
+
+       events = VFIO_GROUP_NOTIFY_SET_KVM;
+       ret = vfio_register_notifier(&mdev->dev, VFIO_GROUP_NOTIFY, &events,
+                               &vgpu->vdev.group_notifier);
+       if (ret != 0) {
+               gvt_err("vfio_register_notifier for group failed: %d\n", ret);
+               goto undo_iommu;
+       }
+
+       return kvmgt_guest_init(mdev);
+
+undo_iommu:
+       vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY,
+                                       &vgpu->vdev.iommu_notifier);
+out:
+       return ret;
+}
+
+static void __intel_vgpu_release(struct intel_vgpu *vgpu)
+{
+       struct kvmgt_guest_info *info;
+
+       if (!handle_valid(vgpu->handle))
+               return;
+
+       vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY,
+                                       &vgpu->vdev.iommu_notifier);
+       vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY,
+                                       &vgpu->vdev.group_notifier);
+
+       info = (struct kvmgt_guest_info *)vgpu->handle;
+       kvmgt_guest_exit(info);
+       vgpu->handle = 0;
+}
+
+static void intel_vgpu_release(struct mdev_device *mdev)
+{
+       struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+
+       __intel_vgpu_release(vgpu);
+}
+
+static void intel_vgpu_release_work(struct work_struct *work)
+{
+       struct intel_vgpu *vgpu = container_of(work, struct intel_vgpu,
+                                       vdev.release_work);
+       __intel_vgpu_release(vgpu);
+}
+
+static uint64_t intel_vgpu_get_bar0_addr(struct intel_vgpu *vgpu)
+{
+       u32 start_lo, start_hi;
+       u32 mem_type;
+       int pos = PCI_BASE_ADDRESS_0;
+
+       start_lo = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + pos)) &
+                       PCI_BASE_ADDRESS_MEM_MASK;
+       mem_type = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + pos)) &
+                       PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+
+       switch (mem_type) {
+       case PCI_BASE_ADDRESS_MEM_TYPE_64:
+               start_hi = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space
+                                               + pos + 4));
+               break;
+       case PCI_BASE_ADDRESS_MEM_TYPE_32:
+       case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+               /* 1M mem BAR treated as 32-bit BAR */
+       default:
+               /* mem unknown type treated as 32-bit BAR */
+               start_hi = 0;
+               break;
+       }
+
+       return ((u64)start_hi << 32) | start_lo;
+}
+
+static ssize_t intel_vgpu_rw(struct mdev_device *mdev, char *buf,
+                       size_t count, loff_t *ppos, bool is_write)
+{
+       struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+       unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+       uint64_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+       int ret = -EINVAL;
+
+
+       if (index >= VFIO_PCI_NUM_REGIONS) {
+               gvt_err("invalid index: %u\n", index);
+               return -EINVAL;
+       }
+
+       switch (index) {
+       case VFIO_PCI_CONFIG_REGION_INDEX:
+               if (is_write)
+                       ret = intel_gvt_ops->emulate_cfg_write(vgpu, pos,
+                                               buf, count);
+               else
+                       ret = intel_gvt_ops->emulate_cfg_read(vgpu, pos,
+                                               buf, count);
+               break;
+       case VFIO_PCI_BAR0_REGION_INDEX:
+       case VFIO_PCI_BAR1_REGION_INDEX:
+               if (is_write) {
+                       uint64_t bar0_start = intel_vgpu_get_bar0_addr(vgpu);
+
+                       ret = intel_gvt_ops->emulate_mmio_write(vgpu,
+                                               bar0_start + pos, buf, count);
+               } else {
+                       uint64_t bar0_start = intel_vgpu_get_bar0_addr(vgpu);
+
+                       ret = intel_gvt_ops->emulate_mmio_read(vgpu,
+                                               bar0_start + pos, buf, count);
+               }
+               break;
+       case VFIO_PCI_BAR2_REGION_INDEX:
+       case VFIO_PCI_BAR3_REGION_INDEX:
+       case VFIO_PCI_BAR4_REGION_INDEX:
+       case VFIO_PCI_BAR5_REGION_INDEX:
+       case VFIO_PCI_VGA_REGION_INDEX:
+       case VFIO_PCI_ROM_REGION_INDEX:
+       default:
+               gvt_err("unsupported region: %u\n", index);
+       }
+
+       return ret == 0 ? count : ret;
+}
+
+static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       unsigned int done = 0;
+       int ret;
+
+       while (count) {
+               size_t filled;
+
+               if (count >= 4 && !(*ppos % 4)) {
+                       u32 val;
+
+                       ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
+                                       ppos, false);
+                       if (ret <= 0)
+                               goto read_err;
+
+                       if (copy_to_user(buf, &val, sizeof(val)))
+                               goto read_err;
+
+                       filled = 4;
+               } else if (count >= 2 && !(*ppos % 2)) {
+                       u16 val;
+
+                       ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
+                                       ppos, false);
+                       if (ret <= 0)
+                               goto read_err;
+
+                       if (copy_to_user(buf, &val, sizeof(val)))
+                               goto read_err;
+
+                       filled = 2;
+               } else {
+                       u8 val;
+
+                       ret = intel_vgpu_rw(mdev, &val, sizeof(val), ppos,
+                                       false);
+                       if (ret <= 0)
+                               goto read_err;
+
+                       if (copy_to_user(buf, &val, sizeof(val)))
+                               goto read_err;
+
+                       filled = 1;
+               }
+
+               count -= filled;
+               done += filled;
+               *ppos += filled;
+               buf += filled;
+       }
+
+       return done;
+
+read_err:
+       return -EFAULT;
+}
+
+static ssize_t intel_vgpu_write(struct mdev_device *mdev,
+                               const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       unsigned int done = 0;
+       int ret;
+
+       while (count) {
+               size_t filled;
+
+               if (count >= 4 && !(*ppos % 4)) {
+                       u32 val;
+
+                       if (copy_from_user(&val, buf, sizeof(val)))
+                               goto write_err;
+
+                       ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
+                                       ppos, true);
+                       if (ret <= 0)
+                               goto write_err;
+
+                       filled = 4;
+               } else if (count >= 2 && !(*ppos % 2)) {
+                       u16 val;
+
+                       if (copy_from_user(&val, buf, sizeof(val)))
+                               goto write_err;
+
+                       ret = intel_vgpu_rw(mdev, (char *)&val,
+                                       sizeof(val), ppos, true);
+                       if (ret <= 0)
+                               goto write_err;
+
+                       filled = 2;
+               } else {
+                       u8 val;
+
+                       if (copy_from_user(&val, buf, sizeof(val)))
+                               goto write_err;
+
+                       ret = intel_vgpu_rw(mdev, &val, sizeof(val),
+                                       ppos, true);
+                       if (ret <= 0)
+                               goto write_err;
+
+                       filled = 1;
+               }
+
+               count -= filled;
+               done += filled;
+               *ppos += filled;
+               buf += filled;
+       }
+
+       return done;
+write_err:
+       return -EFAULT;
+}
+
+static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma)
+{
+       unsigned int index;
+       u64 virtaddr;
+       unsigned long req_size, pgoff = 0;
+       pgprot_t pg_prot;
+       struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+
+       index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
+       if (index >= VFIO_PCI_ROM_REGION_INDEX)
+               return -EINVAL;
+
+       if (vma->vm_end < vma->vm_start)
+               return -EINVAL;
+       if ((vma->vm_flags & VM_SHARED) == 0)
+               return -EINVAL;
+       if (index != VFIO_PCI_BAR2_REGION_INDEX)
+               return -EINVAL;
+
+       pg_prot = vma->vm_page_prot;
+       virtaddr = vma->vm_start;
+       req_size = vma->vm_end - vma->vm_start;
+       pgoff = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT;
+
+       return remap_pfn_range(vma, virtaddr, pgoff, req_size, pg_prot);
+}
+
+static int intel_vgpu_get_irq_count(struct intel_vgpu *vgpu, int type)
+{
+       if (type == VFIO_PCI_INTX_IRQ_INDEX || type == VFIO_PCI_MSI_IRQ_INDEX)
+               return 1;
+
+       return 0;
+}
+
+static int intel_vgpu_set_intx_mask(struct intel_vgpu *vgpu,
+                       unsigned int index, unsigned int start,
+                       unsigned int count, uint32_t flags,
+                       void *data)
+{
+       return 0;
+}
+
+static int intel_vgpu_set_intx_unmask(struct intel_vgpu *vgpu,
+                       unsigned int index, unsigned int start,
+                       unsigned int count, uint32_t flags, void *data)
+{
+       return 0;
+}
+
+static int intel_vgpu_set_intx_trigger(struct intel_vgpu *vgpu,
+               unsigned int index, unsigned int start, unsigned int count,
+               uint32_t flags, void *data)
+{
+       return 0;
+}
+
+static int intel_vgpu_set_msi_trigger(struct intel_vgpu *vgpu,
+               unsigned int index, unsigned int start, unsigned int count,
+               uint32_t flags, void *data)
+{
+       struct eventfd_ctx *trigger;
+
+       if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+               int fd = *(int *)data;
+
+               trigger = eventfd_ctx_fdget(fd);
+               if (IS_ERR(trigger)) {
+                       gvt_err("eventfd_ctx_fdget failed\n");
+                       return PTR_ERR(trigger);
+               }
+               vgpu->vdev.msi_trigger = trigger;
+       }
+
+       return 0;
+}
+
+static int intel_vgpu_set_irqs(struct intel_vgpu *vgpu, uint32_t flags,
+               unsigned int index, unsigned int start, unsigned int count,
+               void *data)
+{
+       int (*func)(struct intel_vgpu *vgpu, unsigned int index,
+                       unsigned int start, unsigned int count, uint32_t flags,
+                       void *data) = NULL;
+
+       switch (index) {
+       case VFIO_PCI_INTX_IRQ_INDEX:
+               switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+               case VFIO_IRQ_SET_ACTION_MASK:
+                       func = intel_vgpu_set_intx_mask;
+                       break;
+               case VFIO_IRQ_SET_ACTION_UNMASK:
+                       func = intel_vgpu_set_intx_unmask;
+                       break;
+               case VFIO_IRQ_SET_ACTION_TRIGGER:
+                       func = intel_vgpu_set_intx_trigger;
+                       break;
+               }
+               break;
+       case VFIO_PCI_MSI_IRQ_INDEX:
+               switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+               case VFIO_IRQ_SET_ACTION_MASK:
+               case VFIO_IRQ_SET_ACTION_UNMASK:
+                       /* XXX Need masking support exported */
+                       break;
+               case VFIO_IRQ_SET_ACTION_TRIGGER:
+                       func = intel_vgpu_set_msi_trigger;
+                       break;
+               }
+               break;
+       }
+
+       if (!func)
+               return -ENOTTY;
+
+       return func(vgpu, index, start, count, flags, data);
+}
+
+static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
+                            unsigned long arg)
+{
+       struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+       unsigned long minsz;
+
+       gvt_dbg_core("vgpu%d ioctl, cmd: %d\n", vgpu->id, cmd);
+
+       if (cmd == VFIO_DEVICE_GET_INFO) {
+               struct vfio_device_info info;
+
+               minsz = offsetofend(struct vfio_device_info, num_irqs);
+
+               if (copy_from_user(&info, (void __user *)arg, minsz))
+                       return -EFAULT;
+
+               if (info.argsz < minsz)
+                       return -EINVAL;
+
+               info.flags = VFIO_DEVICE_FLAGS_PCI;
+               info.flags |= VFIO_DEVICE_FLAGS_RESET;
+               info.num_regions = VFIO_PCI_NUM_REGIONS;
+               info.num_irqs = VFIO_PCI_NUM_IRQS;
+
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
+
+       } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
+               struct vfio_region_info info;
+               struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
+               int i, ret;
+               struct vfio_region_info_cap_sparse_mmap *sparse = NULL;
+               size_t size;
+               int nr_areas = 1;
+               int cap_type_id;
+
+               minsz = offsetofend(struct vfio_region_info, offset);
+
+               if (copy_from_user(&info, (void __user *)arg, minsz))
+                       return -EFAULT;
+
+               if (info.argsz < minsz)
+                       return -EINVAL;
+
+               switch (info.index) {
+               case VFIO_PCI_CONFIG_REGION_INDEX:
+                       info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+                       info.size = INTEL_GVT_MAX_CFG_SPACE_SZ;
+                       info.flags = VFIO_REGION_INFO_FLAG_READ |
+                                    VFIO_REGION_INFO_FLAG_WRITE;
+                       break;
+               case VFIO_PCI_BAR0_REGION_INDEX:
+                       info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+                       info.size = vgpu->cfg_space.bar[info.index].size;
+                       if (!info.size) {
+                               info.flags = 0;
+                               break;
+                       }
+
+                       info.flags = VFIO_REGION_INFO_FLAG_READ |
+                                    VFIO_REGION_INFO_FLAG_WRITE;
+                       break;
+               case VFIO_PCI_BAR1_REGION_INDEX:
+                       info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+                       info.size = 0;
+                       info.flags = 0;
+                       break;
+               case VFIO_PCI_BAR2_REGION_INDEX:
+                       info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+                       info.flags = VFIO_REGION_INFO_FLAG_CAPS |
+                                       VFIO_REGION_INFO_FLAG_MMAP |
+                                       VFIO_REGION_INFO_FLAG_READ |
+                                       VFIO_REGION_INFO_FLAG_WRITE;
+                       info.size = gvt_aperture_sz(vgpu->gvt);
+
+                       size = sizeof(*sparse) +
+                                       (nr_areas * sizeof(*sparse->areas));
+                       sparse = kzalloc(size, GFP_KERNEL);
+                       if (!sparse)
+                               return -ENOMEM;
+
+                       sparse->nr_areas = nr_areas;
+                       cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
+                       sparse->areas[0].offset =
+                                       PAGE_ALIGN(vgpu_aperture_offset(vgpu));
+                       sparse->areas[0].size = vgpu_aperture_sz(vgpu);
+                       if (!caps.buf) {
+                               kfree(caps.buf);
+                               caps.buf = NULL;
+                               caps.size = 0;
+                       }
+                       break;
+
+               case VFIO_PCI_BAR3_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:
+                       info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+                       info.size = 0;
+
+                       info.flags = 0;
+                       gvt_dbg_core("get region info bar:%d\n", info.index);
+                       break;
+
+               case VFIO_PCI_ROM_REGION_INDEX:
+               case VFIO_PCI_VGA_REGION_INDEX:
+                       gvt_dbg_core("get region info index:%d\n", info.index);
+                       break;
+               default:
+                       {
+                               struct vfio_region_info_cap_type cap_type;
+
+                               if (info.index >= VFIO_PCI_NUM_REGIONS +
+                                               vgpu->vdev.num_regions)
+                                       return -EINVAL;
+
+                               i = info.index - VFIO_PCI_NUM_REGIONS;
+
+                               info.offset =
+                                       VFIO_PCI_INDEX_TO_OFFSET(info.index);
+                               info.size = vgpu->vdev.region[i].size;
+                               info.flags = vgpu->vdev.region[i].flags;
+
+                               cap_type.type = vgpu->vdev.region[i].type;
+                               cap_type.subtype = vgpu->vdev.region[i].subtype;
+
+                               ret = vfio_info_add_capability(&caps,
+                                               VFIO_REGION_INFO_CAP_TYPE,
+                                               &cap_type);
+                               if (ret)
+                                       return ret;
+                       }
+               }
+
+               if ((info.flags & VFIO_REGION_INFO_FLAG_CAPS) && sparse) {
+                       switch (cap_type_id) {
+                       case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
+                               ret = vfio_info_add_capability(&caps,
+                                       VFIO_REGION_INFO_CAP_SPARSE_MMAP,
+                                       sparse);
+                               kfree(sparse);
+                               if (ret)
+                                       return ret;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+               }
+
+               if (caps.size) {
+                       if (info.argsz < sizeof(info) + caps.size) {
+                               info.argsz = sizeof(info) + caps.size;
+                               info.cap_offset = 0;
+                       } else {
+                               vfio_info_cap_shift(&caps, sizeof(info));
+                               if (copy_to_user((void __user *)arg +
+                                                 sizeof(info), caps.buf,
+                                                 caps.size)) {
+                                       kfree(caps.buf);
+                                       return -EFAULT;
+                               }
+                               info.cap_offset = sizeof(info);
+                       }
+
+                       kfree(caps.buf);
+               }
+
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
+       } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
+               struct vfio_irq_info info;
+
+               minsz = offsetofend(struct vfio_irq_info, count);
+
+               if (copy_from_user(&info, (void __user *)arg, minsz))
+                       return -EFAULT;
+
+               if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_IRQS)
+                       return -EINVAL;
+
+               switch (info.index) {
+               case VFIO_PCI_INTX_IRQ_INDEX:
+               case VFIO_PCI_MSI_IRQ_INDEX:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               info.flags = VFIO_IRQ_INFO_EVENTFD;
+
+               info.count = intel_vgpu_get_irq_count(vgpu, info.index);
+
+               if (info.index == VFIO_PCI_INTX_IRQ_INDEX)
+                       info.flags |= (VFIO_IRQ_INFO_MASKABLE |
+                                      VFIO_IRQ_INFO_AUTOMASKED);
+               else
+                       info.flags |= VFIO_IRQ_INFO_NORESIZE;
+
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
+       } else if (cmd == VFIO_DEVICE_SET_IRQS) {
+               struct vfio_irq_set hdr;
+               u8 *data = NULL;
+               int ret = 0;
+               size_t data_size = 0;
+
+               minsz = offsetofend(struct vfio_irq_set, count);
+
+               if (copy_from_user(&hdr, (void __user *)arg, minsz))
+                       return -EFAULT;
+
+               if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
+                       int max = intel_vgpu_get_irq_count(vgpu, hdr.index);
+
+                       ret = vfio_set_irqs_validate_and_prepare(&hdr, max,
+                                               VFIO_PCI_NUM_IRQS, &data_size);
+                       if (ret) {
+                               gvt_err("intel:vfio_set_irqs_validate_and_prepare failed\n");
+                               return -EINVAL;
+                       }
+                       if (data_size) {
+                               data = memdup_user((void __user *)(arg + minsz),
+                                                  data_size);
+                               if (IS_ERR(data))
+                                       return PTR_ERR(data);
+                       }
+               }
+
+               ret = intel_vgpu_set_irqs(vgpu, hdr.flags, hdr.index,
+                                       hdr.start, hdr.count, data);
+               kfree(data);
+
+               return ret;
+       } else if (cmd == VFIO_DEVICE_RESET) {
+               intel_gvt_ops->vgpu_reset(vgpu);
+               return 0;
+       }
+
+       return 0;
+}
+
+static const struct parent_ops intel_vgpu_ops = {
+       .supported_type_groups  = intel_vgpu_type_groups,
+       .create                 = intel_vgpu_create,
+       .remove                 = intel_vgpu_remove,
+
+       .open                   = intel_vgpu_open,
+       .release                = intel_vgpu_release,
+
+       .read                   = intel_vgpu_read,
+       .write                  = intel_vgpu_write,
+       .mmap                   = intel_vgpu_mmap,
+       .ioctl                  = intel_vgpu_ioctl,
+};
+
 static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops)
 {
        if (!intel_gvt_init_vgpu_type_groups(gvt))
@@ -349,22 +1110,28 @@ static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops)
 
        intel_gvt_ops = ops;
 
-       /* MDEV is not yet available */
-       return -ENODEV;
+       return mdev_register_device(dev, &intel_vgpu_ops);
 }
 
 static void kvmgt_host_exit(struct device *dev, void *gvt)
 {
        intel_gvt_cleanup_vgpu_type_groups(gvt);
+       mdev_unregister_device(dev);
 }
 
 static int kvmgt_write_protect_add(unsigned long handle, u64 gfn)
 {
-       struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle;
-       struct kvm *kvm = info->kvm;
+       struct kvmgt_guest_info *info;
+       struct kvm *kvm;
        struct kvm_memory_slot *slot;
        int idx;
 
+       if (!handle_valid(handle))
+               return -ESRCH;
+
+       info = (struct kvmgt_guest_info *)handle;
+       kvm = info->kvm;
+
        idx = srcu_read_lock(&kvm->srcu);
        slot = gfn_to_memslot(kvm, gfn);
 
@@ -384,11 +1151,17 @@ out:
 
 static int kvmgt_write_protect_remove(unsigned long handle, u64 gfn)
 {
-       struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle;
-       struct kvm *kvm = info->kvm;
+       struct kvmgt_guest_info *info;
+       struct kvm *kvm;
        struct kvm_memory_slot *slot;
        int idx;
 
+       if (!handle_valid(handle))
+               return 0;
+
+       info = (struct kvmgt_guest_info *)handle;
+       kvm = info->kvm;
+
        idx = srcu_read_lock(&kvm->srcu);
        slot = gfn_to_memslot(kvm, gfn);
 
@@ -476,6 +1249,85 @@ static int kvmgt_detect_host(void)
        return kvmgt_check_guest() ? -ENODEV : 0;
 }
 
+static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu, struct kvm *kvm)
+{
+       struct intel_vgpu *itr;
+       struct kvmgt_guest_info *info;
+       int id;
+       bool ret = false;
+
+       mutex_lock(&vgpu->gvt->lock);
+       for_each_active_vgpu(vgpu->gvt, itr, id) {
+               if (!handle_valid(itr->handle))
+                       continue;
+
+               info = (struct kvmgt_guest_info *)itr->handle;
+               if (kvm && kvm == info->kvm) {
+                       ret = true;
+                       goto out;
+               }
+       }
+out:
+       mutex_unlock(&vgpu->gvt->lock);
+       return ret;
+}
+
+static int kvmgt_guest_init(struct mdev_device *mdev)
+{
+       struct kvmgt_guest_info *info;
+       struct intel_vgpu *vgpu;
+       struct kvm *kvm;
+
+       vgpu = mdev_get_drvdata(mdev);
+       if (handle_valid(vgpu->handle))
+               return -EEXIST;
+
+       kvm = vgpu->vdev.kvm;
+       if (!kvm || kvm->mm != current->mm) {
+               gvt_err("KVM is required to use Intel vGPU\n");
+               return -ESRCH;
+       }
+
+       if (__kvmgt_vgpu_exist(vgpu, kvm))
+               return -EEXIST;
+
+       info = vzalloc(sizeof(struct kvmgt_guest_info));
+       if (!info)
+               return -ENOMEM;
+
+       vgpu->handle = (unsigned long)info;
+       info->vgpu = vgpu;
+       info->kvm = kvm;
+
+       kvmgt_protect_table_init(info);
+       gvt_cache_init(vgpu);
+
+       info->track_node.track_write = kvmgt_page_track_write;
+       info->track_node.track_flush_slot = kvmgt_page_track_flush_slot;
+       kvm_page_track_register_notifier(kvm, &info->track_node);
+
+       return 0;
+}
+
+static bool kvmgt_guest_exit(struct kvmgt_guest_info *info)
+{
+       struct intel_vgpu *vgpu;
+
+       if (!info) {
+               gvt_err("kvmgt_guest_info invalid\n");
+               return false;
+       }
+
+       vgpu = info->vgpu;
+
+       kvm_page_track_unregister_notifier(info->kvm, &info->track_node);
+       kvmgt_protect_table_destroy(info);
+       gvt_cache_destroy(vgpu);
+       vfree(info);
+
+       return true;
+}
+
 static int kvmgt_attach_vgpu(void *vgpu, unsigned long *handle)
 {
        /* nothing to do here */
@@ -489,63 +1341,72 @@ static void kvmgt_detach_vgpu(unsigned long handle)
 
 static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data)
 {
-       struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle;
-       struct intel_vgpu *vgpu = info->vgpu;
+       struct kvmgt_guest_info *info;
+       struct intel_vgpu *vgpu;
 
-       if (vgpu->vdev.msi_trigger)
-               return eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1;
+       if (!handle_valid(handle))
+               return -ESRCH;
 
-       return false;
+       info = (struct kvmgt_guest_info *)handle;
+       vgpu = info->vgpu;
+
+       if (eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1)
+               return 0;
+
+       return -EFAULT;
 }
 
 static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn)
 {
        unsigned long pfn;
-       struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle;
+       struct kvmgt_guest_info *info;
+       struct device *dev;
        int rc;
 
+       if (!handle_valid(handle))
+               return INTEL_GVT_INVALID_ADDR;
+
+       info = (struct kvmgt_guest_info *)handle;
        pfn = gvt_cache_find(info->vgpu, gfn);
        if (pfn != 0)
                return pfn;
 
-       rc = kvmgt_pin_pages(info->vgpu->vdev.mdev, &gfn, 1,
-                            IOMMU_READ | IOMMU_WRITE, &pfn);
+       pfn = INTEL_GVT_INVALID_ADDR;
+       dev = &info->vgpu->vdev.mdev->dev;
+       rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn);
        if (rc != 1) {
-               gvt_err("vfio_pin_pages failed for gfn: 0x%lx\n", gfn);
-               return 0;
+               gvt_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", gfn, rc);
+               return INTEL_GVT_INVALID_ADDR;
        }
 
        gvt_cache_add(info->vgpu, gfn, pfn);
        return pfn;
 }
 
-static void *kvmgt_gpa_to_hva(unsigned long handle, unsigned long gpa)
+static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa,
+                       void *buf, unsigned long len, bool write)
 {
-       unsigned long pfn;
-       gfn_t gfn = gpa_to_gfn(gpa);
+       struct kvmgt_guest_info *info;
+       struct kvm *kvm;
+       int ret;
+       bool kthread = current->mm == NULL;
 
-       pfn = kvmgt_gfn_to_pfn(handle, gfn);
-       if (!pfn)
-               return NULL;
+       if (!handle_valid(handle))
+               return -ESRCH;
 
-       return (char *)pfn_to_kaddr(pfn) + offset_in_page(gpa);
-}
+       info = (struct kvmgt_guest_info *)handle;
+       kvm = info->kvm;
 
-static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa,
-                       void *buf, unsigned long len, bool write)
-{
-       void *hva = NULL;
+       if (kthread)
+               use_mm(kvm->mm);
 
-       hva = kvmgt_gpa_to_hva(handle, gpa);
-       if (!hva)
-               return -EFAULT;
+       ret = write ? kvm_write_guest(kvm, gpa, buf, len) :
+                     kvm_read_guest(kvm, gpa, buf, len);
 
-       if (write)
-               memcpy(hva, buf, len);
-       else
-               memcpy(buf, hva, len);
+       if (kthread)
+               unuse_mm(kvm->mm);
 
-       return 0;
+       return ret;
 }
 
 static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa,
index 83af17ad0f1f131d6d397e3df2e15521d0c24b55..6d949965867190458abaa653636ed4ab6702a4aa 100644 (file)
@@ -134,6 +134,7 @@ static const struct xpad_device {
        { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
        { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
        { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
+       { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
        { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -1044,9 +1045,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
                packet->data[7] = 0x00;
                packet->data[8] = strong / 512; /* left actuator */
                packet->data[9] = weak / 512;   /* right actuator */
-               packet->data[10] = 0xFF;
-               packet->data[11] = 0x00;
-               packet->data[12] = 0x00;
+               packet->data[10] = 0xFF; /* on period */
+               packet->data[11] = 0x00; /* off period */
+               packet->data[12] = 0xFF; /* repeat count */
                packet->len = 13;
                packet->pending = true;
                break;
index 29093657f2ef8233c667aace8406790a7d859f1d..582462d0af758566a3611b3b7bac7328b6d491a0 100644 (file)
 #include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/spinlock.h>
 
 struct gpio_button_data {
        const struct gpio_keys_button *button;
        struct input_dev *input;
+       struct gpio_desc *gpiod;
 
        struct timer_list release_timer;
        unsigned int release_delay;     /* in msecs, for IRQ-only buttons */
@@ -140,7 +140,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
                 */
                disable_irq(bdata->irq);
 
-               if (gpio_is_valid(bdata->button->gpio))
+               if (bdata->gpiod)
                        cancel_delayed_work_sync(&bdata->work);
                else
                        del_timer_sync(&bdata->release_timer);
@@ -358,19 +358,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
        const struct gpio_keys_button *button = bdata->button;
        struct input_dev *input = bdata->input;
        unsigned int type = button->type ?: EV_KEY;
-       int state = gpio_get_value_cansleep(button->gpio);
+       int state;
 
+       state = gpiod_get_value_cansleep(bdata->gpiod);
        if (state < 0) {
-               dev_err(input->dev.parent, "failed to get gpio state\n");
+               dev_err(input->dev.parent,
+                       "failed to get gpio state: %d\n", state);
                return;
        }
 
-       state = (state ? 1 : 0) ^ button->active_low;
        if (type == EV_ABS) {
                if (state)
                        input_event(input, type, button->code, button->value);
        } else {
-               input_event(input, type, button->code, !!state);
+               input_event(input, type, button->code, state);
        }
        input_sync(input);
 }
@@ -456,7 +457,7 @@ static void gpio_keys_quiesce_key(void *data)
 {
        struct gpio_button_data *bdata = data;
 
-       if (gpio_is_valid(bdata->button->gpio))
+       if (bdata->gpiod)
                cancel_delayed_work_sync(&bdata->work);
        else
                del_timer_sync(&bdata->release_timer);
@@ -465,7 +466,8 @@ static void gpio_keys_quiesce_key(void *data)
 static int gpio_keys_setup_key(struct platform_device *pdev,
                                struct input_dev *input,
                                struct gpio_button_data *bdata,
-                               const struct gpio_keys_button *button)
+                               const struct gpio_keys_button *button,
+                               struct fwnode_handle *child)
 {
        const char *desc = button->desc ? button->desc : "gpio_keys";
        struct device *dev = &pdev->dev;
@@ -478,18 +480,56 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
        bdata->button = button;
        spin_lock_init(&bdata->lock);
 
-       if (gpio_is_valid(button->gpio)) {
+       if (child) {
+               bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child);
+               if (IS_ERR(bdata->gpiod)) {
+                       error = PTR_ERR(bdata->gpiod);
+                       if (error == -ENOENT) {
+                               /*
+                                * GPIO is optional, we may be dealing with
+                                * purely interrupt-driven setup.
+                                */
+                               bdata->gpiod = NULL;
+                       } else {
+                               if (error != -EPROBE_DEFER)
+                                       dev_err(dev, "failed to get gpio: %d\n",
+                                               error);
+                               return error;
+                       }
+               } else {
+                       error = gpiod_direction_input(bdata->gpiod);
+                       if (error) {
+                               dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
+                                       desc_to_gpio(bdata->gpiod), error);
+                               return error;
+                       }
+               }
+       } else if (gpio_is_valid(button->gpio)) {
+               /*
+                * Legacy GPIO number, so request the GPIO here and
+                * convert it to descriptor.
+                */
+               unsigned flags = GPIOF_IN;
+
+               if (button->active_low)
+                       flags |= GPIOF_ACTIVE_LOW;
 
-               error = devm_gpio_request_one(&pdev->dev, button->gpio,
-                                             GPIOF_IN, desc);
+               error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
+                                             desc);
                if (error < 0) {
                        dev_err(dev, "Failed to request GPIO %d, error %d\n",
                                button->gpio, error);
                        return error;
                }
 
+               bdata->gpiod = gpio_to_desc(button->gpio);
+               if (!bdata->gpiod)
+                       return -EINVAL;
+       }
+
+       if (bdata->gpiod) {
                if (button->debounce_interval) {
-                       error = gpio_set_debounce(button->gpio,
+                       error = gpiod_set_debounce(bdata->gpiod,
                                        button->debounce_interval * 1000);
                        /* use timer if gpiolib doesn't provide debounce */
                        if (error < 0)
@@ -500,7 +540,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
                if (button->irq) {
                        bdata->irq = button->irq;
                } else {
-                       irq = gpio_to_irq(button->gpio);
+                       irq = gpiod_to_irq(bdata->gpiod);
                        if (irq < 0) {
                                error = irq;
                                dev_err(dev,
@@ -518,9 +558,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 
        } else {
                if (!button->irq) {
-                       dev_err(dev, "No IRQ specified\n");
+                       dev_err(dev, "Found button without gpio or irq\n");
                        return -EINVAL;
                }
+
                bdata->irq = button->irq;
 
                if (button->type && button->type != EV_KEY) {
@@ -575,7 +616,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
 
        for (i = 0; i < ddata->pdata->nbuttons; i++) {
                struct gpio_button_data *bdata = &ddata->data[i];
-               if (gpio_is_valid(bdata->button->gpio))
+               if (bdata->gpiod)
                        gpio_keys_gpio_report_event(bdata);
        }
        input_sync(input);
@@ -612,25 +653,18 @@ static void gpio_keys_close(struct input_dev *input)
  * Handlers for alternative sources of platform_data
  */
 
-#ifdef CONFIG_OF
 /*
- * Translate OpenFirmware node properties into platform_data
+ * Translate properties into platform_data
  */
 static struct gpio_keys_platform_data *
 gpio_keys_get_devtree_pdata(struct device *dev)
 {
-       struct device_node *node, *pp;
        struct gpio_keys_platform_data *pdata;
        struct gpio_keys_button *button;
-       int error;
+       struct fwnode_handle *child;
        int nbuttons;
-       int i;
 
-       node = dev->of_node;
-       if (!node)
-               return ERR_PTR(-ENODEV);
-
-       nbuttons = of_get_available_child_count(node);
+       nbuttons = device_get_child_node_count(dev);
        if (nbuttons == 0)
                return ERR_PTR(-ENODEV);
 
@@ -640,64 +674,47 @@ gpio_keys_get_devtree_pdata(struct device *dev)
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
-       pdata->nbuttons = nbuttons;
-
-       pdata->rep = !!of_get_property(node, "autorepeat", NULL);
-
-       of_property_read_string(node, "label", &pdata->name);
-
-       i = 0;
-       for_each_available_child_of_node(node, pp) {
-               enum of_gpio_flags flags;
+       button = (struct gpio_keys_button *)(pdata + 1);
 
-               button = &pdata->buttons[i++];
+       pdata->buttons = button;
+       pdata->nbuttons = nbuttons;
 
-               button->gpio = of_get_gpio_flags(pp, 0, &flags);
-               if (button->gpio < 0) {
-                       error = button->gpio;
-                       if (error != -ENOENT) {
-                               if (error != -EPROBE_DEFER)
-                                       dev_err(dev,
-                                               "Failed to get gpio flags, error: %d\n",
-                                               error);
-                               return ERR_PTR(error);
-                       }
-               } else {
-                       button->active_low = flags & OF_GPIO_ACTIVE_LOW;
-               }
+       pdata->rep = device_property_read_bool(dev, "autorepeat");
 
-               button->irq = irq_of_parse_and_map(pp, 0);
+       device_property_read_string(dev, "label", &pdata->name);
 
-               if (!gpio_is_valid(button->gpio) && !button->irq) {
-                       dev_err(dev, "Found button without gpios or irqs\n");
-                       return ERR_PTR(-EINVAL);
-               }
+       device_for_each_child_node(dev, child) {
+               if (is_of_node(child))
+                       button->irq =
+                               irq_of_parse_and_map(to_of_node(child), 0);
 
-               if (of_property_read_u32(pp, "linux,code", &button->code)) {
-                       dev_err(dev, "Button without keycode: 0x%x\n",
-                               button->gpio);
+               if (fwnode_property_read_u32(child, "linux,code",
+                                            &button->code)) {
+                       dev_err(dev, "Button without keycode\n");
+                       fwnode_handle_put(child);
                        return ERR_PTR(-EINVAL);
                }
 
-               button->desc = of_get_property(pp, "label", NULL);
+               fwnode_property_read_string(child, "label", &button->desc);
 
-               if (of_property_read_u32(pp, "linux,input-type", &button->type))
+               if (fwnode_property_read_u32(child, "linux,input-type",
+                                            &button->type))
                        button->type = EV_KEY;
 
-               button->wakeup = of_property_read_bool(pp, "wakeup-source") ||
-                                /* legacy name */
-                                of_property_read_bool(pp, "gpio-key,wakeup");
+               button->wakeup =
+                       fwnode_property_read_bool(child, "wakeup-source") ||
+                       /* legacy name */
+                       fwnode_property_read_bool(child, "gpio-key,wakeup");
 
-               button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
+               button->can_disable =
+                       fwnode_property_read_bool(child, "linux,can-disable");
 
-               if (of_property_read_u32(pp, "debounce-interval",
+               if (fwnode_property_read_u32(child, "debounce-interval",
                                         &button->debounce_interval))
                        button->debounce_interval = 5;
-       }
 
-       if (pdata->nbuttons == 0)
-               return ERR_PTR(-EINVAL);
+               button++;
+       }
 
        return pdata;
 }
@@ -708,20 +725,11 @@ static const struct of_device_id gpio_keys_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
 
-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_get_devtree_pdata(struct device *dev)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-#endif
-
 static int gpio_keys_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
+       struct fwnode_handle *child = NULL;
        struct gpio_keys_drvdata *ddata;
        struct input_dev *input;
        size_t size;
@@ -774,14 +782,28 @@ static int gpio_keys_probe(struct platform_device *pdev)
                const struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_button_data *bdata = &ddata->data[i];
 
-               error = gpio_keys_setup_key(pdev, input, bdata, button);
-               if (error)
+               if (!dev_get_platdata(dev)) {
+                       child = device_get_next_child_node(&pdev->dev, child);
+                       if (!child) {
+                               dev_err(&pdev->dev,
+                                       "missing child device node for entry %d\n",
+                                       i);
+                               return -EINVAL;
+                       }
+               }
+
+               error = gpio_keys_setup_key(pdev, input, bdata, button, child);
+               if (error) {
+                       fwnode_handle_put(child);
                        return error;
+               }
 
                if (button->wakeup)
                        wakeup = 1;
        }
 
+       fwnode_handle_put(child);
+
        error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
        if (error) {
                dev_err(dev, "Unable to export keys/switches, error: %d\n",
@@ -814,8 +836,7 @@ static int gpio_keys_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int gpio_keys_suspend(struct device *dev)
+static int __maybe_unused gpio_keys_suspend(struct device *dev)
 {
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
        struct input_dev *input = ddata->input;
@@ -837,7 +858,7 @@ static int gpio_keys_suspend(struct device *dev)
        return 0;
 }
 
-static int gpio_keys_resume(struct device *dev)
+static int __maybe_unused gpio_keys_resume(struct device *dev)
 {
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
        struct input_dev *input = ddata->input;
@@ -863,7 +884,6 @@ static int gpio_keys_resume(struct device *dev)
        gpio_keys_report_state(ddata);
        return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
 
@@ -873,7 +893,7 @@ static struct platform_driver gpio_keys_device_driver = {
        .driver         = {
                .name   = "gpio-keys",
                .pm     = &gpio_keys_pm_ops,
-               .of_match_table = of_match_ptr(gpio_keys_of_match),
+               .of_match_table = gpio_keys_of_match,
        }
 };
 
index 62bdb1d48c49dbd990ce37f2da335ee8d60b472d..bed4f2086158e3073b325dcc75fbcac3c51df4da 100644 (file)
 #define DRV_NAME       "gpio-keys-polled"
 
 struct gpio_keys_button_data {
+       struct gpio_desc *gpiod;
        int last_state;
        int count;
        int threshold;
-       int can_sleep;
 };
 
 struct gpio_keys_polled_dev {
@@ -46,7 +46,7 @@ struct gpio_keys_polled_dev {
 };
 
 static void gpio_keys_button_event(struct input_polled_dev *dev,
-                                  struct gpio_keys_button *button,
+                                  const struct gpio_keys_button *button,
                                   int state)
 {
        struct gpio_keys_polled_dev *bdev = dev->private;
@@ -70,21 +70,22 @@ static void gpio_keys_button_event(struct input_polled_dev *dev,
 }
 
 static void gpio_keys_polled_check_state(struct input_polled_dev *dev,
-                                        struct gpio_keys_button *button,
+                                        const struct gpio_keys_button *button,
                                         struct gpio_keys_button_data *bdata)
 {
        int state;
 
-       if (bdata->can_sleep)
-               state = !!gpiod_get_value_cansleep(button->gpiod);
-       else
-               state = !!gpiod_get_value(button->gpiod);
-
-       gpio_keys_button_event(dev, button, state);
+       state = gpiod_get_value_cansleep(bdata->gpiod);
+       if (state < 0) {
+               dev_err(dev->input->dev.parent,
+                       "failed to get gpio state: %d\n", state);
+       } else {
+               gpio_keys_button_event(dev, button, state);
 
-       if (state != bdata->last_state) {
-               bdata->count = 0;
-               bdata->last_state = state;
+               if (state != bdata->last_state) {
+                       bdata->count = 0;
+                       bdata->last_state = state;
+               }
        }
 }
 
@@ -142,48 +143,35 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
                pdata->disable(bdev->dev);
 }
 
-static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
+static struct gpio_keys_platform_data *
+gpio_keys_polled_get_devtree_pdata(struct device *dev)
 {
        struct gpio_keys_platform_data *pdata;
        struct gpio_keys_button *button;
        struct fwnode_handle *child;
-       int error;
        int nbuttons;
 
        nbuttons = device_get_child_node_count(dev);
        if (nbuttons == 0)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button),
                             GFP_KERNEL);
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
+       button = (struct gpio_keys_button *)(pdata + 1);
+
+       pdata->buttons = button;
+       pdata->nbuttons = nbuttons;
 
        pdata->rep = device_property_present(dev, "autorepeat");
        device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
 
        device_for_each_child_node(dev, child) {
-               struct gpio_desc *desc;
-
-               desc = devm_get_gpiod_from_child(dev, NULL, child);
-               if (IS_ERR(desc)) {
-                       error = PTR_ERR(desc);
-                       if (error != -EPROBE_DEFER)
-                               dev_err(dev,
-                                       "Failed to get gpio flags, error: %d\n",
-                                       error);
-                       fwnode_handle_put(child);
-                       return ERR_PTR(error);
-               }
-
-               button = &pdata->buttons[pdata->nbuttons++];
-               button->gpiod = desc;
-
-               if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
-                       dev_err(dev, "Button without keycode: %d\n",
-                               pdata->nbuttons - 1);
+               if (fwnode_property_read_u32(child, "linux,code",
+                                            &button->code)) {
+                       dev_err(dev, "button without keycode\n");
                        fwnode_handle_put(child);
                        return ERR_PTR(-EINVAL);
                }
@@ -206,10 +194,9 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
                if (fwnode_property_read_u32(child, "debounce-interval",
                                             &button->debounce_interval))
                        button->debounce_interval = 5;
-       }
 
-       if (pdata->nbuttons == 0)
-               return ERR_PTR(-EINVAL);
+               button++;
+       }
 
        return pdata;
 }
@@ -220,7 +207,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
        int i, min = 0, max = 0;
 
        for (i = 0; i < pdata->nbuttons; i++) {
-               struct gpio_keys_button *button = &pdata->buttons[i];
+               const struct gpio_keys_button *button = &pdata->buttons[i];
 
                if (button->type != EV_ABS || button->code != code)
                        continue;
@@ -230,6 +217,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
                if (button->value > max)
                        max = button->value;
        }
+
        input_set_abs_params(input, code, min, max, 0, 0);
 }
 
@@ -242,6 +230,7 @@ MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
 static int gpio_keys_polled_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct fwnode_handle *child = NULL;
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
        struct gpio_keys_polled_dev *bdev;
        struct input_polled_dev *poll_dev;
@@ -254,10 +243,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                pdata = gpio_keys_polled_get_devtree_pdata(dev);
                if (IS_ERR(pdata))
                        return PTR_ERR(pdata);
-               if (!pdata) {
-                       dev_err(dev, "missing platform data\n");
-                       return -EINVAL;
-               }
        }
 
        if (!pdata->poll_interval) {
@@ -300,20 +285,48 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                __set_bit(EV_REP, input->evbit);
 
        for (i = 0; i < pdata->nbuttons; i++) {
-               struct gpio_keys_button *button = &pdata->buttons[i];
+               const struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_keys_button_data *bdata = &bdev->data[i];
                unsigned int type = button->type ?: EV_KEY;
 
                if (button->wakeup) {
                        dev_err(dev, DRV_NAME " does not support wakeup\n");
+                       fwnode_handle_put(child);
                        return -EINVAL;
                }
 
-               /*
-                * Legacy GPIO number so request the GPIO here and
-                * convert it to descriptor.
-                */
-               if (!button->gpiod && gpio_is_valid(button->gpio)) {
+               if (!dev_get_platdata(dev)) {
+                       /* No legacy static platform data */
+                       child = device_get_next_child_node(dev, child);
+                       if (!child) {
+                               dev_err(dev, "missing child device node\n");
+                               return -EINVAL;
+                       }
+
+                       bdata->gpiod = devm_get_gpiod_from_child(dev, NULL,
+                                                                child);
+                       if (IS_ERR(bdata->gpiod)) {
+                               error = PTR_ERR(bdata->gpiod);
+                               if (error != -EPROBE_DEFER)
+                                       dev_err(dev,
+                                               "failed to get gpio: %d\n",
+                                               error);
+                               fwnode_handle_put(child);
+                               return error;
+                       }
+
+                       error = gpiod_direction_input(bdata->gpiod);
+                       if (error) {
+                               dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
+                                       desc_to_gpio(bdata->gpiod), error);
+                               fwnode_handle_put(child);
+                               return error;
+                       }
+               } else if (gpio_is_valid(button->gpio)) {
+                       /*
+                        * Legacy GPIO number so request the GPIO here and
+                        * convert it to descriptor.
+                        */
                        unsigned flags = GPIOF_IN;
 
                        if (button->active_low)
@@ -322,18 +335,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                        error = devm_gpio_request_one(&pdev->dev, button->gpio,
                                        flags, button->desc ? : DRV_NAME);
                        if (error) {
-                               dev_err(dev, "unable to claim gpio %u, err=%d\n",
+                               dev_err(dev,
+                                       "unable to claim gpio %u, err=%d\n",
                                        button->gpio, error);
                                return error;
                        }
 
-                       button->gpiod = gpio_to_desc(button->gpio);
+                       bdata->gpiod = gpio_to_desc(button->gpio);
+                       if (!bdata->gpiod) {
+                               dev_err(dev,
+                                       "unable to convert gpio %u to descriptor\n",
+                                       button->gpio);
+                               return -EINVAL;
+                       }
                }
 
-               if (IS_ERR(button->gpiod))
-                       return PTR_ERR(button->gpiod);
-
-               bdata->can_sleep = gpiod_cansleep(button->gpiod);
                bdata->last_state = -1;
                bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
                                                pdata->poll_interval);
@@ -344,6 +360,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                                                        button->code);
        }
 
+       fwnode_handle_put(child);
+
        bdev->poll_dev = poll_dev;
        bdev->dev = dev;
        bdev->pdata = pdata;
index 265d641c40e205767d96fbe81b7f794d32a0dc06..632523d4f5dc11b21e1591ccd79f841dbb640194 100644 (file)
@@ -182,7 +182,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0 || irq >= NR_IRQS) {
+       if (irq < 0) {
                dev_err(&pdev->dev, "failed to get platform irq\n");
                return -EINVAL;
        }
index fcef5d1365e2a3034e3a9544f7e403a0680a5058..e24443376e756fe6290cfba7e5dbb0aa5f336b9f 100644 (file)
@@ -316,7 +316,7 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
        error = of_property_read_u32(np, "marvell,debounce-interval",
                                     &pdata->debounce_interval);
        if (error) {
-               dev_err(dev, "failed to parse debpunce-interval\n");
+               dev_err(dev, "failed to parse debounce-interval\n");
                return error;
        }
 
index 9002298698fce303de6a61b0253c6b0a667b4818..3048ef3e3e1639e2f7d24b9e60c6cf45cfe01c8a 100644 (file)
@@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
        int error, col, row;
        u8 reg, state, code;
 
-       /* Initial read of the key event FIFO */
-       error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+       do {
+               error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+               if (error < 0) {
+                       dev_err(&keypad_data->client->dev,
+                               "unable to read REG_KEY_EVENT_A\n");
+                       break;
+               }
+
+               /* Assume that key code 0 signifies empty FIFO */
+               if (reg <= 0)
+                       break;
 
-       /* Assume that key code 0 signifies empty FIFO */
-       while (error >= 0 && reg > 0) {
                state = reg & KEY_EVENT_VALUE;
                code  = reg & KEY_EVENT_CODE;
 
@@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
 
                /* Read for next loop */
                error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
-       }
-
-       if (error < 0)
-               dev_err(&keypad_data->client->dev,
-                       "unable to read REG_KEY_EVENT_A\n");
+       } while (1);
 
        input_sync(input);
 }
index 7ffb614ce5664cd7955600a216b121e7c61a1fe2..1ae4d9617ff807c71ac011f79413d6faeed2d202 100644 (file)
@@ -625,11 +625,12 @@ config INPUT_DA9055_ONKEY
          will be called da9055_onkey.
 
 config INPUT_DA9063_ONKEY
-       tristate "Dialog DA9062/63 OnKey"
+       tristate "Dialog DA9063/62/61 OnKey"
        depends on MFD_DA9063 || MFD_DA9062
        help
-         Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs
-         as an input device capable of reporting the power button status.
+         Support the ONKEY of Dialog DA9063, DA9062 and DA9061 Power
+         Management ICs as an input device capable of reporting the
+         power button status.
 
          To compile this driver as a module, choose M here: the module
          will be called da9063_onkey.
index b0d445390ee44dfe3fb2bf3fea11d0d8f9257a62..2124390ec38c606bf55ba0d953f681862d9c962f 100644 (file)
@@ -538,8 +538,13 @@ static int bma150_probe(struct i2c_client *client,
                return -EIO;
        }
 
+       /*
+        * Note if the IIO CONFIG_BMA180 driver is enabled we want to fail
+        * the probe for the bma180 as the iio driver is preferred.
+        */
        chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
-       if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) {
+       if (chip_id != BMA150_CHIP_ID &&
+           (IS_ENABLED(CONFIG_BMA180) || chip_id != BMA180_CHIP_ID)) {
                dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
                return -EINVAL;
        }
@@ -643,7 +648,9 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
 
 static const struct i2c_device_id bma150_id[] = {
        { "bma150", 0 },
+#if !IS_ENABLED(CONFIG_BMA180)
        { "bma180", 0 },
+#endif
        { "smb380", 0 },
        { "bma023", 0 },
        { }
index bb863e062b03b3cf66317c8899401478e2f06930..b4ff1e86d3d30fee8a4e3ff4e33dd066c6a869b0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * OnKey device driver for DA9063 and DA9062 PMICs
+ * OnKey device driver for DA9063, DA9062 and DA9061 PMICs
  * Copyright (C) 2015  Dialog Semiconductor Ltd.
  *
  * This program is free software; you can redistribute it and/or
@@ -87,6 +87,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = {
        { .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
        { },
 };
+MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
 
 static void da9063_poll_on(struct work_struct *work)
 {
@@ -149,13 +150,13 @@ static void da9063_poll_on(struct work_struct *work)
                         * and then send shutdown command
                         */
                        dev_dbg(&onkey->input->dev,
-                               "Sending SHUTDOWN to DA9063 ...\n");
+                               "Sending SHUTDOWN to PMIC ...\n");
                        error = regmap_write(onkey->regmap,
                                             config->onkey_shutdown,
                                             config->onkey_shutdown_mask);
                        if (error)
                                dev_err(&onkey->input->dev,
-                                       "Cannot SHUTDOWN DA9063: %d\n",
+                                       "Cannot SHUTDOWN PMIC: %d\n",
                                        error);
                }
        }
@@ -300,6 +301,6 @@ static struct platform_driver da9063_onkey_driver = {
 module_platform_driver(da9063_onkey_driver);
 
 MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
-MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062");
+MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
index 2adfd86c869a5364312a2d8df904d2bd7df68b52..0a2b865b100040d99731abe52c1261c5f390f1b3 100644 (file)
@@ -18,8 +18,6 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -27,7 +25,6 @@
 #include <linux/regulator/consumer.h>
 
 #include <dt-bindings/input/ti-drv260x.h>
-#include <linux/platform_data/drv260x-pdata.h>
 
 #define DRV260X_STATUS         0x0
 #define DRV260X_MODE           0x1
@@ -468,90 +465,39 @@ static const struct regmap_config drv260x_regmap_config = {
        .cache_type = REGCACHE_NONE,
 };
 
-#ifdef CONFIG_OF
-static int drv260x_parse_dt(struct device *dev,
-                           struct drv260x_data *haptics)
-{
-       struct device_node *np = dev->of_node;
-       unsigned int voltage;
-       int error;
-
-       error = of_property_read_u32(np, "mode", &haptics->mode);
-       if (error) {
-               dev_err(dev, "%s: No entry for mode\n", __func__);
-               return error;
-       }
-
-       error = of_property_read_u32(np, "library-sel", &haptics->library);
-       if (error) {
-               dev_err(dev, "%s: No entry for library selection\n",
-                       __func__);
-               return error;
-       }
-
-       error = of_property_read_u32(np, "vib-rated-mv", &voltage);
-       if (!error)
-               haptics->rated_voltage = drv260x_calculate_voltage(voltage);
-
-
-       error = of_property_read_u32(np, "vib-overdrive-mv", &voltage);
-       if (!error)
-               haptics->overdrive_voltage = drv260x_calculate_voltage(voltage);
-
-       return 0;
-}
-#else
-static inline int drv260x_parse_dt(struct device *dev,
-                                  struct drv260x_data *haptics)
-{
-       dev_err(dev, "no platform data defined\n");
-
-       return -EINVAL;
-}
-#endif
-
 static int drv260x_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       const struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev);
+       struct device *dev = &client->dev;
        struct drv260x_data *haptics;
+       u32 voltage;
        int error;
 
-       haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
+       haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL);
        if (!haptics)
                return -ENOMEM;
 
-       haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
-       haptics->rated_voltage = DRV260X_DEF_RATED_VOLT;
-
-       if (pdata) {
-               haptics->mode = pdata->mode;
-               haptics->library = pdata->library_selection;
-               if (pdata->vib_overdrive_voltage)
-                       haptics->overdrive_voltage = drv260x_calculate_voltage(pdata->vib_overdrive_voltage);
-               if (pdata->vib_rated_voltage)
-                       haptics->rated_voltage = drv260x_calculate_voltage(pdata->vib_rated_voltage);
-       } else if (client->dev.of_node) {
-               error = drv260x_parse_dt(&client->dev, haptics);
-               if (error)
-                       return error;
-       } else {
-               dev_err(&client->dev, "Platform data not set\n");
-               return -ENODEV;
+       error = device_property_read_u32(dev, "mode", &haptics->mode);
+       if (error) {
+               dev_err(dev, "Can't fetch 'mode' property: %d\n", error);
+               return error;
        }
 
-
        if (haptics->mode < DRV260X_LRA_MODE ||
            haptics->mode > DRV260X_ERM_MODE) {
-               dev_err(&client->dev,
-                       "Vibrator mode is invalid: %i\n",
-                       haptics->mode);
+               dev_err(dev, "Vibrator mode is invalid: %i\n", haptics->mode);
                return -EINVAL;
        }
 
+       error = device_property_read_u32(dev, "library-sel", &haptics->library);
+       if (error) {
+               dev_err(dev, "Can't fetch 'library-sel' property: %d\n", error);
+               return error;
+       }
+
        if (haptics->library < DRV260X_LIB_EMPTY ||
            haptics->library > DRV260X_ERM_LIB_F) {
-               dev_err(&client->dev,
+               dev_err(dev,
                        "Library value is invalid: %i\n", haptics->library);
                return -EINVAL;
        }
@@ -559,40 +505,44 @@ static int drv260x_probe(struct i2c_client *client,
        if (haptics->mode == DRV260X_LRA_MODE &&
            haptics->library != DRV260X_LIB_EMPTY &&
            haptics->library != DRV260X_LIB_LRA) {
-               dev_err(&client->dev,
-                       "LRA Mode with ERM Library mismatch\n");
+               dev_err(dev, "LRA Mode with ERM Library mismatch\n");
                return -EINVAL;
        }
 
        if (haptics->mode == DRV260X_ERM_MODE &&
            (haptics->library == DRV260X_LIB_EMPTY ||
             haptics->library == DRV260X_LIB_LRA)) {
-               dev_err(&client->dev,
-                       "ERM Mode with LRA Library mismatch\n");
+               dev_err(dev, "ERM Mode with LRA Library mismatch\n");
                return -EINVAL;
        }
 
-       haptics->regulator = devm_regulator_get(&client->dev, "vbat");
+       error = device_property_read_u32(dev, "vib-rated-mv", &voltage);
+       haptics->rated_voltage = error ? DRV260X_DEF_RATED_VOLT :
+                                        drv260x_calculate_voltage(voltage);
+
+       error = device_property_read_u32(dev, "vib-overdrive-mv", &voltage);
+       haptics->overdrive_voltage = error ? DRV260X_DEF_OD_CLAMP_VOLT :
+                                            drv260x_calculate_voltage(voltage);
+
+       haptics->regulator = devm_regulator_get(dev, "vbat");
        if (IS_ERR(haptics->regulator)) {
                error = PTR_ERR(haptics->regulator);
-               dev_err(&client->dev,
-                       "unable to get regulator, error: %d\n", error);
+               dev_err(dev, "unable to get regulator, error: %d\n", error);
                return error;
        }
 
-       haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
+       haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable",
                                                       GPIOD_OUT_HIGH);
        if (IS_ERR(haptics->enable_gpio))
                return PTR_ERR(haptics->enable_gpio);
 
-       haptics->input_dev = devm_input_allocate_device(&client->dev);
+       haptics->input_dev = devm_input_allocate_device(dev);
        if (!haptics->input_dev) {
                dev_err(&client->dev, "Failed to allocate input device\n");
                return -ENOMEM;
        }
 
        haptics->input_dev->name = "drv260x:haptics";
-       haptics->input_dev->dev.parent = client->dev.parent;
        haptics->input_dev->close = drv260x_close;
        input_set_drvdata(haptics->input_dev, haptics);
        input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
@@ -600,8 +550,7 @@ static int drv260x_probe(struct i2c_client *client,
        error = input_ff_create_memless(haptics->input_dev, NULL,
                                        drv260x_haptics_play);
        if (error) {
-               dev_err(&client->dev, "input_ff_create() failed: %d\n",
-                       error);
+               dev_err(dev, "input_ff_create() failed: %d\n", error);
                return error;
        }
 
@@ -613,21 +562,19 @@ static int drv260x_probe(struct i2c_client *client,
        haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config);
        if (IS_ERR(haptics->regmap)) {
                error = PTR_ERR(haptics->regmap);
-               dev_err(&client->dev, "Failed to allocate register map: %d\n",
-                       error);
+               dev_err(dev, "Failed to allocate register map: %d\n", error);
                return error;
        }
 
        error = drv260x_init(haptics);
        if (error) {
-               dev_err(&client->dev, "Device init failed: %d\n", error);
+               dev_err(dev, "Device init failed: %d\n", error);
                return error;
        }
 
        error = input_register_device(haptics->input_dev);
        if (error) {
-               dev_err(&client->dev, "couldn't register input device: %d\n",
-                       error);
+               dev_err(dev, "couldn't register input device: %d\n", error);
                return error;
        }
 
index ef9bc12b3be3565d816c9890556dedd922c4ae95..dcb6d8e94b11215e07f4d5225b585e21ffd680f0 100644 (file)
@@ -125,8 +125,8 @@ static void drv2665_close(struct input_dev *input)
 
        cancel_work_sync(&haptics->work);
 
-       error = regmap_update_bits(haptics->regmap,
-                                  DRV2665_CTRL_2, DRV2665_STANDBY, 1);
+       error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+                                  DRV2665_STANDBY, DRV2665_STANDBY);
        if (error)
                dev_err(&haptics->client->dev,
                        "Failed to enter standby mode: %d\n", error);
@@ -240,7 +240,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev)
 
        if (haptics->input_dev->users) {
                ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
-                               DRV2665_STANDBY, 1);
+                                        DRV2665_STANDBY, DRV2665_STANDBY);
                if (ret) {
                        dev_err(dev, "Failed to set standby mode\n");
                        regulator_disable(haptics->regulator);
index d5ba7481328cf289fa8da9a326421ca1da0fa07c..2849bb6906a8f799dae30a022937a47740595a28 100644 (file)
@@ -256,7 +256,7 @@ static void drv2667_close(struct input_dev *input)
        cancel_work_sync(&haptics->work);
 
        error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
-                               DRV2667_STANDBY, 1);
+                                  DRV2667_STANDBY, DRV2667_STANDBY);
        if (error)
                dev_err(&haptics->client->dev,
                        "Failed to enter standby mode: %d\n", error);
@@ -415,7 +415,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev)
 
        if (haptics->input_dev->users) {
                ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
-                               DRV2667_STANDBY, 1);
+                                        DRV2667_STANDBY, DRV2667_STANDBY);
                if (ret) {
                        dev_err(dev, "Failed to set standby mode\n");
                        regulator_disable(haptics->regulator);
index c14b82709b0f09481c7fc6c8c52c0e384dd33da1..908b51089dee4b1cb128393cba441eecc477c994 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/acpi.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio_keys.h>
+#include <linux/gpio.h>
 #include <linux/platform_device.h>
 
 /*
@@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev,
                        continue;
 
                gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
-               if (gpio < 0)
+               if (!gpio_is_valid(gpio))
                        continue;
 
                gpio_keys[n_buttons].type = info->event_type;
@@ -166,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev)
 
        button_info = (struct soc_button_info *)id->driver_data;
 
+       if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
+               dev_dbg(&pdev->dev, "no GPIO attached, ignoring...\n");
+               return -ENODEV;
+       }
+
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
index 3273217ce80c8feecdf7d1b4d4c98c63264901b1..cc74a41bdb0d24d7e5eddd0f1e019ab01cea71c4 100644 (file)
@@ -150,12 +150,20 @@ static int tps6521x_pb_probe(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id tps6521x_pwrbtn_id_table[] = {
+       { "tps65218-pwrbutton", },
+       { "tps65217-pwrbutton", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps6521x_pwrbtn_id_table);
+
 static struct platform_driver tps6521x_pb_driver = {
        .probe  = tps6521x_pb_probe,
        .driver = {
                .name   = "tps6521x_pwrbutton",
                .of_match_table = of_tps6521x_pb_match,
        },
+       .id_table = tps6521x_pwrbtn_id_table,
 };
 module_platform_driver(tps6521x_pb_driver);
 
index 6d7de9bfed9a7f2bdf872474f156613740632539..328edc8c8786339d009abb99fe6e000d9edbb805 100644 (file)
@@ -1153,15 +1153,13 @@ static void alps_process_packet_v7(struct psmouse *psmouse)
                alps_process_touchpad_packet_v7(psmouse);
 }
 
-static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte)
+static enum SS4_PACKET_ID alps_get_pkt_id_ss4_v2(unsigned char *byte)
 {
-       unsigned char pkt_id = SS4_PACKET_ID_IDLE;
+       enum SS4_PACKET_ID pkt_id = SS4_PACKET_ID_IDLE;
 
        switch (byte[3] & 0x30) {
        case 0x00:
-               if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
-                   (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
-                   byte[5] == 0x00) {
+               if (SS4_IS_IDLE_V2(byte)) {
                        pkt_id = SS4_PACKET_ID_IDLE;
                } else {
                        pkt_id = SS4_PACKET_ID_ONE;
@@ -1188,7 +1186,7 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
                              unsigned char *p, struct psmouse *psmouse)
 {
        struct alps_data *priv = psmouse->private;
-       unsigned char pkt_id;
+       enum SS4_PACKET_ID pkt_id;
        unsigned int no_data_x, no_data_y;
 
        pkt_id = alps_get_pkt_id_ss4_v2(p);
@@ -1267,18 +1265,12 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
                break;
 
        case SS4_PACKET_ID_STICK:
-               if (!(priv->flags & ALPS_DUALPOINT)) {
-                       psmouse_warn(psmouse,
-                                    "Rejected trackstick packet from non DualPoint device");
-               } else {
-                       int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f));
-                       int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f));
-                       int pressure = (s8)(p[4] & 0x7f);
-
-                       input_report_rel(priv->dev2, REL_X, x);
-                       input_report_rel(priv->dev2, REL_Y, -y);
-                       input_report_abs(priv->dev2, ABS_PRESSURE, pressure);
-               }
+               /*
+                * x, y, and pressure are decoded in
+                * alps_process_packet_ss4_v2()
+                */
+               f->first_mp = 0;
+               f->is_mp = 0;
                break;
 
        case SS4_PACKET_ID_IDLE:
@@ -1346,6 +1338,27 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
 
        priv->multi_packet = 0;
 
+       /* Report trackstick */
+       if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) {
+               if (!(priv->flags & ALPS_DUALPOINT)) {
+                       psmouse_warn(psmouse,
+                                    "Rejected trackstick packet from non DualPoint device");
+                       return;
+               }
+
+               input_report_rel(dev2, REL_X, SS4_TS_X_V2(packet));
+               input_report_rel(dev2, REL_Y, SS4_TS_Y_V2(packet));
+               input_report_abs(dev2, ABS_PRESSURE, SS4_TS_Z_V2(packet));
+
+               input_report_key(dev2, BTN_LEFT, f->ts_left);
+               input_report_key(dev2, BTN_RIGHT, f->ts_right);
+               input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
+
+               input_sync(dev2);
+               return;
+       }
+
+       /* Report touchpad */
        alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4);
 
        input_mt_report_finger_count(dev, f->fingers);
@@ -1356,13 +1369,6 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
 
        input_report_abs(dev, ABS_PRESSURE, f->pressure);
        input_sync(dev);
-
-       if (priv->flags & ALPS_DUALPOINT) {
-               input_report_key(dev2, BTN_LEFT, f->ts_left);
-               input_report_key(dev2, BTN_RIGHT, f->ts_right);
-               input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
-               input_sync(dev2);
-       }
 }
 
 static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
index b9417e2d7ad3a7ba01aff4d7c5504a619090b0b5..cde6f4bd8ea2e3f0f70fbccf3f684e5cd079ec04 100644 (file)
@@ -54,7 +54,15 @@ enum SS4_PACKET_ID {
 
 #define SS4_MASK_NORMAL_BUTTONS                0x07
 
-#define SS4_1F_X_V2(_b)                ((_b[0] & 0x0007) |             \
+#define SS4_IS_IDLE_V2(_b)     (((_b[0]) == 0x18) &&           \
+                                ((_b[1]) == 0x10) &&           \
+                                ((_b[2]) == 0x00) &&           \
+                                ((_b[3] & 0x88) == 0x08) &&    \
+                                ((_b[4]) == 0x10) &&           \
+                                ((_b[5]) == 0x00)              \
+                               )
+
+#define SS4_1F_X_V2(_b)                (((_b[0]) & 0x0007) |           \
                                 ((_b[1] << 3) & 0x0078) |      \
                                 ((_b[1] << 2) & 0x0380) |      \
                                 ((_b[2] << 5) & 0x1C00)        \
@@ -101,6 +109,18 @@ enum SS4_PACKET_ID {
 #define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10)
 #define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10)
 
+#define SS4_TS_X_V2(_b)                (s8)(                           \
+                                ((_b[0] & 0x01) << 7) |        \
+                                (_b[1] & 0x7F)         \
+                               )
+
+#define SS4_TS_Y_V2(_b)                (s8)(                           \
+                                ((_b[3] & 0x01) << 7) |        \
+                                (_b[2] & 0x7F)         \
+                               )
+
+#define SS4_TS_Z_V2(_b)                (s8)(_b[4] & 0x7F)
+
 
 #define SS4_MFPACKET_NO_AX     8160    /* X-Coordinate value */
 #define SS4_MFPACKET_NO_AY     4080    /* Y-Coordinate value */
@@ -146,7 +166,7 @@ struct alps_protocol_info {
  *   (aka command mode response) identifies the firmware minor version.  This
  *   can be used to distinguish different hardware models which are not
  *   uniquely identifiable through their E7 responses.
- * @protocol_info: information about protcol used by the device.
+ * @protocol_info: information about protocol used by the device.
  *
  * Many (but not all) ALPS touchpads can be identified by looking at the
  * values returned in the "E7 report" and/or the "EC report."  This table
index d15b338130213c53489baa600d6dcea1500790d4..fa598f7f4372c1ed0167b941a57a4b663a5361de 100644 (file)
@@ -1093,19 +1093,18 @@ static int elan_probe(struct i2c_client *client,
        if (error)
                return error;
 
+       dev_info(&client->dev,
+                "Elan Touchpad: Module ID: 0x%04x, Firmware: 0x%04x, Sample: 0x%04x, IAP: 0x%04x\n",
+                data->product_id,
+                data->fw_version,
+                data->sm_version,
+                data->iap_version);
+
        dev_dbg(&client->dev,
-               "Elan Touchpad Information:\n"
-               "    Module product ID:  0x%04x\n"
-               "    Firmware Version:  0x%04x\n"
-               "    Sample Version:  0x%04x\n"
-               "    IAP Version:  0x%04x\n"
+               "Elan Touchpad Extra Information:\n"
                "    Max ABS X,Y:   %d,%d\n"
                "    Width X,Y:   %d,%d\n"
                "    Resolution X,Y:   %d,%d (dots/mm)\n",
-               data->product_id,
-               data->fw_version,
-               data->sm_version,
-               data->iap_version,
                data->max_x, data->max_y,
                data->width_x, data->width_y,
                data->x_res, data->y_res);
index 4c8a55857e004aadb1ccfdf43165862c3e5286d5..30cc627a4f4531ff93014ea94bf9835b0b37e8bc 100644 (file)
@@ -27,6 +27,27 @@ config RMI4_SPI
 
          If unsure, say N.
 
+config RMI4_SMB
+       tristate "RMI4 SMB Support"
+       depends on RMI4_CORE && I2C
+       help
+         Say Y here if you want to support RMI4 devices connected to an SMB
+         bus.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the module will be
+         called rmi_smbus.
+
+config RMI4_F03
+        bool "RMI4 Function 03 (PS2 Guest)"
+        depends on RMI4_CORE && SERIO
+        help
+          Say Y here if you want to add support for RMI4 function 03.
+
+          Function 03 provides PS2 guest support for RMI4 devices. This
+          includes support for TrackPoints on TouchPads.
+
 config RMI4_2D_SENSOR
        bool
        depends on RMI4_CORE
@@ -62,13 +83,34 @@ config RMI4_F30
          Function 30 provides GPIO and LED support for RMI4 devices. This
          includes support for buttons on TouchPads and ClickPads.
 
+config RMI4_F34
+       bool "RMI4 Function 34 (Device reflash)"
+       depends on RMI4_CORE
+       select FW_LOADER
+       help
+         Say Y here if you want to add support for RMI4 function 34.
+
+         Function 34 provides support for upgrading the firmware on the RMI4
+         device via the firmware loader interface. This is triggered using a
+         sysfs attribute.
+
 config RMI4_F54
        bool "RMI4 Function 54 (Analog diagnostics)"
        depends on RMI4_CORE
        depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
        select VIDEOBUF2_VMALLOC
+       select RMI4_F55
        help
          Say Y here if you want to add support for RMI4 function 54
 
          Function 54 provides access to various diagnostic features in certain
          RMI4 touch sensors.
+
+config RMI4_F55
+       bool "RMI4 Function 55 (Sensor tuning)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 55
+
+         Function 55 provides access to the RMI4 touch sensor tuning
+         mechanism.
index 0bafc8502c4b98b5e8a5629470592b7b7400b6f0..9aaac3dd8613d66176c7ca7c01873184bd9013b5 100644 (file)
@@ -4,11 +4,15 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
 rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
 
 # Function drivers
+rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
 rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
 rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
 rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
+rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
 rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
+rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
 
 # Transports
 obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
 obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
+obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
index e97bd7fabccc5ec3b483070b3d58a55cca12b1f2..07007ff8e29fff7bf0d245a0174b17e8fcbccf29 100644 (file)
@@ -177,10 +177,12 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
                                sensor->dmax = DMAX * res_x;
                }
 
-               input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
-               input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
-               input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
-               input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+               input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
+               input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
+               input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
+               input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+               input_set_abs_params(input, ABS_MT_TOOL_TYPE,
+                                    0, MT_TOOL_MAX, 0, 0);
 
                if (sensor->sensor_type == rmi_sensor_touchpad)
                        input_flags = INPUT_MT_POINTER;
index 77fcdfef003c6f96f19a796ffa410ba9b2026f82..c871bef4dac098f3af9c57bdd132a99e0758a72b 100644 (file)
@@ -67,6 +67,8 @@ struct rmi_2d_sensor {
        u8 report_rel;
        u8 x_mm;
        u8 y_mm;
+       enum rmi_reg_state dribble;
+       enum rmi_reg_state palm_detect;
 };
 
 int rmi_2d_sensor_of_probe(struct device *dev,
index ef8c747c35e76f0c77eaf86300f724e30cf6e0ff..1c40d94ca506cceb776798cb8db1444e36824ffc 100644 (file)
@@ -230,6 +230,9 @@ err_put_device:
 
 void rmi_unregister_function(struct rmi_function *fn)
 {
+       rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n",
+                       fn->fd.function_number);
+
        device_del(&fn->dev);
        of_node_put(fn->dev.of_node);
        put_device(&fn->dev);
@@ -302,6 +305,9 @@ struct bus_type rmi_bus_type = {
 
 static struct rmi_function_handler *fn_handlers[] = {
        &rmi_f01_handler,
+#ifdef CONFIG_RMI4_F03
+       &rmi_f03_handler,
+#endif
 #ifdef CONFIG_RMI4_F11
        &rmi_f11_handler,
 #endif
@@ -311,9 +317,15 @@ static struct rmi_function_handler *fn_handlers[] = {
 #ifdef CONFIG_RMI4_F30
        &rmi_f30_handler,
 #endif
+#ifdef CONFIG_RMI4_F34
+       &rmi_f34_handler,
+#endif
 #ifdef CONFIG_RMI4_F54
        &rmi_f54_handler,
 #endif
+#ifdef CONFIG_RMI4_F55
+       &rmi_f55_handler,
+#endif
 };
 
 static void __rmi_unregister_function_handlers(int start_idx)
index 899579830536f2245316203e2662f2211697c553..b7625a9ac66ab5384727cc83496223be3aedbe92 100644 (file)
@@ -104,6 +104,18 @@ rmi_get_platform_data(struct rmi_device *d)
 
 bool rmi_is_physical_device(struct device *dev);
 
+/**
+ * rmi_reset - reset a RMI4 device
+ * @d: Pointer to an RMI device
+ *
+ * Calls for a reset of each function implemented by a specific device.
+ * Returns 0 on success or a negative error code.
+ */
+static inline int rmi_reset(struct rmi_device *d)
+{
+       return d->driver->reset_handler(d);
+}
+
 /**
  * rmi_read - read a single byte
  * @d: Pointer to an RMI device
index 4a88312fbd25405051f9ef422b4a71d95059c7a2..11447ab1055cd4beadf7eca752bdf9494d76cef1 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/bitmap.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
+#include <linux/irq.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/of.h>
 #define RMI_DEVICE_RESET_CMD   0x01
 #define DEFAULT_RESET_DELAY_MS 100
 
-static void rmi_free_function_list(struct rmi_device *rmi_dev)
+void rmi_free_function_list(struct rmi_device *rmi_dev)
 {
        struct rmi_function *fn, *tmp;
        struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
 
+       rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n");
+
+       devm_kfree(&rmi_dev->dev, data->irq_memory);
+       data->irq_memory = NULL;
+       data->irq_status = NULL;
+       data->fn_irq_bits = NULL;
+       data->current_irq_mask = NULL;
+       data->new_irq_mask = NULL;
+
        data->f01_container = NULL;
+       data->f34_container = NULL;
 
        /* Doing it in the reverse order so F01 will be removed last */
        list_for_each_entry_safe_reverse(fn, tmp,
@@ -133,7 +144,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
        }
 }
 
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
+static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
 {
        struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
        struct device *dev = &rmi_dev->dev;
@@ -143,7 +154,7 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
        if (!data)
                return 0;
 
-       if (!rmi_dev->xport->attn_data) {
+       if (!data->attn_data.data) {
                error = rmi_read_block(rmi_dev,
                                data->f01_container->fd.data_base_addr + 1,
                                data->irq_status, data->num_of_irq_regs);
@@ -178,7 +189,81 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests);
+
+void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
+                      void *data, size_t size)
+{
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi4_attn_data attn_data;
+       void *fifo_data;
+
+       if (!drvdata->enabled)
+               return;
+
+       fifo_data = kmemdup(data, size, GFP_ATOMIC);
+       if (!fifo_data)
+               return;
+
+       attn_data.irq_status = irq_status;
+       attn_data.size = size;
+       attn_data.data = fifo_data;
+
+       kfifo_put(&drvdata->attn_fifo, attn_data);
+}
+EXPORT_SYMBOL_GPL(rmi_set_attn_data);
+
+static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
+{
+       struct rmi_device *rmi_dev = dev_id;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi4_attn_data attn_data = {0};
+       int ret, count;
+
+       count = kfifo_get(&drvdata->attn_fifo, &attn_data);
+       if (count) {
+               *(drvdata->irq_status) = attn_data.irq_status;
+               drvdata->attn_data = attn_data;
+       }
+
+       ret = rmi_process_interrupt_requests(rmi_dev);
+       if (ret)
+               rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
+                       "Failed to process interrupt request: %d\n", ret);
+
+       if (count)
+               kfree(attn_data.data);
+
+       if (!kfifo_is_empty(&drvdata->attn_fifo))
+               return rmi_irq_fn(irq, dev_id);
+
+       return IRQ_HANDLED;
+}
+
+static int rmi_irq_init(struct rmi_device *rmi_dev)
+{
+       struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       int irq_flags = irq_get_trigger_type(pdata->irq);
+       int ret;
+
+       if (!irq_flags)
+               irq_flags = IRQF_TRIGGER_LOW;
+
+       ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL,
+                                       rmi_irq_fn, irq_flags | IRQF_ONESHOT,
+                                       dev_name(rmi_dev->xport->dev),
+                                       rmi_dev);
+       if (ret < 0) {
+               dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n",
+                       pdata->irq);
+
+               return ret;
+       }
+
+       data->enabled = true;
+
+       return 0;
+}
 
 static int suspend_one_function(struct rmi_function *fn)
 {
@@ -248,7 +333,7 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev)
        return 0;
 }
 
-static int enable_sensor(struct rmi_device *rmi_dev)
+int rmi_enable_sensor(struct rmi_device *rmi_dev)
 {
        int retval = 0;
 
@@ -379,8 +464,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
        return 0;
 }
 
-int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
-                       u16 pdt_address)
+static int rmi_read_pdt_entry(struct rmi_device *rmi_dev,
+                             struct pdt_entry *entry, u16 pdt_address)
 {
        u8 buf[RMI_PDT_ENTRY_SIZE];
        int error;
@@ -403,7 +488,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rmi_read_pdt_entry);
 
 static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
                                      struct rmi_function_descriptor *fd)
@@ -422,6 +506,7 @@ static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
 
 static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
                             int page,
+                            int *empty_pages,
                             void *ctx,
                             int (*callback)(struct rmi_device *rmi_dev,
                                             void *ctx,
@@ -449,20 +534,30 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
                        return retval;
        }
 
-       return (data->f01_bootloader_mode || addr == pdt_start) ?
+       /*
+        * Count number of empty PDT pages. If a gap of two pages
+        * or more is found, stop scanning.
+        */
+       if (addr == pdt_start)
+               ++*empty_pages;
+       else
+               *empty_pages = 0;
+
+       return (data->bootloader_mode || *empty_pages >= 2) ?
                                        RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
 }
 
-static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
-                       int (*callback)(struct rmi_device *rmi_dev,
-                                       void *ctx,
-                                       const struct pdt_entry *entry))
+int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+                int (*callback)(struct rmi_device *rmi_dev,
+                void *ctx, const struct pdt_entry *entry))
 {
        int page;
+       int empty_pages = 0;
        int retval = RMI_SCAN_DONE;
 
        for (page = 0; page <= RMI4_MAX_PAGE; page++) {
-               retval = rmi_scan_pdt_page(rmi_dev, page, ctx, callback);
+               retval = rmi_scan_pdt_page(rmi_dev, page, &empty_pages,
+                                          ctx, callback);
                if (retval != RMI_SCAN_CONTINUE)
                        break;
        }
@@ -600,7 +695,6 @@ free_struct_buff:
        kfree(struct_buf);
        return ret;
 }
-EXPORT_SYMBOL_GPL(rmi_read_register_desc);
 
 const struct rmi_register_desc_item *rmi_get_register_desc_item(
                                struct rmi_register_descriptor *rdesc, u16 reg)
@@ -616,7 +710,6 @@ const struct rmi_register_desc_item *rmi_get_register_desc_item(
 
        return NULL;
 }
-EXPORT_SYMBOL_GPL(rmi_get_register_desc_item);
 
 size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
 {
@@ -630,7 +723,6 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
        }
        return size;
 }
-EXPORT_SYMBOL_GPL(rmi_register_desc_calc_size);
 
 /* Compute the register offset relative to the base address */
 int rmi_register_desc_calc_reg_offset(
@@ -648,7 +740,6 @@ int rmi_register_desc_calc_reg_offset(
        }
        return -1;
 }
-EXPORT_SYMBOL_GPL(rmi_register_desc_calc_reg_offset);
 
 bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
        u8 subpacket)
@@ -657,51 +748,55 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
                                subpacket) == subpacket;
 }
 
-/* Indicates that flash programming is enabled (bootloader mode). */
-#define RMI_F01_STATUS_BOOTLOADER(status)      (!!((status) & 0x40))
-
-/*
- * Given the PDT entry for F01, read the device status register to determine
- * if we're stuck in bootloader mode or not.
- *
- */
 static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,
                                     const struct pdt_entry *pdt)
 {
-       int error;
-       u8 device_status;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       int ret;
+       u8 status;
 
-       error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start,
-                        &device_status);
-       if (error) {
-               dev_err(&rmi_dev->dev,
-                       "Failed to read device status: %d.\n", error);
-               return error;
+       if (pdt->function_number == 0x34 && pdt->function_version > 1) {
+               ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
+               if (ret) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F34 status: %d.\n", ret);
+                       return ret;
+               }
+
+               if (status & BIT(7))
+                       data->bootloader_mode = true;
+       } else if (pdt->function_number == 0x01) {
+               ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
+               if (ret) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F01 status: %d.\n", ret);
+                       return ret;
+               }
+
+               if (status & BIT(6))
+                       data->bootloader_mode = true;
        }
 
-       return RMI_F01_STATUS_BOOTLOADER(device_status);
+       return 0;
 }
 
 static int rmi_count_irqs(struct rmi_device *rmi_dev,
                         void *ctx, const struct pdt_entry *pdt)
 {
-       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
        int *irq_count = ctx;
+       int ret;
 
        *irq_count += pdt->interrupt_source_count;
-       if (pdt->function_number == 0x01) {
-               data->f01_bootloader_mode =
-                       rmi_check_bootloader_mode(rmi_dev, pdt);
-               if (data->f01_bootloader_mode)
-                       dev_warn(&rmi_dev->dev,
-                               "WARNING: RMI4 device is in bootloader mode!\n");
-       }
+
+       ret = rmi_check_bootloader_mode(rmi_dev, pdt);
+       if (ret < 0)
+               return ret;
 
        return RMI_SCAN_CONTINUE;
 }
 
-static int rmi_initial_reset(struct rmi_device *rmi_dev,
-                            void *ctx, const struct pdt_entry *pdt)
+int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
+                     const struct pdt_entry *pdt)
 {
        int error;
 
@@ -720,6 +815,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
                        return RMI_SCAN_DONE;
                }
 
+               rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Sending reset\n");
                error = rmi_write_block(rmi_dev, cmd_addr, &cmd_buf, 1);
                if (error) {
                        dev_err(&rmi_dev->dev,
@@ -776,6 +872,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
 
        if (pdt->function_number == 0x01)
                data->f01_container = fn;
+       else if (pdt->function_number == 0x34)
+               data->f34_container = fn;
 
        list_add_tail(&fn->node, &data->function_list);
 
@@ -786,23 +884,95 @@ err_put_fn:
        return error;
 }
 
-int rmi_driver_suspend(struct rmi_device *rmi_dev)
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake)
 {
-       int retval = 0;
+       struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       int irq = pdata->irq;
+       int irq_flags;
+       int retval;
+
+       mutex_lock(&data->enabled_mutex);
+
+       if (data->enabled)
+               goto out;
+
+       enable_irq(irq);
+       data->enabled = true;
+       if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+               retval = disable_irq_wake(irq);
+               if (!retval)
+                       dev_warn(&rmi_dev->dev,
+                                "Failed to disable irq for wake: %d\n",
+                                retval);
+       }
+
+       /*
+        * Call rmi_process_interrupt_requests() after enabling irq,
+        * otherwise we may lose interrupt on edge-triggered systems.
+        */
+       irq_flags = irq_get_trigger_type(pdata->irq);
+       if (irq_flags & IRQ_TYPE_EDGE_BOTH)
+               rmi_process_interrupt_requests(rmi_dev);
+
+out:
+       mutex_unlock(&data->enabled_mutex);
+}
+
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
+{
+       struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi4_attn_data attn_data = {0};
+       int irq = pdata->irq;
+       int retval, count;
+
+       mutex_lock(&data->enabled_mutex);
+
+       if (!data->enabled)
+               goto out;
+
+       data->enabled = false;
+       disable_irq(irq);
+       if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+               retval = enable_irq_wake(irq);
+               if (!retval)
+                       dev_warn(&rmi_dev->dev,
+                                "Failed to enable irq for wake: %d\n",
+                                retval);
+       }
+
+       /* make sure the fifo is clean */
+       while (!kfifo_is_empty(&data->attn_fifo)) {
+               count = kfifo_get(&data->attn_fifo, &attn_data);
+               if (count)
+                       kfree(attn_data.data);
+       }
+
+out:
+       mutex_unlock(&data->enabled_mutex);
+}
+
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
+{
+       int retval;
 
        retval = rmi_suspend_functions(rmi_dev);
        if (retval)
                dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
                        retval);
 
+       rmi_disable_irq(rmi_dev, enable_wake);
        return retval;
 }
 EXPORT_SYMBOL_GPL(rmi_driver_suspend);
 
-int rmi_driver_resume(struct rmi_device *rmi_dev)
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake)
 {
        int retval;
 
+       rmi_enable_irq(rmi_dev, clear_wake);
+
        retval = rmi_resume_functions(rmi_dev);
        if (retval)
                dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
@@ -816,6 +986,9 @@ static int rmi_driver_remove(struct device *dev)
 {
        struct rmi_device *rmi_dev = to_rmi_device(dev);
 
+       rmi_disable_irq(rmi_dev, false);
+
+       rmi_f34_remove_sysfs(rmi_dev);
        rmi_free_function_list(rmi_dev);
 
        return 0;
@@ -842,15 +1015,95 @@ static inline int rmi_driver_of_probe(struct device *dev,
 }
 #endif
 
+int rmi_probe_interrupts(struct rmi_driver_data *data)
+{
+       struct rmi_device *rmi_dev = data->rmi_dev;
+       struct device *dev = &rmi_dev->dev;
+       int irq_count;
+       size_t size;
+       int retval;
+
+       /*
+        * We need to count the IRQs and allocate their storage before scanning
+        * the PDT and creating the function entries, because adding a new
+        * function can trigger events that result in the IRQ related storage
+        * being accessed.
+        */
+       rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
+       irq_count = 0;
+       data->bootloader_mode = false;
+
+       retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
+       if (retval < 0) {
+               dev_err(dev, "IRQ counting failed with code %d.\n", retval);
+               return retval;
+       }
+
+       if (data->bootloader_mode)
+               dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n");
+
+       data->irq_count = irq_count;
+       data->num_of_irq_regs = (data->irq_count + 7) / 8;
+
+       size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
+       data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
+       if (!data->irq_memory) {
+               dev_err(dev, "Failed to allocate memory for irq masks.\n");
+               return retval;
+       }
+
+       data->irq_status        = data->irq_memory + size * 0;
+       data->fn_irq_bits       = data->irq_memory + size * 1;
+       data->current_irq_mask  = data->irq_memory + size * 2;
+       data->new_irq_mask      = data->irq_memory + size * 3;
+
+       return retval;
+}
+
+int rmi_init_functions(struct rmi_driver_data *data)
+{
+       struct rmi_device *rmi_dev = data->rmi_dev;
+       struct device *dev = &rmi_dev->dev;
+       int irq_count;
+       int retval;
+
+       irq_count = 0;
+       rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__);
+       retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
+       if (retval < 0) {
+               dev_err(dev, "Function creation failed with code %d.\n",
+                       retval);
+               goto err_destroy_functions;
+       }
+
+       if (!data->f01_container) {
+               dev_err(dev, "Missing F01 container!\n");
+               retval = -EINVAL;
+               goto err_destroy_functions;
+       }
+
+       retval = rmi_read_block(rmi_dev,
+                               data->f01_container->fd.control_base_addr + 1,
+                               data->current_irq_mask, data->num_of_irq_regs);
+       if (retval < 0) {
+               dev_err(dev, "%s: Failed to read current IRQ mask.\n",
+                       __func__);
+               goto err_destroy_functions;
+       }
+
+       return 0;
+
+err_destroy_functions:
+       rmi_free_function_list(rmi_dev);
+       return retval;
+}
+
 static int rmi_driver_probe(struct device *dev)
 {
        struct rmi_driver *rmi_driver;
        struct rmi_driver_data *data;
        struct rmi_device_platform_data *pdata;
        struct rmi_device *rmi_dev;
-       size_t size;
-       void *irq_memory;
-       int irq_count;
        int retval;
 
        rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n",
@@ -916,35 +1169,12 @@ static int rmi_driver_probe(struct device *dev)
                         PDT_PROPERTIES_LOCATION, retval);
        }
 
-       /*
-        * We need to count the IRQs and allocate their storage before scanning
-        * the PDT and creating the function entries, because adding a new
-        * function can trigger events that result in the IRQ related storage
-        * being accessed.
-        */
-       rmi_dbg(RMI_DEBUG_CORE, dev, "Counting IRQs.\n");
-       irq_count = 0;
-       retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
-       if (retval < 0) {
-               dev_err(dev, "IRQ counting failed with code %d.\n", retval);
-               goto err;
-       }
-       data->irq_count = irq_count;
-       data->num_of_irq_regs = (data->irq_count + 7) / 8;
-
        mutex_init(&data->irq_mutex);
+       mutex_init(&data->enabled_mutex);
 
-       size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
-       irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
-       if (!irq_memory) {
-               dev_err(dev, "Failed to allocate memory for irq masks.\n");
+       retval = rmi_probe_interrupts(data);
+       if (retval)
                goto err;
-       }
-
-       data->irq_status        = irq_memory + size * 0;
-       data->fn_irq_bits       = irq_memory + size * 1;
-       data->current_irq_mask  = irq_memory + size * 2;
-       data->new_irq_mask      = irq_memory + size * 3;
 
        if (rmi_dev->xport->input) {
                /*
@@ -961,36 +1191,20 @@ static int rmi_driver_probe(struct device *dev)
                        dev_err(dev, "%s: Failed to allocate input device.\n",
                                __func__);
                        retval = -ENOMEM;
-                       goto err_destroy_functions;
+                       goto err;
                }
                rmi_driver_set_input_params(rmi_dev, data->input);
                data->input->phys = devm_kasprintf(dev, GFP_KERNEL,
                                                "%s/input0", dev_name(dev));
        }
 
-       irq_count = 0;
-       rmi_dbg(RMI_DEBUG_CORE, dev, "Creating functions.");
-       retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
-       if (retval < 0) {
-               dev_err(dev, "Function creation failed with code %d.\n",
-                       retval);
-               goto err_destroy_functions;
-       }
-
-       if (!data->f01_container) {
-               dev_err(dev, "Missing F01 container!\n");
-               retval = -EINVAL;
-               goto err_destroy_functions;
-       }
+       retval = rmi_init_functions(data);
+       if (retval)
+               goto err;
 
-       retval = rmi_read_block(rmi_dev,
-                               data->f01_container->fd.control_base_addr + 1,
-                               data->current_irq_mask, data->num_of_irq_regs);
-       if (retval < 0) {
-               dev_err(dev, "%s: Failed to read current IRQ mask.\n",
-                       __func__);
-               goto err_destroy_functions;
-       }
+       retval = rmi_f34_create_sysfs(rmi_dev);
+       if (retval)
+               goto err;
 
        if (data->input) {
                rmi_driver_set_input_name(rmi_dev, data->input);
@@ -1003,9 +1217,13 @@ static int rmi_driver_probe(struct device *dev)
                }
        }
 
+       retval = rmi_irq_init(rmi_dev);
+       if (retval < 0)
+               goto err_destroy_functions;
+
        if (data->f01_container->dev.driver)
                /* Driver already bound, so enable ATTN now. */
-               return enable_sensor(rmi_dev);
+               return rmi_enable_sensor(rmi_dev);
 
        return 0;
 
index 8dfbebe9bf86ae96d07a922e28bccfa0b66ebe75..24f8f764d171cafb18fbc878b707006ecdfcc658 100644 (file)
@@ -51,9 +51,6 @@ struct pdt_entry {
        u8 function_number;
 };
 
-int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
-                       u16 pdt_address);
-
 #define RMI_REG_DESC_PRESENSE_BITS     (32 * BITS_PER_BYTE)
 #define RMI_REG_DESC_SUBPACKET_BITS    (37 * BITS_PER_BYTE)
 
@@ -95,12 +92,40 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
 bool rmi_is_physical_driver(struct device_driver *);
 int rmi_register_physical_driver(void);
 void rmi_unregister_physical_driver(void);
+void rmi_free_function_list(struct rmi_device *rmi_dev);
+int rmi_enable_sensor(struct rmi_device *rmi_dev);
+int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+                int (*callback)(struct rmi_device *rmi_dev, void *ctx,
+                const struct pdt_entry *entry));
+int rmi_probe_interrupts(struct rmi_driver_data *data);
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake);
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake);
+int rmi_init_functions(struct rmi_driver_data *data);
+int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
+                     const struct pdt_entry *pdt);
 
 char *rmi_f01_get_product_ID(struct rmi_function *fn);
 
+#ifdef CONFIG_RMI4_F34
+int rmi_f34_create_sysfs(struct rmi_device *rmi_dev);
+void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev);
+#else
+static inline int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
+{
+       return 0;
+}
+
+static inline void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
+{
+}
+#endif /* CONFIG_RMI_F34 */
+
 extern struct rmi_function_handler rmi_f01_handler;
+extern struct rmi_function_handler rmi_f03_handler;
 extern struct rmi_function_handler rmi_f11_handler;
 extern struct rmi_function_handler rmi_f12_handler;
 extern struct rmi_function_handler rmi_f30_handler;
+extern struct rmi_function_handler rmi_f34_handler;
 extern struct rmi_function_handler rmi_f54_handler;
+extern struct rmi_function_handler rmi_f55_handler;
 #endif
index b5d2dfc23bad9fc7d5a626762518817713adbefa..18baf4ceb9407e6cad636ec9d41f638b9aba2131 100644 (file)
@@ -62,6 +62,8 @@ struct f01_basic_properties {
 #define RMI_F01_STATUS_CODE(status)            ((status) & 0x0f)
 /* The device has lost its configuration for some reason. */
 #define RMI_F01_STATUS_UNCONFIGURED(status)    (!!((status) & 0x80))
+/* The device is in bootloader mode */
+#define RMI_F01_STATUS_BOOTLOADER(status)      ((status) & 0x40)
 
 /* Control register bits */
 
@@ -326,12 +328,12 @@ static int rmi_f01_probe(struct rmi_function *fn)
        }
 
        switch (pdata->power_management.nosleep) {
-       case RMI_F01_NOSLEEP_DEFAULT:
+       case RMI_REG_STATE_DEFAULT:
                break;
-       case RMI_F01_NOSLEEP_OFF:
+       case RMI_REG_STATE_OFF:
                f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
                break;
-       case RMI_F01_NOSLEEP_ON:
+       case RMI_REG_STATE_ON:
                f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
                break;
        }
@@ -593,6 +595,10 @@ static int rmi_f01_attention(struct rmi_function *fn,
                return error;
        }
 
+       if (RMI_F01_STATUS_BOOTLOADER(device_status))
+               dev_warn(&fn->dev,
+                        "Device in bootloader mode, please update firmware\n");
+
        if (RMI_F01_STATUS_UNCONFIGURED(device_status)) {
                dev_warn(&fn->dev, "Device reset detected.\n");
                error = rmi_dev->driver->reset_handler(rmi_dev);
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
new file mode 100644 (file)
index 0000000..8a7ca3e
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat
+ * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/serio.h>
+#include <linux/notifier.h>
+#include "rmi_driver.h"
+
+#define RMI_F03_RX_DATA_OFB            0x01
+#define RMI_F03_OB_SIZE                        2
+
+#define RMI_F03_OB_OFFSET              2
+#define RMI_F03_OB_DATA_OFFSET         1
+#define RMI_F03_OB_FLAG_TIMEOUT                BIT(6)
+#define RMI_F03_OB_FLAG_PARITY         BIT(7)
+
+#define RMI_F03_DEVICE_COUNT           0x07
+#define RMI_F03_BYTES_PER_DEVICE       0x07
+#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4
+#define RMI_F03_QUEUE_LENGTH           0x0F
+
+struct f03_data {
+       struct rmi_function *fn;
+
+       struct serio *serio;
+
+       u8 device_count;
+       u8 rx_queue_length;
+};
+
+static int rmi_f03_pt_write(struct serio *id, unsigned char val)
+{
+       struct f03_data *f03 = id->port_data;
+       int error;
+
+       rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev,
+               "%s: Wrote %.2hhx to PS/2 passthrough address",
+               __func__, val);
+
+       error = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val);
+       if (error) {
+               dev_err(&f03->fn->dev,
+                       "%s: Failed to write to F03 TX register (%d).\n",
+                       __func__, error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int rmi_f03_initialize(struct f03_data *f03)
+{
+       struct rmi_function *fn = f03->fn;
+       struct device *dev = &fn->dev;
+       int error;
+       u8 bytes_per_device;
+       u8 query1;
+       u8 query2[RMI_F03_DEVICE_COUNT * RMI_F03_BYTES_PER_DEVICE];
+       size_t query2_len;
+
+       error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1);
+       if (error) {
+               dev_err(dev, "Failed to read query register (%d).\n", error);
+               return error;
+       }
+
+       f03->device_count = query1 & RMI_F03_DEVICE_COUNT;
+       bytes_per_device = (query1 >> RMI_F03_BYTES_PER_DEVICE_SHIFT) &
+                               RMI_F03_BYTES_PER_DEVICE;
+
+       query2_len = f03->device_count * bytes_per_device;
+
+       /*
+        * The first generation of image sensors don't have a second part to
+        * their f03 query, as such we have to set some of these values manually
+        */
+       if (query2_len < 1) {
+               f03->device_count = 1;
+               f03->rx_queue_length = 7;
+       } else {
+               error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
+                                      query2, query2_len);
+               if (error) {
+                       dev_err(dev,
+                               "Failed to read second set of query registers (%d).\n",
+                               error);
+                       return error;
+               }
+
+               f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH;
+       }
+
+       return 0;
+}
+
+static int rmi_f03_register_pt(struct f03_data *f03)
+{
+       struct serio *serio;
+
+       serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+       if (!serio)
+               return -ENOMEM;
+
+       serio->id.type = SERIO_8042;
+       serio->write = rmi_f03_pt_write;
+       serio->port_data = f03;
+
+       strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
+               sizeof(serio->name));
+       strlcpy(serio->phys, "synaptics-rmi4-pt/serio1",
+               sizeof(serio->phys));
+       serio->dev.parent = &f03->fn->dev;
+
+       f03->serio = serio;
+
+       serio_register_port(serio);
+
+       return 0;
+}
+
+static int rmi_f03_probe(struct rmi_function *fn)
+{
+       struct device *dev = &fn->dev;
+       struct f03_data *f03;
+       int error;
+
+       f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL);
+       if (!f03)
+               return -ENOMEM;
+
+       f03->fn = fn;
+
+       error = rmi_f03_initialize(f03);
+       if (error < 0)
+               return error;
+
+       if (f03->device_count != 1)
+               dev_warn(dev, "found %d devices on PS/2 passthrough",
+                        f03->device_count);
+
+       dev_set_drvdata(dev, f03);
+
+       error = rmi_f03_register_pt(f03);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int rmi_f03_config(struct rmi_function *fn)
+{
+       fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+       return 0;
+}
+
+static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+       struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+       u16 data_addr = fn->fd.data_base_addr;
+       const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
+       u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
+       u8 ob_status;
+       u8 ob_data;
+       unsigned int serio_flags;
+       int i;
+       int error;
+
+       if (!rmi_dev)
+               return -ENODEV;
+
+       if (drvdata->attn_data.data) {
+               /* First grab the data passed by the transport device */
+               if (drvdata->attn_data.size < ob_len) {
+                       dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n");
+                       return 0;
+               }
+
+               memcpy(obs, drvdata->attn_data.data, ob_len);
+
+               drvdata->attn_data.data += ob_len;
+               drvdata->attn_data.size -= ob_len;
+       } else {
+               /* Grab all of the data registers, and check them for data */
+               error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
+                                      &obs, ob_len);
+               if (error) {
+                       dev_err(&fn->dev,
+                               "%s: Failed to read F03 output buffers: %d\n",
+                               __func__, error);
+                       serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
+                       return error;
+               }
+       }
+
+       for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) {
+               ob_status = obs[i];
+               ob_data = obs[i + RMI_F03_OB_DATA_OFFSET];
+               serio_flags = 0;
+
+               if (!(ob_status & RMI_F03_RX_DATA_OFB))
+                       continue;
+
+               if (ob_status & RMI_F03_OB_FLAG_TIMEOUT)
+                       serio_flags |= SERIO_TIMEOUT;
+               if (ob_status & RMI_F03_OB_FLAG_PARITY)
+                       serio_flags |= SERIO_PARITY;
+
+               rmi_dbg(RMI_DEBUG_FN, &fn->dev,
+                       "%s: Received %.2hhx from PS2 guest T: %c P: %c\n",
+                       __func__, ob_data,
+                       serio_flags & SERIO_TIMEOUT ?  'Y' : 'N',
+                       serio_flags & SERIO_PARITY ? 'Y' : 'N');
+
+               serio_interrupt(f03->serio, ob_data, serio_flags);
+       }
+
+       return 0;
+}
+
+static void rmi_f03_remove(struct rmi_function *fn)
+{
+       struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+
+       serio_unregister_port(f03->serio);
+}
+
+struct rmi_function_handler rmi_f03_handler = {
+       .driver = {
+               .name = "rmi4_f03",
+       },
+       .func = 0x03,
+       .probe = rmi_f03_probe,
+       .config = rmi_f03_config,
+       .attention = rmi_f03_attention,
+       .remove = rmi_f03_remove,
+};
+
+MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>");
+MODULE_DESCRIPTION("RMI F03 module");
+MODULE_LICENSE("GPL");
index f798f427a46fde82f9580fa964c41452963c3260..bc5e37f30ac1cf4022ac5a8a17f63fb1793d2ce0 100644 (file)
@@ -571,31 +571,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger)
 
 static void rmi_f11_finger_handler(struct f11_data *f11,
                                   struct rmi_2d_sensor *sensor,
-                                  unsigned long *irq_bits, int num_irq_regs)
+                                  unsigned long *irq_bits, int num_irq_regs,
+                                  int size)
 {
        const u8 *f_state = f11->data.f_state;
        u8 finger_state;
        u8 i;
+       int abs_fingers;
+       int rel_fingers;
+       int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES;
 
        int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
                                  num_irq_regs * 8);
        int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
                                  num_irq_regs * 8);
 
-       for (i = 0; i < sensor->nbr_fingers; i++) {
-               /* Possible of having 4 fingers per f_statet register */
-               finger_state = rmi_f11_parse_finger_state(f_state, i);
-               if (finger_state == F11_RESERVED) {
-                       pr_err("Invalid finger state[%d]: 0x%02x", i,
-                               finger_state);
-                       continue;
-               }
+       if (abs_bits) {
+               if (abs_size > size)
+                       abs_fingers = size / RMI_F11_ABS_BYTES;
+               else
+                       abs_fingers = sensor->nbr_fingers;
+
+               for (i = 0; i < abs_fingers; i++) {
+                       /* Possible of having 4 fingers per f_state register */
+                       finger_state = rmi_f11_parse_finger_state(f_state, i);
+                       if (finger_state == F11_RESERVED) {
+                               pr_err("Invalid finger state[%d]: 0x%02x", i,
+                                       finger_state);
+                               continue;
+                       }
 
-               if (abs_bits)
                        rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
                                                        finger_state, i);
+               }
+       }
+
+       if (rel_bits) {
+               if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
+                       rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
+               else
+                       rel_fingers = sensor->nbr_fingers;
 
-               if (rel_bits)
+               for (i = 0; i < rel_fingers; i++)
                        rmi_f11_rel_pos_report(f11, i);
        }
 
@@ -611,7 +628,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
                                              sensor->nbr_fingers,
                                              sensor->dmax);
 
-               for (i = 0; i < sensor->nbr_fingers; i++) {
+               for (i = 0; i < abs_fingers; i++) {
                        finger_state = rmi_f11_parse_finger_state(f_state, i);
                        if (finger_state == F11_RESERVED)
                                /* no need to send twice the error */
@@ -1062,8 +1079,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
                rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata);
                if (rc)
                        return rc;
-       } else if (pdata->sensor_pdata) {
-               f11->sensor_pdata = *pdata->sensor_pdata;
+       } else {
+               f11->sensor_pdata = pdata->sensor_pdata;
        }
 
        f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait;
@@ -1124,6 +1141,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
        sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad;
        sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking;
        sensor->dmax = f11->sensor_pdata.dmax;
+       sensor->dribble = f11->sensor_pdata.dribble;
+       sensor->palm_detect = f11->sensor_pdata.palm_detect;
 
        if (f11->sens_query.has_physical_props) {
                sensor->x_mm = f11->sens_query.x_sensor_size_mm;
@@ -1191,11 +1210,33 @@ static int rmi_f11_initialize(struct rmi_function *fn)
                ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
                        sensor->axis_align.delta_y_threshold;
 
-       if (f11->sens_query.has_dribble)
-               ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);
+       if (f11->sens_query.has_dribble) {
+               switch (sensor->dribble) {
+               case RMI_REG_STATE_OFF:
+                       ctrl->ctrl0_11[0] &= ~BIT(6);
+                       break;
+               case RMI_REG_STATE_ON:
+                       ctrl->ctrl0_11[0] |= BIT(6);
+                       break;
+               case RMI_REG_STATE_DEFAULT:
+               default:
+                       break;
+               }
+       }
 
-       if (f11->sens_query.has_palm_det)
-               ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
+       if (f11->sens_query.has_palm_det) {
+               switch (sensor->palm_detect) {
+               case RMI_REG_STATE_OFF:
+                       ctrl->ctrl0_11[11] &= ~BIT(0);
+                       break;
+               case RMI_REG_STATE_ON:
+                       ctrl->ctrl0_11[11] |= BIT(0);
+                       break;
+               case RMI_REG_STATE_DEFAULT:
+               default:
+                       break;
+               }
+       }
 
        rc = f11_write_control_regs(fn, &f11->sens_query,
                           &f11->dev_controls, fn->fd.query_base_addr);
@@ -1241,12 +1282,21 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
        struct f11_data *f11 = dev_get_drvdata(&fn->dev);
        u16 data_base_addr = fn->fd.data_base_addr;
        int error;
+       int valid_bytes = f11->sensor.pkt_size;
 
-       if (rmi_dev->xport->attn_data) {
-               memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data,
-                       f11->sensor.attn_size);
-               rmi_dev->xport->attn_data += f11->sensor.attn_size;
-               rmi_dev->xport->attn_size -= f11->sensor.attn_size;
+       if (drvdata->attn_data.data) {
+               /*
+                * The valid data in the attention report is less then
+                * expected. Only process the complete fingers.
+                */
+               if (f11->sensor.attn_size > drvdata->attn_data.size)
+                       valid_bytes = drvdata->attn_data.size;
+               else
+                       valid_bytes = f11->sensor.attn_size;
+               memcpy(f11->sensor.data_pkt, drvdata->attn_data.data,
+                       valid_bytes);
+               drvdata->attn_data.data += f11->sensor.attn_size;
+               drvdata->attn_data.size -= f11->sensor.attn_size;
        } else {
                error = rmi_read_block(rmi_dev,
                                data_base_addr, f11->sensor.data_pkt,
@@ -1256,7 +1306,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
        }
 
        rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
-                               drvdata->num_of_irq_regs);
+                               drvdata->num_of_irq_regs, valid_bytes);
 
        return 0;
 }
index 332c02f0b107c02f1ae5f5a404ed13b5ee39885d..07aff4356fe0ea751984e59fbb7292b14bf9503e 100644 (file)
@@ -26,9 +26,12 @@ enum rmi_f12_object_type {
        RMI_F12_OBJECT_SMALL_OBJECT             = 0x0D,
 };
 
+#define F12_DATA1_BYTES_PER_OBJ                        8
+
 struct f12_data {
        struct rmi_2d_sensor sensor;
        struct rmi_2d_sensor_platform_data sensor_pdata;
+       bool has_dribble;
 
        u16 data_addr;
 
@@ -68,10 +71,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
        u8 buf[15];
        int pitch_x = 0;
        int pitch_y = 0;
-       int clip_x_low = 0;
-       int clip_x_high = 0;
-       int clip_y_low = 0;
-       int clip_y_high = 0;
        int rx_receivers = 0;
        int tx_receivers = 0;
        int sensor_flags = 0;
@@ -124,7 +123,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
        }
 
        rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n",
-               __func__, clip_x_low, clip_x_high, clip_y_low, clip_y_high);
+               __func__,
+               sensor->axis_align.clip_x_low, sensor->axis_align.clip_x_high,
+               sensor->axis_align.clip_y_low, sensor->axis_align.clip_y_high);
 
        if (rmi_register_desc_has_subpacket(item, 3)) {
                rx_receivers = buf[offset];
@@ -146,12 +147,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
        return 0;
 }
 
-static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
+static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
 {
        int i;
        struct rmi_2d_sensor *sensor = &f12->sensor;
+       int objects = f12->data1->num_subpackets;
+
+       if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size)
+               objects = size / F12_DATA1_BYTES_PER_OBJ;
 
-       for (i = 0; i < f12->data1->num_subpackets; i++) {
+       for (i = 0; i < objects; i++) {
                struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
 
                obj->type = RMI_2D_OBJECT_NONE;
@@ -182,7 +187,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
 
                rmi_2d_sensor_abs_process(sensor, obj, i);
 
-               data1 += 8;
+               data1 += F12_DATA1_BYTES_PER_OBJ;
        }
 
        if (sensor->kernel_tracking)
@@ -192,7 +197,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
                                      sensor->nbr_fingers,
                                      sensor->dmax);
 
-       for (i = 0; i < sensor->nbr_fingers; i++)
+       for (i = 0; i < objects; i++)
                rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
 }
 
@@ -201,14 +206,20 @@ static int rmi_f12_attention(struct rmi_function *fn,
 {
        int retval;
        struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
        struct f12_data *f12 = dev_get_drvdata(&fn->dev);
        struct rmi_2d_sensor *sensor = &f12->sensor;
-
-       if (rmi_dev->xport->attn_data) {
-               memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
-                       sensor->attn_size);
-               rmi_dev->xport->attn_data += sensor->attn_size;
-               rmi_dev->xport->attn_size -= sensor->attn_size;
+       int valid_bytes = sensor->pkt_size;
+
+       if (drvdata->attn_data.data) {
+               if (sensor->attn_size > drvdata->attn_data.size)
+                       valid_bytes = drvdata->attn_data.size;
+               else
+                       valid_bytes = sensor->attn_size;
+               memcpy(sensor->data_pkt, drvdata->attn_data.data,
+                       valid_bytes);
+               drvdata->attn_data.data += sensor->attn_size;
+               drvdata->attn_data.size -= sensor->attn_size;
        } else {
                retval = rmi_read_block(rmi_dev, f12->data_addr,
                                        sensor->data_pkt, sensor->pkt_size);
@@ -221,19 +232,83 @@ static int rmi_f12_attention(struct rmi_function *fn,
 
        if (f12->data1)
                rmi_f12_process_objects(f12,
-                       &sensor->data_pkt[f12->data1_offset]);
+                       &sensor->data_pkt[f12->data1_offset], valid_bytes);
 
        input_mt_sync_frame(sensor->input);
 
        return 0;
 }
 
+static int rmi_f12_write_control_regs(struct rmi_function *fn)
+{
+       int ret;
+       const struct rmi_register_desc_item *item;
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct f12_data *f12 = dev_get_drvdata(&fn->dev);
+       int control_size;
+       char buf[3];
+       u16 control_offset = 0;
+       u8 subpacket_offset = 0;
+
+       if (f12->has_dribble
+           && (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) {
+               item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
+               if (item) {
+                       control_offset = rmi_register_desc_calc_reg_offset(
+                                               &f12->control_reg_desc, 20);
+
+                       /*
+                        * The byte containing the EnableDribble bit will be
+                        * in either byte 0 or byte 2 of control 20. Depending
+                        * on the existence of subpacket 0. If control 20 is
+                        * larger then 3 bytes, just read the first 3.
+                        */
+                       control_size = min(item->reg_size, 3UL);
+
+                       ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr
+                                       + control_offset, buf, control_size);
+                       if (ret)
+                               return ret;
+
+                       if (rmi_register_desc_has_subpacket(item, 0))
+                               subpacket_offset += 1;
+
+                       switch (f12->sensor.dribble) {
+                       case RMI_REG_STATE_OFF:
+                               buf[subpacket_offset] &= ~BIT(2);
+                               break;
+                       case RMI_REG_STATE_ON:
+                               buf[subpacket_offset] |= BIT(2);
+                               break;
+                       case RMI_REG_STATE_DEFAULT:
+                       default:
+                               break;
+                       }
+
+                       ret = rmi_write_block(rmi_dev,
+                               fn->fd.control_base_addr + control_offset,
+                               buf, control_size);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+
+}
+
 static int rmi_f12_config(struct rmi_function *fn)
 {
        struct rmi_driver *drv = fn->rmi_dev->driver;
+       int ret;
 
        drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
 
+       ret = rmi_f12_write_control_regs(fn);
+       if (ret)
+               dev_warn(&fn->dev,
+                       "Failed to write F12 control registers: %d\n", ret);
+
        return 0;
 }
 
@@ -247,7 +322,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
        const struct rmi_register_desc_item *item;
        struct rmi_2d_sensor *sensor;
        struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
-       struct rmi_transport_dev *xport = rmi_dev->xport;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
        u16 data_offset = 0;
 
        rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
@@ -260,7 +335,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
        }
        ++query_addr;
 
-       if (!(buf & 0x1)) {
+       if (!(buf & BIT(0))) {
                dev_err(&fn->dev,
                        "Behavior of F12 without register descriptors is undefined.\n");
                return -ENODEV;
@@ -270,12 +345,14 @@ static int rmi_f12_probe(struct rmi_function *fn)
        if (!f12)
                return -ENOMEM;
 
+       f12->has_dribble = !!(buf & BIT(3));
+
        if (fn->dev.of_node) {
                ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
                if (ret)
                        return ret;
-       } else if (pdata->sensor_pdata) {
-               f12->sensor_pdata = *pdata->sensor_pdata;
+       } else {
+               f12->sensor_pdata = pdata->sensor_pdata;
        }
 
        ret = rmi_read_register_desc(rmi_dev, query_addr,
@@ -318,6 +395,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
 
        sensor->x_mm = f12->sensor_pdata.x_mm;
        sensor->y_mm = f12->sensor_pdata.y_mm;
+       sensor->dribble = f12->sensor_pdata.dribble;
 
        if (sensor->sensor_type == rmi_sensor_default)
                sensor->sensor_type =
@@ -343,7 +421,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
         * HID attention reports.
         */
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 0);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
@@ -357,15 +435,15 @@ static int rmi_f12_probe(struct rmi_function *fn)
        }
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 2);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 3);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 4);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
@@ -377,22 +455,22 @@ static int rmi_f12_probe(struct rmi_function *fn)
        }
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 6);
-       if (item && !xport->attn_data) {
+       if (item && !drvdata->attn_data.data) {
                f12->data6 = item;
                f12->data6_offset = data_offset;
                data_offset += item->reg_size;
        }
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 7);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 8);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 9);
-       if (item && !xport->attn_data) {
+       if (item && !drvdata->attn_data.data) {
                f12->data9 = item;
                f12->data9_offset = data_offset;
                data_offset += item->reg_size;
@@ -401,27 +479,27 @@ static int rmi_f12_probe(struct rmi_function *fn)
        }
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 10);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 11);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 12);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 13);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 14);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 15);
-       if (item && !xport->attn_data) {
+       if (item && !drvdata->attn_data.data) {
                f12->data15 = item;
                f12->data15_offset = data_offset;
                data_offset += item->reg_size;
index 760aff1bc4207814ddebe1fa5e99bb9687a95189..f4b491e3e0fd4486c2680fab77515d91abaec4aa 100644 (file)
@@ -99,6 +99,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
 {
        struct f30_data *f30 = dev_get_drvdata(&fn->dev);
        struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
        int retval;
        int gpiled = 0;
        int value = 0;
@@ -109,11 +110,15 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
                return 0;
 
        /* Read the gpi led data. */
-       if (rmi_dev->xport->attn_data) {
-               memcpy(f30->data_regs, rmi_dev->xport->attn_data,
+       if (drvdata->attn_data.data) {
+               if (drvdata->attn_data.size < f30->register_count) {
+                       dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
+                       return 0;
+               }
+               memcpy(f30->data_regs, drvdata->attn_data.data,
                        f30->register_count);
-               rmi_dev->xport->attn_data += f30->register_count;
-               rmi_dev->xport->attn_size -= f30->register_count;
+               drvdata->attn_data.data += f30->register_count;
+               drvdata->attn_data.size -= f30->register_count;
        } else {
                retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
                        f30->data_regs, f30->register_count);
@@ -192,7 +197,7 @@ static int rmi_f30_config(struct rmi_function *fn)
                                rmi_get_platform_data(fn->rmi_dev);
        int error;
 
-       if (pdata->f30_data && pdata->f30_data->disable) {
+       if (pdata->f30_data.disable) {
                drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
        } else {
                /* Write Control Register values back to device */
@@ -351,7 +356,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
        f30->gpioled_key_map = (u16 *)map_memory;
 
        pdata = rmi_get_platform_data(rmi_dev);
-       if (pdata && f30->has_gpio) {
+       if (f30->has_gpio) {
                button = BTN_LEFT;
                for (i = 0; i < f30->gpioled_count; i++) {
                        if (rmi_f30_is_valid_button(i, f30->ctrl)) {
@@ -362,8 +367,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
                                 * f30->has_mech_mouse_btns, but I am
                                 * not sure, so use only the pdata info
                                 */
-                               if (pdata->f30_data &&
-                                   pdata->f30_data->buttonpad)
+                               if (pdata->f30_data.buttonpad)
                                        break;
                        }
                }
@@ -378,7 +382,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
        const struct rmi_device_platform_data *pdata =
                                rmi_get_platform_data(fn->rmi_dev);
 
-       if (pdata->f30_data && pdata->f30_data->disable)
+       if (pdata->f30_data.disable)
                return 0;
 
        rc = rmi_f30_initialize(fn);
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
new file mode 100644 (file)
index 0000000..9774dfb
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+
+#include "rmi_driver.h"
+#include "rmi_f34.h"
+
+static int rmi_f34_write_bootloader_id(struct f34_data *f34)
+{
+       struct rmi_function *fn = f34->fn;
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       u8 bootloader_id[F34_BOOTLOADER_ID_LEN];
+       int ret;
+
+       ret = rmi_read_block(rmi_dev, fn->fd.query_base_addr,
+                            bootloader_id, sizeof(bootloader_id));
+       if (ret) {
+               dev_err(&fn->dev, "%s: Reading bootloader ID failed: %d\n",
+                               __func__, ret);
+               return ret;
+       }
+
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: writing bootloader id '%c%c'\n",
+                       __func__, bootloader_id[0], bootloader_id[1]);
+
+       ret = rmi_write_block(rmi_dev,
+                             fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET,
+                             bootloader_id, sizeof(bootloader_id));
+       if (ret) {
+               dev_err(&fn->dev, "Failed to write bootloader ID: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34_command(struct f34_data *f34, u8 command,
+                          unsigned int timeout, bool write_bl_id)
+{
+       struct rmi_function *fn = f34->fn;
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       int ret;
+
+       if (write_bl_id) {
+               ret = rmi_f34_write_bootloader_id(f34);
+               if (ret)
+                       return ret;
+       }
+
+       init_completion(&f34->v5.cmd_done);
+
+       ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+       if (ret) {
+               dev_err(&f34->fn->dev,
+                       "%s: Failed to read cmd register: %d (command %#02x)\n",
+                       __func__, ret, command);
+               return ret;
+       }
+
+       f34->v5.status |= command & 0x0f;
+
+       ret = rmi_write(rmi_dev, f34->v5.ctrl_address, f34->v5.status);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev,
+                       "Failed to write F34 command %#02x: %d\n",
+                       command, ret);
+               return ret;
+       }
+
+       if (!wait_for_completion_timeout(&f34->v5.cmd_done,
+                               msecs_to_jiffies(timeout))) {
+
+               ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+               if (ret) {
+                       dev_err(&f34->fn->dev,
+                               "%s: cmd %#02x timed out: %d\n",
+                               __func__, command, ret);
+                       return ret;
+               }
+
+               if (f34->v5.status & 0x7f) {
+                       dev_err(&f34->fn->dev,
+                               "%s: cmd %#02x timed out, status: %#02x\n",
+                               __func__, command, f34->v5.status);
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+       struct f34_data *f34 = dev_get_drvdata(&fn->dev);
+       int ret;
+
+       if (f34->bl_version != 5)
+               return 0;
+
+       ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n",
+               __func__, f34->v5.status, ret);
+
+       if (!ret && !(f34->v5.status & 0x7f))
+               complete(&f34->v5.cmd_done);
+
+       return 0;
+}
+
+static int rmi_f34_write_blocks(struct f34_data *f34, const void *data,
+                               int block_count, u8 command)
+{
+       struct rmi_function *fn = f34->fn;
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       u16 address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET;
+       u8 start_address[] = { 0, 0 };
+       int i;
+       int ret;
+
+       ret = rmi_write_block(rmi_dev, fn->fd.data_base_addr,
+                             start_address, sizeof(start_address));
+       if (ret) {
+               dev_err(&fn->dev, "Failed to write initial zeros: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < block_count; i++) {
+               ret = rmi_write_block(rmi_dev, address,
+                                     data, f34->v5.block_size);
+               if (ret) {
+                       dev_err(&fn->dev,
+                               "failed to write block #%d: %d\n", i, ret);
+                       return ret;
+               }
+
+               ret = rmi_f34_command(f34, command, F34_IDLE_WAIT_MS, false);
+               if (ret) {
+                       dev_err(&fn->dev,
+                               "Failed to write command for block #%d: %d\n",
+                               i, ret);
+                       return ret;
+               }
+
+               rmi_dbg(RMI_DEBUG_FN, &fn->dev, "wrote block %d of %d\n",
+                       i + 1, block_count);
+
+               data += f34->v5.block_size;
+       }
+
+       return 0;
+}
+
+static int rmi_f34_write_firmware(struct f34_data *f34, const void *data)
+{
+       return rmi_f34_write_blocks(f34, data, f34->v5.fw_blocks,
+                                   F34_WRITE_FW_BLOCK);
+}
+
+static int rmi_f34_write_config(struct f34_data *f34, const void *data)
+{
+       return rmi_f34_write_blocks(f34, data, f34->v5.config_blocks,
+                                   F34_WRITE_CONFIG_BLOCK);
+}
+
+int rmi_f34_enable_flash(struct f34_data *f34)
+{
+       return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG,
+                              F34_ENABLE_WAIT_MS, true);
+}
+
+static int rmi_f34_flash_firmware(struct f34_data *f34,
+                                 const struct rmi_f34_firmware *syn_fw)
+{
+       struct rmi_function *fn = f34->fn;
+       int ret;
+
+       if (syn_fw->image_size) {
+               dev_info(&fn->dev, "Erasing firmware...\n");
+               ret = rmi_f34_command(f34, F34_ERASE_ALL,
+                                     F34_ERASE_WAIT_MS, true);
+               if (ret)
+                       return ret;
+
+               dev_info(&fn->dev, "Writing firmware (%d bytes)...\n",
+                        syn_fw->image_size);
+               ret = rmi_f34_write_firmware(f34, syn_fw->data);
+               if (ret)
+                       return ret;
+       }
+
+       if (syn_fw->config_size) {
+               /*
+                * We only need to erase config if we haven't updated
+                * firmware.
+                */
+               if (!syn_fw->image_size) {
+                       dev_info(&fn->dev, "Erasing config...\n");
+                       ret = rmi_f34_command(f34, F34_ERASE_CONFIG,
+                                             F34_ERASE_WAIT_MS, true);
+                       if (ret)
+                               return ret;
+               }
+
+               dev_info(&fn->dev, "Writing config (%d bytes)...\n",
+                        syn_fw->config_size);
+               ret = rmi_f34_write_config(f34,
+                               &syn_fw->data[syn_fw->image_size]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
+{
+       const struct rmi_f34_firmware *syn_fw;
+       int ret;
+
+       syn_fw = (const struct rmi_f34_firmware *)fw->data;
+       BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) !=
+                       F34_FW_IMAGE_OFFSET);
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+               "FW size:%d, checksum:%08x, image_size:%d, config_size:%d\n",
+               (int)fw->size,
+               le32_to_cpu(syn_fw->checksum),
+               le32_to_cpu(syn_fw->image_size),
+               le32_to_cpu(syn_fw->config_size));
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+               "FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n",
+               syn_fw->bootloader_version,
+               (int)sizeof(syn_fw->product_id), syn_fw->product_id,
+               syn_fw->product_info[0], syn_fw->product_info[1]);
+
+       if (syn_fw->image_size &&
+           syn_fw->image_size != f34->v5.fw_blocks * f34->v5.block_size) {
+               dev_err(&f34->fn->dev,
+                       "Bad firmware image: fw size %d, expected %d\n",
+                       syn_fw->image_size,
+                       f34->v5.fw_blocks * f34->v5.block_size);
+               ret = -EILSEQ;
+               goto out;
+       }
+
+       if (syn_fw->config_size &&
+           syn_fw->config_size != f34->v5.config_blocks * f34->v5.block_size) {
+               dev_err(&f34->fn->dev,
+                       "Bad firmware image: config size %d, expected %d\n",
+                       syn_fw->config_size,
+                       f34->v5.config_blocks * f34->v5.block_size);
+               ret = -EILSEQ;
+               goto out;
+       }
+
+       if (syn_fw->image_size && !syn_fw->config_size) {
+               dev_err(&f34->fn->dev, "Bad firmware image: no config data\n");
+               ret = -EILSEQ;
+               goto out;
+       }
+
+       dev_info(&f34->fn->dev, "Firmware image OK\n");
+       mutex_lock(&f34->v5.flash_mutex);
+
+       ret = rmi_f34_flash_firmware(f34, syn_fw);
+
+       mutex_unlock(&f34->v5.flash_mutex);
+
+out:
+       return ret;
+}
+
+static int rmi_firmware_update(struct rmi_driver_data *data,
+                              const struct firmware *fw)
+{
+       struct rmi_device *rmi_dev = data->rmi_dev;
+       struct device *dev = &rmi_dev->dev;
+       struct f34_data *f34;
+       int ret;
+
+       if (!data->f34_container) {
+               dev_warn(dev, "%s: No F34 present!\n", __func__);
+               return -EINVAL;
+       }
+
+       f34 = dev_get_drvdata(&data->f34_container->dev);
+
+       if (f34->bl_version == 7) {
+               if (data->pdt_props & HAS_BSR) {
+                       dev_err(dev, "%s: LTS not supported\n", __func__);
+                       return -ENODEV;
+               }
+       } else if (f34->bl_version != 5) {
+               dev_warn(dev, "F34 V%d not supported!\n",
+                        data->f34_container->fd.function_version);
+               return -ENODEV;
+       }
+
+       /* Enter flash mode */
+       if (f34->bl_version == 7)
+               ret = rmi_f34v7_start_reflash(f34, fw);
+       else
+               ret = rmi_f34_enable_flash(f34);
+       if (ret)
+               return ret;
+
+       rmi_disable_irq(rmi_dev, false);
+
+       /* Tear down functions and re-probe */
+       rmi_free_function_list(rmi_dev);
+
+       ret = rmi_probe_interrupts(data);
+       if (ret)
+               return ret;
+
+       ret = rmi_init_functions(data);
+       if (ret)
+               return ret;
+
+       if (!data->bootloader_mode || !data->f34_container) {
+               dev_warn(dev, "%s: No F34 present or not in bootloader!\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       rmi_enable_irq(rmi_dev, false);
+
+       f34 = dev_get_drvdata(&data->f34_container->dev);
+
+       /* Perform firmware update */
+       if (f34->bl_version == 7)
+               ret = rmi_f34v7_do_reflash(f34, fw);
+       else
+               ret = rmi_f34_update_firmware(f34, fw);
+
+       dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret);
+
+       rmi_disable_irq(rmi_dev, false);
+
+       /* Re-probe */
+       rmi_dbg(RMI_DEBUG_FN, dev, "Re-probing device\n");
+       rmi_free_function_list(rmi_dev);
+
+       ret = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset);
+       if (ret < 0)
+               dev_warn(dev, "RMI reset failed!\n");
+
+       ret = rmi_probe_interrupts(data);
+       if (ret)
+               return ret;
+
+       ret = rmi_init_functions(data);
+       if (ret)
+               return ret;
+
+       rmi_enable_irq(rmi_dev, false);
+
+       if (data->f01_container->dev.driver)
+               /* Driver already bound, so enable ATTN now. */
+               return rmi_enable_sensor(rmi_dev);
+
+       rmi_dbg(RMI_DEBUG_FN, dev, "%s complete\n", __func__);
+
+       return ret;
+}
+
+static int rmi_firmware_update(struct rmi_driver_data *data,
+                              const struct firmware *fw);
+
+static ssize_t rmi_driver_update_fw_store(struct device *dev,
+                                         struct device_attribute *dattr,
+                                         const char *buf, size_t count)
+{
+       struct rmi_driver_data *data = dev_get_drvdata(dev);
+       char fw_name[NAME_MAX];
+       const struct firmware *fw;
+       size_t copy_count = count;
+       int ret;
+
+       if (count == 0 || count >= NAME_MAX)
+               return -EINVAL;
+
+       if (buf[count - 1] == '\0' || buf[count - 1] == '\n')
+               copy_count -= 1;
+
+       strncpy(fw_name, buf, copy_count);
+       fw_name[copy_count] = '\0';
+
+       ret = request_firmware(&fw, fw_name, dev);
+       if (ret)
+               return ret;
+
+       dev_info(dev, "Flashing %s\n", fw_name);
+
+       ret = rmi_firmware_update(data, fw);
+
+       release_firmware(fw);
+
+       return ret ?: count;
+}
+
+static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
+
+static struct attribute *rmi_firmware_attrs[] = {
+       &dev_attr_update_fw.attr,
+       NULL
+};
+
+static struct attribute_group rmi_firmware_attr_group = {
+       .attrs = rmi_firmware_attrs,
+};
+
+static int rmi_f34_probe(struct rmi_function *fn)
+{
+       struct f34_data *f34;
+       unsigned char f34_queries[9];
+       bool has_config_id;
+       u8 version = fn->fd.function_version;
+       int ret;
+
+       f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
+       if (!f34)
+               return -ENOMEM;
+
+       f34->fn = fn;
+       dev_set_drvdata(&fn->dev, f34);
+
+       /* v5 code only supported version 0, try V7 probe */
+       if (version > 0)
+               return rmi_f34v7_probe(f34);
+       else if (version != 0)
+               return -ENODEV;
+
+       f34->bl_version = 5;
+
+       ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+                            f34_queries, sizeof(f34_queries));
+       if (ret) {
+               dev_err(&fn->dev, "%s: Failed to query properties\n",
+                       __func__);
+               return ret;
+       }
+
+       snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
+                "%c%c", f34_queries[0], f34_queries[1]);
+
+       mutex_init(&f34->v5.flash_mutex);
+       init_completion(&f34->v5.cmd_done);
+
+       f34->v5.block_size = get_unaligned_le16(&f34_queries[3]);
+       f34->v5.fw_blocks = get_unaligned_le16(&f34_queries[5]);
+       f34->v5.config_blocks = get_unaligned_le16(&f34_queries[7]);
+       f34->v5.ctrl_address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET +
+               f34->v5.block_size;
+       has_config_id = f34_queries[2] & (1 << 2);
+
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Bootloader ID: %s\n",
+               f34->bootloader_id);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Block size: %d\n",
+               f34->v5.block_size);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "FW blocks: %d\n",
+               f34->v5.fw_blocks);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "CFG blocks: %d\n",
+               f34->v5.config_blocks);
+
+       if (has_config_id) {
+               ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
+                                    f34_queries, sizeof(f34_queries));
+               if (ret) {
+                       dev_err(&fn->dev, "Failed to read F34 config ID\n");
+                       return ret;
+               }
+
+               snprintf(f34->configuration_id, sizeof(f34->configuration_id),
+                        "%02x%02x%02x%02x",
+                        f34_queries[0], f34_queries[1],
+                        f34_queries[2], f34_queries[3]);
+
+               rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n",
+                        f34->configuration_id);
+       }
+
+       return 0;
+}
+
+int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
+{
+       return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
+}
+
+void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
+{
+       sysfs_remove_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
+}
+
+struct rmi_function_handler rmi_f34_handler = {
+       .driver = {
+               .name = "rmi4_f34",
+       },
+       .func = 0x34,
+       .probe = rmi_f34_probe,
+       .attention = rmi_f34_attention,
+};
diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h
new file mode 100644 (file)
index 0000000..2c21056
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _RMI_F34_H
+#define _RMI_F34_H
+
+/* F34 image file offsets. */
+#define F34_FW_IMAGE_OFFSET    0x100
+
+/* F34 register offsets. */
+#define F34_BLOCK_DATA_OFFSET  2
+
+/* F34 commands */
+#define F34_WRITE_FW_BLOCK     0x2
+#define F34_ERASE_ALL          0x3
+#define F34_READ_CONFIG_BLOCK  0x5
+#define F34_WRITE_CONFIG_BLOCK 0x6
+#define F34_ERASE_CONFIG       0x7
+#define F34_ENABLE_FLASH_PROG  0xf
+
+#define F34_STATUS_IN_PROGRESS 0xff
+#define F34_STATUS_IDLE                0x80
+
+#define F34_IDLE_WAIT_MS       500
+#define F34_ENABLE_WAIT_MS     300
+#define F34_ERASE_WAIT_MS      5000
+
+#define F34_BOOTLOADER_ID_LEN  2
+
+/* F34 V7 defines */
+#define V7_FLASH_STATUS_OFFSET         0
+#define V7_PARTITION_ID_OFFSET         1
+#define V7_BLOCK_NUMBER_OFFSET         2
+#define V7_TRANSFER_LENGTH_OFFSET      3
+#define V7_COMMAND_OFFSET              4
+#define V7_PAYLOAD_OFFSET              5
+#define V7_BOOTLOADER_ID_OFFSET                1
+
+#define IMAGE_HEADER_VERSION_10                0x10
+
+#define CONFIG_ID_SIZE                 32
+#define PRODUCT_ID_SIZE                        10
+
+#define ENABLE_WAIT_MS                 (1 * 1000)
+#define WRITE_WAIT_MS                  (3 * 1000)
+
+#define MIN_SLEEP_TIME_US              50
+#define MAX_SLEEP_TIME_US              100
+
+#define HAS_BSR                                BIT(5)
+#define HAS_CONFIG_ID                  BIT(3)
+#define HAS_GUEST_CODE                 BIT(6)
+#define HAS_DISP_CFG                   BIT(5)
+
+/* F34 V7 commands */
+#define CMD_V7_IDLE                    0
+#define CMD_V7_ENTER_BL                        1
+#define CMD_V7_READ                    2
+#define CMD_V7_WRITE                   3
+#define CMD_V7_ERASE                   4
+#define CMD_V7_ERASE_AP                        5
+#define CMD_V7_SENSOR_ID               6
+
+#define v7_CMD_IDLE                    0
+#define v7_CMD_WRITE_FW                        1
+#define v7_CMD_WRITE_CONFIG            2
+#define v7_CMD_WRITE_LOCKDOWN          3
+#define v7_CMD_WRITE_GUEST_CODE                4
+#define v7_CMD_READ_CONFIG             5
+#define v7_CMD_ERASE_ALL               6
+#define v7_CMD_ERASE_UI_FIRMWARE       7
+#define v7_CMD_ERASE_UI_CONFIG         8
+#define v7_CMD_ERASE_BL_CONFIG         9
+#define v7_CMD_ERASE_DISP_CONFIG       10
+#define v7_CMD_ERASE_FLASH_CONFIG      11
+#define v7_CMD_ERASE_GUEST_CODE                12
+#define v7_CMD_ENABLE_FLASH_PROG       13
+
+#define v7_UI_CONFIG_AREA              0
+#define v7_PM_CONFIG_AREA              1
+#define v7_BL_CONFIG_AREA              2
+#define v7_DP_CONFIG_AREA              3
+#define v7_FLASH_CONFIG_AREA           4
+
+/* F34 V7 partition IDs */
+#define BOOTLOADER_PARTITION           1
+#define DEVICE_CONFIG_PARTITION                2
+#define FLASH_CONFIG_PARTITION         3
+#define MANUFACTURING_BLOCK_PARTITION  4
+#define GUEST_SERIALIZATION_PARTITION  5
+#define GLOBAL_PARAMETERS_PARTITION    6
+#define CORE_CODE_PARTITION            7
+#define CORE_CONFIG_PARTITION          8
+#define GUEST_CODE_PARTITION           9
+#define DISPLAY_CONFIG_PARTITION       10
+
+/* F34 V7 container IDs */
+#define TOP_LEVEL_CONTAINER                    0
+#define UI_CONTAINER                           1
+#define UI_CONFIG_CONTAINER                    2
+#define BL_CONTAINER                           3
+#define BL_IMAGE_CONTAINER                     4
+#define BL_CONFIG_CONTAINER                    5
+#define BL_LOCKDOWN_INFO_CONTAINER             6
+#define PERMANENT_CONFIG_CONTAINER             7
+#define GUEST_CODE_CONTAINER                   8
+#define BL_PROTOCOL_DESCRIPTOR_CONTAINER       9
+#define UI_PROTOCOL_DESCRIPTOR_CONTAINER       10
+#define RMI_SELF_DISCOVERY_CONTAINER           11
+#define RMI_PAGE_CONTENT_CONTAINER             12
+#define GENERAL_INFORMATION_CONTAINER          13
+#define DEVICE_CONFIG_CONTAINER                        14
+#define FLASH_CONFIG_CONTAINER                 15
+#define GUEST_SERIALIZATION_CONTAINER          16
+#define GLOBAL_PARAMETERS_CONTAINER            17
+#define CORE_CODE_CONTAINER                    18
+#define CORE_CONFIG_CONTAINER                  19
+#define DISPLAY_CONFIG_CONTAINER               20
+
+struct f34v7_query_1_7 {
+       u8 bl_minor_revision;                   /* query 1 */
+       u8 bl_major_revision;
+       __le32 bl_fw_id;                        /* query 2 */
+       u8 minimum_write_size;                  /* query 3 */
+       __le16 block_size;
+       __le16 flash_page_size;
+       __le16 adjustable_partition_area_size;  /* query 4 */
+       __le16 flash_config_length;             /* query 5 */
+       __le16 payload_length;                  /* query 6 */
+       u8 partition_support[4];                /* query 7 */
+} __packed;
+
+struct f34v7_data_1_5 {
+       u8 partition_id;
+       __le16 block_offset;
+       __le16 transfer_length;
+       u8 command;
+       u8 payload[2];
+} __packed;
+
+struct block_data {
+       const void *data;
+       int size;
+};
+
+struct partition_table {
+       u8 partition_id;
+       u8 byte_1_reserved;
+       __le16 partition_length;
+       __le16 start_physical_address;
+       __le16 partition_properties;
+} __packed;
+
+struct physical_address {
+       u16 ui_firmware;
+       u16 ui_config;
+       u16 dp_config;
+       u16 guest_code;
+};
+
+struct container_descriptor {
+       __le32 content_checksum;
+       __le16 container_id;
+       u8 minor_version;
+       u8 major_version;
+       u8 reserved_08;
+       u8 reserved_09;
+       u8 reserved_0a;
+       u8 reserved_0b;
+       u8 container_option_flags[4];
+       __le32 content_options_length;
+       __le32 content_options_address;
+       __le32 content_length;
+       __le32 content_address;
+} __packed;
+
+struct block_count {
+       u16 ui_firmware;
+       u16 ui_config;
+       u16 dp_config;
+       u16 fl_config;
+       u16 pm_config;
+       u16 bl_config;
+       u16 lockdown;
+       u16 guest_code;
+};
+
+struct image_header_10 {
+       __le32 checksum;
+       u8 reserved_04;
+       u8 reserved_05;
+       u8 minor_header_version;
+       u8 major_header_version;
+       u8 reserved_08;
+       u8 reserved_09;
+       u8 reserved_0a;
+       u8 reserved_0b;
+       __le32 top_level_container_start_addr;
+};
+
+struct image_metadata {
+       bool contains_firmware_id;
+       bool contains_bootloader;
+       bool contains_display_cfg;
+       bool contains_guest_code;
+       bool contains_flash_config;
+       unsigned int firmware_id;
+       unsigned int checksum;
+       unsigned int bootloader_size;
+       unsigned int display_cfg_offset;
+       unsigned char bl_version;
+       unsigned char product_id[PRODUCT_ID_SIZE + 1];
+       unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1];
+       struct block_data bootloader;
+       struct block_data ui_firmware;
+       struct block_data ui_config;
+       struct block_data dp_config;
+       struct block_data fl_config;
+       struct block_data bl_config;
+       struct block_data guest_code;
+       struct block_data lockdown;
+       struct block_count blkcount;
+       struct physical_address phyaddr;
+};
+
+struct register_offset {
+       u8 properties;
+       u8 properties_2;
+       u8 block_size;
+       u8 block_count;
+       u8 gc_block_count;
+       u8 flash_status;
+       u8 partition_id;
+       u8 block_number;
+       u8 transfer_length;
+       u8 flash_cmd;
+       u8 payload;
+};
+
+struct rmi_f34_firmware {
+       __le32 checksum;
+       u8 pad1[3];
+       u8 bootloader_version;
+       __le32 image_size;
+       __le32 config_size;
+       u8 product_id[10];
+       u8 product_info[2];
+       u8 pad2[228];
+       u8 data[];
+};
+
+struct f34v5_data {
+       u16 block_size;
+       u16 fw_blocks;
+       u16 config_blocks;
+       u16 ctrl_address;
+       u8 status;
+
+       struct completion cmd_done;
+       struct mutex flash_mutex;
+};
+
+struct f34v7_data {
+       bool has_display_cfg;
+       bool has_guest_code;
+       bool force_update;
+       bool in_bl_mode;
+       u8 *read_config_buf;
+       size_t read_config_buf_size;
+       u8 command;
+       u8 flash_status;
+       u16 block_size;
+       u16 config_block_count;
+       u16 config_size;
+       u16 config_area;
+       u16 flash_config_length;
+       u16 payload_length;
+       u8 partitions;
+       u16 partition_table_bytes;
+       bool new_partition_table;
+
+       struct register_offset off;
+       struct block_count blkcount;
+       struct physical_address phyaddr;
+       struct image_metadata img;
+
+       const void *config_data;
+       const void *image;
+};
+
+struct f34_data {
+       struct rmi_function *fn;
+
+       u8 bl_version;
+       unsigned char bootloader_id[5];
+       unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1];
+
+       union {
+               struct f34v5_data v5;
+               struct f34v7_data v7;
+       };
+};
+
+int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw);
+int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw);
+int rmi_f34v7_probe(struct f34_data *f34);
+
+#endif /* _RMI_F34_H */
diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c
new file mode 100644 (file)
index 0000000..ca31f95
--- /dev/null
@@ -0,0 +1,1372 @@
+/*
+ * Copyright (c) 2016, Zodiac Inflight Innovations
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "rmi_driver.h"
+#include "rmi_f34.h"
+
+static int rmi_f34v7_read_flash_status(struct f34_data *f34)
+{
+       u8 status;
+       u8 command;
+       int ret;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       f34->fn->fd.data_base_addr + f34->v7.off.flash_status,
+                       &status,
+                       sizeof(status));
+       if (ret < 0) {
+               rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                       "%s: Failed to read flash status\n", __func__);
+               return ret;
+       }
+
+       f34->v7.in_bl_mode = status >> 7;
+       f34->v7.flash_status = status & 0x1f;
+
+       if (f34->v7.flash_status != 0x00) {
+               dev_err(&f34->fn->dev, "%s: status=%d, command=0x%02x\n",
+                       __func__, f34->v7.flash_status, f34->v7.command);
+       }
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       f34->fn->fd.data_base_addr + f34->v7.off.flash_cmd,
+                       &command,
+                       sizeof(command));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read flash command\n",
+                       __func__);
+               return ret;
+       }
+
+       f34->v7.command = command;
+
+       return 0;
+}
+
+static int rmi_f34v7_wait_for_idle(struct f34_data *f34, int timeout_ms)
+{
+       int count = 0;
+       int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1;
+
+       do {
+               usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US);
+
+               count++;
+
+               rmi_f34v7_read_flash_status(f34);
+
+               if ((f34->v7.command == v7_CMD_IDLE)
+                   && (f34->v7.flash_status == 0x00)) {
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "Idle status detected\n");
+                       return 0;
+               }
+       } while (count < timeout_count);
+
+       dev_err(&f34->fn->dev,
+               "%s: Timed out waiting for idle status\n", __func__);
+
+       return -ETIMEDOUT;
+}
+
+static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34,
+                                                     u8 cmd)
+{
+       int ret;
+       u8 base;
+       struct f34v7_data_1_5 data_1_5;
+
+       base = f34->fn->fd.data_base_addr;
+
+       memset(&data_1_5, 0, sizeof(data_1_5));
+
+       switch (cmd) {
+       case v7_CMD_ERASE_ALL:
+               data_1_5.partition_id = CORE_CODE_PARTITION;
+               data_1_5.command = CMD_V7_ERASE_AP;
+               break;
+       case v7_CMD_ERASE_UI_FIRMWARE:
+               data_1_5.partition_id = CORE_CODE_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_BL_CONFIG:
+               data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_UI_CONFIG:
+               data_1_5.partition_id = CORE_CONFIG_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_DISP_CONFIG:
+               data_1_5.partition_id = DISPLAY_CONFIG_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_FLASH_CONFIG:
+               data_1_5.partition_id = FLASH_CONFIG_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_GUEST_CODE:
+               data_1_5.partition_id = GUEST_CODE_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ENABLE_FLASH_PROG:
+               data_1_5.partition_id = BOOTLOADER_PARTITION;
+               data_1_5.command = CMD_V7_ENTER_BL;
+               break;
+       }
+
+       data_1_5.payload[0] = f34->bootloader_id[0];
+       data_1_5.payload[1] = f34->bootloader_id[1];
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.partition_id,
+                       &data_1_5, sizeof(data_1_5));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev,
+                       "%s: Failed to write single transaction command\n",
+                       __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_write_command(struct f34_data *f34, u8 cmd)
+{
+       int ret;
+       u8 base;
+       u8 command;
+
+       base = f34->fn->fd.data_base_addr;
+
+       switch (cmd) {
+       case v7_CMD_WRITE_FW:
+       case v7_CMD_WRITE_CONFIG:
+       case v7_CMD_WRITE_GUEST_CODE:
+               command = CMD_V7_WRITE;
+               break;
+       case v7_CMD_READ_CONFIG:
+               command = CMD_V7_READ;
+               break;
+       case v7_CMD_ERASE_ALL:
+               command = CMD_V7_ERASE_AP;
+               break;
+       case v7_CMD_ERASE_UI_FIRMWARE:
+       case v7_CMD_ERASE_BL_CONFIG:
+       case v7_CMD_ERASE_UI_CONFIG:
+       case v7_CMD_ERASE_DISP_CONFIG:
+       case v7_CMD_ERASE_FLASH_CONFIG:
+       case v7_CMD_ERASE_GUEST_CODE:
+               command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ENABLE_FLASH_PROG:
+               command = CMD_V7_ENTER_BL;
+               break;
+       default:
+               dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n",
+                       __func__, cmd);
+               return -EINVAL;
+       }
+
+       f34->v7.command = command;
+
+       switch (cmd) {
+       case v7_CMD_ERASE_ALL:
+       case v7_CMD_ERASE_UI_FIRMWARE:
+       case v7_CMD_ERASE_BL_CONFIG:
+       case v7_CMD_ERASE_UI_CONFIG:
+       case v7_CMD_ERASE_DISP_CONFIG:
+       case v7_CMD_ERASE_FLASH_CONFIG:
+       case v7_CMD_ERASE_GUEST_CODE:
+       case v7_CMD_ENABLE_FLASH_PROG:
+               ret = rmi_f34v7_write_command_single_transaction(f34, cmd);
+               if (ret < 0)
+                       return ret;
+               else
+                       return 0;
+       default:
+               break;
+       }
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: writing cmd %02X\n",
+               __func__, command);
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.flash_cmd,
+                       &command, sizeof(command));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write flash command\n",
+                       __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_write_partition_id(struct f34_data *f34, u8 cmd)
+{
+       int ret;
+       u8 base;
+       u8 partition;
+
+       base = f34->fn->fd.data_base_addr;
+
+       switch (cmd) {
+       case v7_CMD_WRITE_FW:
+               partition = CORE_CODE_PARTITION;
+               break;
+       case v7_CMD_WRITE_CONFIG:
+       case v7_CMD_READ_CONFIG:
+               if (f34->v7.config_area == v7_UI_CONFIG_AREA)
+                       partition = CORE_CONFIG_PARTITION;
+               else if (f34->v7.config_area == v7_DP_CONFIG_AREA)
+                       partition = DISPLAY_CONFIG_PARTITION;
+               else if (f34->v7.config_area == v7_PM_CONFIG_AREA)
+                       partition = GUEST_SERIALIZATION_PARTITION;
+               else if (f34->v7.config_area == v7_BL_CONFIG_AREA)
+                       partition = GLOBAL_PARAMETERS_PARTITION;
+               else if (f34->v7.config_area == v7_FLASH_CONFIG_AREA)
+                       partition = FLASH_CONFIG_PARTITION;
+               break;
+       case v7_CMD_WRITE_GUEST_CODE:
+               partition = GUEST_CODE_PARTITION;
+               break;
+       case v7_CMD_ERASE_ALL:
+               partition = CORE_CODE_PARTITION;
+               break;
+       case v7_CMD_ERASE_BL_CONFIG:
+               partition = GLOBAL_PARAMETERS_PARTITION;
+               break;
+       case v7_CMD_ERASE_UI_CONFIG:
+               partition = CORE_CONFIG_PARTITION;
+               break;
+       case v7_CMD_ERASE_DISP_CONFIG:
+               partition = DISPLAY_CONFIG_PARTITION;
+               break;
+       case v7_CMD_ERASE_FLASH_CONFIG:
+               partition = FLASH_CONFIG_PARTITION;
+               break;
+       case v7_CMD_ERASE_GUEST_CODE:
+               partition = GUEST_CODE_PARTITION;
+               break;
+       case v7_CMD_ENABLE_FLASH_PROG:
+               partition = BOOTLOADER_PARTITION;
+               break;
+       default:
+               dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n",
+                       __func__, cmd);
+               return -EINVAL;
+       }
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.partition_id,
+                       &partition, sizeof(partition));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write partition ID\n",
+                       __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34)
+{
+       int ret;
+       u8 base;
+       __le16 length;
+       u16 block_number = 0;
+
+       base = f34->fn->fd.data_base_addr;
+
+       f34->v7.config_area = v7_FLASH_CONFIG_AREA;
+
+       ret = rmi_f34v7_write_partition_id(f34, v7_CMD_READ_CONFIG);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.block_number,
+                       &block_number, sizeof(block_number));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+                       __func__);
+               return ret;
+       }
+
+       put_unaligned_le16(f34->v7.flash_config_length, &length);
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.transfer_length,
+                       &length, sizeof(length));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write transfer length\n",
+                       __func__);
+               return ret;
+       }
+
+       ret = rmi_f34v7_write_command(f34, v7_CMD_READ_CONFIG);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write command\n",
+                       __func__);
+               return ret;
+       }
+
+       ret = rmi_f34v7_wait_for_idle(f34, WRITE_WAIT_MS);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to wait for idle status\n",
+                       __func__);
+               return ret;
+       }
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.payload,
+                       f34->v7.read_config_buf,
+                       f34->v7.partition_table_bytes);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read block data\n",
+                       __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void rmi_f34v7_parse_partition_table(struct f34_data *f34,
+                                           const void *partition_table,
+                                           struct block_count *blkcount,
+                                           struct physical_address *phyaddr)
+{
+       int i;
+       int index;
+       u16 partition_length;
+       u16 physical_address;
+       const struct partition_table *ptable;
+
+       for (i = 0; i < f34->v7.partitions; i++) {
+               index = i * 8 + 2;
+               ptable = partition_table + index;
+               partition_length = le16_to_cpu(ptable->partition_length);
+               physical_address = le16_to_cpu(ptable->start_physical_address);
+               rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                       "%s: Partition entry %d: %*ph\n",
+                       __func__, i, sizeof(struct partition_table), ptable);
+               switch (ptable->partition_id & 0x1f) {
+               case CORE_CODE_PARTITION:
+                       blkcount->ui_firmware = partition_length;
+                       phyaddr->ui_firmware = physical_address;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Core code block count: %d\n",
+                               __func__, blkcount->ui_firmware);
+                       break;
+               case CORE_CONFIG_PARTITION:
+                       blkcount->ui_config = partition_length;
+                       phyaddr->ui_config = physical_address;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Core config block count: %d\n",
+                               __func__, blkcount->ui_config);
+                       break;
+               case DISPLAY_CONFIG_PARTITION:
+                       blkcount->dp_config = partition_length;
+                       phyaddr->dp_config = physical_address;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Display config block count: %d\n",
+                               __func__, blkcount->dp_config);
+                       break;
+               case FLASH_CONFIG_PARTITION:
+                       blkcount->fl_config = partition_length;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Flash config block count: %d\n",
+                               __func__, blkcount->fl_config);
+                       break;
+               case GUEST_CODE_PARTITION:
+                       blkcount->guest_code = partition_length;
+                       phyaddr->guest_code = physical_address;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Guest code block count: %d\n",
+                               __func__, blkcount->guest_code);
+                       break;
+               case GUEST_SERIALIZATION_PARTITION:
+                       blkcount->pm_config = partition_length;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Guest serialization block count: %d\n",
+                               __func__, blkcount->pm_config);
+                       break;
+               case GLOBAL_PARAMETERS_PARTITION:
+                       blkcount->bl_config = partition_length;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Global parameters block count: %d\n",
+                               __func__, blkcount->bl_config);
+                       break;
+               case DEVICE_CONFIG_PARTITION:
+                       blkcount->lockdown = partition_length;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Device config block count: %d\n",
+                               __func__, blkcount->lockdown);
+                       break;
+               }
+       }
+}
+
+static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34)
+{
+       int ret;
+       u8 base;
+       int offset;
+       u8 query_0;
+       struct f34v7_query_1_7 query_1_7;
+
+       base = f34->fn->fd.query_base_addr;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base,
+                       &query_0,
+                       sizeof(query_0));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev,
+                       "%s: Failed to read query 0\n", __func__);
+               return ret;
+       }
+
+       offset = (query_0 & 0x7) + 1;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base + offset,
+                       &query_1_7,
+                       sizeof(query_1_7));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n",
+                       __func__);
+               return ret;
+       }
+
+       f34->bootloader_id[0] = query_1_7.bl_minor_revision;
+       f34->bootloader_id[1] = query_1_7.bl_major_revision;
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Bootloader V%d.%d\n",
+               f34->bootloader_id[1], f34->bootloader_id[0]);
+
+       return 0;
+}
+
+static int rmi_f34v7_read_queries(struct f34_data *f34)
+{
+       int ret;
+       int i, j;
+       u8 base;
+       int offset;
+       u8 *ptable;
+       u8 query_0;
+       struct f34v7_query_1_7 query_1_7;
+
+       base = f34->fn->fd.query_base_addr;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base,
+                       &query_0,
+                       sizeof(query_0));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev,
+                       "%s: Failed to read query 0\n", __func__);
+               return ret;
+       }
+
+       offset = (query_0 & 0x07) + 1;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base + offset,
+                       &query_1_7,
+                       sizeof(query_1_7));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n",
+                       __func__);
+               return ret;
+       }
+
+       f34->bootloader_id[0] = query_1_7.bl_minor_revision;
+       f34->bootloader_id[1] = query_1_7.bl_major_revision;
+
+       f34->v7.block_size = le16_to_cpu(query_1_7.block_size);
+       f34->v7.flash_config_length =
+                       le16_to_cpu(query_1_7.flash_config_length);
+       f34->v7.payload_length = le16_to_cpu(query_1_7.payload_length);
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.block_size = %d\n",
+                __func__, f34->v7.block_size);
+
+       f34->v7.off.flash_status = V7_FLASH_STATUS_OFFSET;
+       f34->v7.off.partition_id = V7_PARTITION_ID_OFFSET;
+       f34->v7.off.block_number = V7_BLOCK_NUMBER_OFFSET;
+       f34->v7.off.transfer_length = V7_TRANSFER_LENGTH_OFFSET;
+       f34->v7.off.flash_cmd = V7_COMMAND_OFFSET;
+       f34->v7.off.payload = V7_PAYLOAD_OFFSET;
+
+       f34->v7.has_display_cfg = query_1_7.partition_support[1] & HAS_DISP_CFG;
+       f34->v7.has_guest_code =
+                       query_1_7.partition_support[1] & HAS_GUEST_CODE;
+
+       if (query_0 & HAS_CONFIG_ID) {
+               char f34_ctrl[CONFIG_ID_SIZE];
+               int i = 0;
+               u8 *p = f34->configuration_id;
+               *p = '\0';
+
+               ret = rmi_read_block(f34->fn->rmi_dev,
+                               f34->fn->fd.control_base_addr,
+                               f34_ctrl,
+                               sizeof(f34_ctrl));
+               if (ret)
+                       return ret;
+
+               /* Eat leading zeros */
+               while (i < sizeof(f34_ctrl) && !f34_ctrl[i])
+                       i++;
+
+               for (; i < sizeof(f34_ctrl); i++)
+                       p += snprintf(p, f34->configuration_id
+                                     + sizeof(f34->configuration_id) - p,
+                                     "%02X", f34_ctrl[i]);
+
+               rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n",
+                       f34->configuration_id);
+       }
+
+       f34->v7.partitions = 0;
+       for (i = 0; i < sizeof(query_1_7.partition_support); i++)
+               for (j = 0; j < 8; j++)
+                       if (query_1_7.partition_support[i] & (1 << j))
+                               f34->v7.partitions++;
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n",
+               __func__, sizeof(query_1_7.partition_support),
+               query_1_7.partition_support);
+
+
+       f34->v7.partition_table_bytes = f34->v7.partitions * 8 + 2;
+
+       f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev,
+                       f34->v7.partition_table_bytes,
+                       GFP_KERNEL);
+       if (!f34->v7.read_config_buf) {
+               f34->v7.read_config_buf_size = 0;
+               return -ENOMEM;
+       }
+
+       f34->v7.read_config_buf_size = f34->v7.partition_table_bytes;
+       ptable = f34->v7.read_config_buf;
+
+       ret = rmi_f34v7_read_f34v7_partition_table(f34);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read partition table\n",
+                               __func__);
+               return ret;
+       }
+
+       rmi_f34v7_parse_partition_table(f34, ptable,
+                                       &f34->v7.blkcount, &f34->v7.phyaddr);
+
+       return 0;
+}
+
+static int rmi_f34v7_check_ui_firmware_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
+
+       if (block_count != f34->v7.blkcount.ui_firmware) {
+               dev_err(&f34->fn->dev,
+                       "UI firmware size mismatch: %d != %d\n",
+                       block_count, f34->v7.blkcount.ui_firmware);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_check_ui_config_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.ui_config.size / f34->v7.block_size;
+
+       if (block_count != f34->v7.blkcount.ui_config) {
+               dev_err(&f34->fn->dev, "UI config size mismatch\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_check_dp_config_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.dp_config.size / f34->v7.block_size;
+
+       if (block_count != f34->v7.blkcount.dp_config) {
+               dev_err(&f34->fn->dev, "Display config size mismatch\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_check_guest_code_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.guest_code.size / f34->v7.block_size;
+       if (block_count != f34->v7.blkcount.guest_code) {
+               dev_err(&f34->fn->dev, "Guest code size mismatch\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_check_bl_config_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.bl_config.size / f34->v7.block_size;
+
+       if (block_count != f34->v7.blkcount.bl_config) {
+               dev_err(&f34->fn->dev, "Bootloader config size mismatch\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_erase_config(struct f34_data *f34)
+{
+       int ret;
+
+       dev_info(&f34->fn->dev, "Erasing config...\n");
+
+       switch (f34->v7.config_area) {
+       case v7_UI_CONFIG_AREA:
+               ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_CONFIG);
+               if (ret < 0)
+                       return ret;
+               break;
+       case v7_DP_CONFIG_AREA:
+               ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_DISP_CONFIG);
+               if (ret < 0)
+                       return ret;
+               break;
+       case v7_BL_CONFIG_AREA:
+               ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_BL_CONFIG);
+               if (ret < 0)
+                       return ret;
+               break;
+       }
+
+       ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int rmi_f34v7_erase_guest_code(struct f34_data *f34)
+{
+       int ret;
+
+       dev_info(&f34->fn->dev, "Erasing guest code...\n");
+
+       ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_GUEST_CODE);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rmi_f34v7_erase_all(struct f34_data *f34)
+{
+       int ret;
+
+       dev_info(&f34->fn->dev, "Erasing firmware...\n");
+
+       ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_FIRMWARE);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+       if (ret < 0)
+               return ret;
+
+       f34->v7.config_area = v7_UI_CONFIG_AREA;
+       ret = rmi_f34v7_erase_config(f34);
+       if (ret < 0)
+               return ret;
+
+       if (f34->v7.has_display_cfg) {
+               f34->v7.config_area = v7_DP_CONFIG_AREA;
+               ret = rmi_f34v7_erase_config(f34);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (f34->v7.new_partition_table && f34->v7.has_guest_code) {
+               ret = rmi_f34v7_erase_guest_code(f34);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt,
+                                      u8 command)
+{
+       int ret;
+       u8 base;
+       __le16 length;
+       u16 transfer;
+       u16 max_transfer;
+       u16 remaining = block_cnt;
+       u16 block_number = 0;
+       u16 index = 0;
+
+       base = f34->fn->fd.data_base_addr;
+
+       ret = rmi_f34v7_write_partition_id(f34, command);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.block_number,
+                       &block_number, sizeof(block_number));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+                       __func__);
+               return ret;
+       }
+
+       max_transfer = min(f34->v7.payload_length,
+                          (u16)(PAGE_SIZE / f34->v7.block_size));
+
+       do {
+               transfer = min(remaining, max_transfer);
+               put_unaligned_le16(transfer, &length);
+
+               ret = rmi_write_block(f34->fn->rmi_dev,
+                               base + f34->v7.off.transfer_length,
+                               &length, sizeof(length));
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Write transfer length fail (%d remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               ret = rmi_f34v7_write_command(f34, command);
+               if (ret < 0)
+                       return ret;
+
+               ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Wait for idle failed (%d blks remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               ret = rmi_read_block(f34->fn->rmi_dev,
+                               base + f34->v7.off.payload,
+                               &f34->v7.read_config_buf[index],
+                               transfer * f34->v7.block_size);
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Read block failed (%d blks remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               index += (transfer * f34->v7.block_size);
+               remaining -= transfer;
+       } while (remaining);
+
+       return 0;
+}
+
+static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34,
+                                       const void *block_ptr, u16 block_cnt,
+                                       u8 command)
+{
+       int ret;
+       u8 base;
+       __le16 length;
+       u16 transfer;
+       u16 max_transfer;
+       u16 remaining = block_cnt;
+       u16 block_number = 0;
+
+       base = f34->fn->fd.data_base_addr;
+
+       ret = rmi_f34v7_write_partition_id(f34, command);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.block_number,
+                       &block_number, sizeof(block_number));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+                       __func__);
+               return ret;
+       }
+
+       if (f34->v7.payload_length > (PAGE_SIZE / f34->v7.block_size))
+               max_transfer = PAGE_SIZE / f34->v7.block_size;
+       else
+               max_transfer = f34->v7.payload_length;
+
+       do {
+               transfer = min(remaining, max_transfer);
+               put_unaligned_le16(transfer, &length);
+
+               ret = rmi_write_block(f34->fn->rmi_dev,
+                               base + f34->v7.off.transfer_length,
+                               &length, sizeof(length));
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Write transfer length fail (%d remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               ret = rmi_f34v7_write_command(f34, command);
+               if (ret < 0)
+                       return ret;
+
+               ret = rmi_write_block(f34->fn->rmi_dev,
+                               base + f34->v7.off.payload,
+                               block_ptr, transfer * f34->v7.block_size);
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Failed writing data (%d blks remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Failed wait for idle (%d blks remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               block_ptr += (transfer * f34->v7.block_size);
+               remaining -= transfer;
+       } while (remaining);
+
+       return 0;
+}
+
+static int rmi_f34v7_write_config(struct f34_data *f34)
+{
+       return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.config_data,
+                                           f34->v7.config_block_count,
+                                           v7_CMD_WRITE_CONFIG);
+}
+
+static int rmi_f34v7_write_ui_config(struct f34_data *f34)
+{
+       f34->v7.config_area = v7_UI_CONFIG_AREA;
+       f34->v7.config_data = f34->v7.img.ui_config.data;
+       f34->v7.config_size = f34->v7.img.ui_config.size;
+       f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+       return rmi_f34v7_write_config(f34);
+}
+
+static int rmi_f34v7_write_dp_config(struct f34_data *f34)
+{
+       f34->v7.config_area = v7_DP_CONFIG_AREA;
+       f34->v7.config_data = f34->v7.img.dp_config.data;
+       f34->v7.config_size = f34->v7.img.dp_config.size;
+       f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+       return rmi_f34v7_write_config(f34);
+}
+
+static int rmi_f34v7_write_guest_code(struct f34_data *f34)
+{
+       return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.guest_code.data,
+                                           f34->v7.img.guest_code.size /
+                                                       f34->v7.block_size,
+                                           v7_CMD_WRITE_GUEST_CODE);
+}
+
+static int rmi_f34v7_write_flash_config(struct f34_data *f34)
+{
+       int ret;
+
+       f34->v7.config_area = v7_FLASH_CONFIG_AREA;
+       f34->v7.config_data = f34->v7.img.fl_config.data;
+       f34->v7.config_size = f34->v7.img.fl_config.size;
+       f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+       if (f34->v7.config_block_count != f34->v7.blkcount.fl_config) {
+               dev_err(&f34->fn->dev, "%s: Flash config size mismatch\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_FLASH_CONFIG);
+       if (ret < 0)
+               return ret;
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+               "%s: Erase flash config command written\n", __func__);
+
+       ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_write_config(f34);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rmi_f34v7_write_partition_table(struct f34_data *f34)
+{
+       u16 block_count;
+       int ret;
+
+       block_count = f34->v7.blkcount.bl_config;
+       f34->v7.config_area = v7_BL_CONFIG_AREA;
+       f34->v7.config_size = f34->v7.block_size * block_count;
+       devm_kfree(&f34->fn->dev, f34->v7.read_config_buf);
+       f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev,
+                                              f34->v7.config_size, GFP_KERNEL);
+       if (!f34->v7.read_config_buf) {
+               f34->v7.read_config_buf_size = 0;
+               return -ENOMEM;
+       }
+
+       f34->v7.read_config_buf_size = f34->v7.config_size;
+
+       ret = rmi_f34v7_read_f34v7_blocks(f34, block_count, v7_CMD_READ_CONFIG);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_erase_config(f34);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_write_flash_config(f34);
+       if (ret < 0)
+               return ret;
+
+       f34->v7.config_area = v7_BL_CONFIG_AREA;
+       f34->v7.config_data = f34->v7.read_config_buf;
+       f34->v7.config_size = f34->v7.img.bl_config.size;
+       f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+       ret = rmi_f34v7_write_config(f34);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rmi_f34v7_write_firmware(struct f34_data *f34)
+{
+       u16 blk_count;
+
+       blk_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
+
+       return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.ui_firmware.data,
+                                           blk_count, v7_CMD_WRITE_FW);
+}
+
+static void rmi_f34v7_compare_partition_tables(struct f34_data *f34)
+{
+       if (f34->v7.phyaddr.ui_firmware != f34->v7.img.phyaddr.ui_firmware) {
+               f34->v7.new_partition_table = true;
+               return;
+       }
+
+       if (f34->v7.phyaddr.ui_config != f34->v7.img.phyaddr.ui_config) {
+               f34->v7.new_partition_table = true;
+               return;
+       }
+
+       if (f34->v7.has_display_cfg &&
+           f34->v7.phyaddr.dp_config != f34->v7.img.phyaddr.dp_config) {
+               f34->v7.new_partition_table = true;
+               return;
+       }
+
+       if (f34->v7.has_guest_code &&
+           f34->v7.phyaddr.guest_code != f34->v7.img.phyaddr.guest_code) {
+               f34->v7.new_partition_table = true;
+               return;
+       }
+
+       f34->v7.new_partition_table = false;
+}
+
+static void rmi_f34v7_parse_img_header_10_bl_container(struct f34_data *f34,
+                                                      const void *image)
+{
+       int i;
+       int num_of_containers;
+       unsigned int addr;
+       unsigned int container_id;
+       unsigned int length;
+       const void *content;
+       const struct container_descriptor *descriptor;
+
+       num_of_containers = f34->v7.img.bootloader.size / 4 - 1;
+
+       for (i = 1; i <= num_of_containers; i++) {
+               addr = get_unaligned_le32(f34->v7.img.bootloader.data + i * 4);
+               descriptor = image + addr;
+               container_id = le16_to_cpu(descriptor->container_id);
+               content = image + le32_to_cpu(descriptor->content_address);
+               length = le32_to_cpu(descriptor->content_length);
+               switch (container_id) {
+               case BL_CONFIG_CONTAINER:
+               case GLOBAL_PARAMETERS_CONTAINER:
+                       f34->v7.img.bl_config.data = content;
+                       f34->v7.img.bl_config.size = length;
+                       break;
+               case BL_LOCKDOWN_INFO_CONTAINER:
+               case DEVICE_CONFIG_CONTAINER:
+                       f34->v7.img.lockdown.data = content;
+                       f34->v7.img.lockdown.size = length;
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void rmi_f34v7_parse_image_header_10(struct f34_data *f34)
+{
+       unsigned int i;
+       unsigned int num_of_containers;
+       unsigned int addr;
+       unsigned int offset;
+       unsigned int container_id;
+       unsigned int length;
+       const void *image = f34->v7.image;
+       const u8 *content;
+       const struct container_descriptor *descriptor;
+       const struct image_header_10 *header = image;
+
+       f34->v7.img.checksum = le32_to_cpu(header->checksum);
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.img.checksum=%X\n",
+               __func__, f34->v7.img.checksum);
+
+       /* address of top level container */
+       offset = le32_to_cpu(header->top_level_container_start_addr);
+       descriptor = image + offset;
+
+       /* address of top level container content */
+       offset = le32_to_cpu(descriptor->content_address);
+       num_of_containers = le32_to_cpu(descriptor->content_length) / 4;
+
+       for (i = 0; i < num_of_containers; i++) {
+               addr = get_unaligned_le32(image + offset);
+               offset += 4;
+               descriptor = image + addr;
+               container_id = le16_to_cpu(descriptor->container_id);
+               content = image + le32_to_cpu(descriptor->content_address);
+               length = le32_to_cpu(descriptor->content_length);
+
+               rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                       "%s: container_id=%d, length=%d\n", __func__,
+                       container_id, length);
+
+               switch (container_id) {
+               case UI_CONTAINER:
+               case CORE_CODE_CONTAINER:
+                       f34->v7.img.ui_firmware.data = content;
+                       f34->v7.img.ui_firmware.size = length;
+                       break;
+               case UI_CONFIG_CONTAINER:
+               case CORE_CONFIG_CONTAINER:
+                       f34->v7.img.ui_config.data = content;
+                       f34->v7.img.ui_config.size = length;
+                       break;
+               case BL_CONTAINER:
+                       f34->v7.img.bl_version = *content;
+                       f34->v7.img.bootloader.data = content;
+                       f34->v7.img.bootloader.size = length;
+                       rmi_f34v7_parse_img_header_10_bl_container(f34, image);
+                       break;
+               case GUEST_CODE_CONTAINER:
+                       f34->v7.img.contains_guest_code = true;
+                       f34->v7.img.guest_code.data = content;
+                       f34->v7.img.guest_code.size = length;
+                       break;
+               case DISPLAY_CONFIG_CONTAINER:
+                       f34->v7.img.contains_display_cfg = true;
+                       f34->v7.img.dp_config.data = content;
+                       f34->v7.img.dp_config.size = length;
+                       break;
+               case FLASH_CONFIG_CONTAINER:
+                       f34->v7.img.contains_flash_config = true;
+                       f34->v7.img.fl_config.data = content;
+                       f34->v7.img.fl_config.size = length;
+                       break;
+               case GENERAL_INFORMATION_CONTAINER:
+                       f34->v7.img.contains_firmware_id = true;
+                       f34->v7.img.firmware_id =
+                               get_unaligned_le32(content + 4);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static int rmi_f34v7_parse_image_info(struct f34_data *f34)
+{
+       const struct image_header_10 *header = f34->v7.image;
+
+       memset(&f34->v7.img, 0x00, sizeof(f34->v7.img));
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+               "%s: header->major_header_version = %d\n",
+               __func__, header->major_header_version);
+
+       switch (header->major_header_version) {
+       case IMAGE_HEADER_VERSION_10:
+               rmi_f34v7_parse_image_header_10(f34);
+               break;
+       default:
+               dev_err(&f34->fn->dev, "Unsupported image file format %02X\n",
+                       header->major_header_version);
+               return -EINVAL;
+       }
+
+       if (!f34->v7.img.contains_flash_config) {
+               dev_err(&f34->fn->dev, "%s: No flash config in fw image\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       rmi_f34v7_parse_partition_table(f34, f34->v7.img.fl_config.data,
+                       &f34->v7.img.blkcount, &f34->v7.img.phyaddr);
+
+       rmi_f34v7_compare_partition_tables(f34);
+
+       return 0;
+}
+
+int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw)
+{
+       int ret;
+
+       rmi_f34v7_read_queries_bl_version(f34);
+
+       f34->v7.image = fw->data;
+
+       ret = rmi_f34v7_parse_image_info(f34);
+       if (ret < 0)
+               goto fail;
+
+       if (!f34->v7.new_partition_table) {
+               ret = rmi_f34v7_check_ui_firmware_size(f34);
+               if (ret < 0)
+                       goto fail;
+
+               ret = rmi_f34v7_check_ui_config_size(f34);
+               if (ret < 0)
+                       goto fail;
+
+               if (f34->v7.has_display_cfg &&
+                   f34->v7.img.contains_display_cfg) {
+                       ret = rmi_f34v7_check_dp_config_size(f34);
+                       if (ret < 0)
+                               goto fail;
+               }
+
+               if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) {
+                       ret = rmi_f34v7_check_guest_code_size(f34);
+                       if (ret < 0)
+                               goto fail;
+               }
+       } else {
+               ret = rmi_f34v7_check_bl_config_size(f34);
+               if (ret < 0)
+                       goto fail;
+       }
+
+       ret = rmi_f34v7_erase_all(f34);
+       if (ret < 0)
+               goto fail;
+
+       if (f34->v7.new_partition_table) {
+               ret = rmi_f34v7_write_partition_table(f34);
+               if (ret < 0)
+                       goto fail;
+               dev_info(&f34->fn->dev, "%s: Partition table programmed\n",
+                        __func__);
+       }
+
+       dev_info(&f34->fn->dev, "Writing firmware (%d bytes)...\n",
+                f34->v7.img.ui_firmware.size);
+
+       ret = rmi_f34v7_write_firmware(f34);
+       if (ret < 0)
+               goto fail;
+
+       dev_info(&f34->fn->dev, "Writing config (%d bytes)...\n",
+                f34->v7.img.ui_config.size);
+
+       f34->v7.config_area = v7_UI_CONFIG_AREA;
+       ret = rmi_f34v7_write_ui_config(f34);
+       if (ret < 0)
+               goto fail;
+
+       if (f34->v7.has_display_cfg && f34->v7.img.contains_display_cfg) {
+               dev_info(&f34->fn->dev, "Writing display config...\n");
+
+               ret = rmi_f34v7_write_dp_config(f34);
+               if (ret < 0)
+                       goto fail;
+       }
+
+       if (f34->v7.new_partition_table) {
+               if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) {
+                       dev_info(&f34->fn->dev, "Writing guest code...\n");
+
+                       ret = rmi_f34v7_write_guest_code(f34);
+                       if (ret < 0)
+                               goto fail;
+               }
+       }
+
+fail:
+       return ret;
+}
+
+static int rmi_f34v7_enter_flash_prog(struct f34_data *f34)
+{
+       int ret;
+
+       ret = rmi_f34v7_read_flash_status(f34);
+       if (ret < 0)
+               return ret;
+
+       if (f34->v7.in_bl_mode)
+               return 0;
+
+       ret = rmi_f34v7_write_command(f34, v7_CMD_ENABLE_FLASH_PROG);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+       if (ret < 0)
+               return ret;
+
+       if (!f34->v7.in_bl_mode) {
+               dev_err(&f34->fn->dev, "%s: BL mode not entered\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw)
+{
+       int ret = 0;
+
+       f34->v7.config_area = v7_UI_CONFIG_AREA;
+       f34->v7.image = fw->data;
+
+       ret = rmi_f34v7_parse_image_info(f34);
+       if (ret < 0)
+               goto exit;
+
+       if (!f34->v7.force_update && f34->v7.new_partition_table) {
+               dev_err(&f34->fn->dev, "%s: Partition table mismatch\n",
+                               __func__);
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       dev_info(&f34->fn->dev, "Firmware image OK\n");
+
+       ret = rmi_f34v7_read_flash_status(f34);
+       if (ret < 0)
+               goto exit;
+
+       if (f34->v7.in_bl_mode) {
+               dev_info(&f34->fn->dev, "%s: Device in bootloader mode\n",
+                               __func__);
+       }
+
+       rmi_f34v7_enter_flash_prog(f34);
+
+       return 0;
+
+exit:
+       return ret;
+}
+
+int rmi_f34v7_probe(struct f34_data *f34)
+{
+       int ret;
+
+       /* Read bootloader version */
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       f34->fn->fd.query_base_addr + V7_BOOTLOADER_ID_OFFSET,
+                       f34->bootloader_id,
+                       sizeof(f34->bootloader_id));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read bootloader ID\n",
+                       __func__);
+               return ret;
+       }
+
+       if (f34->bootloader_id[1] == '5') {
+               f34->bl_version = 5;
+       } else if (f34->bootloader_id[1] == '6') {
+               f34->bl_version = 6;
+       } else if (f34->bootloader_id[1] == 7) {
+               f34->bl_version = 7;
+       } else {
+               dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       memset(&f34->v7.blkcount, 0x00, sizeof(f34->v7.blkcount));
+       memset(&f34->v7.phyaddr, 0x00, sizeof(f34->v7.phyaddr));
+       rmi_f34v7_read_queries(f34);
+
+       f34->v7.force_update = false;
+       return 0;
+}
index cf805b960866215f52e96b2ae9a21ae373ddedfb..dea63e2db3e6213f5e83d6067870a16cc5707e6d 100644 (file)
@@ -200,7 +200,7 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
 
        error = rmi_write(rmi_dev, fn->fd.command_base_addr, F54_GET_REPORT);
        if (error < 0)
-               return error;
+               goto unlock;
 
        init_completion(&f54->cmd_done);
 
@@ -209,15 +209,18 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
 
        queue_delayed_work(f54->workqueue, &f54->work, 0);
 
+unlock:
        mutex_unlock(&f54->data_mutex);
 
-       return 0;
+       return error;
 }
 
 static size_t rmi_f54_get_report_size(struct f54_data *f54)
 {
-       u8 rx = f54->num_rx_electrodes ? : f54->num_rx_electrodes;
-       u8 tx = f54->num_tx_electrodes ? : f54->num_tx_electrodes;
+       struct rmi_device *rmi_dev = f54->fn->rmi_dev;
+       struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+       u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
+       u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
        size_t size;
 
        switch (rmi_f54_get_reptype(f54, f54->input)) {
@@ -401,6 +404,10 @@ static int rmi_f54_vidioc_enum_input(struct file *file, void *priv,
 
 static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
 {
+       struct rmi_device *rmi_dev = f54->fn->rmi_dev;
+       struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+       u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
+       u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
        struct v4l2_pix_format *f = &f54->format;
        enum rmi_f54_report_type reptype;
        int ret;
@@ -415,8 +422,8 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
 
        f54->input = i;
 
-       f->width = f54->num_rx_electrodes;
-       f->height = f54->num_tx_electrodes;
+       f->width = rx;
+       f->height = tx;
        f->field = V4L2_FIELD_NONE;
        f->colorspace = V4L2_COLORSPACE_RAW;
        f->bytesperline = f->width * sizeof(u16);
diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c
new file mode 100644 (file)
index 0000000..37390ca
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012-2015 Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define F55_NAME               "rmi4_f55"
+
+/* F55 data offsets */
+#define F55_NUM_RX_OFFSET      0
+#define F55_NUM_TX_OFFSET      1
+#define F55_PHYS_CHAR_OFFSET   2
+
+/* Only read required query registers */
+#define F55_QUERY_LEN          3
+
+/* F55 capabilities */
+#define F55_CAP_SENSOR_ASSIGN  BIT(0)
+
+struct f55_data {
+       struct rmi_function *fn;
+
+       u8 qry[F55_QUERY_LEN];
+       u8 num_rx_electrodes;
+       u8 cfg_num_rx_electrodes;
+       u8 num_tx_electrodes;
+       u8 cfg_num_tx_electrodes;
+};
+
+static int rmi_f55_detect(struct rmi_function *fn)
+{
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+       struct f55_data *f55;
+       int error;
+
+       f55 = dev_get_drvdata(&fn->dev);
+
+       error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+                              &f55->qry, sizeof(f55->qry));
+       if (error) {
+               dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
+                       __func__);
+               return error;
+       }
+
+       f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
+       f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
+
+       f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
+       f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
+
+       drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
+       drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
+
+       if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
+               int i, total;
+               u8 buf[256];
+
+               /*
+                * Calculate the number of enabled receive and transmit
+                * electrodes by reading F55:Ctrl1 (sensor receiver assignment)
+                * and F55:Ctrl2 (sensor transmitter assignment). The number of
+                * enabled electrodes is the sum of all field entries with a
+                * value other than 0xff.
+                */
+               error = rmi_read_block(fn->rmi_dev,
+                                      fn->fd.control_base_addr + 1,
+                                      buf, f55->num_rx_electrodes);
+               if (!error) {
+                       total = 0;
+                       for (i = 0; i < f55->num_rx_electrodes; i++) {
+                               if (buf[i] != 0xff)
+                                       total++;
+                       }
+                       f55->cfg_num_rx_electrodes = total;
+                       drv_data->num_rx_electrodes = total;
+               }
+
+               error = rmi_read_block(fn->rmi_dev,
+                                      fn->fd.control_base_addr + 2,
+                                      buf, f55->num_tx_electrodes);
+               if (!error) {
+                       total = 0;
+                       for (i = 0; i < f55->num_tx_electrodes; i++) {
+                               if (buf[i] != 0xff)
+                                       total++;
+                       }
+                       f55->cfg_num_tx_electrodes = total;
+                       drv_data->num_tx_electrodes = total;
+               }
+       }
+
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
+               f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
+               f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
+
+       return 0;
+}
+
+static int rmi_f55_probe(struct rmi_function *fn)
+{
+       struct f55_data *f55;
+
+       f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
+       if (!f55)
+               return -ENOMEM;
+
+       f55->fn = fn;
+       dev_set_drvdata(&fn->dev, f55);
+
+       return rmi_f55_detect(fn);
+}
+
+struct rmi_function_handler rmi_f55_handler = {
+       .driver = {
+               .name = F55_NAME,
+       },
+       .func = 0x55,
+       .probe = rmi_f55_probe,
+};
index 1ebc2c1debae31e5d1479466085a9d7fbcfc586f..082306d7c207993c71a898a4dd17583a55ba8b4d 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/i2c.h>
 #include <linux/rmi.h>
-#include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
@@ -35,8 +34,6 @@ struct rmi_i2c_xport {
        struct mutex page_mutex;
        int page;
 
-       int irq;
-
        u8 *tx_buf;
        size_t tx_buf_size;
 
@@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
        .read_block     = rmi_i2c_read_block,
 };
 
-static irqreturn_t rmi_i2c_irq(int irq, void *dev_id)
-{
-       struct rmi_i2c_xport *rmi_i2c = dev_id;
-       struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev;
-       int ret;
-
-       ret = rmi_process_interrupt_requests(rmi_dev);
-       if (ret)
-               rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
-                       "Failed to process interrupt request: %d\n", ret);
-
-       return IRQ_HANDLED;
-}
-
-static int rmi_i2c_init_irq(struct i2c_client *client)
-{
-       struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
-       int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq));
-       int ret;
-
-       if (!irq_flags)
-               irq_flags = IRQF_TRIGGER_LOW;
-
-       ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL,
-                       rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name,
-                       rmi_i2c);
-       if (ret < 0) {
-               dev_warn(&client->dev, "Failed to register interrupt %d\n",
-                       rmi_i2c->irq);
-
-               return ret;
-       }
-
-       return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id rmi_i2c_of_match[] = {
        { .compatible = "syna,rmi4-i2c" },
@@ -255,8 +216,7 @@ static int rmi_i2c_probe(struct i2c_client *client,
        if (!client->dev.of_node && client_pdata)
                *pdata = *client_pdata;
 
-       if (client->irq > 0)
-               rmi_i2c->irq = client->irq;
+       pdata->irq = client->irq;
 
        rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
                        dev_name(&client->dev));
@@ -321,10 +281,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
        if (retval)
                return retval;
 
-       retval = rmi_i2c_init_irq(client);
-       if (retval < 0)
-               return retval;
-
        dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
                        client->addr);
        return 0;
@@ -337,18 +293,10 @@ static int rmi_i2c_suspend(struct device *dev)
        struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
        int ret;
 
-       ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+       ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-       disable_irq(rmi_i2c->irq);
-       if (device_may_wakeup(&client->dev)) {
-               ret = enable_irq_wake(rmi_i2c->irq);
-               if (!ret)
-                       dev_warn(dev, "Failed to enable irq for wake: %d\n",
-                               ret);
-       }
-
        regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
                               rmi_i2c->supplies);
 
@@ -368,15 +316,7 @@ static int rmi_i2c_resume(struct device *dev)
 
        msleep(rmi_i2c->startup_delay);
 
-       enable_irq(rmi_i2c->irq);
-       if (device_may_wakeup(&client->dev)) {
-               ret = disable_irq_wake(rmi_i2c->irq);
-               if (!ret)
-                       dev_warn(dev, "Failed to disable irq for wake: %d\n",
-                               ret);
-       }
-
-       ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+       ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
@@ -391,12 +331,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
        struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
        int ret;
 
-       ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+       ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-       disable_irq(rmi_i2c->irq);
-
        regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
                               rmi_i2c->supplies);
 
@@ -416,9 +354,7 @@ static int rmi_i2c_runtime_resume(struct device *dev)
 
        msleep(rmi_i2c->startup_delay);
 
-       enable_irq(rmi_i2c->irq);
-
-       ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+       ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
new file mode 100644 (file)
index 0000000..7675255
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2015 - 2016 Red Hat, Inc
+ * Copyright (c) 2011, 2012 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kconfig.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define SMB_PROTOCOL_VERSION_ADDRESS   0xfd
+#define SMB_MAX_COUNT                  32
+#define RMI_SMB2_MAP_SIZE              8 /* 8 entry of 4 bytes each */
+#define RMI_SMB2_MAP_FLAGS_WE          0x01
+
+struct mapping_table_entry {
+       __le16 rmiaddr;
+       u8 readcount;
+       u8 flags;
+};
+
+struct rmi_smb_xport {
+       struct rmi_transport_dev xport;
+       struct i2c_client *client;
+
+       struct mutex page_mutex;
+       int page;
+       u8 table_index;
+       struct mutex mappingtable_mutex;
+       struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE];
+};
+
+static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
+{
+       struct i2c_client *client = rmi_smb->client;
+       int retval;
+
+       /* Check if for SMBus new version device by reading version byte. */
+       retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
+       if (retval < 0) {
+               dev_err(&client->dev, "failed to get SMBus version number!\n");
+               return retval;
+       }
+       return retval + 1;
+}
+
+/* SMB block write - wrapper over ic2_smb_write_block */
+static int smb_block_write(struct rmi_transport_dev *xport,
+                             u8 commandcode, const void *buf, size_t len)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       struct i2c_client *client = rmi_smb->client;
+       int retval;
+
+       retval = i2c_smbus_write_block_data(client, commandcode, len, buf);
+
+       rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
+               "wrote %zd bytes at %#04x: %d (%*ph)\n",
+               len, commandcode, retval, (int)len, buf);
+
+       return retval;
+}
+
+/*
+ * The function to get command code for smbus operations and keeps
+ * records to the driver mapping table
+ */
+static int rmi_smb_get_command_code(struct rmi_transport_dev *xport,
+               u16 rmiaddr, int bytecount, bool isread, u8 *commandcode)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       int i;
+       int retval;
+       struct mapping_table_entry mapping_data[1];
+
+       mutex_lock(&rmi_smb->mappingtable_mutex);
+       for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) {
+               if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) {
+                       if (isread) {
+                               if (rmi_smb->mapping_table[i].readcount
+                                                       == bytecount) {
+                                       *commandcode = i;
+                                       retval = 0;
+                                       goto exit;
+                               }
+                       } else {
+                               if (rmi_smb->mapping_table[i].flags &
+                                                       RMI_SMB2_MAP_FLAGS_WE) {
+                                       *commandcode = i;
+                                       retval = 0;
+                                       goto exit;
+                               }
+                       }
+               }
+       }
+       i = rmi_smb->table_index;
+       rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE;
+
+       /* constructs mapping table data entry. 4 bytes each entry */
+       memset(mapping_data, 0, sizeof(mapping_data));
+
+       mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr);
+       mapping_data[0].readcount = bytecount;
+       mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+
+       retval = smb_block_write(xport, i + 0x80, mapping_data,
+                                sizeof(mapping_data));
+
+       if (retval < 0) {
+               /*
+                * if not written to device mapping table
+                * clear the driver mapping table records
+                */
+               rmi_smb->mapping_table[i].rmiaddr = 0x0000;
+               rmi_smb->mapping_table[i].readcount = 0;
+               rmi_smb->mapping_table[i].flags = 0;
+               goto exit;
+       }
+       /* save to the driver level mapping table */
+       rmi_smb->mapping_table[i].rmiaddr = rmiaddr;
+       rmi_smb->mapping_table[i].readcount = bytecount;
+       rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+       *commandcode = i;
+
+exit:
+       mutex_unlock(&rmi_smb->mappingtable_mutex);
+
+       return retval;
+}
+
+static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+                               const void *databuff, size_t len)
+{
+       int retval = 0;
+       u8 commandcode;
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       int cur_len = (int)len;
+
+       mutex_lock(&rmi_smb->page_mutex);
+
+       while (cur_len > 0) {
+               /*
+                * break into 32 bytes chunks to write get command code
+                */
+               int block_len = min_t(int, len, SMB_MAX_COUNT);
+
+               retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+                                                 false, &commandcode);
+               if (retval < 0)
+                       goto exit;
+
+               retval = smb_block_write(xport, commandcode,
+                                        databuff, block_len);
+               if (retval < 0)
+                       goto exit;
+
+               /* prepare to write next block of bytes */
+               cur_len -= SMB_MAX_COUNT;
+               databuff += SMB_MAX_COUNT;
+               rmiaddr += SMB_MAX_COUNT;
+       }
+exit:
+       mutex_unlock(&rmi_smb->page_mutex);
+       return retval;
+}
+
+/* SMB block read - wrapper over ic2_smb_read_block */
+static int smb_block_read(struct rmi_transport_dev *xport,
+                            u8 commandcode, void *buf, size_t len)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       struct i2c_client *client = rmi_smb->client;
+       int retval;
+
+       retval = i2c_smbus_read_block_data(client, commandcode, buf);
+       if (retval < 0)
+               return retval;
+
+       return retval;
+}
+
+static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+                             void *databuff, size_t len)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       int retval;
+       u8 commandcode;
+       int cur_len = (int)len;
+
+       mutex_lock(&rmi_smb->page_mutex);
+       memset(databuff, 0, len);
+
+       while (cur_len > 0) {
+               /* break into 32 bytes chunks to write get command code */
+               int block_len =  min_t(int, cur_len, SMB_MAX_COUNT);
+
+               retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+                                                 true, &commandcode);
+               if (retval < 0)
+                       goto exit;
+
+               retval = smb_block_read(xport, commandcode,
+                                       databuff, block_len);
+               if (retval < 0)
+                       goto exit;
+
+               /* prepare to read next block of bytes */
+               cur_len -= SMB_MAX_COUNT;
+               databuff += SMB_MAX_COUNT;
+               rmiaddr += SMB_MAX_COUNT;
+       }
+
+       retval = 0;
+
+exit:
+       mutex_unlock(&rmi_smb->page_mutex);
+       return retval;
+}
+
+static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
+{
+       /* the mapping table has been flushed, discard the current one */
+       mutex_lock(&rmi_smb->mappingtable_mutex);
+       memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table));
+       mutex_unlock(&rmi_smb->mappingtable_mutex);
+}
+
+static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
+{
+       int retval;
+
+       /* we need to get the smbus version to activate the touchpad */
+       retval = rmi_smb_get_version(rmi_smb);
+       if (retval < 0)
+               return retval;
+
+       return 0;
+}
+
+static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+
+       rmi_smb_clear_state(rmi_smb);
+
+       /*
+        * we do not call the actual reset command, it has to be handled in
+        * PS/2 or there will be races between PS/2 and SMBus.
+        * PS/2 should ensure that a psmouse_reset is called before
+        * intializing the device and after it has been removed to be in a known
+        * state.
+        */
+       return rmi_smb_enable_smbus_mode(rmi_smb);
+}
+
+static const struct rmi_transport_ops rmi_smb_ops = {
+       .write_block    = rmi_smb_write_block,
+       .read_block     = rmi_smb_read_block,
+       .reset          = rmi_smb_reset,
+};
+
+static int rmi_smb_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
+       struct rmi_smb_xport *rmi_smb;
+       int retval;
+       int smbus_version;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+                                    I2C_FUNC_SMBUS_HOST_NOTIFY)) {
+               dev_err(&client->dev,
+                       "adapter does not support required functionality.\n");
+               return -ENODEV;
+       }
+
+       if (client->irq <= 0) {
+               dev_err(&client->dev, "no IRQ provided, giving up.\n");
+               return client->irq ? client->irq : -ENODEV;
+       }
+
+       rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport),
+                               GFP_KERNEL);
+       if (!rmi_smb)
+               return -ENOMEM;
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data, aborting\n");
+               return -ENOMEM;
+       }
+
+       rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
+               dev_name(&client->dev));
+
+       rmi_smb->client = client;
+       mutex_init(&rmi_smb->page_mutex);
+       mutex_init(&rmi_smb->mappingtable_mutex);
+
+       rmi_smb->xport.dev = &client->dev;
+       rmi_smb->xport.pdata = *pdata;
+       rmi_smb->xport.pdata.irq = client->irq;
+       rmi_smb->xport.proto_name = "smb2";
+       rmi_smb->xport.ops = &rmi_smb_ops;
+
+       retval = rmi_smb_get_version(rmi_smb);
+       if (retval < 0)
+               return retval;
+
+       smbus_version = retval;
+       rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
+               smbus_version);
+
+       if (smbus_version != 2) {
+               dev_err(&client->dev, "Unrecognized SMB version %d.\n",
+                               smbus_version);
+               return -ENODEV;
+       }
+
+       i2c_set_clientdata(client, rmi_smb);
+
+       retval = rmi_register_transport_device(&rmi_smb->xport);
+       if (retval) {
+               dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
+                       client->addr);
+               i2c_set_clientdata(client, NULL);
+               return retval;
+       }
+
+       dev_info(&client->dev, "registered rmi smb driver at %#04x.\n",
+                       client->addr);
+       return 0;
+
+}
+
+static int rmi_smb_remove(struct i2c_client *client)
+{
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+
+       rmi_unregister_transport_device(&rmi_smb->xport);
+
+       return 0;
+}
+
+static int __maybe_unused rmi_smb_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+       int ret;
+
+       ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true);
+       if (ret)
+               dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+       return ret;
+}
+
+static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+       int ret;
+
+       ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false);
+       if (ret)
+               dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+       return ret;
+}
+
+static int __maybe_unused rmi_smb_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+       struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev;
+       int ret;
+
+       rmi_smb_reset(&rmi_smb->xport, 0);
+
+       rmi_reset(rmi_dev);
+
+       ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true);
+       if (ret)
+               dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+       return 0;
+}
+
+static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+       int ret;
+
+       ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false);
+       if (ret)
+               dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+       return 0;
+}
+
+static const struct dev_pm_ops rmi_smb_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
+       SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
+                          NULL)
+};
+
+static const struct i2c_device_id rmi_id[] = {
+       { "rmi4_smbus", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rmi_id);
+
+static struct i2c_driver rmi_smb_driver = {
+       .driver = {
+               .name   = "rmi4_smbus",
+               .pm     = &rmi_smb_pm,
+       },
+       .id_table       = rmi_id,
+       .probe          = rmi_smb_probe,
+       .remove         = rmi_smb_remove,
+};
+
+module_i2c_driver(rmi_smb_driver);
+
+MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("RMI4 SMBus driver");
+MODULE_LICENSE("GPL");
index 4ebef607e2141ad574fe161366308c08e101dc68..69548d7d1f10f8f3d9fac4cc3e2e828971a7687c 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/rmi.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
-#include <linux/irq.h>
 #include <linux/of.h>
 #include "rmi_driver.h"
 
@@ -44,8 +43,6 @@ struct rmi_spi_xport {
        struct mutex page_mutex;
        int page;
 
-       int irq;
-
        u8 *rx_buf;
        u8 *tx_buf;
        int xfer_buf_size;
@@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = {
        .read_block     = rmi_spi_read_block,
 };
 
-static irqreturn_t rmi_spi_irq(int irq, void *dev_id)
-{
-       struct rmi_spi_xport *rmi_spi = dev_id;
-       struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev;
-       int ret;
-
-       ret = rmi_process_interrupt_requests(rmi_dev);
-       if (ret)
-               rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
-                       "Failed to process interrupt request: %d\n", ret);
-
-       return IRQ_HANDLED;
-}
-
-static int rmi_spi_init_irq(struct spi_device *spi)
-{
-       struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
-       int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq));
-       int ret;
-
-       if (!irq_flags)
-               irq_flags = IRQF_TRIGGER_LOW;
-
-       ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL,
-                       rmi_spi_irq, irq_flags | IRQF_ONESHOT,
-                       dev_name(&spi->dev), rmi_spi);
-       if (ret < 0) {
-               dev_warn(&spi->dev, "Failed to register interrupt %d\n",
-                       rmi_spi->irq);
-               return ret;
-       }
-
-       return 0;
-}
-
 #ifdef CONFIG_OF
 static int rmi_spi_of_probe(struct spi_device *spi,
                        struct rmi_device_platform_data *pdata)
@@ -440,8 +402,7 @@ static int rmi_spi_probe(struct spi_device *spi)
                return retval;
        }
 
-       if (spi->irq > 0)
-               rmi_spi->irq = spi->irq;
+       pdata->irq = spi->irq;
 
        rmi_spi->spi = spi;
        mutex_init(&rmi_spi->page_mutex);
@@ -477,10 +438,6 @@ static int rmi_spi_probe(struct spi_device *spi)
        if (retval)
                return retval;
 
-       retval = rmi_spi_init_irq(spi);
-       if (retval < 0)
-               return retval;
-
        dev_info(&spi->dev, "registered RMI SPI driver\n");
        return 0;
 }
@@ -492,17 +449,10 @@ static int rmi_spi_suspend(struct device *dev)
        struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
        int ret;
 
-       ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+       ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-       disable_irq(rmi_spi->irq);
-       if (device_may_wakeup(&spi->dev)) {
-               ret = enable_irq_wake(rmi_spi->irq);
-               if (!ret)
-                       dev_warn(dev, "Failed to enable irq for wake: %d\n",
-                               ret);
-       }
        return ret;
 }
 
@@ -512,15 +462,7 @@ static int rmi_spi_resume(struct device *dev)
        struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
        int ret;
 
-       enable_irq(rmi_spi->irq);
-       if (device_may_wakeup(&spi->dev)) {
-               ret = disable_irq_wake(rmi_spi->irq);
-               if (!ret)
-                       dev_warn(dev, "Failed to disable irq for wake: %d\n",
-                               ret);
-       }
-
-       ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+       ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
@@ -535,12 +477,10 @@ static int rmi_spi_runtime_suspend(struct device *dev)
        struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
        int ret;
 
-       ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+       ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-       disable_irq(rmi_spi->irq);
-
        return 0;
 }
 
@@ -550,9 +490,7 @@ static int rmi_spi_runtime_resume(struct device *dev)
        struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
        int ret;
 
-       enable_irq(rmi_spi->irq);
-
-       ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+       ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
index 073246c7d1634eef411c1bf07d7f72ab47cad369..73a4e68448fc57fef4a09f0ccaacf19c41790acf 100644 (file)
@@ -517,79 +517,7 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
        {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
                },
        },
        { }
@@ -1131,10 +1059,10 @@ static int __init i8042_pnp_init(void)
        return 0;
 }
 
-#else
+#else  /* !CONFIG_PNP */
 static inline int i8042_pnp_init(void) { return 0; }
 static inline void i8042_pnp_exit(void) { }
-#endif
+#endif /* CONFIG_PNP */
 
 static int __init i8042_platform_init(void)
 {
index 89abfdb539ac750ff50eca67f77b2fe6898ff6f0..62685a76891363b93d1d6a1d4db613fad814686b 100644 (file)
@@ -387,7 +387,7 @@ static int i8042_aux_write(struct serio *serio, unsigned char c)
 
 
 /*
- * i8042_aux_close attempts to clear AUX or KBD port state by disabling
+ * i8042_port_close attempts to clear AUX or KBD port state by disabling
  * and then re-enabling it.
  */
 
index fe9877a6af9e252b37e8b9955bd31b06b8c801b7..d50ee490c9ccacf653a3b04dbecbc43b0f78ec2e 100644 (file)
@@ -55,6 +55,7 @@ static const struct of_device_id mx25_tcq_ids[] = {
        { .compatible = "fsl,imx25-tcq", },
        { /* Sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, mx25_tcq_ids);
 
 #define TSC_4WIRE_PRE_INDEX 0
 #define TSC_4WIRE_X_INDEX 1
index 8275267eac25441f308e6103e82d48830d1feb71..7098e0a47019539b7cc3482fe3043576a123e348 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/log2.h>
 
 /* ADC configuration registers field define */
 #define ADC_AIEN               (0x1 << 7)
 #define ADC_CONV_DISABLE       0x1F
+#define ADC_AVGE               (0x1 << 5)
 #define ADC_CAL                        (0x1 << 7)
 #define ADC_CALF               0x2
 #define ADC_12BIT_MODE         (0x2 << 2)
+#define ADC_CONV_MODE_MASK     (0x3 << 2)
 #define ADC_IPG_CLK            0x00
+#define ADC_INPUT_CLK_MASK     0x3
 #define ADC_CLK_DIV_8          (0x03 << 5)
+#define ADC_CLK_DIV_MASK       (0x3 << 5)
 #define ADC_SHORT_SAMPLE_MODE  (0x0 << 4)
+#define ADC_SAMPLE_MODE_MASK   (0x1 << 4)
 #define ADC_HARDWARE_TRIGGER   (0x1 << 13)
+#define ADC_AVGS_SHIFT         14
+#define ADC_AVGS_MASK          (0x3 << 14)
 #define SELECT_CHANNEL_4       0x04
 #define SELECT_CHANNEL_1       0x01
 #define DISABLE_CONVERSION_INT (0x0 << 7)
@@ -84,8 +92,10 @@ struct imx6ul_tsc {
        struct clk *adc_clk;
        struct gpio_desc *xnur_gpio;
 
-       int measure_delay_time;
-       int pre_charge_time;
+       u32 measure_delay_time;
+       u32 pre_charge_time;
+       bool average_enable;
+       u32 average_select;
 
        struct completion completion;
 };
@@ -96,17 +106,23 @@ struct imx6ul_tsc {
  */
 static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
 {
-       int adc_hc = 0;
-       int adc_gc;
-       int adc_gs;
-       int adc_cfg;
-       int timeout;
+       u32 adc_hc = 0;
+       u32 adc_gc;
+       u32 adc_gs;
+       u32 adc_cfg;
+       unsigned long timeout;
 
        reinit_completion(&tsc->completion);
 
        adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
+       adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK);
        adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
+       adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
        adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
+       if (tsc->average_enable) {
+               adc_cfg &= ~ADC_AVGS_MASK;
+               adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT;
+       }
        adc_cfg &= ~ADC_HARDWARE_TRIGGER;
        writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
 
@@ -118,6 +134,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
        /* start ADC calibration */
        adc_gc = readl(tsc->adc_regs + REG_ADC_GC);
        adc_gc |= ADC_CAL;
+       if (tsc->average_enable)
+               adc_gc |= ADC_AVGE;
        writel(adc_gc, tsc->adc_regs + REG_ADC_GC);
 
        timeout = wait_for_completion_timeout
@@ -148,7 +166,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
  */
 static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
 {
-       int adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
+       u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
 
        adc_hc0 = DISABLE_CONVERSION_INT;
        writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
@@ -173,8 +191,8 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
  */
 static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
 {
-       int basic_setting = 0;
-       int start;
+       u32 basic_setting = 0;
+       u32 start;
 
        basic_setting |= tsc->measure_delay_time << 8;
        basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
@@ -209,8 +227,8 @@ static int imx6ul_tsc_init(struct imx6ul_tsc *tsc)
 
 static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
 {
-       int tsc_flow;
-       int adc_cfg;
+       u32 tsc_flow;
+       u32 adc_cfg;
 
        /* TSC controller enters to idle status */
        tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
@@ -227,8 +245,8 @@ static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
 static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(2);
-       int state_machine;
-       int debug_mode2;
+       u32 state_machine;
+       u32 debug_mode2;
 
        do {
                if (time_after(jiffies, timeout))
@@ -246,10 +264,10 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
 static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
 {
        struct imx6ul_tsc *tsc = dev_id;
-       int status;
-       int value;
-       int x, y;
-       int start;
+       u32 status;
+       u32 value;
+       u32 x, y;
+       u32 start;
 
        status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS);
 
@@ -289,8 +307,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
 static irqreturn_t adc_irq_fn(int irq, void *dev_id)
 {
        struct imx6ul_tsc *tsc = dev_id;
-       int coco;
-       int value;
+       u32 coco;
+       u32 value;
 
        coco = readl(tsc->adc_regs + REG_ADC_HS);
        if (coco & 0x01) {
@@ -346,6 +364,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
        int err;
        int tsc_irq;
        int adc_irq;
+       u32 average_samples;
 
        tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
        if (!tsc)
@@ -450,6 +469,30 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
        if (err)
                tsc->pre_charge_time = 0xfff;
 
+       err = of_property_read_u32(np, "touchscreen-average-samples",
+                                  &average_samples);
+       if (err)
+               average_samples = 1;
+
+       switch (average_samples) {
+       case 1:
+               tsc->average_enable = false;
+               tsc->average_select = 0; /* value unused; initialize anyway */
+               break;
+       case 4:
+       case 8:
+       case 16:
+       case 32:
+               tsc->average_enable = true;
+               tsc->average_select = ilog2(average_samples) - 2;
+               break;
+       default:
+               dev_err(&pdev->dev,
+                       "touchscreen-average-samples (%u) must be 1, 4, 8, 16 or 32\n",
+                       average_samples);
+               return -EINVAL;
+       }
+
        err = input_register_device(tsc->input);
        if (err) {
                dev_err(&pdev->dev,
index 552a3773f79d0b7815d6d180f7aabc9083ff6c92..703d7f983d0aff95bf451f9efba1564c05e5647f 100644 (file)
@@ -33,7 +33,7 @@
 
 /*****************************************************************
  * Protocol
- * Version : MIP 4.0 Rev 4.6
+ * Version : MIP 4.0 Rev 5.4
  *****************************************************************/
 
 /* Address */
@@ -81,6 +81,9 @@
 #define MIP4_R1_INFO_IC_HW_CATEGORY            0x77
 #define MIP4_R1_INFO_CONTACT_THD_SCR           0x78
 #define MIP4_R1_INFO_CONTACT_THD_KEY           0x7A
+#define MIP4_R1_INFO_PID                               0x7C
+#define MIP4_R1_INFO_VID                               0x7E
+#define MIP4_R1_INFO_SLAVE_ADDR                        0x80
 
 #define MIP4_R0_EVENT                          0x02
 #define MIP4_R1_EVENT_SUPPORTED_FUNC           0x00
@@ -157,7 +160,9 @@ struct mip4_ts {
 
        char phys[32];
        char product_name[16];
+       u16 product_id;
        char ic_name[4];
+       char fw_name[32];
 
        unsigned int max_x;
        unsigned int max_y;
@@ -264,6 +269,23 @@ static int mip4_query_device(struct mip4_ts *ts)
                dev_dbg(&ts->client->dev, "product name: %.*s\n",
                        (int)sizeof(ts->product_name), ts->product_name);
 
+       /* Product ID */
+       cmd[0] = MIP4_R0_INFO;
+       cmd[1] = MIP4_R1_INFO_PID;
+       error = mip4_i2c_xfer(ts, cmd, sizeof(cmd), buf, 2);
+       if (error) {
+               dev_warn(&ts->client->dev,
+                        "Failed to retrieve product id: %d\n", error);
+       } else {
+               ts->product_id = get_unaligned_le16(&buf[0]);
+               dev_dbg(&ts->client->dev, "product id: %04X\n", ts->product_id);
+       }
+
+       /* Firmware name */
+       snprintf(ts->fw_name, sizeof(ts->fw_name),
+               "melfas_mip4_%04X.fw", ts->product_id);
+       dev_dbg(&ts->client->dev, "firmware name: %s\n", ts->fw_name);
+
        /* IC name */
        cmd[0] = MIP4_R0_INFO;
        cmd[1] = MIP4_R1_INFO_IC_NAME;
@@ -1269,11 +1291,11 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev,
        const struct firmware *fw;
        int error;
 
-       error = request_firmware(&fw, MIP4_FW_NAME, dev);
+       error = request_firmware(&fw, ts->fw_name, dev);
        if (error) {
                dev_err(&ts->client->dev,
                        "Failed to retrieve firmware %s: %d\n",
-                       MIP4_FW_NAME, error);
+                       ts->fw_name, error);
                return error;
        }
 
@@ -1348,6 +1370,25 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
 
 static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL);
 
+static ssize_t mip4_sysfs_read_product_id(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;
+
+       mutex_lock(&ts->input->mutex);
+
+       count = snprintf(buf, PAGE_SIZE, "%04X\n", ts->product_id);
+
+       mutex_unlock(&ts->input->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(product_id, S_IRUGO, mip4_sysfs_read_product_id, NULL);
+
 static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
@@ -1371,6 +1412,7 @@ static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL);
 static struct attribute *mip4_attrs[] = {
        &dev_attr_fw_version.attr,
        &dev_attr_hw_version.attr,
+       &dev_attr_product_id.attr,
        &dev_attr_ic_name.attr,
        &dev_attr_update_fw.attr,
        NULL,
@@ -1435,6 +1477,7 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        input->id.bustype = BUS_I2C;
        input->id.vendor = 0x13c5;
+       input->id.product = ts->product_id;
 
        input->open = mip4_input_open;
        input->close = mip4_input_close;
@@ -1572,6 +1615,6 @@ static struct i2c_driver mip4_driver = {
 module_i2c_driver(mip4_driver);
 
 MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
-MODULE_VERSION("2016.09.28");
+MODULE_VERSION("2016.10.31");
 MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
 MODULE_LICENSE("GPL");
index a99fb5cac5a0e189c20360aaba33c6c2ab1ad25f..2658afa016c94a88bc04489772a183e6e687c2e5 100644 (file)
@@ -669,7 +669,7 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts,
 
                if (ts->boot_mode == RAYDIUM_TS_MAIN) {
                        dev_err(&client->dev,
-                               "failied to jump to boot loader: %d\n",
+                               "failed to jump to boot loader: %d\n",
                                error);
                        return -EIO;
                }
index f502c8488be86361592187acdffdecb164c4dfbd..404830a4a36630822aaa29aa7bcec77fdcd6bc3b 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/input/touchscreen.h>
 #include <linux/pm.h>
 #include <linux/irq.h>
+#include <linux/regulator/consumer.h>
 
 #include <asm/unaligned.h>
 
@@ -73,6 +74,7 @@ struct silead_ts_data {
        struct i2c_client *client;
        struct gpio_desc *gpio_power;
        struct input_dev *input;
+       struct regulator_bulk_data regulators[2];
        char fw_name[64];
        struct touchscreen_properties prop;
        u32 max_fingers;
@@ -433,6 +435,13 @@ static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
 }
 #endif
 
+static void silead_disable_regulator(void *arg)
+{
+       struct silead_ts_data *data = arg;
+
+       regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
+}
+
 static int silead_ts_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
@@ -465,6 +474,26 @@ static int silead_ts_probe(struct i2c_client *client,
        if (client->irq <= 0)
                return -ENODEV;
 
+       data->regulators[0].supply = "vddio";
+       data->regulators[1].supply = "avdd";
+       error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
+                                       data->regulators);
+       if (error)
+               return error;
+
+       /*
+        * Enable regulators at probe and disable them at remove, we need
+        * to keep the chip powered otherwise it forgets its firmware.
+        */
+       error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+                                     data->regulators);
+       if (error)
+               return error;
+
+       error = devm_add_action_or_reset(dev, silead_disable_regulator, data);
+       if (error)
+               return error;
+
        /* Power GPIO pin */
        data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
        if (IS_ERR(data->gpio_power)) {
index aecec6d3246370004a0e9434a1f58303e96b7c46..11e13c56126fba31fca9c59d66252ffeced55c8a 100644 (file)
@@ -2565,22 +2565,22 @@ static int gigaset_post_reset(struct usb_interface *intf)
 
 
 static const struct gigaset_ops gigops = {
-       gigaset_write_cmd,
-       gigaset_write_room,
-       gigaset_chars_in_buffer,
-       gigaset_brkchars,
-       gigaset_init_bchannel,
-       gigaset_close_bchannel,
-       gigaset_initbcshw,
-       gigaset_freebcshw,
-       gigaset_reinitbcshw,
-       gigaset_initcshw,
-       gigaset_freecshw,
-       gigaset_set_modem_ctrl,
-       gigaset_baud_rate,
-       gigaset_set_line_ctrl,
-       gigaset_isoc_send_skb,
-       gigaset_isoc_input,
+       .write_cmd = gigaset_write_cmd,
+       .write_room = gigaset_write_room,
+       .chars_in_buffer = gigaset_chars_in_buffer,
+       .brkchars = gigaset_brkchars,
+       .init_bchannel = gigaset_init_bchannel,
+       .close_bchannel = gigaset_close_bchannel,
+       .initbcshw = gigaset_initbcshw,
+       .freebcshw = gigaset_freebcshw,
+       .reinitbcshw = gigaset_reinitbcshw,
+       .initcshw = gigaset_initcshw,
+       .freecshw = gigaset_freecshw,
+       .set_modem_ctrl = gigaset_set_modem_ctrl,
+       .baud_rate = gigaset_baud_rate,
+       .set_line_ctrl = gigaset_set_line_ctrl,
+       .send_skb = gigaset_isoc_send_skb,
+       .handle_input = gigaset_isoc_input,
 };
 
 /* bas_gigaset_init
index b90776ef56ec8d2d35e8b51a79f75c2ecd472ab1..ab0b63a4d045f0b8b84c80daddc746a118596d5d 100644 (file)
@@ -445,22 +445,22 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
 }
 
 static const struct gigaset_ops ops = {
-       gigaset_write_cmd,
-       gigaset_write_room,
-       gigaset_chars_in_buffer,
-       gigaset_brkchars,
-       gigaset_init_bchannel,
-       gigaset_close_bchannel,
-       gigaset_initbcshw,
-       gigaset_freebcshw,
-       gigaset_reinitbcshw,
-       gigaset_initcshw,
-       gigaset_freecshw,
-       gigaset_set_modem_ctrl,
-       gigaset_baud_rate,
-       gigaset_set_line_ctrl,
-       gigaset_m10x_send_skb,  /* asyncdata.c */
-       gigaset_m10x_input,     /* asyncdata.c */
+       .write_cmd = gigaset_write_cmd,
+       .write_room = gigaset_write_room,
+       .chars_in_buffer = gigaset_chars_in_buffer,
+       .brkchars = gigaset_brkchars,
+       .init_bchannel = gigaset_init_bchannel,
+       .close_bchannel = gigaset_close_bchannel,
+       .initbcshw = gigaset_initbcshw,
+       .freebcshw = gigaset_freebcshw,
+       .reinitbcshw = gigaset_reinitbcshw,
+       .initcshw = gigaset_initcshw,
+       .freecshw = gigaset_freecshw,
+       .set_modem_ctrl = gigaset_set_modem_ctrl,
+       .baud_rate = gigaset_baud_rate,
+       .set_line_ctrl = gigaset_set_line_ctrl,
+       .send_skb = gigaset_m10x_send_skb,      /* asyncdata.c */
+       .handle_input = gigaset_m10x_input,     /* asyncdata.c */
 };
 
 
index 5f306e2eece5e2a93c1dd86ac8eb29ab59a33e06..eade36dafa3408f192b618cd1c52323235ed2d34 100644 (file)
@@ -862,22 +862,22 @@ static int gigaset_pre_reset(struct usb_interface *intf)
 }
 
 static const struct gigaset_ops ops = {
-       gigaset_write_cmd,
-       gigaset_write_room,
-       gigaset_chars_in_buffer,
-       gigaset_brkchars,
-       gigaset_init_bchannel,
-       gigaset_close_bchannel,
-       gigaset_initbcshw,
-       gigaset_freebcshw,
-       gigaset_reinitbcshw,
-       gigaset_initcshw,
-       gigaset_freecshw,
-       gigaset_set_modem_ctrl,
-       gigaset_baud_rate,
-       gigaset_set_line_ctrl,
-       gigaset_m10x_send_skb,
-       gigaset_m10x_input,
+       .write_cmd = gigaset_write_cmd,
+       .write_room = gigaset_write_room,
+       .chars_in_buffer = gigaset_chars_in_buffer,
+       .brkchars = gigaset_brkchars,
+       .init_bchannel = gigaset_init_bchannel,
+       .close_bchannel = gigaset_close_bchannel,
+       .initbcshw = gigaset_initbcshw,
+       .freebcshw = gigaset_freebcshw,
+       .reinitbcshw = gigaset_reinitbcshw,
+       .initcshw = gigaset_initcshw,
+       .freecshw = gigaset_freecshw,
+       .set_modem_ctrl = gigaset_set_modem_ctrl,
+       .baud_rate = gigaset_baud_rate,
+       .set_line_ctrl = gigaset_set_line_ctrl,
+       .send_skb = gigaset_m10x_send_skb,
+       .handle_input = gigaset_m10x_input,
 };
 
 /*
index bf04d2a3cf4afe4614765b2b3d08d32ec77571a6..2d12c6ceeb89ae08bb6c100fd77320386010a043 100644 (file)
@@ -659,7 +659,7 @@ int jiftime(char *s, long mark)
 
 static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
 
-void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt,
                      va_list args)
 {
        /* if head == NULL the fmt contains the full info */
@@ -669,23 +669,24 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
        u_char          *p;
        isdn_ctrl       ic;
        int             len;
+       const u_char    *data;
 
        if (!cs) {
                printk(KERN_WARNING "HiSax: No CardStatus for message");
                return;
        }
        spin_lock_irqsave(&cs->statlock, flags);
-       p = tmpbuf;
        if (head) {
+               p = tmpbuf;
                p += jiftime(p, jiffies);
                p += sprintf(p, " %s", head);
                p += vsprintf(p, fmt, args);
                *p++ = '\n';
                *p = 0;
                len = p - tmpbuf;
-               p = tmpbuf;
+               data = tmpbuf;
        } else {
-               p = fmt;
+               data = fmt;
                len = strlen(fmt);
        }
        if (len > HISAX_STATUS_BUFSIZE) {
@@ -699,13 +700,12 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
        if (i >= len)
                i = len;
        len -= i;
-       memcpy(cs->status_write, p, i);
+       memcpy(cs->status_write, data, i);
        cs->status_write += i;
        if (cs->status_write > cs->status_end)
                cs->status_write = cs->status_buf;
-       p += i;
        if (len) {
-               memcpy(cs->status_write, p, len);
+               memcpy(cs->status_write, data + i, len);
                cs->status_write += len;
        }
 #ifdef KERNELSTACK_DEBUG
@@ -729,7 +729,7 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
        }
 }
 
-void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
+void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...)
 {
        va_list args;
 
index 6ead6314e6d25977e84902dba491da94610a96ae..338d0408b3778a87992825928a13106ebb18b9a4 100644 (file)
@@ -1288,9 +1288,9 @@ int jiftime(char *s, long mark);
 int HiSax_command(isdn_ctrl *ic);
 int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
 __printf(3, 4)
-void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
+void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...);
 __printf(3, 0)
-void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args);
 void HiSax_reportcard(int cardnr, int sel);
 int QuickHex(char *txt, u_char *p, int cnt);
 void LogFrame(struct IsdnCardState *cs, u_char *p, int size);
index 91d57304d4d312cdebc317fbe6320b21e232d892..336523ec077c9cbdbe8941f2e2e42596f7a74b73 100644 (file)
@@ -80,9 +80,9 @@ static int isdn_concap_dl_disconn_req(struct concap_proto *concap)
 }
 
 struct concap_device_ops isdn_concap_reliable_dl_dops = {
-       &isdn_concap_dl_data_req,
-       &isdn_concap_dl_connect_req,
-       &isdn_concap_dl_disconn_req
+       .data_req = &isdn_concap_dl_data_req,
+       .connect_req = &isdn_concap_dl_connect_req,
+       .disconn_req = &isdn_concap_dl_disconn_req
 };
 
 /* The following should better go into a dedicated source file such that
index 0c5d8de41b23ab513fd4e03c51f3c528e06e515d..ba60076e0b9510df45bfe45e24563e684c3a7c1e 100644 (file)
@@ -53,14 +53,14 @@ static int isdn_x25iface_disconn_ind(struct concap_proto *);
 
 
 static struct concap_proto_ops ix25_pops = {
-       &isdn_x25iface_proto_new,
-       &isdn_x25iface_proto_del,
-       &isdn_x25iface_proto_restart,
-       &isdn_x25iface_proto_close,
-       &isdn_x25iface_xmit,
-       &isdn_x25iface_receive,
-       &isdn_x25iface_connect_ind,
-       &isdn_x25iface_disconn_ind
+       .proto_new = &isdn_x25iface_proto_new,
+       .proto_del = &isdn_x25iface_proto_del,
+       .restart = &isdn_x25iface_proto_restart,
+       .close = &isdn_x25iface_proto_close,
+       .encap_and_xmit = &isdn_x25iface_xmit,
+       .data_ind = &isdn_x25iface_receive,
+       .connect_ind = &isdn_x25iface_connect_ind,
+       .disconn_ind = &isdn_x25iface_disconn_ind
 };
 
 /* error message helper function */
index 1ed0584f494e415d5529cdf28612c1e701b6e721..4ce3b6f118304048c0fb4d0db7c1d4da7463e8e7 100644 (file)
@@ -40,6 +40,22 @@ config MFD_ACT8945A
          linear regulators, along with a complete ActivePath battery
          charger.
 
+config MFD_SUN4I_GPADC
+       tristate "Allwinner sunxi platforms' GPADC MFD driver"
+       select MFD_CORE
+       select REGMAP_MMIO
+       select REGMAP_IRQ
+       depends on ARCH_SUNXI || COMPILE_TEST
+       help
+         Select this to get support for Allwinner SoCs (A10, A13 and A31) ADC.
+         This driver will only map the hardware interrupt and registers, you
+         have to select individual drivers based on this MFD to be able to use
+         the ADC or the thermal sensor. This will try to probe the ADC driver
+         sun4i-gpadc-iio and the hwmon driver iio_hwmon.
+
+         To compile this driver as a module, choose M here: the module will be
+         called sun4i-gpadc.
+
 config MFD_AS3711
        bool "AMS AS3711"
        select MFD_CORE
@@ -293,6 +309,7 @@ config MFD_DLN2
 
 config MFD_EXYNOS_LPASS
        tristate "Samsung Exynos SoC Low Power Audio Subsystem"
+       depends on ARCH_EXYNOS || COMPILE_TEST
        select MFD_CORE
        select REGMAP_MMIO
        help
@@ -563,7 +580,7 @@ config MFD_MAX14577
 config MFD_MAX77620
        bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support"
        depends on I2C=y
-       depends on OF
+       depends on OF || COMPILE_TEST
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -578,7 +595,7 @@ config MFD_MAX77620
 config MFD_MAX77686
        tristate "Maxim Semiconductor MAX77686/802 PMIC Support"
        depends on I2C
-       depends on OF
+       depends on OF || COMPILE_TEST
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -877,7 +894,8 @@ config MFD_RN5T618
        select MFD_CORE
        select REGMAP_I2C
        help
-         Say yes here to add support for the Ricoh RN5T567 or R5T618 PMIC.
+         Say yes here to add support for the Ricoh RN5T567,
+          RN5T618, RC5T619 PMIC.
          This driver provides common support for accessing the device,
          additional drivers must be enabled in order to use the
          functionality of the device.
@@ -951,7 +969,7 @@ config MFD_SMSC
 
 config ABX500_CORE
        bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
-       default y if ARCH_U300 || ARCH_U8500
+       default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST
        help
          Say yes here if you have the ABX500 Mixed Signal IC family
          chips. This core driver expose register access functions.
index 7bb5a50127cbb32bf3c2959705eafbb7c741a65b..dda4d4f73ad743b7cdde1f085dd494c0a1701656 100644 (file)
@@ -211,3 +211,4 @@ obj-$(CONFIG_INTEL_SOC_PMIC)        += intel-soc-pmic.o
 obj-$(CONFIG_MFD_MT6397)       += mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
+obj-$(CONFIG_MFD_SUN4I_GPADC)  += sun4i-gpadc.o
index 6a5a98806cb817a28c782117a2a171c6975525a5..099635bed18850a7efc4e781688cee434e48e04a 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/notifier.h>
 #include <linux/slab.h>
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
@@ -628,20 +628,10 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100)
  exit_no_debugfs:
        return;
 }
-static inline void ab3100_remove_debugfs(void)
-{
-       debugfs_remove(ab3100_set_reg_file);
-       debugfs_remove(ab3100_get_reg_file);
-       debugfs_remove(ab3100_reg_file);
-       debugfs_remove(ab3100_dir);
-}
 #else
 static inline void ab3100_setup_debugfs(struct ab3100 *ab3100)
 {
 }
-static inline void ab3100_remove_debugfs(void)
-{
-}
 #endif
 
 /*
@@ -949,45 +939,22 @@ static int ab3100_probe(struct i2c_client *client,
        return err;
 }
 
-static int ab3100_remove(struct i2c_client *client)
-{
-       struct ab3100 *ab3100 = i2c_get_clientdata(client);
-
-       /* Unregister subdevices */
-       mfd_remove_devices(&client->dev);
-       ab3100_remove_debugfs();
-       i2c_unregister_device(ab3100->testreg_client);
-       return 0;
-}
-
 static const struct i2c_device_id ab3100_id[] = {
        { "ab3100", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(i2c, ab3100_id);
 
 static struct i2c_driver ab3100_driver = {
        .driver = {
-               .name   = "ab3100",
+               .name                   = "ab3100",
+               .suppress_bind_attrs    = true,
        },
        .id_table       = ab3100_id,
        .probe          = ab3100_probe,
-       .remove         = ab3100_remove,
 };
 
 static int __init ab3100_i2c_init(void)
 {
        return i2c_add_driver(&ab3100_driver);
 }
-
-static void __exit ab3100_i2c_exit(void)
-{
-       i2c_del_driver(&ab3100_driver);
-}
-
 subsys_initcall(ab3100_i2c_init);
-module_exit(ab3100_i2c_exit);
-
-MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
-MODULE_DESCRIPTION("AB3100 core driver");
-MODULE_LICENSE("GPL");
index 589eebfc13df9faf8ef5fed5c993e428a5a5ccf9..6e00124cef01a0772f24c4c5d880ec3f66332ef2 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/irqdomain.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
@@ -123,6 +123,10 @@ static DEFINE_SPINLOCK(on_stat_lock);
 static u8 turn_on_stat_mask = 0xFF;
 static u8 turn_on_stat_set;
 static bool no_bm; /* No battery management */
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
 module_param(no_bm, bool, S_IRUGO);
 
 #define AB9540_MODEM_CTRL2_REG                 0x23
@@ -1324,25 +1328,6 @@ static int ab8500_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int ab8500_remove(struct platform_device *pdev)
-{
-       struct ab8500 *ab8500 = platform_get_drvdata(pdev);
-
-       if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
-                       ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
-               sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
-       else
-               sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
-
-       if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
-                       ab8500->chip_id >= AB8500_CUT2P0)
-               sysfs_remove_group(&ab8500->dev->kobj, &ab8505_attr_group);
-
-       mfd_remove_devices(ab8500->dev);
-
-       return 0;
-}
-
 static const struct platform_device_id ab8500_id[] = {
        { "ab8500-core", AB8500_VERSION_AB8500 },
        { "ab8505-i2c", AB8500_VERSION_AB8505 },
@@ -1354,9 +1339,9 @@ static const struct platform_device_id ab8500_id[] = {
 static struct platform_driver ab8500_core_driver = {
        .driver = {
                .name = "ab8500-core",
+               .suppress_bind_attrs = true,
        },
        .probe  = ab8500_probe,
-       .remove = ab8500_remove,
        .id_table = ab8500_id,
 };
 
@@ -1364,14 +1349,4 @@ static int __init ab8500_core_init(void)
 {
        return platform_driver_register(&ab8500_core_driver);
 }
-
-static void __exit ab8500_core_exit(void)
-{
-       platform_driver_unregister(&ab8500_core_driver);
-}
 core_initcall(ab8500_core_init);
-module_exit(ab8500_core_exit);
-
-MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
-MODULE_DESCRIPTION("AB8500 MFD core");
-MODULE_LICENSE("GPL v2");
index acf6c00b14b92c3bfb8f990df5778e5267c281ad..c1c815241e028375e3820e861251a8288bac730d 100644 (file)
@@ -74,7 +74,7 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/debugfs.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
@@ -3234,33 +3234,16 @@ err:
        return -ENOMEM;
 }
 
-static int ab8500_debug_remove(struct platform_device *plf)
-{
-       debugfs_remove_recursive(ab8500_dir);
-
-       return 0;
-}
-
 static struct platform_driver ab8500_debug_driver = {
        .driver = {
                .name = "ab8500-debug",
+               .suppress_bind_attrs = true,
        },
        .probe  = ab8500_debug_probe,
-       .remove = ab8500_debug_remove
 };
 
 static int __init ab8500_debug_init(void)
 {
        return platform_driver_register(&ab8500_debug_driver);
 }
-
-static void __exit ab8500_debug_exit(void)
-{
-       platform_driver_unregister(&ab8500_debug_driver);
-}
 subsys_initcall(ab8500_debug_init);
-module_exit(ab8500_debug_exit);
-
-MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
-MODULE_DESCRIPTION("AB8500 DEBUG");
-MODULE_LICENSE("GPL v2");
index 97dcadc8fa8bfd898c16f788851f6b43a06b979e..f4e94869d6129a60d1da63cd851cbf0183ceb8fd 100644 (file)
@@ -5,9 +5,9 @@
  * Author: Arun R Murthy <arun.murthy@stericsson.com>
  * Author: Daniel Willerud <daniel.willerud@stericsson.com>
  * Author: Johan Palsson <johan.palsson@stericsson.com>
+ * Author: M'boumba Cedric Madianga
  */
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
@@ -1054,11 +1054,7 @@ static int __init ab8500_gpadc_init(void)
 {
        return platform_driver_register(&ab8500_gpadc_driver);
 }
-
-static void __exit ab8500_gpadc_exit(void)
-{
-       platform_driver_unregister(&ab8500_gpadc_driver);
-}
+subsys_initcall_sync(ab8500_gpadc_init);
 
 /**
  * ab8540_gpadc_get_otp() - returns OTP values
@@ -1077,14 +1073,3 @@ void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
        *ibat_l  = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo;
        *ibat_h  = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi;
 }
-
-subsys_initcall_sync(ab8500_gpadc_init);
-module_exit(ab8500_gpadc_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Arun R Murthy");
-MODULE_AUTHOR("Daniel Willerud");
-MODULE_AUTHOR("Johan Palsson");
-MODULE_AUTHOR("M'boumba Cedric Madianga");
-MODULE_ALIAS("platform:ab8500_gpadc");
-MODULE_DESCRIPTION("AB8500 GPADC driver");
index 207cc497958a855c0abe012bbee749dfac650f93..80c0efa66ac13d1e5485cd9cee9461d79b43e594 100644 (file)
@@ -1,11 +1,14 @@
 /*
+ * AB8500 system control driver
+ *
  * Copyright (C) ST-Ericsson SA 2010
  * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
  * License terms: GNU General Public License (GPL) version 2
  */
 
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/reboot.h>
@@ -158,7 +161,3 @@ static int __init ab8500_sysctrl_init(void)
        return platform_driver_register(&ab8500_sysctrl_driver);
 }
 arch_initcall(ab8500_sysctrl_init);
-
-MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com");
-MODULE_DESCRIPTION("AB8500 system control driver");
-MODULE_LICENSE("GPL v2");
index fe418995108c6f75ea23908d97e8e6cefd6ecefe..0d3846a4767cba7479f68d7ab4badded7bb3019b 100644 (file)
@@ -8,7 +8,8 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/mfd/abx500.h>
 
 static LIST_HEAD(abx500_list);
@@ -150,7 +151,3 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
                return -ENOTSUPP;
 }
 EXPORT_SYMBOL(abx500_startup_irq_enabled);
-
-MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
-MODULE_DESCRIPTION("ABX500 core driver");
-MODULE_LICENSE("GPL");
index 41767f7239bbec98916da2de1ea1924b1b3beeba..b6d4bc63c42624388efc230355b2f0a0fd192f92 100644 (file)
@@ -1553,6 +1553,7 @@ EXPORT_SYMBOL_GPL(arizona_dev_init);
 
 int arizona_dev_exit(struct arizona *arizona)
 {
+       disable_irq(arizona->irq);
        pm_runtime_disable(arizona->dev);
 
        regulator_disable(arizona->dcvdd);
index 5e18d3c77582b02050da45db97ee87fc1777bab9..2e01975f042d5f63d0a29cdccb0000d0d1f358ad 100644 (file)
@@ -398,10 +398,10 @@ err_ctrlif:
 err_boot_done:
        free_irq(arizona->irq, arizona);
 err_main_irq:
-       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
+       regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1),
                            arizona->irq_chip);
 err_aod:
-       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
+       regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0),
                            arizona->aod_irq_chip);
 err:
        return ret;
@@ -413,9 +413,9 @@ int arizona_irq_exit(struct arizona *arizona)
                free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR),
                         arizona);
        free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
-       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
+       regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1),
                            arizona->irq_chip);
-       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
+       regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0),
                            arizona->aod_irq_chip);
        free_irq(arizona->irq, arizona);
 
index b1b865822c07e854050354d5c18b9010edeca6ca..d35a5fe6c950299787def746155a6c3fa61a99bc 100644 (file)
@@ -69,10 +69,11 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
 
-/*
- * This is useless for OF-enabled devices, but it is needed by I2C subsystem
- */
 static const struct i2c_device_id axp20x_i2c_id[] = {
+       { "axp152", 0 },
+       { "axp202", 0 },
+       { "axp209", 0 },
+       { "axp221", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
index ba130be32e61363bef79298e5aa90c46bf8fb915..ed918de84238c33d83c9f60f26db069bec14a82d 100644 (file)
@@ -98,6 +98,7 @@ static const struct regmap_range axp22x_volatile_ranges[] = {
        regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_PWR_OP_MODE),
        regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
        regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
+       regmap_reg_range(AXP22X_PMIC_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
        regmap_reg_range(AXP20X_FG_RES, AXP20X_FG_RES),
 };
 
@@ -135,6 +136,7 @@ static const struct regmap_range axp806_writeable_ranges[] = {
        regmap_reg_range(AXP806_PWR_OUT_CTRL1, AXP806_CLDO3_V_CTRL),
        regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ2_EN),
        regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
+       regmap_reg_range(AXP806_REG_ADDR_EXT, AXP806_REG_ADDR_EXT),
 };
 
 static const struct regmap_range axp806_volatile_ranges[] = {
@@ -305,7 +307,7 @@ static const struct regmap_config axp806_regmap_config = {
        .val_bits       = 8,
        .wr_table       = &axp806_writeable_table,
        .volatile_table = &axp806_volatile_table,
-       .max_register   = AXP806_VREF_TEMP_WARN_L,
+       .max_register   = AXP806_REG_ADDR_EXT,
        .cache_type     = REGCACHE_RBTREE,
 };
 
index 0d76d690176b4efd46c04246a5ccfff0a223b0c0..c572a35a934136f1c23190a2f58f5fc1bb9a8192 100644 (file)
@@ -67,7 +67,7 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri,
        /* Secondary I2C slave address is the base address with A(2) asserted */
        bcm590xx->i2c_sec = i2c_new_dummy(i2c_pri->adapter,
                                          i2c_pri->addr | BIT(2));
-       if (IS_ERR_OR_NULL(bcm590xx->i2c_sec)) {
+       if (!bcm590xx->i2c_sec) {
                dev_err(&i2c_pri->dev, "failed to add secondary I2C device\n");
                return -ENODEV;
        }
index f6b78aafdb557ac2f8f97b0b8392a0b682b528ad..c090974340ad38c2013fbf716f9be6576c960012 100644 (file)
@@ -292,6 +292,7 @@ static const struct reg_default cs47l24_reg_default[] = {
        { 0x00000502, 0x0000 },    /* R1282  - AIF1 Rx Pin Ctrl */
        { 0x00000503, 0x0000 },    /* R1283  - AIF1 Rate Ctrl */
        { 0x00000504, 0x0000 },    /* R1284  - AIF1 Format */
+       { 0x00000505, 0x0040 },    /* R1285  - AIF1 Tx BCLK Rate */
        { 0x00000506, 0x0040 },    /* R1286  - AIF1 Rx BCLK Rate */
        { 0x00000507, 0x1818 },    /* R1287  - AIF1 Frame Ctrl 1 */
        { 0x00000508, 0x1818 },    /* R1288  - AIF1 Frame Ctrl 2 */
@@ -318,6 +319,7 @@ static const struct reg_default cs47l24_reg_default[] = {
        { 0x00000542, 0x0000 },    /* R1346  - AIF2 Rx Pin Ctrl */
        { 0x00000543, 0x0000 },    /* R1347  - AIF2 Rate Ctrl */
        { 0x00000544, 0x0000 },    /* R1348  - AIF2 Format */
+       { 0x00000545, 0x0040 },    /* R1349  - AIF2 Tx BCLK Rate */
        { 0x00000546, 0x0040 },    /* R1350  - AIF2 Rx BCLK Rate */
        { 0x00000547, 0x1818 },    /* R1351  - AIF2 Frame Ctrl 1 */
        { 0x00000548, 0x1818 },    /* R1352  - AIF2 Frame Ctrl 2 */
@@ -340,6 +342,7 @@ static const struct reg_default cs47l24_reg_default[] = {
        { 0x00000582, 0x0000 },    /* R1410  - AIF3 Rx Pin Ctrl */
        { 0x00000583, 0x0000 },    /* R1411  - AIF3 Rate Ctrl */
        { 0x00000584, 0x0000 },    /* R1412  - AIF3 Format */
+       { 0x00000585, 0x0040 },    /* R1413  - AIF3 Tx BCLK Rate */
        { 0x00000586, 0x0040 },    /* R1414  - AIF3 Rx BCLK Rate */
        { 0x00000587, 0x1818 },    /* R1415  - AIF3 Frame Ctrl 1 */
        { 0x00000588, 0x1818 },    /* R1416  - AIF3 Frame Ctrl 2 */
@@ -923,6 +926,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_AIF1_RX_PIN_CTRL:
        case ARIZONA_AIF1_RATE_CTRL:
        case ARIZONA_AIF1_FORMAT:
+       case ARIZONA_AIF1_TX_BCLK_RATE:
        case ARIZONA_AIF1_RX_BCLK_RATE:
        case ARIZONA_AIF1_FRAME_CTRL_1:
        case ARIZONA_AIF1_FRAME_CTRL_2:
@@ -949,6 +953,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_AIF2_RX_PIN_CTRL:
        case ARIZONA_AIF2_RATE_CTRL:
        case ARIZONA_AIF2_FORMAT:
+       case ARIZONA_AIF2_TX_BCLK_RATE:
        case ARIZONA_AIF2_RX_BCLK_RATE:
        case ARIZONA_AIF2_FRAME_CTRL_1:
        case ARIZONA_AIF2_FRAME_CTRL_2:
@@ -971,6 +976,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_AIF3_RX_PIN_CTRL:
        case ARIZONA_AIF3_RATE_CTRL:
        case ARIZONA_AIF3_FORMAT:
+       case ARIZONA_AIF3_TX_BCLK_RATE:
        case ARIZONA_AIF3_RX_BCLK_RATE:
        case ARIZONA_AIF3_FRAME_CTRL_1:
        case ARIZONA_AIF3_FRAME_CTRL_2:
index dff2f19296b881801a00afde363a53acf939b633..4d0a5f38038a75f893c20fb07e944dfc04375e29 100644 (file)
@@ -32,6 +32,7 @@
 #include <sound/pcm.h>
 
 #include <linux/mfd/davinci_voicecodec.h>
+#include <mach/hardware.h>
 
 static const struct regmap_config davinci_vc_regmap = {
        .reg_bits = 32,
index 77b2675cf8f5df53b035ae1f3a373b7cb50754b8..ac430a396a89945b0cad1542db8a11b68b497fa5 100644 (file)
@@ -187,6 +187,7 @@ static const struct of_device_id mx25_tsadc_ids[] = {
        { .compatible = "fsl,imx25-tsadc" },
        { /* Sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, mx25_tsadc_ids);
 
 static struct platform_driver mx25_tsadc_driver = {
        .driver = {
index 0fc62995695ba8e6912e85e62ac49a31a2cf8244..ba706adee38b551379e429f42b1de558d333c5b7 100644 (file)
@@ -169,6 +169,7 @@ static const struct of_device_id hi655x_pmic_match[] = {
        { .compatible = "hisilicon,hi655x-pmic", },
        {},
 };
+MODULE_DEVICE_TABLE(of, hi655x_pmic_match);
 
 static struct platform_driver hi655x_pmic_driver = {
        .driver = {
index 9ff243970e93ef1c025df40ca3e4474f59c371f5..78dbcf8b0befc90dea990644f24bf7b32e1c035e 100644 (file)
@@ -41,6 +41,7 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev,
 
        /* Probably it is enough to set this for iDMA capable devices only */
        pci_set_master(pdev);
+       pci_try_set_mwi(pdev);
 
        ret = intel_lpss_probe(&pdev->dev, info);
        if (ret)
index f9a8c5203873a2f8b6ac4a68e5582eddd69b3103..699c8c7c90528759c673192d14d804d9c46db89a 100644 (file)
@@ -42,6 +42,7 @@
 #define BXTWC_GPIOIRQ0         0x4E0B
 #define BXTWC_GPIOIRQ1         0x4E0C
 #define BXTWC_CRITIRQ          0x4E0D
+#define BXTWC_TMUIRQ           0x4FB6
 
 /* Interrupt MASK Registers */
 #define BXTWC_MIRQLVL1         0x4E0E
@@ -59,6 +60,7 @@
 #define BXTWC_MGPIO0IRQ                0x4E19
 #define BXTWC_MGPIO1IRQ                0x4E1A
 #define BXTWC_MCRITIRQ         0x4E1B
+#define BXTWC_MTMUIRQ          0x4FB7
 
 /* Whiskey Cove PMIC share same ACPI ID between different platforms */
 #define BROXTON_PMIC_WC_HRV    4
@@ -92,6 +94,7 @@ enum bxtwc_irqs_level2 {
        BXTWC_GPIO0_IRQ,
        BXTWC_GPIO1_IRQ,
        BXTWC_CRIT_IRQ,
+       BXTWC_TMU_IRQ,
 };
 
 static const struct regmap_irq bxtwc_regmap_irqs[] = {
@@ -120,6 +123,10 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
        REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03),
 };
 
+static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = {
+       REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06),
+};
+
 static struct regmap_irq_chip bxtwc_regmap_irq_chip = {
        .name = "bxtwc_irq_chip",
        .status_base = BXTWC_IRQLVL1,
@@ -138,6 +145,15 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = {
        .num_regs = 10,
 };
 
+static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = {
+       .name = "bxtwc_irq_chip_tmu",
+       .status_base = BXTWC_TMUIRQ,
+       .mask_base = BXTWC_MTMUIRQ,
+       .irqs = bxtwc_regmap_irqs_tmu,
+       .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu),
+       .num_regs = 1,
+};
+
 static struct resource gpio_resources[] = {
        DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"),
        DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"),
@@ -166,6 +182,10 @@ static struct resource bcu_resources[] = {
        DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"),
 };
 
+static struct resource tmu_resources[] = {
+       DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"),
+};
+
 static struct mfd_cell bxt_wc_dev[] = {
        {
                .name = "bxt_wcove_gpadc",
@@ -192,6 +212,12 @@ static struct mfd_cell bxt_wc_dev[] = {
                .num_resources = ARRAY_SIZE(bcu_resources),
                .resources = bcu_resources,
        },
+       {
+               .name = "bxt_wcove_tmu",
+               .num_resources = ARRAY_SIZE(tmu_resources),
+               .resources = tmu_resources,
+       },
+
        {
                .name = "bxt_wcove_gpio",
                .num_resources = ARRAY_SIZE(gpio_resources),
@@ -402,6 +428,15 @@ static int bxtwc_probe(struct platform_device *pdev)
                goto err_irq_chip_level2;
        }
 
+       ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
+                                 IRQF_ONESHOT | IRQF_SHARED,
+                                 0, &bxtwc_regmap_irq_chip_tmu,
+                                 &pmic->irq_chip_data_tmu);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n");
+               goto err_irq_chip_tmu;
+       }
+
        ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev,
                              ARRAY_SIZE(bxt_wc_dev), NULL, 0,
                              NULL);
@@ -431,6 +466,8 @@ static int bxtwc_probe(struct platform_device *pdev)
 err_sysfs:
        mfd_remove_devices(&pdev->dev);
 err_mfd:
+       regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
+err_irq_chip_tmu:
        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
 err_irq_chip_level2:
        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
@@ -446,6 +483,7 @@ static int bxtwc_remove(struct platform_device *pdev)
        mfd_remove_devices(&pdev->dev);
        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
+       regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
 
        return 0;
 }
@@ -481,7 +519,7 @@ static const struct acpi_device_id bxtwc_acpi_ids[] = {
        { "INT34D3", },
        { }
 };
-MODULE_DEVICE_TABLE(acpi, pmic_acpi_ids);
+MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids);
 
 static struct platform_driver bxtwc_driver = {
        .probe = bxtwc_probe,
index c8dee47b45d96f6e4aca9862cfaad7555de41082..1ef7575547e69d715972685fa46bdf10eb91f619 100644 (file)
@@ -493,6 +493,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
        [LPC_LPT] = {
                .name = "Lynx Point",
                .iTCO_version = 2,
+               .gpio_version = ICH_V5_GPIO,
        },
        [LPC_LPT_LP] = {
                .name = "Lynx Point_LP",
@@ -530,6 +531,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
        [LPC_9S] = {
                .name = "9 Series",
                .iTCO_version = 2,
+               .gpio_version = ICH_V5_GPIO,
        },
 };
 
index 8f8bacb67a15a4608de39efa80f30a0f7a550d02..ee9e9ea104447a47c7fd222a61e9f78d098bc121 100644 (file)
@@ -431,9 +431,6 @@ static void palmas_power_off(void)
        unsigned int addr;
        int ret, slave;
 
-       if (!palmas_dev)
-               return;
-
        slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
        addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL);
 
index 7f9620ec61e8f28f6954273c687f19e233d3c3d7..f08758f6b418f02fc1772770d321e9770b9d9435 100644 (file)
 #define        SSBI_REG_ADDR_IRQ_CONFIG        (SSBI_REG_ADDR_IRQ_BASE + 7)
 #define        SSBI_REG_ADDR_IRQ_RT_STATUS     (SSBI_REG_ADDR_IRQ_BASE + 8)
 
+#define        PM8821_SSBI_REG_ADDR_IRQ_BASE   0x100
+#define        PM8821_SSBI_REG_ADDR_IRQ_MASTER0 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0x30)
+#define        PM8821_SSBI_REG_ADDR_IRQ_MASTER1 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0xb0)
+#define        PM8821_SSBI_REG(m, b, offset) \
+                       ((m == 0) ? \
+                       (PM8821_SSBI_REG_ADDR_IRQ_MASTER0 + b + offset) : \
+                       (PM8821_SSBI_REG_ADDR_IRQ_MASTER1 + b + offset))
+#define        PM8821_SSBI_ADDR_IRQ_ROOT(m, b)         PM8821_SSBI_REG(m, b, 0x0)
+#define        PM8821_SSBI_ADDR_IRQ_CLEAR(m, b)        PM8821_SSBI_REG(m, b, 0x01)
+#define        PM8821_SSBI_ADDR_IRQ_MASK(m, b)         PM8821_SSBI_REG(m, b, 0x08)
+#define        PM8821_SSBI_ADDR_IRQ_RT_STATUS(m, b)    PM8821_SSBI_REG(m, b, 0x0f)
+
+#define        PM8821_BLOCKS_PER_MASTER        7
+
 #define        PM_IRQF_LVL_SEL                 0x01    /* level select */
 #define        PM_IRQF_MASK_FE                 0x02    /* mask falling edge */
 #define        PM_IRQF_MASK_RE                 0x04    /* mask rising edge */
@@ -54,6 +68,7 @@
 #define REG_HWREV_2            0x0E8  /* PMIC4 revision 2 */
 
 #define PM8XXX_NR_IRQS         256
+#define PM8821_NR_IRQS         112
 
 struct pm_irq_chip {
        struct regmap           *regmap;
@@ -65,6 +80,12 @@ struct pm_irq_chip {
        u8                      config[0];
 };
 
+struct pm_irq_data {
+       int num_irqs;
+       const struct irq_domain_ops  *irq_domain_ops;
+       void (*irq_handler)(struct irq_desc *desc);
+};
+
 static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
                                 unsigned int *ip)
 {
@@ -182,6 +203,78 @@ static void pm8xxx_irq_handler(struct irq_desc *desc)
        chained_irq_exit(irq_chip, desc);
 }
 
+static void pm8821_irq_block_handler(struct pm_irq_chip *chip,
+                                    int master, int block)
+{
+       int pmirq, irq, i, ret;
+       unsigned int bits;
+
+       ret = regmap_read(chip->regmap,
+                         PM8821_SSBI_ADDR_IRQ_ROOT(master, block), &bits);
+       if (ret) {
+               pr_err("Reading block %d failed ret=%d", block, ret);
+               return;
+       }
+
+       /* Convert block offset to global block number */
+       block += (master * PM8821_BLOCKS_PER_MASTER) - 1;
+
+       /* Check IRQ bits */
+       for (i = 0; i < 8; i++) {
+               if (bits & BIT(i)) {
+                       pmirq = block * 8 + i;
+                       irq = irq_find_mapping(chip->irqdomain, pmirq);
+                       generic_handle_irq(irq);
+               }
+       }
+}
+
+static inline void pm8821_irq_master_handler(struct pm_irq_chip *chip,
+                                            int master, u8 master_val)
+{
+       int block;
+
+       for (block = 1; block < 8; block++)
+               if (master_val & BIT(block))
+                       pm8821_irq_block_handler(chip, master, block);
+}
+
+static void pm8821_irq_handler(struct irq_desc *desc)
+{
+       struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
+       struct irq_chip *irq_chip = irq_desc_get_chip(desc);
+       unsigned int master;
+       int ret;
+
+       chained_irq_enter(irq_chip, desc);
+       ret = regmap_read(chip->regmap,
+                         PM8821_SSBI_REG_ADDR_IRQ_MASTER0, &master);
+       if (ret) {
+               pr_err("Failed to read master 0 ret=%d\n", ret);
+               goto done;
+       }
+
+       /* bits 1 through 7 marks the first 7 blocks in master 0 */
+       if (master & GENMASK(7, 1))
+               pm8821_irq_master_handler(chip, 0, master);
+
+       /* bit 0 marks if master 1 contains any bits */
+       if (!(master & BIT(0)))
+               goto done;
+
+       ret = regmap_read(chip->regmap,
+                         PM8821_SSBI_REG_ADDR_IRQ_MASTER1, &master);
+       if (ret) {
+               pr_err("Failed to read master 1 ret=%d\n", ret);
+               goto done;
+       }
+
+       pm8821_irq_master_handler(chip, 1, master);
+
+done:
+       chained_irq_exit(irq_chip, desc);
+}
+
 static void pm8xxx_irq_mask_ack(struct irq_data *d)
 {
        struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
@@ -299,6 +392,104 @@ static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
        .map = pm8xxx_irq_domain_map,
 };
 
+static void pm8821_irq_mask_ack(struct irq_data *d)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = irqd_to_hwirq(d);
+       u8 block, master;
+       int irq_bit, rc;
+
+       block = pmirq / 8;
+       master = block / PM8821_BLOCKS_PER_MASTER;
+       irq_bit = pmirq % 8;
+       block %= PM8821_BLOCKS_PER_MASTER;
+
+       rc = regmap_update_bits(chip->regmap,
+                               PM8821_SSBI_ADDR_IRQ_MASK(master, block),
+                               BIT(irq_bit), BIT(irq_bit));
+       if (rc) {
+               pr_err("Failed to mask IRQ:%d rc=%d\n", pmirq, rc);
+               return;
+       }
+
+       rc = regmap_update_bits(chip->regmap,
+                               PM8821_SSBI_ADDR_IRQ_CLEAR(master, block),
+                               BIT(irq_bit), BIT(irq_bit));
+       if (rc)
+               pr_err("Failed to CLEAR IRQ:%d rc=%d\n", pmirq, rc);
+}
+
+static void pm8821_irq_unmask(struct irq_data *d)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = irqd_to_hwirq(d);
+       int irq_bit, rc;
+       u8 block, master;
+
+       block = pmirq / 8;
+       master = block / PM8821_BLOCKS_PER_MASTER;
+       irq_bit = pmirq % 8;
+       block %= PM8821_BLOCKS_PER_MASTER;
+
+       rc = regmap_update_bits(chip->regmap,
+                               PM8821_SSBI_ADDR_IRQ_MASK(master, block),
+                               BIT(irq_bit), ~BIT(irq_bit));
+       if (rc)
+               pr_err("Failed to read/write unmask IRQ:%d rc=%d\n", pmirq, rc);
+
+}
+
+static int pm8821_irq_get_irqchip_state(struct irq_data *d,
+                                       enum irqchip_irq_state which,
+                                       bool *state)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       int rc, pmirq = irqd_to_hwirq(d);
+       u8 block, irq_bit, master;
+       unsigned int bits;
+
+       block = pmirq / 8;
+       master = block / PM8821_BLOCKS_PER_MASTER;
+       irq_bit = pmirq % 8;
+       block %= PM8821_BLOCKS_PER_MASTER;
+
+       rc = regmap_read(chip->regmap,
+               PM8821_SSBI_ADDR_IRQ_RT_STATUS(master, block), &bits);
+       if (rc) {
+               pr_err("Reading Status of IRQ %d failed rc=%d\n", pmirq, rc);
+               return rc;
+       }
+
+       *state = !!(bits & BIT(irq_bit));
+
+       return rc;
+}
+
+static struct irq_chip pm8821_irq_chip = {
+       .name           = "pm8821",
+       .irq_mask_ack   = pm8821_irq_mask_ack,
+       .irq_unmask     = pm8821_irq_unmask,
+       .irq_get_irqchip_state = pm8821_irq_get_irqchip_state,
+       .flags          = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
+};
+
+static int pm8821_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                  irq_hw_number_t hwirq)
+{
+       struct pm_irq_chip *chip = d->host_data;
+
+       irq_set_chip_and_handler(irq, &pm8821_irq_chip, handle_level_irq);
+       irq_set_chip_data(irq, chip);
+       irq_set_noprobe(irq);
+
+       return 0;
+}
+
+static const struct irq_domain_ops pm8821_irq_domain_ops = {
+       .xlate = irq_domain_xlate_twocell,
+       .map = pm8821_irq_domain_map,
+};
+
 static const struct regmap_config ssbi_regmap_config = {
        .reg_bits = 16,
        .val_bits = 8,
@@ -308,22 +499,41 @@ static const struct regmap_config ssbi_regmap_config = {
        .reg_write = ssbi_reg_write
 };
 
+static const struct pm_irq_data pm8xxx_data = {
+       .num_irqs = PM8XXX_NR_IRQS,
+       .irq_domain_ops = &pm8xxx_irq_domain_ops,
+       .irq_handler = pm8xxx_irq_handler,
+};
+
+static const struct pm_irq_data pm8821_data = {
+       .num_irqs = PM8821_NR_IRQS,
+       .irq_domain_ops = &pm8821_irq_domain_ops,
+       .irq_handler = pm8821_irq_handler,
+};
+
 static const struct of_device_id pm8xxx_id_table[] = {
-       { .compatible = "qcom,pm8018", },
-       { .compatible = "qcom,pm8058", },
-       { .compatible = "qcom,pm8921", },
+       { .compatible = "qcom,pm8018", .data = &pm8xxx_data},
+       { .compatible = "qcom,pm8058", .data = &pm8xxx_data},
+       { .compatible = "qcom,pm8821", .data = &pm8821_data},
+       { .compatible = "qcom,pm8921", .data = &pm8xxx_data},
        { }
 };
 MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
 
 static int pm8xxx_probe(struct platform_device *pdev)
 {
+       const struct pm_irq_data *data;
        struct regmap *regmap;
        int irq, rc;
        unsigned int val;
        u32 rev;
        struct pm_irq_chip *chip;
-       unsigned int nirqs = PM8XXX_NR_IRQS;
+
+       data = of_device_get_match_data(&pdev->dev);
+       if (!data) {
+               dev_err(&pdev->dev, "No matching driver data found\n");
+               return -EINVAL;
+       }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
@@ -354,25 +564,26 @@ static int pm8xxx_probe(struct platform_device *pdev)
        rev |= val << BITS_PER_BYTE;
 
        chip = devm_kzalloc(&pdev->dev, sizeof(*chip) +
-                                       sizeof(chip->config[0]) * nirqs,
-                                       GFP_KERNEL);
+                           sizeof(chip->config[0]) * data->num_irqs,
+                           GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, chip);
        chip->regmap = regmap;
-       chip->num_irqs = nirqs;
+       chip->num_irqs = data->num_irqs;
        chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
        chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
        spin_lock_init(&chip->pm_irq_lock);
 
-       chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, nirqs,
-                                               &pm8xxx_irq_domain_ops,
+       chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
+                                               data->num_irqs,
+                                               data->irq_domain_ops,
                                                chip);
        if (!chip->irqdomain)
                return -ENODEV;
 
-       irq_set_chained_handler_and_data(irq, pm8xxx_irq_handler, chip);
+       irq_set_chained_handler_and_data(irq, data->irq_handler, chip);
        irq_set_irq_wake(irq, 1);
 
        rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
index 0f8acc5882a45261ffb5f90cffc23807d90b3412..2c9acdba7c2d36d5d5853bd3073a724d991e1426 100644 (file)
@@ -290,6 +290,24 @@ static void rk808_device_shutdown(void)
                dev_err(&rk808_i2c_client->dev, "power off error!\n");
 }
 
+static void rk818_device_shutdown(void)
+{
+       int ret;
+       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+
+       if (!rk808) {
+               dev_warn(&rk808_i2c_client->dev,
+                        "have no rk818, so do nothing here\n");
+               return;
+       }
+
+       ret = regmap_update_bits(rk808->regmap,
+                                RK818_DEVCTRL_REG,
+                                DEV_OFF, DEV_OFF);
+       if (ret)
+               dev_err(&rk808_i2c_client->dev, "power off error!\n");
+}
+
 static const struct of_device_id rk808_of_match[] = {
        { .compatible = "rockchip,rk808" },
        { .compatible = "rockchip,rk818" },
@@ -304,6 +322,7 @@ static int rk808_probe(struct i2c_client *client,
        struct rk808 *rk808;
        const struct rk808_reg_data *pre_init_reg;
        const struct mfd_cell *cells;
+       void (*pm_pwroff_fn)(void);
        int nr_pre_init_regs;
        int nr_cells;
        int pm_off = 0;
@@ -331,6 +350,7 @@ static int rk808_probe(struct i2c_client *client,
                nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
                cells = rk808s;
                nr_cells = ARRAY_SIZE(rk808s);
+               pm_pwroff_fn = rk808_device_shutdown;
                break;
        case RK818_ID:
                rk808->regmap_cfg = &rk818_regmap_config;
@@ -339,6 +359,7 @@ static int rk808_probe(struct i2c_client *client,
                nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
                cells = rk818s;
                nr_cells = ARRAY_SIZE(rk818s);
+               pm_pwroff_fn = rk818_device_shutdown;
                break;
        default:
                dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
@@ -393,7 +414,7 @@ static int rk808_probe(struct i2c_client *client,
                                "rockchip,system-power-controller");
        if (pm_off && !pm_power_off) {
                rk808_i2c_client = client;
-               pm_power_off = rk808_device_shutdown;
+               pm_power_off = pm_pwroff_fn;
        }
 
        return 0;
index ee94080e1cbb704a6106b97d63fffe74e64a5daa..8131d1975745ec51a6219979f517827508c65497 100644 (file)
@@ -87,6 +87,7 @@ static int rn5t618_restart(struct notifier_block *this,
 static const struct of_device_id rn5t618_of_match[] = {
        { .compatible = "ricoh,rn5t567", .data = (void *)RN5T567 },
        { .compatible = "ricoh,rn5t618", .data = (void *)RN5T618 },
+       { .compatible = "ricoh,rc5t619", .data = (void *)RC5T619 },
        { }
 };
 MODULE_DEVICE_TABLE(of, rn5t618_of_match);
index c180b7533bbad7e953db2ff4c627cf7102a5fb62..e6a3d999a376a68877933b6e3d7b8403e299e1d4 100644 (file)
@@ -753,7 +753,7 @@ static int si476x_core_probe(struct i2c_client *client,
                                       ARRAY_SIZE(core->supplies),
                                       core->supplies);
        if (rval) {
-               dev_err(&client->dev, "Failet to gett all of the regulators\n");
+               dev_err(&client->dev, "Failed to get all of the regulators\n");
                goto free_gpio;
        }
 
diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c
new file mode 100644 (file)
index 0000000..9cfc881
--- /dev/null
@@ -0,0 +1,181 @@
+/* ADC MFD core driver for sunxi platforms
+ *
+ * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/sun4i-gpadc.h>
+
+#define ARCH_SUN4I_A10 0
+#define ARCH_SUN5I_A13 1
+#define ARCH_SUN6I_A31 2
+
+static struct resource adc_resources[] = {
+       DEFINE_RES_IRQ_NAMED(SUN4I_GPADC_IRQ_FIFO_DATA, "FIFO_DATA_PENDING"),
+       DEFINE_RES_IRQ_NAMED(SUN4I_GPADC_IRQ_TEMP_DATA, "TEMP_DATA_PENDING"),
+};
+
+static const struct regmap_irq sun4i_gpadc_regmap_irq[] = {
+       REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_FIFO_DATA, 0,
+                      SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN),
+       REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_TEMP_DATA, 0,
+                      SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN),
+};
+
+static const struct regmap_irq_chip sun4i_gpadc_regmap_irq_chip = {
+       .name = "sun4i_gpadc_irq_chip",
+       .status_base = SUN4I_GPADC_INT_FIFOS,
+       .ack_base = SUN4I_GPADC_INT_FIFOS,
+       .mask_base = SUN4I_GPADC_INT_FIFOC,
+       .init_ack_masked = true,
+       .mask_invert = true,
+       .irqs = sun4i_gpadc_regmap_irq,
+       .num_irqs = ARRAY_SIZE(sun4i_gpadc_regmap_irq),
+       .num_regs = 1,
+};
+
+static struct mfd_cell sun4i_gpadc_cells[] = {
+       {
+               .name   = "sun4i-a10-gpadc-iio",
+               .resources = adc_resources,
+               .num_resources = ARRAY_SIZE(adc_resources),
+       },
+       { .name = "iio_hwmon" }
+};
+
+static struct mfd_cell sun5i_gpadc_cells[] = {
+       {
+               .name   = "sun5i-a13-gpadc-iio",
+               .resources = adc_resources,
+               .num_resources = ARRAY_SIZE(adc_resources),
+       },
+       { .name = "iio_hwmon" },
+};
+
+static struct mfd_cell sun6i_gpadc_cells[] = {
+       {
+               .name   = "sun6i-a31-gpadc-iio",
+               .resources = adc_resources,
+               .num_resources = ARRAY_SIZE(adc_resources),
+       },
+       { .name = "iio_hwmon" },
+};
+
+static const struct regmap_config sun4i_gpadc_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .fast_io = true,
+};
+
+static const struct of_device_id sun4i_gpadc_of_match[] = {
+       {
+               .compatible = "allwinner,sun4i-a10-ts",
+               .data = (void *)ARCH_SUN4I_A10,
+       }, {
+               .compatible = "allwinner,sun5i-a13-ts",
+               .data = (void *)ARCH_SUN5I_A13,
+       }, {
+               .compatible = "allwinner,sun6i-a31-ts",
+               .data = (void *)ARCH_SUN6I_A31,
+       }, { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_match);
+
+static int sun4i_gpadc_probe(struct platform_device *pdev)
+{
+       struct sun4i_gpadc_dev *dev;
+       struct resource *mem;
+       const struct of_device_id *of_id;
+       const struct mfd_cell *cells;
+       unsigned int irq, size;
+       int ret;
+
+       of_id = of_match_node(sun4i_gpadc_of_match, pdev->dev.of_node);
+       if (!of_id)
+               return -EINVAL;
+
+       switch ((long)of_id->data) {
+       case ARCH_SUN4I_A10:
+               cells = sun4i_gpadc_cells;
+               size = ARRAY_SIZE(sun4i_gpadc_cells);
+               break;
+       case ARCH_SUN5I_A13:
+               cells = sun5i_gpadc_cells;
+               size = ARRAY_SIZE(sun5i_gpadc_cells);
+               break;
+       case ARCH_SUN6I_A31:
+               cells = sun6i_gpadc_cells;
+               size = ARRAY_SIZE(sun6i_gpadc_cells);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(dev->base))
+               return PTR_ERR(dev->base);
+
+       dev->dev = &pdev->dev;
+       dev_set_drvdata(dev->dev, dev);
+
+       dev->regmap = devm_regmap_init_mmio(dev->dev, dev->base,
+                                           &sun4i_gpadc_regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               dev_err(&pdev->dev, "failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
+       /* Disable all interrupts */
+       regmap_write(dev->regmap, SUN4I_GPADC_INT_FIFOC, 0);
+
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_regmap_add_irq_chip(&pdev->dev, dev->regmap, irq,
+                                      IRQF_ONESHOT, 0,
+                                      &sun4i_gpadc_regmap_irq_chip,
+                                      &dev->regmap_irqc);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add irq chip: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_mfd_add_devices(dev->dev, 0, cells, size, NULL, 0, NULL);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add MFD devices: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct platform_driver sun4i_gpadc_driver = {
+       .driver = {
+               .name = "sun4i-gpadc",
+               .of_match_table = of_match_ptr(sun4i_gpadc_of_match),
+       },
+       .probe = sun4i_gpadc_probe,
+};
+
+module_platform_driver(sun4i_gpadc_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi platforms' GPADC MFD core driver");
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
+MODULE_LICENSE("GPL v2");
index 274bf39968aaa1a9c9527fe0093cc7790d05f1f6..cc9e563f23aa6072d6160c9b33abe4c901bc1584 100644 (file)
@@ -53,7 +53,7 @@ int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
 EXPORT_SYMBOL_GPL(tc3589x_reg_read);
 
 /**
- * tc3589x_reg_read() - write a single TC3589x register
+ * tc3589x_reg_write() - write a single TC3589x register
  * @tc3589x:   Device to write to
  * @reg:       Register to read
  * @data:      Value to write
@@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(tc3589x_block_write);
  * @tc3589x:   Device to write to
  * @reg:       Register to write
  * @mask:      Mask of bits to set
- * @values:    Value to set
+ * @val:       Value to set
  */
 int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
 {
index 9a4d8684dd32bd5beaf73547271bd2b1ee42431f..f769c7d4e335ac20da4db26ae5d7eb024d0b9987 100644 (file)
@@ -42,26 +42,6 @@ static struct resource pb_resources[] = {
        DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"),
 };
 
-struct tps65217_irq {
-       int mask;
-       int interrupt;
-};
-
-static const struct tps65217_irq tps65217_irqs[] = {
-       [TPS65217_IRQ_PB] = {
-               .mask = TPS65217_INT_PBM,
-               .interrupt = TPS65217_INT_PBI,
-       },
-       [TPS65217_IRQ_AC] = {
-               .mask = TPS65217_INT_ACM,
-               .interrupt = TPS65217_INT_ACI,
-       },
-       [TPS65217_IRQ_USB] = {
-               .mask = TPS65217_INT_USBM,
-               .interrupt = TPS65217_INT_USBI,
-       },
-};
-
 static void tps65217_irq_lock(struct irq_data *data)
 {
        struct tps65217 *tps = irq_data_get_irq_chip_data(data);
@@ -74,37 +54,32 @@ static void tps65217_irq_sync_unlock(struct irq_data *data)
        struct tps65217 *tps = irq_data_get_irq_chip_data(data);
        int ret;
 
-       ret = tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
-                               TPS65217_PROTECT_NONE);
+       ret = tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
+                               tps->irq_mask, TPS65217_PROTECT_NONE);
        if (ret != 0)
                dev_err(tps->dev, "Failed to sync IRQ masks\n");
 
        mutex_unlock(&tps->irq_lock);
 }
 
-static inline const struct tps65217_irq *
-irq_to_tps65217_irq(struct tps65217 *tps, struct irq_data *data)
-{
-       return &tps65217_irqs[data->hwirq];
-}
-
 static void tps65217_irq_enable(struct irq_data *data)
 {
        struct tps65217 *tps = irq_data_get_irq_chip_data(data);
-       const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
+       u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
 
-       tps->irq_mask &= ~irq_data->mask;
+       tps->irq_mask &= ~mask;
 }
 
 static void tps65217_irq_disable(struct irq_data *data)
 {
        struct tps65217 *tps = irq_data_get_irq_chip_data(data);
-       const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
+       u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
 
-       tps->irq_mask |= irq_data->mask;
+       tps->irq_mask |= mask;
 }
 
 static struct irq_chip tps65217_irq_chip = {
+       .name                   = "tps65217",
        .irq_bus_lock           = tps65217_irq_lock,
        .irq_bus_sync_unlock    = tps65217_irq_sync_unlock,
        .irq_enable             = tps65217_irq_enable,
@@ -149,8 +124,8 @@ static irqreturn_t tps65217_irq_thread(int irq, void *data)
                return IRQ_NONE;
        }
 
-       for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) {
-               if (status & tps65217_irqs[i].interrupt) {
+       for (i = 0; i < TPS65217_NUM_IRQ; i++) {
+               if (status & BIT(i)) {
                        handle_nested_irq(irq_find_mapping(tps->irq_domain, i));
                        handled = true;
                }
@@ -188,10 +163,9 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
        tps->irq = irq;
 
        /* Mask all interrupt sources */
-       tps->irq_mask = (TPS65217_INT_RESERVEDM | TPS65217_INT_PBM
-                       | TPS65217_INT_ACM | TPS65217_INT_USBM);
-       tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
-                       TPS65217_PROTECT_NONE);
+       tps->irq_mask = TPS65217_INT_MASK;
+       tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
+                         TPS65217_INT_MASK, TPS65217_PROTECT_NONE);
 
        tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
                TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
@@ -209,6 +183,8 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
                return ret;
        }
 
+       enable_irq_wake(irq);
+
        return 0;
 }
 
@@ -424,6 +400,24 @@ static int tps65217_probe(struct i2c_client *client,
        return 0;
 }
 
+static int tps65217_remove(struct i2c_client *client)
+{
+       struct tps65217 *tps = i2c_get_clientdata(client);
+       unsigned int virq;
+       int i;
+
+       for (i = 0; i < TPS65217_NUM_IRQ; i++) {
+               virq = irq_find_mapping(tps->irq_domain, i);
+               if (virq)
+                       irq_dispose_mapping(virq);
+       }
+
+       irq_domain_remove(tps->irq_domain);
+       tps->irq_domain = NULL;
+
+       return 0;
+}
+
 static const struct i2c_device_id tps65217_id_table[] = {
        {"tps65217", TPS65217},
        { /* sentinel */ }
@@ -437,6 +431,7 @@ static struct i2c_driver tps65217_driver = {
        },
        .id_table       = tps65217_id_table,
        .probe          = tps65217_probe,
+       .remove         = tps65217_remove,
 };
 
 static int __init tps65217_init(void)
index ba610adbdbff33503f65cea2ceda2273f95fc2fb..13834a0d28172fe5334f0385571fafb34cc21248 100644 (file)
 
 #define TPS65218_PASSWORD_REGS_UNLOCK   0x7D
 
-/**
- * tps65218_reg_read: Read a single tps65218 register.
- *
- * @tps: Device to read from.
- * @reg: Register to read.
- * @val: Contians the value
- */
-int tps65218_reg_read(struct tps65218 *tps, unsigned int reg,
-                       unsigned int *val)
-{
-       return regmap_read(tps->regmap, reg, val);
-}
-EXPORT_SYMBOL_GPL(tps65218_reg_read);
+static const struct mfd_cell tps65218_cells[] = {
+       {
+               .name = "tps65218-pwrbutton",
+               .of_compatible = "ti,tps65218-pwrbutton",
+       },
+       {
+               .name = "tps65218-gpio",
+               .of_compatible = "ti,tps65218-gpio",
+       },
+       { .name = "tps65218-regulator", },
+};
 
 /**
  * tps65218_reg_write: Write a single tps65218 register.
@@ -93,7 +91,7 @@ static int tps65218_update_bits(struct tps65218 *tps, unsigned int reg,
        int ret;
        unsigned int data;
 
-       ret = tps65218_reg_read(tps, reg, &data);
+       ret = regmap_read(tps->regmap, reg, &data);
        if (ret) {
                dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
                return ret;
@@ -251,7 +249,7 @@ static int tps65218_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
-       ret = tps65218_reg_read(tps, TPS65218_REG_CHIPID, &chipid);
+       ret = regmap_read(tps->regmap, TPS65218_REG_CHIPID, &chipid);
        if (ret) {
                dev_err(tps->dev, "Failed to read chipid: %d\n", ret);
                return ret;
@@ -259,8 +257,10 @@ static int tps65218_probe(struct i2c_client *client,
 
        tps->rev = chipid & TPS65218_CHIPID_REV_MASK;
 
-       ret = of_platform_populate(client->dev.of_node, NULL, NULL,
-                                  &client->dev);
+       ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65218_cells,
+                             ARRAY_SIZE(tps65218_cells), NULL, 0,
+                             regmap_irq_get_domain(tps->irq_data));
+
        if (ret < 0)
                goto err_irq;
 
index a88cfa80dbc4816f3c236d4c4282f59af09893e0..f33567bc428d1f7a2a6e00ef1b962ea8851d417c 100644 (file)
@@ -77,6 +77,23 @@ static struct regmap_irq_chip tps65912_irq_chip = {
        .init_ack_masked = true,
 };
 
+static const struct regmap_range tps65912_yes_ranges[] = {
+       regmap_reg_range(TPS65912_INT_STS, TPS65912_GPIO5),
+};
+
+static const struct regmap_access_table tps65912_volatile_table = {
+       .yes_ranges = tps65912_yes_ranges,
+       .n_yes_ranges = ARRAY_SIZE(tps65912_yes_ranges),
+};
+
+const struct regmap_config tps65912_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+       .volatile_table = &tps65912_volatile_table,
+};
+EXPORT_SYMBOL_GPL(tps65912_regmap_config);
+
 int tps65912_device_init(struct tps65912 *tps)
 {
        int ret;
index ab8b23b5bd22b085d5fbd1a16338cd36a82db729..853113d97c1e8311e812625f79be82a862e71704 100644 (file)
@@ -244,752 +244,752 @@ const struct regmap_irq_chip wm5102_irq = {
 };
 
 static const struct reg_default wm5102_reg_default[] = {
-       { 0x00000008, 0x0019 },   /* R8     - Ctrl IF SPI CFG 1 */ 
-       { 0x00000009, 0x0001 },   /* R9     - Ctrl IF I2C1 CFG 1 */ 
-       { 0x00000020, 0x0000 },   /* R32    - Tone Generator 1 */ 
-       { 0x00000021, 0x1000 },   /* R33    - Tone Generator 2 */ 
-       { 0x00000022, 0x0000 },   /* R34    - Tone Generator 3 */ 
-       { 0x00000023, 0x1000 },   /* R35    - Tone Generator 4 */ 
-       { 0x00000024, 0x0000 },   /* R36    - Tone Generator 5 */ 
-       { 0x00000030, 0x0000 },   /* R48    - PWM Drive 1 */ 
-       { 0x00000031, 0x0100 },   /* R49    - PWM Drive 2 */ 
-       { 0x00000032, 0x0100 },   /* R50    - PWM Drive 3 */ 
-       { 0x00000040, 0x0000 },   /* R64    - Wake control */ 
-       { 0x00000041, 0x0000 },   /* R65    - Sequence control */ 
-       { 0x00000061, 0x01FF },   /* R97    - Sample Rate Sequence Select 1 */ 
-       { 0x00000062, 0x01FF },   /* R98    - Sample Rate Sequence Select 2 */ 
-       { 0x00000063, 0x01FF },   /* R99    - Sample Rate Sequence Select 3 */ 
-       { 0x00000064, 0x01FF },   /* R100   - Sample Rate Sequence Select 4 */ 
+       { 0x00000008, 0x0019 },   /* R8     - Ctrl IF SPI CFG 1 */
+       { 0x00000009, 0x0001 },   /* R9     - Ctrl IF I2C1 CFG 1 */
+       { 0x00000020, 0x0000 },   /* R32    - Tone Generator 1 */
+       { 0x00000021, 0x1000 },   /* R33    - Tone Generator 2 */
+       { 0x00000022, 0x0000 },   /* R34    - Tone Generator 3 */
+       { 0x00000023, 0x1000 },   /* R35    - Tone Generator 4 */
+       { 0x00000024, 0x0000 },   /* R36    - Tone Generator 5 */
+       { 0x00000030, 0x0000 },   /* R48    - PWM Drive 1 */
+       { 0x00000031, 0x0100 },   /* R49    - PWM Drive 2 */
+       { 0x00000032, 0x0100 },   /* R50    - PWM Drive 3 */
+       { 0x00000040, 0x0000 },   /* R64    - Wake control */
+       { 0x00000041, 0x0000 },   /* R65    - Sequence control */
+       { 0x00000061, 0x01FF },   /* R97    - Sample Rate Sequence Select 1 */
+       { 0x00000062, 0x01FF },   /* R98    - Sample Rate Sequence Select 2 */
+       { 0x00000063, 0x01FF },   /* R99    - Sample Rate Sequence Select 3 */
+       { 0x00000064, 0x01FF },   /* R100   - Sample Rate Sequence Select 4 */
        { 0x00000066, 0x01FF },   /* R102   - Always On Triggers Sequence Select 1 */
        { 0x00000067, 0x01FF },   /* R103   - Always On Triggers Sequence Select 2 */
        { 0x00000068, 0x01FF },   /* R104   - Always On Triggers Sequence Select 3 */
        { 0x00000069, 0x01FF },   /* R105   - Always On Triggers Sequence Select 4 */
        { 0x0000006A, 0x01FF },   /* R106   - Always On Triggers Sequence Select 5 */
        { 0x0000006B, 0x01FF },   /* R107   - Always On Triggers Sequence Select 6 */
-       { 0x00000070, 0x0000 },   /* R112   - Comfort Noise Generator */ 
-       { 0x00000090, 0x0000 },   /* R144   - Haptics Control 1 */ 
-       { 0x00000091, 0x7FFF },   /* R145   - Haptics Control 2 */ 
-       { 0x00000092, 0x0000 },   /* R146   - Haptics phase 1 intensity */ 
-       { 0x00000093, 0x0000 },   /* R147   - Haptics phase 1 duration */ 
-       { 0x00000094, 0x0000 },   /* R148   - Haptics phase 2 intensity */ 
-       { 0x00000095, 0x0000 },   /* R149   - Haptics phase 2 duration */ 
-       { 0x00000096, 0x0000 },   /* R150   - Haptics phase 3 intensity */ 
-       { 0x00000097, 0x0000 },   /* R151   - Haptics phase 3 duration */ 
+       { 0x00000070, 0x0000 },   /* R112   - Comfort Noise Generator */
+       { 0x00000090, 0x0000 },   /* R144   - Haptics Control 1 */
+       { 0x00000091, 0x7FFF },   /* R145   - Haptics Control 2 */
+       { 0x00000092, 0x0000 },   /* R146   - Haptics phase 1 intensity */
+       { 0x00000093, 0x0000 },   /* R147   - Haptics phase 1 duration */
+       { 0x00000094, 0x0000 },   /* R148   - Haptics phase 2 intensity */
+       { 0x00000095, 0x0000 },   /* R149   - Haptics phase 2 duration */
+       { 0x00000096, 0x0000 },   /* R150   - Haptics phase 3 intensity */
+       { 0x00000097, 0x0000 },   /* R151   - Haptics phase 3 duration */
        { 0x00000100, 0x0002 },   /* R256   - Clock 32k 1 */
-       { 0x00000101, 0x0304 },   /* R257   - System Clock 1 */ 
-       { 0x00000102, 0x0011 },   /* R258   - Sample rate 1 */ 
-       { 0x00000103, 0x0011 },   /* R259   - Sample rate 2 */ 
-       { 0x00000104, 0x0011 },   /* R260   - Sample rate 3 */ 
-       { 0x00000112, 0x0305 },   /* R274   - Async clock 1 */ 
-       { 0x00000113, 0x0011 },   /* R275   - Async sample rate 1 */ 
+       { 0x00000101, 0x0304 },   /* R257   - System Clock 1 */
+       { 0x00000102, 0x0011 },   /* R258   - Sample rate 1 */
+       { 0x00000103, 0x0011 },   /* R259   - Sample rate 2 */
+       { 0x00000104, 0x0011 },   /* R260   - Sample rate 3 */
+       { 0x00000112, 0x0305 },   /* R274   - Async clock 1 */
+       { 0x00000113, 0x0011 },   /* R275   - Async sample rate 1 */
        { 0x00000114, 0x0011 },   /* R276   - Async sample rate 2 */
-       { 0x00000149, 0x0000 },   /* R329   - Output system clock */ 
-       { 0x0000014A, 0x0000 },   /* R330   - Output async clock */ 
-       { 0x00000152, 0x0000 },   /* R338   - Rate Estimator 1 */ 
-       { 0x00000153, 0x0000 },   /* R339   - Rate Estimator 2 */ 
-       { 0x00000154, 0x0000 },   /* R340   - Rate Estimator 3 */ 
-       { 0x00000155, 0x0000 },   /* R341   - Rate Estimator 4 */ 
-       { 0x00000156, 0x0000 },   /* R342   - Rate Estimator 5 */ 
-       { 0x00000161, 0x0000 },   /* R353   - Dynamic Frequency Scaling 1 */ 
+       { 0x00000149, 0x0000 },   /* R329   - Output system clock */
+       { 0x0000014A, 0x0000 },   /* R330   - Output async clock */
+       { 0x00000152, 0x0000 },   /* R338   - Rate Estimator 1 */
+       { 0x00000153, 0x0000 },   /* R339   - Rate Estimator 2 */
+       { 0x00000154, 0x0000 },   /* R340   - Rate Estimator 3 */
+       { 0x00000155, 0x0000 },   /* R341   - Rate Estimator 4 */
+       { 0x00000156, 0x0000 },   /* R342   - Rate Estimator 5 */
+       { 0x00000161, 0x0000 },   /* R353   - Dynamic Frequency Scaling 1 */
        { 0x00000171, 0x0000 },   /* R369   - FLL1 Control 1 */
-       { 0x00000172, 0x0008 },   /* R370   - FLL1 Control 2 */ 
-       { 0x00000173, 0x0018 },   /* R371   - FLL1 Control 3 */ 
-       { 0x00000174, 0x007D },   /* R372   - FLL1 Control 4 */ 
-       { 0x00000175, 0x0004 },   /* R373   - FLL1 Control 5 */ 
-       { 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */ 
+       { 0x00000172, 0x0008 },   /* R370   - FLL1 Control 2 */
+       { 0x00000173, 0x0018 },   /* R371   - FLL1 Control 3 */
+       { 0x00000174, 0x007D },   /* R372   - FLL1 Control 4 */
+       { 0x00000175, 0x0004 },   /* R373   - FLL1 Control 5 */
+       { 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */
        { 0x00000179, 0x0000 },   /* R377   - FLL1 Control 7 */
-       { 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */ 
-       { 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */ 
-       { 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */ 
-       { 0x00000184, 0x0000 },   /* R388   - FLL1 Synchroniser 4 */ 
-       { 0x00000185, 0x0000 },   /* R389   - FLL1 Synchroniser 5 */ 
-       { 0x00000186, 0x0000 },   /* R390   - FLL1 Synchroniser 6 */ 
+       { 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */
+       { 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */
+       { 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */
+       { 0x00000184, 0x0000 },   /* R388   - FLL1 Synchroniser 4 */
+       { 0x00000185, 0x0000 },   /* R389   - FLL1 Synchroniser 5 */
+       { 0x00000186, 0x0000 },   /* R390   - FLL1 Synchroniser 6 */
        { 0x00000187, 0x0001 },   /* R391   - FLL1 Synchroniser 7 */
-       { 0x00000189, 0x0000 },   /* R393   - FLL1 Spread Spectrum */ 
-       { 0x0000018A, 0x0004 },   /* R394   - FLL1 GPIO Clock */ 
-       { 0x00000191, 0x0000 },   /* R401   - FLL2 Control 1 */ 
-       { 0x00000192, 0x0008 },   /* R402   - FLL2 Control 2 */ 
-       { 0x00000193, 0x0018 },   /* R403   - FLL2 Control 3 */ 
-       { 0x00000194, 0x007D },   /* R404   - FLL2 Control 4 */ 
-       { 0x00000195, 0x0004 },   /* R405   - FLL2 Control 5 */ 
-       { 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */ 
+       { 0x00000189, 0x0000 },   /* R393   - FLL1 Spread Spectrum */
+       { 0x0000018A, 0x0004 },   /* R394   - FLL1 GPIO Clock */
+       { 0x00000191, 0x0000 },   /* R401   - FLL2 Control 1 */
+       { 0x00000192, 0x0008 },   /* R402   - FLL2 Control 2 */
+       { 0x00000193, 0x0018 },   /* R403   - FLL2 Control 3 */
+       { 0x00000194, 0x007D },   /* R404   - FLL2 Control 4 */
+       { 0x00000195, 0x0004 },   /* R405   - FLL2 Control 5 */
+       { 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */
        { 0x00000199, 0x0000 },   /* R409   - FLL2 Control 7 */
-       { 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */ 
-       { 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */ 
-       { 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */ 
-       { 0x000001A4, 0x0000 },   /* R420   - FLL2 Synchroniser 4 */ 
-       { 0x000001A5, 0x0000 },   /* R421   - FLL2 Synchroniser 5 */ 
-       { 0x000001A6, 0x0000 },   /* R422   - FLL2 Synchroniser 6 */ 
+       { 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */
+       { 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */
+       { 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */
+       { 0x000001A4, 0x0000 },   /* R420   - FLL2 Synchroniser 4 */
+       { 0x000001A5, 0x0000 },   /* R421   - FLL2 Synchroniser 5 */
+       { 0x000001A6, 0x0000 },   /* R422   - FLL2 Synchroniser 6 */
        { 0x000001A7, 0x0001 },   /* R423   - FLL2 Synchroniser 7 */
-       { 0x000001A9, 0x0000 },   /* R425   - FLL2 Spread Spectrum */ 
-       { 0x000001AA, 0x0004 },   /* R426   - FLL2 GPIO Clock */ 
-       { 0x00000200, 0x0006 },   /* R512   - Mic Charge Pump 1 */ 
-       { 0x00000210, 0x00D4 },   /* R528   - LDO1 Control 1 */ 
+       { 0x000001A9, 0x0000 },   /* R425   - FLL2 Spread Spectrum */
+       { 0x000001AA, 0x0004 },   /* R426   - FLL2 GPIO Clock */
+       { 0x00000200, 0x0006 },   /* R512   - Mic Charge Pump 1 */
+       { 0x00000210, 0x00D4 },   /* R528   - LDO1 Control 1 */
        { 0x00000212, 0x0000 },   /* R530   - LDO1 Control 2 */
-       { 0x00000213, 0x0344 },   /* R531   - LDO2 Control 1 */ 
-       { 0x00000218, 0x01A6 },   /* R536   - Mic Bias Ctrl 1 */ 
-       { 0x00000219, 0x01A6 },   /* R537   - Mic Bias Ctrl 2 */ 
-       { 0x0000021A, 0x01A6 },   /* R538   - Mic Bias Ctrl 3 */ 
-       { 0x00000293, 0x0000 },   /* R659   - Accessory Detect Mode 1 */ 
-       { 0x0000029B, 0x0020 },   /* R667   - Headphone Detect 1 */ 
+       { 0x00000213, 0x0344 },   /* R531   - LDO2 Control 1 */
+       { 0x00000218, 0x01A6 },   /* R536   - Mic Bias Ctrl 1 */
+       { 0x00000219, 0x01A6 },   /* R537   - Mic Bias Ctrl 2 */
+       { 0x0000021A, 0x01A6 },   /* R538   - Mic Bias Ctrl 3 */
+       { 0x00000293, 0x0000 },   /* R659   - Accessory Detect Mode 1 */
+       { 0x0000029B, 0x0020 },   /* R667   - Headphone Detect 1 */
        { 0x000002A2, 0x0000 },   /* R674   - Micd clamp control */
-       { 0x000002A3, 0x1102 },   /* R675   - Mic Detect 1 */ 
-       { 0x000002A4, 0x009F },   /* R676   - Mic Detect 2 */ 
+       { 0x000002A3, 0x1102 },   /* R675   - Mic Detect 1 */
+       { 0x000002A4, 0x009F },   /* R676   - Mic Detect 2 */
        { 0x000002A6, 0x3737 },   /* R678   - Mic Detect Level 1 */
        { 0x000002A7, 0x2C37 },   /* R679   - Mic Detect Level 2 */
        { 0x000002A8, 0x1422 },   /* R680   - Mic Detect Level 3 */
        { 0x000002A9, 0x030A },   /* R681   - Mic Detect Level 4 */
-       { 0x000002C3, 0x0000 },   /* R707   - Mic noise mix control 1 */ 
-       { 0x000002CB, 0x0000 },   /* R715   - Isolation control */ 
-       { 0x000002D3, 0x0000 },   /* R723   - Jack detect analogue */ 
-       { 0x00000300, 0x0000 },   /* R768   - Input Enables */ 
-       { 0x00000308, 0x0000 },   /* R776   - Input Rate */ 
-       { 0x00000309, 0x0022 },   /* R777   - Input Volume Ramp */ 
-       { 0x00000310, 0x2080 },   /* R784   - IN1L Control */ 
-       { 0x00000311, 0x0180 },   /* R785   - ADC Digital Volume 1L */ 
-       { 0x00000312, 0x0000 },   /* R786   - DMIC1L Control */ 
-       { 0x00000314, 0x0080 },   /* R788   - IN1R Control */ 
-       { 0x00000315, 0x0180 },   /* R789   - ADC Digital Volume 1R */ 
-       { 0x00000316, 0x0000 },   /* R790   - DMIC1R Control */ 
-       { 0x00000318, 0x2080 },   /* R792   - IN2L Control */ 
-       { 0x00000319, 0x0180 },   /* R793   - ADC Digital Volume 2L */ 
-       { 0x0000031A, 0x0000 },   /* R794   - DMIC2L Control */ 
-       { 0x0000031C, 0x0080 },   /* R796   - IN2R Control */ 
-       { 0x0000031D, 0x0180 },   /* R797   - ADC Digital Volume 2R */ 
-       { 0x0000031E, 0x0000 },   /* R798   - DMIC2R Control */ 
-       { 0x00000320, 0x2080 },   /* R800   - IN3L Control */ 
-       { 0x00000321, 0x0180 },   /* R801   - ADC Digital Volume 3L */ 
-       { 0x00000322, 0x0000 },   /* R802   - DMIC3L Control */ 
-       { 0x00000324, 0x0080 },   /* R804   - IN3R Control */ 
-       { 0x00000325, 0x0180 },   /* R805   - ADC Digital Volume 3R */ 
-       { 0x00000326, 0x0000 },   /* R806   - DMIC3R Control */ 
-       { 0x00000400, 0x0000 },   /* R1024  - Output Enables 1 */ 
-       { 0x00000408, 0x0000 },   /* R1032  - Output Rate 1 */ 
-       { 0x00000409, 0x0022 },   /* R1033  - Output Volume Ramp */ 
+       { 0x000002C3, 0x0000 },   /* R707   - Mic noise mix control 1 */
+       { 0x000002CB, 0x0000 },   /* R715   - Isolation control */
+       { 0x000002D3, 0x0000 },   /* R723   - Jack detect analogue */
+       { 0x00000300, 0x0000 },   /* R768   - Input Enables */
+       { 0x00000308, 0x0000 },   /* R776   - Input Rate */
+       { 0x00000309, 0x0022 },   /* R777   - Input Volume Ramp */
+       { 0x00000310, 0x2080 },   /* R784   - IN1L Control */
+       { 0x00000311, 0x0180 },   /* R785   - ADC Digital Volume 1L */
+       { 0x00000312, 0x0000 },   /* R786   - DMIC1L Control */
+       { 0x00000314, 0x0080 },   /* R788   - IN1R Control */
+       { 0x00000315, 0x0180 },   /* R789   - ADC Digital Volume 1R */
+       { 0x00000316, 0x0000 },   /* R790   - DMIC1R Control */
+       { 0x00000318, 0x2080 },   /* R792   - IN2L Control */
+       { 0x00000319, 0x0180 },   /* R793   - ADC Digital Volume 2L */
+       { 0x0000031A, 0x0000 },   /* R794   - DMIC2L Control */
+       { 0x0000031C, 0x0080 },   /* R796   - IN2R Control */
+       { 0x0000031D, 0x0180 },   /* R797   - ADC Digital Volume 2R */
+       { 0x0000031E, 0x0000 },   /* R798   - DMIC2R Control */
+       { 0x00000320, 0x2080 },   /* R800   - IN3L Control */
+       { 0x00000321, 0x0180 },   /* R801   - ADC Digital Volume 3L */
+       { 0x00000322, 0x0000 },   /* R802   - DMIC3L Control */
+       { 0x00000324, 0x0080 },   /* R804   - IN3R Control */
+       { 0x00000325, 0x0180 },   /* R805   - ADC Digital Volume 3R */
+       { 0x00000326, 0x0000 },   /* R806   - DMIC3R Control */
+       { 0x00000400, 0x0000 },   /* R1024  - Output Enables 1 */
+       { 0x00000408, 0x0000 },   /* R1032  - Output Rate 1 */
+       { 0x00000409, 0x0022 },   /* R1033  - Output Volume Ramp */
        { 0x00000410, 0x6080 },   /* R1040  - Output Path Config 1L */
-       { 0x00000411, 0x0180 },   /* R1041  - DAC Digital Volume 1L */ 
+       { 0x00000411, 0x0180 },   /* R1041  - DAC Digital Volume 1L */
        { 0x00000412, 0x0081 },   /* R1042  - DAC Volume Limit 1L */
-       { 0x00000413, 0x0001 },   /* R1043  - Noise Gate Select 1L */ 
-       { 0x00000414, 0x0080 },   /* R1044  - Output Path Config 1R */ 
-       { 0x00000415, 0x0180 },   /* R1045  - DAC Digital Volume 1R */ 
+       { 0x00000413, 0x0001 },   /* R1043  - Noise Gate Select 1L */
+       { 0x00000414, 0x0080 },   /* R1044  - Output Path Config 1R */
+       { 0x00000415, 0x0180 },   /* R1045  - DAC Digital Volume 1R */
        { 0x00000416, 0x0081 },   /* R1046  - DAC Volume Limit 1R */
-       { 0x00000417, 0x0002 },   /* R1047  - Noise Gate Select 1R */ 
+       { 0x00000417, 0x0002 },   /* R1047  - Noise Gate Select 1R */
        { 0x00000418, 0xA080 },   /* R1048  - Output Path Config 2L */
-       { 0x00000419, 0x0180 },   /* R1049  - DAC Digital Volume 2L */ 
+       { 0x00000419, 0x0180 },   /* R1049  - DAC Digital Volume 2L */
        { 0x0000041A, 0x0081 },   /* R1050  - DAC Volume Limit 2L */
-       { 0x0000041B, 0x0004 },   /* R1051  - Noise Gate Select 2L */ 
-       { 0x0000041C, 0x0080 },   /* R1052  - Output Path Config 2R */ 
-       { 0x0000041D, 0x0180 },   /* R1053  - DAC Digital Volume 2R */ 
+       { 0x0000041B, 0x0004 },   /* R1051  - Noise Gate Select 2L */
+       { 0x0000041C, 0x0080 },   /* R1052  - Output Path Config 2R */
+       { 0x0000041D, 0x0180 },   /* R1053  - DAC Digital Volume 2R */
        { 0x0000041E, 0x0081 },   /* R1054  - DAC Volume Limit 2R */
-       { 0x0000041F, 0x0008 },   /* R1055  - Noise Gate Select 2R */ 
+       { 0x0000041F, 0x0008 },   /* R1055  - Noise Gate Select 2R */
        { 0x00000420, 0xA080 },   /* R1056  - Output Path Config 3L */
-       { 0x00000421, 0x0180 },   /* R1057  - DAC Digital Volume 3L */ 
+       { 0x00000421, 0x0180 },   /* R1057  - DAC Digital Volume 3L */
        { 0x00000422, 0x0081 },   /* R1058  - DAC Volume Limit 3L */
-       { 0x00000423, 0x0010 },   /* R1059  - Noise Gate Select 3L */ 
+       { 0x00000423, 0x0010 },   /* R1059  - Noise Gate Select 3L */
        { 0x00000428, 0xE000 },   /* R1064  - Output Path Config 4L */
-       { 0x00000429, 0x0180 },   /* R1065  - DAC Digital Volume 4L */ 
+       { 0x00000429, 0x0180 },   /* R1065  - DAC Digital Volume 4L */
        { 0x0000042A, 0x0081 },   /* R1066  - Out Volume 4L */
-       { 0x0000042B, 0x0040 },   /* R1067  - Noise Gate Select 4L */ 
-       { 0x0000042D, 0x0180 },   /* R1069  - DAC Digital Volume 4R */ 
+       { 0x0000042B, 0x0040 },   /* R1067  - Noise Gate Select 4L */
+       { 0x0000042D, 0x0180 },   /* R1069  - DAC Digital Volume 4R */
        { 0x0000042E, 0x0081 },   /* R1070  - Out Volume 4R */
-       { 0x0000042F, 0x0080 },   /* R1071  - Noise Gate Select 4R */ 
-       { 0x00000430, 0x0000 },   /* R1072  - Output Path Config 5L */ 
-       { 0x00000431, 0x0180 },   /* R1073  - DAC Digital Volume 5L */ 
+       { 0x0000042F, 0x0080 },   /* R1071  - Noise Gate Select 4R */
+       { 0x00000430, 0x0000 },   /* R1072  - Output Path Config 5L */
+       { 0x00000431, 0x0180 },   /* R1073  - DAC Digital Volume 5L */
        { 0x00000432, 0x0081 },   /* R1074  - DAC Volume Limit 5L */
-       { 0x00000433, 0x0100 },   /* R1075  - Noise Gate Select 5L */ 
-       { 0x00000435, 0x0180 },   /* R1077  - DAC Digital Volume 5R */ 
+       { 0x00000433, 0x0100 },   /* R1075  - Noise Gate Select 5L */
+       { 0x00000435, 0x0180 },   /* R1077  - DAC Digital Volume 5R */
        { 0x00000436, 0x0081 },   /* R1078  - DAC Volume Limit 5R */
        { 0x00000437, 0x0200 },   /* R1079  - Noise Gate Select 5R */
        { 0x00000440, 0x0FFF },   /* R1088  - DRE Enable */
        { 0x00000442, 0x3F0A },   /* R1090  - DRE Control 2 */
        { 0x00000443, 0xDC1F },   /* R1090  - DRE Control 3 */
-       { 0x00000450, 0x0000 },   /* R1104  - DAC AEC Control 1 */ 
+       { 0x00000450, 0x0000 },   /* R1104  - DAC AEC Control 1 */
        { 0x00000458, 0x000B },   /* R1112  - Noise Gate Control */
-       { 0x00000490, 0x0069 },   /* R1168  - PDM SPK1 CTRL 1 */ 
-       { 0x00000491, 0x0000 },   /* R1169  - PDM SPK1 CTRL 2 */ 
-       { 0x00000500, 0x000C },   /* R1280  - AIF1 BCLK Ctrl */ 
-       { 0x00000501, 0x0008 },   /* R1281  - AIF1 Tx Pin Ctrl */ 
-       { 0x00000502, 0x0000 },   /* R1282  - AIF1 Rx Pin Ctrl */ 
-       { 0x00000503, 0x0000 },   /* R1283  - AIF1 Rate Ctrl */ 
-       { 0x00000504, 0x0000 },   /* R1284  - AIF1 Format */ 
-       { 0x00000505, 0x0040 },   /* R1285  - AIF1 Tx BCLK Rate */ 
-       { 0x00000506, 0x0040 },   /* R1286  - AIF1 Rx BCLK Rate */ 
-       { 0x00000507, 0x1818 },   /* R1287  - AIF1 Frame Ctrl 1 */ 
-       { 0x00000508, 0x1818 },   /* R1288  - AIF1 Frame Ctrl 2 */ 
-       { 0x00000509, 0x0000 },   /* R1289  - AIF1 Frame Ctrl 3 */ 
-       { 0x0000050A, 0x0001 },   /* R1290  - AIF1 Frame Ctrl 4 */ 
-       { 0x0000050B, 0x0002 },   /* R1291  - AIF1 Frame Ctrl 5 */ 
-       { 0x0000050C, 0x0003 },   /* R1292  - AIF1 Frame Ctrl 6 */ 
-       { 0x0000050D, 0x0004 },   /* R1293  - AIF1 Frame Ctrl 7 */ 
-       { 0x0000050E, 0x0005 },   /* R1294  - AIF1 Frame Ctrl 8 */ 
-       { 0x0000050F, 0x0006 },   /* R1295  - AIF1 Frame Ctrl 9 */ 
-       { 0x00000510, 0x0007 },   /* R1296  - AIF1 Frame Ctrl 10 */ 
-       { 0x00000511, 0x0000 },   /* R1297  - AIF1 Frame Ctrl 11 */ 
-       { 0x00000512, 0x0001 },   /* R1298  - AIF1 Frame Ctrl 12 */ 
-       { 0x00000513, 0x0002 },   /* R1299  - AIF1 Frame Ctrl 13 */ 
-       { 0x00000514, 0x0003 },   /* R1300  - AIF1 Frame Ctrl 14 */ 
-       { 0x00000515, 0x0004 },   /* R1301  - AIF1 Frame Ctrl 15 */ 
-       { 0x00000516, 0x0005 },   /* R1302  - AIF1 Frame Ctrl 16 */ 
-       { 0x00000517, 0x0006 },   /* R1303  - AIF1 Frame Ctrl 17 */ 
-       { 0x00000518, 0x0007 },   /* R1304  - AIF1 Frame Ctrl 18 */ 
-       { 0x00000519, 0x0000 },   /* R1305  - AIF1 Tx Enables */ 
-       { 0x0000051A, 0x0000 },   /* R1306  - AIF1 Rx Enables */ 
-       { 0x00000540, 0x000C },   /* R1344  - AIF2 BCLK Ctrl */ 
-       { 0x00000541, 0x0008 },   /* R1345  - AIF2 Tx Pin Ctrl */ 
-       { 0x00000542, 0x0000 },   /* R1346  - AIF2 Rx Pin Ctrl */ 
-       { 0x00000543, 0x0000 },   /* R1347  - AIF2 Rate Ctrl */ 
-       { 0x00000544, 0x0000 },   /* R1348  - AIF2 Format */ 
-       { 0x00000545, 0x0040 },   /* R1349  - AIF2 Tx BCLK Rate */ 
-       { 0x00000546, 0x0040 },   /* R1350  - AIF2 Rx BCLK Rate */ 
-       { 0x00000547, 0x1818 },   /* R1351  - AIF2 Frame Ctrl 1 */ 
-       { 0x00000548, 0x1818 },   /* R1352  - AIF2 Frame Ctrl 2 */ 
-       { 0x00000549, 0x0000 },   /* R1353  - AIF2 Frame Ctrl 3 */ 
-       { 0x0000054A, 0x0001 },   /* R1354  - AIF2 Frame Ctrl 4 */ 
-       { 0x00000551, 0x0000 },   /* R1361  - AIF2 Frame Ctrl 11 */ 
-       { 0x00000552, 0x0001 },   /* R1362  - AIF2 Frame Ctrl 12 */ 
-       { 0x00000559, 0x0000 },   /* R1369  - AIF2 Tx Enables */ 
-       { 0x0000055A, 0x0000 },   /* R1370  - AIF2 Rx Enables */ 
-       { 0x00000580, 0x000C },   /* R1408  - AIF3 BCLK Ctrl */ 
-       { 0x00000581, 0x0008 },   /* R1409  - AIF3 Tx Pin Ctrl */ 
-       { 0x00000582, 0x0000 },   /* R1410  - AIF3 Rx Pin Ctrl */ 
-       { 0x00000583, 0x0000 },   /* R1411  - AIF3 Rate Ctrl */ 
-       { 0x00000584, 0x0000 },   /* R1412  - AIF3 Format */ 
-       { 0x00000585, 0x0040 },   /* R1413  - AIF3 Tx BCLK Rate */ 
-       { 0x00000586, 0x0040 },   /* R1414  - AIF3 Rx BCLK Rate */ 
-       { 0x00000587, 0x1818 },   /* R1415  - AIF3 Frame Ctrl 1 */ 
-       { 0x00000588, 0x1818 },   /* R1416  - AIF3 Frame Ctrl 2 */ 
-       { 0x00000589, 0x0000 },   /* R1417  - AIF3 Frame Ctrl 3 */ 
-       { 0x0000058A, 0x0001 },   /* R1418  - AIF3 Frame Ctrl 4 */ 
-       { 0x00000591, 0x0000 },   /* R1425  - AIF3 Frame Ctrl 11 */ 
-       { 0x00000592, 0x0001 },   /* R1426  - AIF3 Frame Ctrl 12 */ 
-       { 0x00000599, 0x0000 },   /* R1433  - AIF3 Tx Enables */ 
-       { 0x0000059A, 0x0000 },   /* R1434  - AIF3 Rx Enables */ 
-       { 0x000005E3, 0x0004 },   /* R1507  - SLIMbus Framer Ref Gear */ 
-       { 0x000005E5, 0x0000 },   /* R1509  - SLIMbus Rates 1 */ 
-       { 0x000005E6, 0x0000 },   /* R1510  - SLIMbus Rates 2 */ 
-       { 0x000005E7, 0x0000 },   /* R1511  - SLIMbus Rates 3 */ 
-       { 0x000005E8, 0x0000 },   /* R1512  - SLIMbus Rates 4 */ 
-       { 0x000005E9, 0x0000 },   /* R1513  - SLIMbus Rates 5 */ 
-       { 0x000005EA, 0x0000 },   /* R1514  - SLIMbus Rates 6 */ 
-       { 0x000005EB, 0x0000 },   /* R1515  - SLIMbus Rates 7 */ 
-       { 0x000005EC, 0x0000 },   /* R1516  - SLIMbus Rates 8 */ 
-       { 0x000005F5, 0x0000 },   /* R1525  - SLIMbus RX Channel Enable */ 
-       { 0x000005F6, 0x0000 },   /* R1526  - SLIMbus TX Channel Enable */ 
-       { 0x00000640, 0x0000 },   /* R1600  - PWM1MIX Input 1 Source */ 
-       { 0x00000641, 0x0080 },   /* R1601  - PWM1MIX Input 1 Volume */ 
-       { 0x00000642, 0x0000 },   /* R1602  - PWM1MIX Input 2 Source */ 
-       { 0x00000643, 0x0080 },   /* R1603  - PWM1MIX Input 2 Volume */ 
-       { 0x00000644, 0x0000 },   /* R1604  - PWM1MIX Input 3 Source */ 
-       { 0x00000645, 0x0080 },   /* R1605  - PWM1MIX Input 3 Volume */ 
-       { 0x00000646, 0x0000 },   /* R1606  - PWM1MIX Input 4 Source */ 
-       { 0x00000647, 0x0080 },   /* R1607  - PWM1MIX Input 4 Volume */ 
-       { 0x00000648, 0x0000 },   /* R1608  - PWM2MIX Input 1 Source */ 
-       { 0x00000649, 0x0080 },   /* R1609  - PWM2MIX Input 1 Volume */ 
-       { 0x0000064A, 0x0000 },   /* R1610  - PWM2MIX Input 2 Source */ 
-       { 0x0000064B, 0x0080 },   /* R1611  - PWM2MIX Input 2 Volume */ 
-       { 0x0000064C, 0x0000 },   /* R1612  - PWM2MIX Input 3 Source */ 
-       { 0x0000064D, 0x0080 },   /* R1613  - PWM2MIX Input 3 Volume */ 
-       { 0x0000064E, 0x0000 },   /* R1614  - PWM2MIX Input 4 Source */ 
-       { 0x0000064F, 0x0080 },   /* R1615  - PWM2MIX Input 4 Volume */ 
-       { 0x00000660, 0x0000 },   /* R1632  - MICMIX Input 1 Source */ 
-       { 0x00000661, 0x0080 },   /* R1633  - MICMIX Input 1 Volume */ 
-       { 0x00000662, 0x0000 },   /* R1634  - MICMIX Input 2 Source */ 
-       { 0x00000663, 0x0080 },   /* R1635  - MICMIX Input 2 Volume */ 
-       { 0x00000664, 0x0000 },   /* R1636  - MICMIX Input 3 Source */ 
-       { 0x00000665, 0x0080 },   /* R1637  - MICMIX Input 3 Volume */ 
-       { 0x00000666, 0x0000 },   /* R1638  - MICMIX Input 4 Source */ 
-       { 0x00000667, 0x0080 },   /* R1639  - MICMIX Input 4 Volume */ 
-       { 0x00000668, 0x0000 },   /* R1640  - NOISEMIX Input 1 Source */ 
-       { 0x00000669, 0x0080 },   /* R1641  - NOISEMIX Input 1 Volume */ 
-       { 0x0000066A, 0x0000 },   /* R1642  - NOISEMIX Input 2 Source */ 
-       { 0x0000066B, 0x0080 },   /* R1643  - NOISEMIX Input 2 Volume */ 
-       { 0x0000066C, 0x0000 },   /* R1644  - NOISEMIX Input 3 Source */ 
-       { 0x0000066D, 0x0080 },   /* R1645  - NOISEMIX Input 3 Volume */ 
-       { 0x0000066E, 0x0000 },   /* R1646  - NOISEMIX Input 4 Source */ 
-       { 0x0000066F, 0x0080 },   /* R1647  - NOISEMIX Input 4 Volume */ 
-       { 0x00000680, 0x0000 },   /* R1664  - OUT1LMIX Input 1 Source */ 
-       { 0x00000681, 0x0080 },   /* R1665  - OUT1LMIX Input 1 Volume */ 
-       { 0x00000682, 0x0000 },   /* R1666  - OUT1LMIX Input 2 Source */ 
-       { 0x00000683, 0x0080 },   /* R1667  - OUT1LMIX Input 2 Volume */ 
-       { 0x00000684, 0x0000 },   /* R1668  - OUT1LMIX Input 3 Source */ 
-       { 0x00000685, 0x0080 },   /* R1669  - OUT1LMIX Input 3 Volume */ 
-       { 0x00000686, 0x0000 },   /* R1670  - OUT1LMIX Input 4 Source */ 
-       { 0x00000687, 0x0080 },   /* R1671  - OUT1LMIX Input 4 Volume */ 
-       { 0x00000688, 0x0000 },   /* R1672  - OUT1RMIX Input 1 Source */ 
-       { 0x00000689, 0x0080 },   /* R1673  - OUT1RMIX Input 1 Volume */ 
-       { 0x0000068A, 0x0000 },   /* R1674  - OUT1RMIX Input 2 Source */ 
-       { 0x0000068B, 0x0080 },   /* R1675  - OUT1RMIX Input 2 Volume */ 
-       { 0x0000068C, 0x0000 },   /* R1676  - OUT1RMIX Input 3 Source */ 
-       { 0x0000068D, 0x0080 },   /* R1677  - OUT1RMIX Input 3 Volume */ 
-       { 0x0000068E, 0x0000 },   /* R1678  - OUT1RMIX Input 4 Source */ 
-       { 0x0000068F, 0x0080 },   /* R1679  - OUT1RMIX Input 4 Volume */ 
-       { 0x00000690, 0x0000 },   /* R1680  - OUT2LMIX Input 1 Source */ 
-       { 0x00000691, 0x0080 },   /* R1681  - OUT2LMIX Input 1 Volume */ 
-       { 0x00000692, 0x0000 },   /* R1682  - OUT2LMIX Input 2 Source */ 
-       { 0x00000693, 0x0080 },   /* R1683  - OUT2LMIX Input 2 Volume */ 
-       { 0x00000694, 0x0000 },   /* R1684  - OUT2LMIX Input 3 Source */ 
-       { 0x00000695, 0x0080 },   /* R1685  - OUT2LMIX Input 3 Volume */ 
-       { 0x00000696, 0x0000 },   /* R1686  - OUT2LMIX Input 4 Source */ 
-       { 0x00000697, 0x0080 },   /* R1687  - OUT2LMIX Input 4 Volume */ 
-       { 0x00000698, 0x0000 },   /* R1688  - OUT2RMIX Input 1 Source */ 
-       { 0x00000699, 0x0080 },   /* R1689  - OUT2RMIX Input 1 Volume */ 
-       { 0x0000069A, 0x0000 },   /* R1690  - OUT2RMIX Input 2 Source */ 
-       { 0x0000069B, 0x0080 },   /* R1691  - OUT2RMIX Input 2 Volume */ 
-       { 0x0000069C, 0x0000 },   /* R1692  - OUT2RMIX Input 3 Source */ 
-       { 0x0000069D, 0x0080 },   /* R1693  - OUT2RMIX Input 3 Volume */ 
-       { 0x0000069E, 0x0000 },   /* R1694  - OUT2RMIX Input 4 Source */ 
-       { 0x0000069F, 0x0080 },   /* R1695  - OUT2RMIX Input 4 Volume */ 
-       { 0x000006A0, 0x0000 },   /* R1696  - OUT3LMIX Input 1 Source */ 
-       { 0x000006A1, 0x0080 },   /* R1697  - OUT3LMIX Input 1 Volume */ 
-       { 0x000006A2, 0x0000 },   /* R1698  - OUT3LMIX Input 2 Source */ 
-       { 0x000006A3, 0x0080 },   /* R1699  - OUT3LMIX Input 2 Volume */ 
-       { 0x000006A4, 0x0000 },   /* R1700  - OUT3LMIX Input 3 Source */ 
-       { 0x000006A5, 0x0080 },   /* R1701  - OUT3LMIX Input 3 Volume */ 
-       { 0x000006A6, 0x0000 },   /* R1702  - OUT3LMIX Input 4 Source */ 
-       { 0x000006A7, 0x0080 },   /* R1703  - OUT3LMIX Input 4 Volume */ 
-       { 0x000006B0, 0x0000 },   /* R1712  - OUT4LMIX Input 1 Source */ 
-       { 0x000006B1, 0x0080 },   /* R1713  - OUT4LMIX Input 1 Volume */ 
-       { 0x000006B2, 0x0000 },   /* R1714  - OUT4LMIX Input 2 Source */ 
-       { 0x000006B3, 0x0080 },   /* R1715  - OUT4LMIX Input 2 Volume */ 
-       { 0x000006B4, 0x0000 },   /* R1716  - OUT4LMIX Input 3 Source */ 
-       { 0x000006B5, 0x0080 },   /* R1717  - OUT4LMIX Input 3 Volume */ 
-       { 0x000006B6, 0x0000 },   /* R1718  - OUT4LMIX Input 4 Source */ 
-       { 0x000006B7, 0x0080 },   /* R1719  - OUT4LMIX Input 4 Volume */ 
-       { 0x000006B8, 0x0000 },   /* R1720  - OUT4RMIX Input 1 Source */ 
-       { 0x000006B9, 0x0080 },   /* R1721  - OUT4RMIX Input 1 Volume */ 
-       { 0x000006BA, 0x0000 },   /* R1722  - OUT4RMIX Input 2 Source */ 
-       { 0x000006BB, 0x0080 },   /* R1723  - OUT4RMIX Input 2 Volume */ 
-       { 0x000006BC, 0x0000 },   /* R1724  - OUT4RMIX Input 3 Source */ 
-       { 0x000006BD, 0x0080 },   /* R1725  - OUT4RMIX Input 3 Volume */ 
-       { 0x000006BE, 0x0000 },   /* R1726  - OUT4RMIX Input 4 Source */ 
-       { 0x000006BF, 0x0080 },   /* R1727  - OUT4RMIX Input 4 Volume */ 
-       { 0x000006C0, 0x0000 },   /* R1728  - OUT5LMIX Input 1 Source */ 
-       { 0x000006C1, 0x0080 },   /* R1729  - OUT5LMIX Input 1 Volume */ 
-       { 0x000006C2, 0x0000 },   /* R1730  - OUT5LMIX Input 2 Source */ 
-       { 0x000006C3, 0x0080 },   /* R1731  - OUT5LMIX Input 2 Volume */ 
-       { 0x000006C4, 0x0000 },   /* R1732  - OUT5LMIX Input 3 Source */ 
-       { 0x000006C5, 0x0080 },   /* R1733  - OUT5LMIX Input 3 Volume */ 
-       { 0x000006C6, 0x0000 },   /* R1734  - OUT5LMIX Input 4 Source */ 
-       { 0x000006C7, 0x0080 },   /* R1735  - OUT5LMIX Input 4 Volume */ 
-       { 0x000006C8, 0x0000 },   /* R1736  - OUT5RMIX Input 1 Source */ 
-       { 0x000006C9, 0x0080 },   /* R1737  - OUT5RMIX Input 1 Volume */ 
-       { 0x000006CA, 0x0000 },   /* R1738  - OUT5RMIX Input 2 Source */ 
-       { 0x000006CB, 0x0080 },   /* R1739  - OUT5RMIX Input 2 Volume */ 
-       { 0x000006CC, 0x0000 },   /* R1740  - OUT5RMIX Input 3 Source */ 
-       { 0x000006CD, 0x0080 },   /* R1741  - OUT5RMIX Input 3 Volume */ 
-       { 0x000006CE, 0x0000 },   /* R1742  - OUT5RMIX Input 4 Source */ 
-       { 0x000006CF, 0x0080 },   /* R1743  - OUT5RMIX Input 4 Volume */ 
-       { 0x00000700, 0x0000 },   /* R1792  - AIF1TX1MIX Input 1 Source */ 
-       { 0x00000701, 0x0080 },   /* R1793  - AIF1TX1MIX Input 1 Volume */ 
-       { 0x00000702, 0x0000 },   /* R1794  - AIF1TX1MIX Input 2 Source */ 
-       { 0x00000703, 0x0080 },   /* R1795  - AIF1TX1MIX Input 2 Volume */ 
-       { 0x00000704, 0x0000 },   /* R1796  - AIF1TX1MIX Input 3 Source */ 
-       { 0x00000705, 0x0080 },   /* R1797  - AIF1TX1MIX Input 3 Volume */ 
-       { 0x00000706, 0x0000 },   /* R1798  - AIF1TX1MIX Input 4 Source */ 
-       { 0x00000707, 0x0080 },   /* R1799  - AIF1TX1MIX Input 4 Volume */ 
-       { 0x00000708, 0x0000 },   /* R1800  - AIF1TX2MIX Input 1 Source */ 
-       { 0x00000709, 0x0080 },   /* R1801  - AIF1TX2MIX Input 1 Volume */ 
-       { 0x0000070A, 0x0000 },   /* R1802  - AIF1TX2MIX Input 2 Source */ 
-       { 0x0000070B, 0x0080 },   /* R1803  - AIF1TX2MIX Input 2 Volume */ 
-       { 0x0000070C, 0x0000 },   /* R1804  - AIF1TX2MIX Input 3 Source */ 
-       { 0x0000070D, 0x0080 },   /* R1805  - AIF1TX2MIX Input 3 Volume */ 
-       { 0x0000070E, 0x0000 },   /* R1806  - AIF1TX2MIX Input 4 Source */ 
-       { 0x0000070F, 0x0080 },   /* R1807  - AIF1TX2MIX Input 4 Volume */ 
-       { 0x00000710, 0x0000 },   /* R1808  - AIF1TX3MIX Input 1 Source */ 
-       { 0x00000711, 0x0080 },   /* R1809  - AIF1TX3MIX Input 1 Volume */ 
-       { 0x00000712, 0x0000 },   /* R1810  - AIF1TX3MIX Input 2 Source */ 
-       { 0x00000713, 0x0080 },   /* R1811  - AIF1TX3MIX Input 2 Volume */ 
-       { 0x00000714, 0x0000 },   /* R1812  - AIF1TX3MIX Input 3 Source */ 
-       { 0x00000715, 0x0080 },   /* R1813  - AIF1TX3MIX Input 3 Volume */ 
-       { 0x00000716, 0x0000 },   /* R1814  - AIF1TX3MIX Input 4 Source */ 
-       { 0x00000717, 0x0080 },   /* R1815  - AIF1TX3MIX Input 4 Volume */ 
-       { 0x00000718, 0x0000 },   /* R1816  - AIF1TX4MIX Input 1 Source */ 
-       { 0x00000719, 0x0080 },   /* R1817  - AIF1TX4MIX Input 1 Volume */ 
-       { 0x0000071A, 0x0000 },   /* R1818  - AIF1TX4MIX Input 2 Source */ 
-       { 0x0000071B, 0x0080 },   /* R1819  - AIF1TX4MIX Input 2 Volume */ 
-       { 0x0000071C, 0x0000 },   /* R1820  - AIF1TX4MIX Input 3 Source */ 
-       { 0x0000071D, 0x0080 },   /* R1821  - AIF1TX4MIX Input 3 Volume */ 
-       { 0x0000071E, 0x0000 },   /* R1822  - AIF1TX4MIX Input 4 Source */ 
-       { 0x0000071F, 0x0080 },   /* R1823  - AIF1TX4MIX Input 4 Volume */ 
-       { 0x00000720, 0x0000 },   /* R1824  - AIF1TX5MIX Input 1 Source */ 
-       { 0x00000721, 0x0080 },   /* R1825  - AIF1TX5MIX Input 1 Volume */ 
-       { 0x00000722, 0x0000 },   /* R1826  - AIF1TX5MIX Input 2 Source */ 
-       { 0x00000723, 0x0080 },   /* R1827  - AIF1TX5MIX Input 2 Volume */ 
-       { 0x00000724, 0x0000 },   /* R1828  - AIF1TX5MIX Input 3 Source */ 
-       { 0x00000725, 0x0080 },   /* R1829  - AIF1TX5MIX Input 3 Volume */ 
-       { 0x00000726, 0x0000 },   /* R1830  - AIF1TX5MIX Input 4 Source */ 
-       { 0x00000727, 0x0080 },   /* R1831  - AIF1TX5MIX Input 4 Volume */ 
-       { 0x00000728, 0x0000 },   /* R1832  - AIF1TX6MIX Input 1 Source */ 
-       { 0x00000729, 0x0080 },   /* R1833  - AIF1TX6MIX Input 1 Volume */ 
-       { 0x0000072A, 0x0000 },   /* R1834  - AIF1TX6MIX Input 2 Source */ 
-       { 0x0000072B, 0x0080 },   /* R1835  - AIF1TX6MIX Input 2 Volume */ 
-       { 0x0000072C, 0x0000 },   /* R1836  - AIF1TX6MIX Input 3 Source */ 
-       { 0x0000072D, 0x0080 },   /* R1837  - AIF1TX6MIX Input 3 Volume */ 
-       { 0x0000072E, 0x0000 },   /* R1838  - AIF1TX6MIX Input 4 Source */ 
-       { 0x0000072F, 0x0080 },   /* R1839  - AIF1TX6MIX Input 4 Volume */ 
-       { 0x00000730, 0x0000 },   /* R1840  - AIF1TX7MIX Input 1 Source */ 
-       { 0x00000731, 0x0080 },   /* R1841  - AIF1TX7MIX Input 1 Volume */ 
-       { 0x00000732, 0x0000 },   /* R1842  - AIF1TX7MIX Input 2 Source */ 
-       { 0x00000733, 0x0080 },   /* R1843  - AIF1TX7MIX Input 2 Volume */ 
-       { 0x00000734, 0x0000 },   /* R1844  - AIF1TX7MIX Input 3 Source */ 
-       { 0x00000735, 0x0080 },   /* R1845  - AIF1TX7MIX Input 3 Volume */ 
-       { 0x00000736, 0x0000 },   /* R1846  - AIF1TX7MIX Input 4 Source */ 
-       { 0x00000737, 0x0080 },   /* R1847  - AIF1TX7MIX Input 4 Volume */ 
-       { 0x00000738, 0x0000 },   /* R1848  - AIF1TX8MIX Input 1 Source */ 
-       { 0x00000739, 0x0080 },   /* R1849  - AIF1TX8MIX Input 1 Volume */ 
-       { 0x0000073A, 0x0000 },   /* R1850  - AIF1TX8MIX Input 2 Source */ 
-       { 0x0000073B, 0x0080 },   /* R1851  - AIF1TX8MIX Input 2 Volume */ 
-       { 0x0000073C, 0x0000 },   /* R1852  - AIF1TX8MIX Input 3 Source */ 
-       { 0x0000073D, 0x0080 },   /* R1853  - AIF1TX8MIX Input 3 Volume */ 
-       { 0x0000073E, 0x0000 },   /* R1854  - AIF1TX8MIX Input 4 Source */ 
-       { 0x0000073F, 0x0080 },   /* R1855  - AIF1TX8MIX Input 4 Volume */ 
-       { 0x00000740, 0x0000 },   /* R1856  - AIF2TX1MIX Input 1 Source */ 
-       { 0x00000741, 0x0080 },   /* R1857  - AIF2TX1MIX Input 1 Volume */ 
-       { 0x00000742, 0x0000 },   /* R1858  - AIF2TX1MIX Input 2 Source */ 
-       { 0x00000743, 0x0080 },   /* R1859  - AIF2TX1MIX Input 2 Volume */ 
-       { 0x00000744, 0x0000 },   /* R1860  - AIF2TX1MIX Input 3 Source */ 
-       { 0x00000745, 0x0080 },   /* R1861  - AIF2TX1MIX Input 3 Volume */ 
-       { 0x00000746, 0x0000 },   /* R1862  - AIF2TX1MIX Input 4 Source */ 
-       { 0x00000747, 0x0080 },   /* R1863  - AIF2TX1MIX Input 4 Volume */ 
-       { 0x00000748, 0x0000 },   /* R1864  - AIF2TX2MIX Input 1 Source */ 
-       { 0x00000749, 0x0080 },   /* R1865  - AIF2TX2MIX Input 1 Volume */ 
-       { 0x0000074A, 0x0000 },   /* R1866  - AIF2TX2MIX Input 2 Source */ 
-       { 0x0000074B, 0x0080 },   /* R1867  - AIF2TX2MIX Input 2 Volume */ 
-       { 0x0000074C, 0x0000 },   /* R1868  - AIF2TX2MIX Input 3 Source */ 
-       { 0x0000074D, 0x0080 },   /* R1869  - AIF2TX2MIX Input 3 Volume */ 
-       { 0x0000074E, 0x0000 },   /* R1870  - AIF2TX2MIX Input 4 Source */ 
-       { 0x0000074F, 0x0080 },   /* R1871  - AIF2TX2MIX Input 4 Volume */ 
-       { 0x00000780, 0x0000 },   /* R1920  - AIF3TX1MIX Input 1 Source */ 
-       { 0x00000781, 0x0080 },   /* R1921  - AIF3TX1MIX Input 1 Volume */ 
-       { 0x00000782, 0x0000 },   /* R1922  - AIF3TX1MIX Input 2 Source */ 
-       { 0x00000783, 0x0080 },   /* R1923  - AIF3TX1MIX Input 2 Volume */ 
-       { 0x00000784, 0x0000 },   /* R1924  - AIF3TX1MIX Input 3 Source */ 
-       { 0x00000785, 0x0080 },   /* R1925  - AIF3TX1MIX Input 3 Volume */ 
-       { 0x00000786, 0x0000 },   /* R1926  - AIF3TX1MIX Input 4 Source */ 
-       { 0x00000787, 0x0080 },   /* R1927  - AIF3TX1MIX Input 4 Volume */ 
-       { 0x00000788, 0x0000 },   /* R1928  - AIF3TX2MIX Input 1 Source */ 
-       { 0x00000789, 0x0080 },   /* R1929  - AIF3TX2MIX Input 1 Volume */ 
-       { 0x0000078A, 0x0000 },   /* R1930  - AIF3TX2MIX Input 2 Source */ 
-       { 0x0000078B, 0x0080 },   /* R1931  - AIF3TX2MIX Input 2 Volume */ 
-       { 0x0000078C, 0x0000 },   /* R1932  - AIF3TX2MIX Input 3 Source */ 
-       { 0x0000078D, 0x0080 },   /* R1933  - AIF3TX2MIX Input 3 Volume */ 
-       { 0x0000078E, 0x0000 },   /* R1934  - AIF3TX2MIX Input 4 Source */ 
-       { 0x0000078F, 0x0080 },   /* R1935  - AIF3TX2MIX Input 4 Volume */ 
-       { 0x000007C0, 0x0000 },   /* R1984  - SLIMTX1MIX Input 1 Source */ 
-       { 0x000007C1, 0x0080 },   /* R1985  - SLIMTX1MIX Input 1 Volume */ 
-       { 0x000007C2, 0x0000 },   /* R1986  - SLIMTX1MIX Input 2 Source */ 
-       { 0x000007C3, 0x0080 },   /* R1987  - SLIMTX1MIX Input 2 Volume */ 
-       { 0x000007C4, 0x0000 },   /* R1988  - SLIMTX1MIX Input 3 Source */ 
-       { 0x000007C5, 0x0080 },   /* R1989  - SLIMTX1MIX Input 3 Volume */ 
-       { 0x000007C6, 0x0000 },   /* R1990  - SLIMTX1MIX Input 4 Source */ 
-       { 0x000007C7, 0x0080 },   /* R1991  - SLIMTX1MIX Input 4 Volume */ 
-       { 0x000007C8, 0x0000 },   /* R1992  - SLIMTX2MIX Input 1 Source */ 
-       { 0x000007C9, 0x0080 },   /* R1993  - SLIMTX2MIX Input 1 Volume */ 
-       { 0x000007CA, 0x0000 },   /* R1994  - SLIMTX2MIX Input 2 Source */ 
-       { 0x000007CB, 0x0080 },   /* R1995  - SLIMTX2MIX Input 2 Volume */ 
-       { 0x000007CC, 0x0000 },   /* R1996  - SLIMTX2MIX Input 3 Source */ 
-       { 0x000007CD, 0x0080 },   /* R1997  - SLIMTX2MIX Input 3 Volume */ 
-       { 0x000007CE, 0x0000 },   /* R1998  - SLIMTX2MIX Input 4 Source */ 
-       { 0x000007CF, 0x0080 },   /* R1999  - SLIMTX2MIX Input 4 Volume */ 
-       { 0x000007D0, 0x0000 },   /* R2000  - SLIMTX3MIX Input 1 Source */ 
-       { 0x000007D1, 0x0080 },   /* R2001  - SLIMTX3MIX Input 1 Volume */ 
-       { 0x000007D2, 0x0000 },   /* R2002  - SLIMTX3MIX Input 2 Source */ 
-       { 0x000007D3, 0x0080 },   /* R2003  - SLIMTX3MIX Input 2 Volume */ 
-       { 0x000007D4, 0x0000 },   /* R2004  - SLIMTX3MIX Input 3 Source */ 
-       { 0x000007D5, 0x0080 },   /* R2005  - SLIMTX3MIX Input 3 Volume */ 
-       { 0x000007D6, 0x0000 },   /* R2006  - SLIMTX3MIX Input 4 Source */ 
-       { 0x000007D7, 0x0080 },   /* R2007  - SLIMTX3MIX Input 4 Volume */ 
-       { 0x000007D8, 0x0000 },   /* R2008  - SLIMTX4MIX Input 1 Source */ 
-       { 0x000007D9, 0x0080 },   /* R2009  - SLIMTX4MIX Input 1 Volume */ 
-       { 0x000007DA, 0x0000 },   /* R2010  - SLIMTX4MIX Input 2 Source */ 
-       { 0x000007DB, 0x0080 },   /* R2011  - SLIMTX4MIX Input 2 Volume */ 
-       { 0x000007DC, 0x0000 },   /* R2012  - SLIMTX4MIX Input 3 Source */ 
-       { 0x000007DD, 0x0080 },   /* R2013  - SLIMTX4MIX Input 3 Volume */ 
-       { 0x000007DE, 0x0000 },   /* R2014  - SLIMTX4MIX Input 4 Source */ 
-       { 0x000007DF, 0x0080 },   /* R2015  - SLIMTX4MIX Input 4 Volume */ 
-       { 0x000007E0, 0x0000 },   /* R2016  - SLIMTX5MIX Input 1 Source */ 
-       { 0x000007E1, 0x0080 },   /* R2017  - SLIMTX5MIX Input 1 Volume */ 
-       { 0x000007E2, 0x0000 },   /* R2018  - SLIMTX5MIX Input 2 Source */ 
-       { 0x000007E3, 0x0080 },   /* R2019  - SLIMTX5MIX Input 2 Volume */ 
-       { 0x000007E4, 0x0000 },   /* R2020  - SLIMTX5MIX Input 3 Source */ 
-       { 0x000007E5, 0x0080 },   /* R2021  - SLIMTX5MIX Input 3 Volume */ 
-       { 0x000007E6, 0x0000 },   /* R2022  - SLIMTX5MIX Input 4 Source */ 
-       { 0x000007E7, 0x0080 },   /* R2023  - SLIMTX5MIX Input 4 Volume */ 
-       { 0x000007E8, 0x0000 },   /* R2024  - SLIMTX6MIX Input 1 Source */ 
-       { 0x000007E9, 0x0080 },   /* R2025  - SLIMTX6MIX Input 1 Volume */ 
-       { 0x000007EA, 0x0000 },   /* R2026  - SLIMTX6MIX Input 2 Source */ 
-       { 0x000007EB, 0x0080 },   /* R2027  - SLIMTX6MIX Input 2 Volume */ 
-       { 0x000007EC, 0x0000 },   /* R2028  - SLIMTX6MIX Input 3 Source */ 
-       { 0x000007ED, 0x0080 },   /* R2029  - SLIMTX6MIX Input 3 Volume */ 
-       { 0x000007EE, 0x0000 },   /* R2030  - SLIMTX6MIX Input 4 Source */ 
-       { 0x000007EF, 0x0080 },   /* R2031  - SLIMTX6MIX Input 4 Volume */ 
-       { 0x000007F0, 0x0000 },   /* R2032  - SLIMTX7MIX Input 1 Source */ 
-       { 0x000007F1, 0x0080 },   /* R2033  - SLIMTX7MIX Input 1 Volume */ 
-       { 0x000007F2, 0x0000 },   /* R2034  - SLIMTX7MIX Input 2 Source */ 
-       { 0x000007F3, 0x0080 },   /* R2035  - SLIMTX7MIX Input 2 Volume */ 
-       { 0x000007F4, 0x0000 },   /* R2036  - SLIMTX7MIX Input 3 Source */ 
-       { 0x000007F5, 0x0080 },   /* R2037  - SLIMTX7MIX Input 3 Volume */ 
-       { 0x000007F6, 0x0000 },   /* R2038  - SLIMTX7MIX Input 4 Source */ 
-       { 0x000007F7, 0x0080 },   /* R2039  - SLIMTX7MIX Input 4 Volume */ 
-       { 0x000007F8, 0x0000 },   /* R2040  - SLIMTX8MIX Input 1 Source */ 
-       { 0x000007F9, 0x0080 },   /* R2041  - SLIMTX8MIX Input 1 Volume */ 
-       { 0x000007FA, 0x0000 },   /* R2042  - SLIMTX8MIX Input 2 Source */ 
-       { 0x000007FB, 0x0080 },   /* R2043  - SLIMTX8MIX Input 2 Volume */ 
-       { 0x000007FC, 0x0000 },   /* R2044  - SLIMTX8MIX Input 3 Source */ 
-       { 0x000007FD, 0x0080 },   /* R2045  - SLIMTX8MIX Input 3 Volume */ 
-       { 0x000007FE, 0x0000 },   /* R2046  - SLIMTX8MIX Input 4 Source */ 
-       { 0x000007FF, 0x0080 },   /* R2047  - SLIMTX8MIX Input 4 Volume */ 
-       { 0x00000880, 0x0000 },   /* R2176  - EQ1MIX Input 1 Source */ 
-       { 0x00000881, 0x0080 },   /* R2177  - EQ1MIX Input 1 Volume */ 
-       { 0x00000882, 0x0000 },   /* R2178  - EQ1MIX Input 2 Source */ 
-       { 0x00000883, 0x0080 },   /* R2179  - EQ1MIX Input 2 Volume */ 
-       { 0x00000884, 0x0000 },   /* R2180  - EQ1MIX Input 3 Source */ 
-       { 0x00000885, 0x0080 },   /* R2181  - EQ1MIX Input 3 Volume */ 
-       { 0x00000886, 0x0000 },   /* R2182  - EQ1MIX Input 4 Source */ 
-       { 0x00000887, 0x0080 },   /* R2183  - EQ1MIX Input 4 Volume */ 
-       { 0x00000888, 0x0000 },   /* R2184  - EQ2MIX Input 1 Source */ 
-       { 0x00000889, 0x0080 },   /* R2185  - EQ2MIX Input 1 Volume */ 
-       { 0x0000088A, 0x0000 },   /* R2186  - EQ2MIX Input 2 Source */ 
-       { 0x0000088B, 0x0080 },   /* R2187  - EQ2MIX Input 2 Volume */ 
-       { 0x0000088C, 0x0000 },   /* R2188  - EQ2MIX Input 3 Source */ 
-       { 0x0000088D, 0x0080 },   /* R2189  - EQ2MIX Input 3 Volume */ 
-       { 0x0000088E, 0x0000 },   /* R2190  - EQ2MIX Input 4 Source */ 
-       { 0x0000088F, 0x0080 },   /* R2191  - EQ2MIX Input 4 Volume */ 
-       { 0x00000890, 0x0000 },   /* R2192  - EQ3MIX Input 1 Source */ 
-       { 0x00000891, 0x0080 },   /* R2193  - EQ3MIX Input 1 Volume */ 
-       { 0x00000892, 0x0000 },   /* R2194  - EQ3MIX Input 2 Source */ 
-       { 0x00000893, 0x0080 },   /* R2195  - EQ3MIX Input 2 Volume */ 
-       { 0x00000894, 0x0000 },   /* R2196  - EQ3MIX Input 3 Source */ 
-       { 0x00000895, 0x0080 },   /* R2197  - EQ3MIX Input 3 Volume */ 
-       { 0x00000896, 0x0000 },   /* R2198  - EQ3MIX Input 4 Source */ 
-       { 0x00000897, 0x0080 },   /* R2199  - EQ3MIX Input 4 Volume */ 
-       { 0x00000898, 0x0000 },   /* R2200  - EQ4MIX Input 1 Source */ 
-       { 0x00000899, 0x0080 },   /* R2201  - EQ4MIX Input 1 Volume */ 
-       { 0x0000089A, 0x0000 },   /* R2202  - EQ4MIX Input 2 Source */ 
-       { 0x0000089B, 0x0080 },   /* R2203  - EQ4MIX Input 2 Volume */ 
-       { 0x0000089C, 0x0000 },   /* R2204  - EQ4MIX Input 3 Source */ 
-       { 0x0000089D, 0x0080 },   /* R2205  - EQ4MIX Input 3 Volume */ 
-       { 0x0000089E, 0x0000 },   /* R2206  - EQ4MIX Input 4 Source */ 
-       { 0x0000089F, 0x0080 },   /* R2207  - EQ4MIX Input 4 Volume */ 
-       { 0x000008C0, 0x0000 },   /* R2240  - DRC1LMIX Input 1 Source */ 
-       { 0x000008C1, 0x0080 },   /* R2241  - DRC1LMIX Input 1 Volume */ 
-       { 0x000008C2, 0x0000 },   /* R2242  - DRC1LMIX Input 2 Source */ 
-       { 0x000008C3, 0x0080 },   /* R2243  - DRC1LMIX Input 2 Volume */ 
-       { 0x000008C4, 0x0000 },   /* R2244  - DRC1LMIX Input 3 Source */ 
-       { 0x000008C5, 0x0080 },   /* R2245  - DRC1LMIX Input 3 Volume */ 
-       { 0x000008C6, 0x0000 },   /* R2246  - DRC1LMIX Input 4 Source */ 
-       { 0x000008C7, 0x0080 },   /* R2247  - DRC1LMIX Input 4 Volume */ 
-       { 0x000008C8, 0x0000 },   /* R2248  - DRC1RMIX Input 1 Source */ 
-       { 0x000008C9, 0x0080 },   /* R2249  - DRC1RMIX Input 1 Volume */ 
-       { 0x000008CA, 0x0000 },   /* R2250  - DRC1RMIX Input 2 Source */ 
-       { 0x000008CB, 0x0080 },   /* R2251  - DRC1RMIX Input 2 Volume */ 
-       { 0x000008CC, 0x0000 },   /* R2252  - DRC1RMIX Input 3 Source */ 
-       { 0x000008CD, 0x0080 },   /* R2253  - DRC1RMIX Input 3 Volume */ 
-       { 0x000008CE, 0x0000 },   /* R2254  - DRC1RMIX Input 4 Source */ 
-       { 0x000008CF, 0x0080 },   /* R2255  - DRC1RMIX Input 4 Volume */ 
-       { 0x00000900, 0x0000 },   /* R2304  - HPLP1MIX Input 1 Source */ 
-       { 0x00000901, 0x0080 },   /* R2305  - HPLP1MIX Input 1 Volume */ 
-       { 0x00000902, 0x0000 },   /* R2306  - HPLP1MIX Input 2 Source */ 
-       { 0x00000903, 0x0080 },   /* R2307  - HPLP1MIX Input 2 Volume */ 
-       { 0x00000904, 0x0000 },   /* R2308  - HPLP1MIX Input 3 Source */ 
-       { 0x00000905, 0x0080 },   /* R2309  - HPLP1MIX Input 3 Volume */ 
-       { 0x00000906, 0x0000 },   /* R2310  - HPLP1MIX Input 4 Source */ 
-       { 0x00000907, 0x0080 },   /* R2311  - HPLP1MIX Input 4 Volume */ 
-       { 0x00000908, 0x0000 },   /* R2312  - HPLP2MIX Input 1 Source */ 
-       { 0x00000909, 0x0080 },   /* R2313  - HPLP2MIX Input 1 Volume */ 
-       { 0x0000090A, 0x0000 },   /* R2314  - HPLP2MIX Input 2 Source */ 
-       { 0x0000090B, 0x0080 },   /* R2315  - HPLP2MIX Input 2 Volume */ 
-       { 0x0000090C, 0x0000 },   /* R2316  - HPLP2MIX Input 3 Source */ 
-       { 0x0000090D, 0x0080 },   /* R2317  - HPLP2MIX Input 3 Volume */ 
-       { 0x0000090E, 0x0000 },   /* R2318  - HPLP2MIX Input 4 Source */ 
-       { 0x0000090F, 0x0080 },   /* R2319  - HPLP2MIX Input 4 Volume */ 
-       { 0x00000910, 0x0000 },   /* R2320  - HPLP3MIX Input 1 Source */ 
-       { 0x00000911, 0x0080 },   /* R2321  - HPLP3MIX Input 1 Volume */ 
-       { 0x00000912, 0x0000 },   /* R2322  - HPLP3MIX Input 2 Source */ 
-       { 0x00000913, 0x0080 },   /* R2323  - HPLP3MIX Input 2 Volume */ 
-       { 0x00000914, 0x0000 },   /* R2324  - HPLP3MIX Input 3 Source */ 
-       { 0x00000915, 0x0080 },   /* R2325  - HPLP3MIX Input 3 Volume */ 
-       { 0x00000916, 0x0000 },   /* R2326  - HPLP3MIX Input 4 Source */ 
-       { 0x00000917, 0x0080 },   /* R2327  - HPLP3MIX Input 4 Volume */ 
-       { 0x00000918, 0x0000 },   /* R2328  - HPLP4MIX Input 1 Source */ 
-       { 0x00000919, 0x0080 },   /* R2329  - HPLP4MIX Input 1 Volume */ 
-       { 0x0000091A, 0x0000 },   /* R2330  - HPLP4MIX Input 2 Source */ 
-       { 0x0000091B, 0x0080 },   /* R2331  - HPLP4MIX Input 2 Volume */ 
-       { 0x0000091C, 0x0000 },   /* R2332  - HPLP4MIX Input 3 Source */ 
-       { 0x0000091D, 0x0080 },   /* R2333  - HPLP4MIX Input 3 Volume */ 
-       { 0x0000091E, 0x0000 },   /* R2334  - HPLP4MIX Input 4 Source */ 
-       { 0x0000091F, 0x0080 },   /* R2335  - HPLP4MIX Input 4 Volume */ 
-       { 0x00000940, 0x0000 },   /* R2368  - DSP1LMIX Input 1 Source */ 
-       { 0x00000941, 0x0080 },   /* R2369  - DSP1LMIX Input 1 Volume */ 
-       { 0x00000942, 0x0000 },   /* R2370  - DSP1LMIX Input 2 Source */ 
-       { 0x00000943, 0x0080 },   /* R2371  - DSP1LMIX Input 2 Volume */ 
-       { 0x00000944, 0x0000 },   /* R2372  - DSP1LMIX Input 3 Source */ 
-       { 0x00000945, 0x0080 },   /* R2373  - DSP1LMIX Input 3 Volume */ 
-       { 0x00000946, 0x0000 },   /* R2374  - DSP1LMIX Input 4 Source */ 
-       { 0x00000947, 0x0080 },   /* R2375  - DSP1LMIX Input 4 Volume */ 
-       { 0x00000948, 0x0000 },   /* R2376  - DSP1RMIX Input 1 Source */ 
-       { 0x00000949, 0x0080 },   /* R2377  - DSP1RMIX Input 1 Volume */ 
-       { 0x0000094A, 0x0000 },   /* R2378  - DSP1RMIX Input 2 Source */ 
-       { 0x0000094B, 0x0080 },   /* R2379  - DSP1RMIX Input 2 Volume */ 
-       { 0x0000094C, 0x0000 },   /* R2380  - DSP1RMIX Input 3 Source */ 
-       { 0x0000094D, 0x0080 },   /* R2381  - DSP1RMIX Input 3 Volume */ 
-       { 0x0000094E, 0x0000 },   /* R2382  - DSP1RMIX Input 4 Source */ 
-       { 0x0000094F, 0x0080 },   /* R2383  - DSP1RMIX Input 4 Volume */ 
-       { 0x00000950, 0x0000 },   /* R2384  - DSP1AUX1MIX Input 1 Source */ 
-       { 0x00000958, 0x0000 },   /* R2392  - DSP1AUX2MIX Input 1 Source */ 
-       { 0x00000960, 0x0000 },   /* R2400  - DSP1AUX3MIX Input 1 Source */ 
-       { 0x00000968, 0x0000 },   /* R2408  - DSP1AUX4MIX Input 1 Source */ 
-       { 0x00000970, 0x0000 },   /* R2416  - DSP1AUX5MIX Input 1 Source */ 
-       { 0x00000978, 0x0000 },   /* R2424  - DSP1AUX6MIX Input 1 Source */ 
-       { 0x00000A80, 0x0000 },   /* R2688  - ASRC1LMIX Input 1 Source */ 
-       { 0x00000A88, 0x0000 },   /* R2696  - ASRC1RMIX Input 1 Source */ 
-       { 0x00000A90, 0x0000 },   /* R2704  - ASRC2LMIX Input 1 Source */ 
-       { 0x00000A98, 0x0000 },   /* R2712  - ASRC2RMIX Input 1 Source */ 
-       { 0x00000B00, 0x0000 },   /* R2816  - ISRC1DEC1MIX Input 1 Source */ 
-       { 0x00000B08, 0x0000 },   /* R2824  - ISRC1DEC2MIX Input 1 Source */ 
-       { 0x00000B20, 0x0000 },   /* R2848  - ISRC1INT1MIX Input 1 Source */ 
-       { 0x00000B28, 0x0000 },   /* R2856  - ISRC1INT2MIX Input 1 Source */ 
-       { 0x00000B40, 0x0000 },   /* R2880  - ISRC2DEC1MIX Input 1 Source */ 
-       { 0x00000B48, 0x0000 },   /* R2888  - ISRC2DEC2MIX Input 1 Source */ 
-       { 0x00000B60, 0x0000 },   /* R2912  - ISRC2INT1MIX Input 1 Source */ 
-       { 0x00000B68, 0x0000 },   /* R2920  - ISRC2INT2MIX Input 1 Source */ 
-       { 0x00000C00, 0xA101 },   /* R3072  - GPIO1 CTRL */ 
-       { 0x00000C01, 0xA101 },   /* R3073  - GPIO2 CTRL */ 
-       { 0x00000C02, 0xA101 },   /* R3074  - GPIO3 CTRL */ 
-       { 0x00000C03, 0xA101 },   /* R3075  - GPIO4 CTRL */ 
-       { 0x00000C04, 0xA101 },   /* R3076  - GPIO5 CTRL */ 
-       { 0x00000C0F, 0x0400 },   /* R3087  - IRQ CTRL 1 */ 
-       { 0x00000C10, 0x1000 },   /* R3088  - GPIO Debounce Config */ 
-       { 0x00000C20, 0x8002 },   /* R3104  - Misc Pad Ctrl 1 */ 
+       { 0x00000490, 0x0069 },   /* R1168  - PDM SPK1 CTRL 1 */
+       { 0x00000491, 0x0000 },   /* R1169  - PDM SPK1 CTRL 2 */
+       { 0x00000500, 0x000C },   /* R1280  - AIF1 BCLK Ctrl */
+       { 0x00000501, 0x0008 },   /* R1281  - AIF1 Tx Pin Ctrl */
+       { 0x00000502, 0x0000 },   /* R1282  - AIF1 Rx Pin Ctrl */
+       { 0x00000503, 0x0000 },   /* R1283  - AIF1 Rate Ctrl */
+       { 0x00000504, 0x0000 },   /* R1284  - AIF1 Format */
+       { 0x00000505, 0x0040 },   /* R1285  - AIF1 Tx BCLK Rate */
+       { 0x00000506, 0x0040 },   /* R1286  - AIF1 Rx BCLK Rate */
+       { 0x00000507, 0x1818 },   /* R1287  - AIF1 Frame Ctrl 1 */
+       { 0x00000508, 0x1818 },   /* R1288  - AIF1 Frame Ctrl 2 */
+       { 0x00000509, 0x0000 },   /* R1289  - AIF1 Frame Ctrl 3 */
+       { 0x0000050A, 0x0001 },   /* R1290  - AIF1 Frame Ctrl 4 */
+       { 0x0000050B, 0x0002 },   /* R1291  - AIF1 Frame Ctrl 5 */
+       { 0x0000050C, 0x0003 },   /* R1292  - AIF1 Frame Ctrl 6 */
+       { 0x0000050D, 0x0004 },   /* R1293  - AIF1 Frame Ctrl 7 */
+       { 0x0000050E, 0x0005 },   /* R1294  - AIF1 Frame Ctrl 8 */
+       { 0x0000050F, 0x0006 },   /* R1295  - AIF1 Frame Ctrl 9 */
+       { 0x00000510, 0x0007 },   /* R1296  - AIF1 Frame Ctrl 10 */
+       { 0x00000511, 0x0000 },   /* R1297  - AIF1 Frame Ctrl 11 */
+       { 0x00000512, 0x0001 },   /* R1298  - AIF1 Frame Ctrl 12 */
+       { 0x00000513, 0x0002 },   /* R1299  - AIF1 Frame Ctrl 13 */
+       { 0x00000514, 0x0003 },   /* R1300  - AIF1 Frame Ctrl 14 */
+       { 0x00000515, 0x0004 },   /* R1301  - AIF1 Frame Ctrl 15 */
+       { 0x00000516, 0x0005 },   /* R1302  - AIF1 Frame Ctrl 16 */
+       { 0x00000517, 0x0006 },   /* R1303  - AIF1 Frame Ctrl 17 */
+       { 0x00000518, 0x0007 },   /* R1304  - AIF1 Frame Ctrl 18 */
+       { 0x00000519, 0x0000 },   /* R1305  - AIF1 Tx Enables */
+       { 0x0000051A, 0x0000 },   /* R1306  - AIF1 Rx Enables */
+       { 0x00000540, 0x000C },   /* R1344  - AIF2 BCLK Ctrl */
+       { 0x00000541, 0x0008 },   /* R1345  - AIF2 Tx Pin Ctrl */
+       { 0x00000542, 0x0000 },   /* R1346  - AIF2 Rx Pin Ctrl */
+       { 0x00000543, 0x0000 },   /* R1347  - AIF2 Rate Ctrl */
+       { 0x00000544, 0x0000 },   /* R1348  - AIF2 Format */
+       { 0x00000545, 0x0040 },   /* R1349  - AIF2 Tx BCLK Rate */
+       { 0x00000546, 0x0040 },   /* R1350  - AIF2 Rx BCLK Rate */
+       { 0x00000547, 0x1818 },   /* R1351  - AIF2 Frame Ctrl 1 */
+       { 0x00000548, 0x1818 },   /* R1352  - AIF2 Frame Ctrl 2 */
+       { 0x00000549, 0x0000 },   /* R1353  - AIF2 Frame Ctrl 3 */
+       { 0x0000054A, 0x0001 },   /* R1354  - AIF2 Frame Ctrl 4 */
+       { 0x00000551, 0x0000 },   /* R1361  - AIF2 Frame Ctrl 11 */
+       { 0x00000552, 0x0001 },   /* R1362  - AIF2 Frame Ctrl 12 */
+       { 0x00000559, 0x0000 },   /* R1369  - AIF2 Tx Enables */
+       { 0x0000055A, 0x0000 },   /* R1370  - AIF2 Rx Enables */
+       { 0x00000580, 0x000C },   /* R1408  - AIF3 BCLK Ctrl */
+       { 0x00000581, 0x0008 },   /* R1409  - AIF3 Tx Pin Ctrl */
+       { 0x00000582, 0x0000 },   /* R1410  - AIF3 Rx Pin Ctrl */
+       { 0x00000583, 0x0000 },   /* R1411  - AIF3 Rate Ctrl */
+       { 0x00000584, 0x0000 },   /* R1412  - AIF3 Format */
+       { 0x00000585, 0x0040 },   /* R1413  - AIF3 Tx BCLK Rate */
+       { 0x00000586, 0x0040 },   /* R1414  - AIF3 Rx BCLK Rate */
+       { 0x00000587, 0x1818 },   /* R1415  - AIF3 Frame Ctrl 1 */
+       { 0x00000588, 0x1818 },   /* R1416  - AIF3 Frame Ctrl 2 */
+       { 0x00000589, 0x0000 },   /* R1417  - AIF3 Frame Ctrl 3 */
+       { 0x0000058A, 0x0001 },   /* R1418  - AIF3 Frame Ctrl 4 */
+       { 0x00000591, 0x0000 },   /* R1425  - AIF3 Frame Ctrl 11 */
+       { 0x00000592, 0x0001 },   /* R1426  - AIF3 Frame Ctrl 12 */
+       { 0x00000599, 0x0000 },   /* R1433  - AIF3 Tx Enables */
+       { 0x0000059A, 0x0000 },   /* R1434  - AIF3 Rx Enables */
+       { 0x000005E3, 0x0004 },   /* R1507  - SLIMbus Framer Ref Gear */
+       { 0x000005E5, 0x0000 },   /* R1509  - SLIMbus Rates 1 */
+       { 0x000005E6, 0x0000 },   /* R1510  - SLIMbus Rates 2 */
+       { 0x000005E7, 0x0000 },   /* R1511  - SLIMbus Rates 3 */
+       { 0x000005E8, 0x0000 },   /* R1512  - SLIMbus Rates 4 */
+       { 0x000005E9, 0x0000 },   /* R1513  - SLIMbus Rates 5 */
+       { 0x000005EA, 0x0000 },   /* R1514  - SLIMbus Rates 6 */
+       { 0x000005EB, 0x0000 },   /* R1515  - SLIMbus Rates 7 */
+       { 0x000005EC, 0x0000 },   /* R1516  - SLIMbus Rates 8 */
+       { 0x000005F5, 0x0000 },   /* R1525  - SLIMbus RX Channel Enable */
+       { 0x000005F6, 0x0000 },   /* R1526  - SLIMbus TX Channel Enable */
+       { 0x00000640, 0x0000 },   /* R1600  - PWM1MIX Input 1 Source */
+       { 0x00000641, 0x0080 },   /* R1601  - PWM1MIX Input 1 Volume */
+       { 0x00000642, 0x0000 },   /* R1602  - PWM1MIX Input 2 Source */
+       { 0x00000643, 0x0080 },   /* R1603  - PWM1MIX Input 2 Volume */
+       { 0x00000644, 0x0000 },   /* R1604  - PWM1MIX Input 3 Source */
+       { 0x00000645, 0x0080 },   /* R1605  - PWM1MIX Input 3 Volume */
+       { 0x00000646, 0x0000 },   /* R1606  - PWM1MIX Input 4 Source */
+       { 0x00000647, 0x0080 },   /* R1607  - PWM1MIX Input 4 Volume */
+       { 0x00000648, 0x0000 },   /* R1608  - PWM2MIX Input 1 Source */
+       { 0x00000649, 0x0080 },   /* R1609  - PWM2MIX Input 1 Volume */
+       { 0x0000064A, 0x0000 },   /* R1610  - PWM2MIX Input 2 Source */
+       { 0x0000064B, 0x0080 },   /* R1611  - PWM2MIX Input 2 Volume */
+       { 0x0000064C, 0x0000 },   /* R1612  - PWM2MIX Input 3 Source */
+       { 0x0000064D, 0x0080 },   /* R1613  - PWM2MIX Input 3 Volume */
+       { 0x0000064E, 0x0000 },   /* R1614  - PWM2MIX Input 4 Source */
+       { 0x0000064F, 0x0080 },   /* R1615  - PWM2MIX Input 4 Volume */
+       { 0x00000660, 0x0000 },   /* R1632  - MICMIX Input 1 Source */
+       { 0x00000661, 0x0080 },   /* R1633  - MICMIX Input 1 Volume */
+       { 0x00000662, 0x0000 },   /* R1634  - MICMIX Input 2 Source */
+       { 0x00000663, 0x0080 },   /* R1635  - MICMIX Input 2 Volume */
+       { 0x00000664, 0x0000 },   /* R1636  - MICMIX Input 3 Source */
+       { 0x00000665, 0x0080 },   /* R1637  - MICMIX Input 3 Volume */
+       { 0x00000666, 0x0000 },   /* R1638  - MICMIX Input 4 Source */
+       { 0x00000667, 0x0080 },   /* R1639  - MICMIX Input 4 Volume */
+       { 0x00000668, 0x0000 },   /* R1640  - NOISEMIX Input 1 Source */
+       { 0x00000669, 0x0080 },   /* R1641  - NOISEMIX Input 1 Volume */
+       { 0x0000066A, 0x0000 },   /* R1642  - NOISEMIX Input 2 Source */
+       { 0x0000066B, 0x0080 },   /* R1643  - NOISEMIX Input 2 Volume */
+       { 0x0000066C, 0x0000 },   /* R1644  - NOISEMIX Input 3 Source */
+       { 0x0000066D, 0x0080 },   /* R1645  - NOISEMIX Input 3 Volume */
+       { 0x0000066E, 0x0000 },   /* R1646  - NOISEMIX Input 4 Source */
+       { 0x0000066F, 0x0080 },   /* R1647  - NOISEMIX Input 4 Volume */
+       { 0x00000680, 0x0000 },   /* R1664  - OUT1LMIX Input 1 Source */
+       { 0x00000681, 0x0080 },   /* R1665  - OUT1LMIX Input 1 Volume */
+       { 0x00000682, 0x0000 },   /* R1666  - OUT1LMIX Input 2 Source */
+       { 0x00000683, 0x0080 },   /* R1667  - OUT1LMIX Input 2 Volume */
+       { 0x00000684, 0x0000 },   /* R1668  - OUT1LMIX Input 3 Source */
+       { 0x00000685, 0x0080 },   /* R1669  - OUT1LMIX Input 3 Volume */
+       { 0x00000686, 0x0000 },   /* R1670  - OUT1LMIX Input 4 Source */
+       { 0x00000687, 0x0080 },   /* R1671  - OUT1LMIX Input 4 Volume */
+       { 0x00000688, 0x0000 },   /* R1672  - OUT1RMIX Input 1 Source */
+       { 0x00000689, 0x0080 },   /* R1673  - OUT1RMIX Input 1 Volume */
+       { 0x0000068A, 0x0000 },   /* R1674  - OUT1RMIX Input 2 Source */
+       { 0x0000068B, 0x0080 },   /* R1675  - OUT1RMIX Input 2 Volume */
+       { 0x0000068C, 0x0000 },   /* R1676  - OUT1RMIX Input 3 Source */
+       { 0x0000068D, 0x0080 },   /* R1677  - OUT1RMIX Input 3 Volume */
+       { 0x0000068E, 0x0000 },   /* R1678  - OUT1RMIX Input 4 Source */
+       { 0x0000068F, 0x0080 },   /* R1679  - OUT1RMIX Input 4 Volume */
+       { 0x00000690, 0x0000 },   /* R1680  - OUT2LMIX Input 1 Source */
+       { 0x00000691, 0x0080 },   /* R1681  - OUT2LMIX Input 1 Volume */
+       { 0x00000692, 0x0000 },   /* R1682  - OUT2LMIX Input 2 Source */
+       { 0x00000693, 0x0080 },   /* R1683  - OUT2LMIX Input 2 Volume */
+       { 0x00000694, 0x0000 },   /* R1684  - OUT2LMIX Input 3 Source */
+       { 0x00000695, 0x0080 },   /* R1685  - OUT2LMIX Input 3 Volume */
+       { 0x00000696, 0x0000 },   /* R1686  - OUT2LMIX Input 4 Source */
+       { 0x00000697, 0x0080 },   /* R1687  - OUT2LMIX Input 4 Volume */
+       { 0x00000698, 0x0000 },   /* R1688  - OUT2RMIX Input 1 Source */
+       { 0x00000699, 0x0080 },   /* R1689  - OUT2RMIX Input 1 Volume */
+       { 0x0000069A, 0x0000 },   /* R1690  - OUT2RMIX Input 2 Source */
+       { 0x0000069B, 0x0080 },   /* R1691  - OUT2RMIX Input 2 Volume */
+       { 0x0000069C, 0x0000 },   /* R1692  - OUT2RMIX Input 3 Source */
+       { 0x0000069D, 0x0080 },   /* R1693  - OUT2RMIX Input 3 Volume */
+       { 0x0000069E, 0x0000 },   /* R1694  - OUT2RMIX Input 4 Source */
+       { 0x0000069F, 0x0080 },   /* R1695  - OUT2RMIX Input 4 Volume */
+       { 0x000006A0, 0x0000 },   /* R1696  - OUT3LMIX Input 1 Source */
+       { 0x000006A1, 0x0080 },   /* R1697  - OUT3LMIX Input 1 Volume */
+       { 0x000006A2, 0x0000 },   /* R1698  - OUT3LMIX Input 2 Source */
+       { 0x000006A3, 0x0080 },   /* R1699  - OUT3LMIX Input 2 Volume */
+       { 0x000006A4, 0x0000 },   /* R1700  - OUT3LMIX Input 3 Source */
+       { 0x000006A5, 0x0080 },   /* R1701  - OUT3LMIX Input 3 Volume */
+       { 0x000006A6, 0x0000 },   /* R1702  - OUT3LMIX Input 4 Source */
+       { 0x000006A7, 0x0080 },   /* R1703  - OUT3LMIX Input 4 Volume */
+       { 0x000006B0, 0x0000 },   /* R1712  - OUT4LMIX Input 1 Source */
+       { 0x000006B1, 0x0080 },   /* R1713  - OUT4LMIX Input 1 Volume */
+       { 0x000006B2, 0x0000 },   /* R1714  - OUT4LMIX Input 2 Source */
+       { 0x000006B3, 0x0080 },   /* R1715  - OUT4LMIX Input 2 Volume */
+       { 0x000006B4, 0x0000 },   /* R1716  - OUT4LMIX Input 3 Source */
+       { 0x000006B5, 0x0080 },   /* R1717  - OUT4LMIX Input 3 Volume */
+       { 0x000006B6, 0x0000 },   /* R1718  - OUT4LMIX Input 4 Source */
+       { 0x000006B7, 0x0080 },   /* R1719  - OUT4LMIX Input 4 Volume */
+       { 0x000006B8, 0x0000 },   /* R1720  - OUT4RMIX Input 1 Source */
+       { 0x000006B9, 0x0080 },   /* R1721  - OUT4RMIX Input 1 Volume */
+       { 0x000006BA, 0x0000 },   /* R1722  - OUT4RMIX Input 2 Source */
+       { 0x000006BB, 0x0080 },   /* R1723  - OUT4RMIX Input 2 Volume */
+       { 0x000006BC, 0x0000 },   /* R1724  - OUT4RMIX Input 3 Source */
+       { 0x000006BD, 0x0080 },   /* R1725  - OUT4RMIX Input 3 Volume */
+       { 0x000006BE, 0x0000 },   /* R1726  - OUT4RMIX Input 4 Source */
+       { 0x000006BF, 0x0080 },   /* R1727  - OUT4RMIX Input 4 Volume */
+       { 0x000006C0, 0x0000 },   /* R1728  - OUT5LMIX Input 1 Source */
+       { 0x000006C1, 0x0080 },   /* R1729  - OUT5LMIX Input 1 Volume */
+       { 0x000006C2, 0x0000 },   /* R1730  - OUT5LMIX Input 2 Source */
+       { 0x000006C3, 0x0080 },   /* R1731  - OUT5LMIX Input 2 Volume */
+       { 0x000006C4, 0x0000 },   /* R1732  - OUT5LMIX Input 3 Source */
+       { 0x000006C5, 0x0080 },   /* R1733  - OUT5LMIX Input 3 Volume */
+       { 0x000006C6, 0x0000 },   /* R1734  - OUT5LMIX Input 4 Source */
+       { 0x000006C7, 0x0080 },   /* R1735  - OUT5LMIX Input 4 Volume */
+       { 0x000006C8, 0x0000 },   /* R1736  - OUT5RMIX Input 1 Source */
+       { 0x000006C9, 0x0080 },   /* R1737  - OUT5RMIX Input 1 Volume */
+       { 0x000006CA, 0x0000 },   /* R1738  - OUT5RMIX Input 2 Source */
+       { 0x000006CB, 0x0080 },   /* R1739  - OUT5RMIX Input 2 Volume */
+       { 0x000006CC, 0x0000 },   /* R1740  - OUT5RMIX Input 3 Source */
+       { 0x000006CD, 0x0080 },   /* R1741  - OUT5RMIX Input 3 Volume */
+       { 0x000006CE, 0x0000 },   /* R1742  - OUT5RMIX Input 4 Source */
+       { 0x000006CF, 0x0080 },   /* R1743  - OUT5RMIX Input 4 Volume */
+       { 0x00000700, 0x0000 },   /* R1792  - AIF1TX1MIX Input 1 Source */
+       { 0x00000701, 0x0080 },   /* R1793  - AIF1TX1MIX Input 1 Volume */
+       { 0x00000702, 0x0000 },   /* R1794  - AIF1TX1MIX Input 2 Source */
+       { 0x00000703, 0x0080 },   /* R1795  - AIF1TX1MIX Input 2 Volume */
+       { 0x00000704, 0x0000 },   /* R1796  - AIF1TX1MIX Input 3 Source */
+       { 0x00000705, 0x0080 },   /* R1797  - AIF1TX1MIX Input 3 Volume */
+       { 0x00000706, 0x0000 },   /* R1798  - AIF1TX1MIX Input 4 Source */
+       { 0x00000707, 0x0080 },   /* R1799  - AIF1TX1MIX Input 4 Volume */
+       { 0x00000708, 0x0000 },   /* R1800  - AIF1TX2MIX Input 1 Source */
+       { 0x00000709, 0x0080 },   /* R1801  - AIF1TX2MIX Input 1 Volume */
+       { 0x0000070A, 0x0000 },   /* R1802  - AIF1TX2MIX Input 2 Source */
+       { 0x0000070B, 0x0080 },   /* R1803  - AIF1TX2MIX Input 2 Volume */
+       { 0x0000070C, 0x0000 },   /* R1804  - AIF1TX2MIX Input 3 Source */
+       { 0x0000070D, 0x0080 },   /* R1805  - AIF1TX2MIX Input 3 Volume */
+       { 0x0000070E, 0x0000 },   /* R1806  - AIF1TX2MIX Input 4 Source */
+       { 0x0000070F, 0x0080 },   /* R1807  - AIF1TX2MIX Input 4 Volume */
+       { 0x00000710, 0x0000 },   /* R1808  - AIF1TX3MIX Input 1 Source */
+       { 0x00000711, 0x0080 },   /* R1809  - AIF1TX3MIX Input 1 Volume */
+       { 0x00000712, 0x0000 },   /* R1810  - AIF1TX3MIX Input 2 Source */
+       { 0x00000713, 0x0080 },   /* R1811  - AIF1TX3MIX Input 2 Volume */
+       { 0x00000714, 0x0000 },   /* R1812  - AIF1TX3MIX Input 3 Source */
+       { 0x00000715, 0x0080 },   /* R1813  - AIF1TX3MIX Input 3 Volume */
+       { 0x00000716, 0x0000 },   /* R1814  - AIF1TX3MIX Input 4 Source */
+       { 0x00000717, 0x0080 },   /* R1815  - AIF1TX3MIX Input 4 Volume */
+       { 0x00000718, 0x0000 },   /* R1816  - AIF1TX4MIX Input 1 Source */
+       { 0x00000719, 0x0080 },   /* R1817  - AIF1TX4MIX Input 1 Volume */
+       { 0x0000071A, 0x0000 },   /* R1818  - AIF1TX4MIX Input 2 Source */
+       { 0x0000071B, 0x0080 },   /* R1819  - AIF1TX4MIX Input 2 Volume */
+       { 0x0000071C, 0x0000 },   /* R1820  - AIF1TX4MIX Input 3 Source */
+       { 0x0000071D, 0x0080 },   /* R1821  - AIF1TX4MIX Input 3 Volume */
+       { 0x0000071E, 0x0000 },   /* R1822  - AIF1TX4MIX Input 4 Source */
+       { 0x0000071F, 0x0080 },   /* R1823  - AIF1TX4MIX Input 4 Volume */
+       { 0x00000720, 0x0000 },   /* R1824  - AIF1TX5MIX Input 1 Source */
+       { 0x00000721, 0x0080 },   /* R1825  - AIF1TX5MIX Input 1 Volume */
+       { 0x00000722, 0x0000 },   /* R1826  - AIF1TX5MIX Input 2 Source */
+       { 0x00000723, 0x0080 },   /* R1827  - AIF1TX5MIX Input 2 Volume */
+       { 0x00000724, 0x0000 },   /* R1828  - AIF1TX5MIX Input 3 Source */
+       { 0x00000725, 0x0080 },   /* R1829  - AIF1TX5MIX Input 3 Volume */
+       { 0x00000726, 0x0000 },   /* R1830  - AIF1TX5MIX Input 4 Source */
+       { 0x00000727, 0x0080 },   /* R1831  - AIF1TX5MIX Input 4 Volume */
+       { 0x00000728, 0x0000 },   /* R1832  - AIF1TX6MIX Input 1 Source */
+       { 0x00000729, 0x0080 },   /* R1833  - AIF1TX6MIX Input 1 Volume */
+       { 0x0000072A, 0x0000 },   /* R1834  - AIF1TX6MIX Input 2 Source */
+       { 0x0000072B, 0x0080 },   /* R1835  - AIF1TX6MIX Input 2 Volume */
+       { 0x0000072C, 0x0000 },   /* R1836  - AIF1TX6MIX Input 3 Source */
+       { 0x0000072D, 0x0080 },   /* R1837  - AIF1TX6MIX Input 3 Volume */
+       { 0x0000072E, 0x0000 },   /* R1838  - AIF1TX6MIX Input 4 Source */
+       { 0x0000072F, 0x0080 },   /* R1839  - AIF1TX6MIX Input 4 Volume */
+       { 0x00000730, 0x0000 },   /* R1840  - AIF1TX7MIX Input 1 Source */
+       { 0x00000731, 0x0080 },   /* R1841  - AIF1TX7MIX Input 1 Volume */
+       { 0x00000732, 0x0000 },   /* R1842  - AIF1TX7MIX Input 2 Source */
+       { 0x00000733, 0x0080 },   /* R1843  - AIF1TX7MIX Input 2 Volume */
+       { 0x00000734, 0x0000 },   /* R1844  - AIF1TX7MIX Input 3 Source */
+       { 0x00000735, 0x0080 },   /* R1845  - AIF1TX7MIX Input 3 Volume */
+       { 0x00000736, 0x0000 },   /* R1846  - AIF1TX7MIX Input 4 Source */
+       { 0x00000737, 0x0080 },   /* R1847  - AIF1TX7MIX Input 4 Volume */
+       { 0x00000738, 0x0000 },   /* R1848  - AIF1TX8MIX Input 1 Source */
+       { 0x00000739, 0x0080 },   /* R1849  - AIF1TX8MIX Input 1 Volume */
+       { 0x0000073A, 0x0000 },   /* R1850  - AIF1TX8MIX Input 2 Source */
+       { 0x0000073B, 0x0080 },   /* R1851  - AIF1TX8MIX Input 2 Volume */
+       { 0x0000073C, 0x0000 },   /* R1852  - AIF1TX8MIX Input 3 Source */
+       { 0x0000073D, 0x0080 },   /* R1853  - AIF1TX8MIX Input 3 Volume */
+       { 0x0000073E, 0x0000 },   /* R1854  - AIF1TX8MIX Input 4 Source */
+       { 0x0000073F, 0x0080 },   /* R1855  - AIF1TX8MIX Input 4 Volume */
+       { 0x00000740, 0x0000 },   /* R1856  - AIF2TX1MIX Input 1 Source */
+       { 0x00000741, 0x0080 },   /* R1857  - AIF2TX1MIX Input 1 Volume */
+       { 0x00000742, 0x0000 },   /* R1858  - AIF2TX1MIX Input 2 Source */
+       { 0x00000743, 0x0080 },   /* R1859  - AIF2TX1MIX Input 2 Volume */
+       { 0x00000744, 0x0000 },   /* R1860  - AIF2TX1MIX Input 3 Source */
+       { 0x00000745, 0x0080 },   /* R1861  - AIF2TX1MIX Input 3 Volume */
+       { 0x00000746, 0x0000 },   /* R1862  - AIF2TX1MIX Input 4 Source */
+       { 0x00000747, 0x0080 },   /* R1863  - AIF2TX1MIX Input 4 Volume */
+       { 0x00000748, 0x0000 },   /* R1864  - AIF2TX2MIX Input 1 Source */
+       { 0x00000749, 0x0080 },   /* R1865  - AIF2TX2MIX Input 1 Volume */
+       { 0x0000074A, 0x0000 },   /* R1866  - AIF2TX2MIX Input 2 Source */
+       { 0x0000074B, 0x0080 },   /* R1867  - AIF2TX2MIX Input 2 Volume */
+       { 0x0000074C, 0x0000 },   /* R1868  - AIF2TX2MIX Input 3 Source */
+       { 0x0000074D, 0x0080 },   /* R1869  - AIF2TX2MIX Input 3 Volume */
+       { 0x0000074E, 0x0000 },   /* R1870  - AIF2TX2MIX Input 4 Source */
+       { 0x0000074F, 0x0080 },   /* R1871  - AIF2TX2MIX Input 4 Volume */
+       { 0x00000780, 0x0000 },   /* R1920  - AIF3TX1MIX Input 1 Source */
+       { 0x00000781, 0x0080 },   /* R1921  - AIF3TX1MIX Input 1 Volume */
+       { 0x00000782, 0x0000 },   /* R1922  - AIF3TX1MIX Input 2 Source */
+       { 0x00000783, 0x0080 },   /* R1923  - AIF3TX1MIX Input 2 Volume */
+       { 0x00000784, 0x0000 },   /* R1924  - AIF3TX1MIX Input 3 Source */
+       { 0x00000785, 0x0080 },   /* R1925  - AIF3TX1MIX Input 3 Volume */
+       { 0x00000786, 0x0000 },   /* R1926  - AIF3TX1MIX Input 4 Source */
+       { 0x00000787, 0x0080 },   /* R1927  - AIF3TX1MIX Input 4 Volume */
+       { 0x00000788, 0x0000 },   /* R1928  - AIF3TX2MIX Input 1 Source */
+       { 0x00000789, 0x0080 },   /* R1929  - AIF3TX2MIX Input 1 Volume */
+       { 0x0000078A, 0x0000 },   /* R1930  - AIF3TX2MIX Input 2 Source */
+       { 0x0000078B, 0x0080 },   /* R1931  - AIF3TX2MIX Input 2 Volume */
+       { 0x0000078C, 0x0000 },   /* R1932  - AIF3TX2MIX Input 3 Source */
+       { 0x0000078D, 0x0080 },   /* R1933  - AIF3TX2MIX Input 3 Volume */
+       { 0x0000078E, 0x0000 },   /* R1934  - AIF3TX2MIX Input 4 Source */
+       { 0x0000078F, 0x0080 },   /* R1935  - AIF3TX2MIX Input 4 Volume */
+       { 0x000007C0, 0x0000 },   /* R1984  - SLIMTX1MIX Input 1 Source */
+       { 0x000007C1, 0x0080 },   /* R1985  - SLIMTX1MIX Input 1 Volume */
+       { 0x000007C2, 0x0000 },   /* R1986  - SLIMTX1MIX Input 2 Source */
+       { 0x000007C3, 0x0080 },   /* R1987  - SLIMTX1MIX Input 2 Volume */
+       { 0x000007C4, 0x0000 },   /* R1988  - SLIMTX1MIX Input 3 Source */
+       { 0x000007C5, 0x0080 },   /* R1989  - SLIMTX1MIX Input 3 Volume */
+       { 0x000007C6, 0x0000 },   /* R1990  - SLIMTX1MIX Input 4 Source */
+       { 0x000007C7, 0x0080 },   /* R1991  - SLIMTX1MIX Input 4 Volume */
+       { 0x000007C8, 0x0000 },   /* R1992  - SLIMTX2MIX Input 1 Source */
+       { 0x000007C9, 0x0080 },   /* R1993  - SLIMTX2MIX Input 1 Volume */
+       { 0x000007CA, 0x0000 },   /* R1994  - SLIMTX2MIX Input 2 Source */
+       { 0x000007CB, 0x0080 },   /* R1995  - SLIMTX2MIX Input 2 Volume */
+       { 0x000007CC, 0x0000 },   /* R1996  - SLIMTX2MIX Input 3 Source */
+       { 0x000007CD, 0x0080 },   /* R1997  - SLIMTX2MIX Input 3 Volume */
+       { 0x000007CE, 0x0000 },   /* R1998  - SLIMTX2MIX Input 4 Source */
+       { 0x000007CF, 0x0080 },   /* R1999  - SLIMTX2MIX Input 4 Volume */
+       { 0x000007D0, 0x0000 },   /* R2000  - SLIMTX3MIX Input 1 Source */
+       { 0x000007D1, 0x0080 },   /* R2001  - SLIMTX3MIX Input 1 Volume */
+       { 0x000007D2, 0x0000 },   /* R2002  - SLIMTX3MIX Input 2 Source */
+       { 0x000007D3, 0x0080 },   /* R2003  - SLIMTX3MIX Input 2 Volume */
+       { 0x000007D4, 0x0000 },   /* R2004  - SLIMTX3MIX Input 3 Source */
+       { 0x000007D5, 0x0080 },   /* R2005  - SLIMTX3MIX Input 3 Volume */
+       { 0x000007D6, 0x0000 },   /* R2006  - SLIMTX3MIX Input 4 Source */
+       { 0x000007D7, 0x0080 },   /* R2007  - SLIMTX3MIX Input 4 Volume */
+       { 0x000007D8, 0x0000 },   /* R2008  - SLIMTX4MIX Input 1 Source */
+       { 0x000007D9, 0x0080 },   /* R2009  - SLIMTX4MIX Input 1 Volume */
+       { 0x000007DA, 0x0000 },   /* R2010  - SLIMTX4MIX Input 2 Source */
+       { 0x000007DB, 0x0080 },   /* R2011  - SLIMTX4MIX Input 2 Volume */
+       { 0x000007DC, 0x0000 },   /* R2012  - SLIMTX4MIX Input 3 Source */
+       { 0x000007DD, 0x0080 },   /* R2013  - SLIMTX4MIX Input 3 Volume */
+       { 0x000007DE, 0x0000 },   /* R2014  - SLIMTX4MIX Input 4 Source */
+       { 0x000007DF, 0x0080 },   /* R2015  - SLIMTX4MIX Input 4 Volume */
+       { 0x000007E0, 0x0000 },   /* R2016  - SLIMTX5MIX Input 1 Source */
+       { 0x000007E1, 0x0080 },   /* R2017  - SLIMTX5MIX Input 1 Volume */
+       { 0x000007E2, 0x0000 },   /* R2018  - SLIMTX5MIX Input 2 Source */
+       { 0x000007E3, 0x0080 },   /* R2019  - SLIMTX5MIX Input 2 Volume */
+       { 0x000007E4, 0x0000 },   /* R2020  - SLIMTX5MIX Input 3 Source */
+       { 0x000007E5, 0x0080 },   /* R2021  - SLIMTX5MIX Input 3 Volume */
+       { 0x000007E6, 0x0000 },   /* R2022  - SLIMTX5MIX Input 4 Source */
+       { 0x000007E7, 0x0080 },   /* R2023  - SLIMTX5MIX Input 4 Volume */
+       { 0x000007E8, 0x0000 },   /* R2024  - SLIMTX6MIX Input 1 Source */
+       { 0x000007E9, 0x0080 },   /* R2025  - SLIMTX6MIX Input 1 Volume */
+       { 0x000007EA, 0x0000 },   /* R2026  - SLIMTX6MIX Input 2 Source */
+       { 0x000007EB, 0x0080 },   /* R2027  - SLIMTX6MIX Input 2 Volume */
+       { 0x000007EC, 0x0000 },   /* R2028  - SLIMTX6MIX Input 3 Source */
+       { 0x000007ED, 0x0080 },   /* R2029  - SLIMTX6MIX Input 3 Volume */
+       { 0x000007EE, 0x0000 },   /* R2030  - SLIMTX6MIX Input 4 Source */
+       { 0x000007EF, 0x0080 },   /* R2031  - SLIMTX6MIX Input 4 Volume */
+       { 0x000007F0, 0x0000 },   /* R2032  - SLIMTX7MIX Input 1 Source */
+       { 0x000007F1, 0x0080 },   /* R2033  - SLIMTX7MIX Input 1 Volume */
+       { 0x000007F2, 0x0000 },   /* R2034  - SLIMTX7MIX Input 2 Source */
+       { 0x000007F3, 0x0080 },   /* R2035  - SLIMTX7MIX Input 2 Volume */
+       { 0x000007F4, 0x0000 },   /* R2036  - SLIMTX7MIX Input 3 Source */
+       { 0x000007F5, 0x0080 },   /* R2037  - SLIMTX7MIX Input 3 Volume */
+       { 0x000007F6, 0x0000 },   /* R2038  - SLIMTX7MIX Input 4 Source */
+       { 0x000007F7, 0x0080 },   /* R2039  - SLIMTX7MIX Input 4 Volume */
+       { 0x000007F8, 0x0000 },   /* R2040  - SLIMTX8MIX Input 1 Source */
+       { 0x000007F9, 0x0080 },   /* R2041  - SLIMTX8MIX Input 1 Volume */
+       { 0x000007FA, 0x0000 },   /* R2042  - SLIMTX8MIX Input 2 Source */
+       { 0x000007FB, 0x0080 },   /* R2043  - SLIMTX8MIX Input 2 Volume */
+       { 0x000007FC, 0x0000 },   /* R2044  - SLIMTX8MIX Input 3 Source */
+       { 0x000007FD, 0x0080 },   /* R2045  - SLIMTX8MIX Input 3 Volume */
+       { 0x000007FE, 0x0000 },   /* R2046  - SLIMTX8MIX Input 4 Source */
+       { 0x000007FF, 0x0080 },   /* R2047  - SLIMTX8MIX Input 4 Volume */
+       { 0x00000880, 0x0000 },   /* R2176  - EQ1MIX Input 1 Source */
+       { 0x00000881, 0x0080 },   /* R2177  - EQ1MIX Input 1 Volume */
+       { 0x00000882, 0x0000 },   /* R2178  - EQ1MIX Input 2 Source */
+       { 0x00000883, 0x0080 },   /* R2179  - EQ1MIX Input 2 Volume */
+       { 0x00000884, 0x0000 },   /* R2180  - EQ1MIX Input 3 Source */
+       { 0x00000885, 0x0080 },   /* R2181  - EQ1MIX Input 3 Volume */
+       { 0x00000886, 0x0000 },   /* R2182  - EQ1MIX Input 4 Source */
+       { 0x00000887, 0x0080 },   /* R2183  - EQ1MIX Input 4 Volume */
+       { 0x00000888, 0x0000 },   /* R2184  - EQ2MIX Input 1 Source */
+       { 0x00000889, 0x0080 },   /* R2185  - EQ2MIX Input 1 Volume */
+       { 0x0000088A, 0x0000 },   /* R2186  - EQ2MIX Input 2 Source */
+       { 0x0000088B, 0x0080 },   /* R2187  - EQ2MIX Input 2 Volume */
+       { 0x0000088C, 0x0000 },   /* R2188  - EQ2MIX Input 3 Source */
+       { 0x0000088D, 0x0080 },   /* R2189  - EQ2MIX Input 3 Volume */
+       { 0x0000088E, 0x0000 },   /* R2190  - EQ2MIX Input 4 Source */
+       { 0x0000088F, 0x0080 },   /* R2191  - EQ2MIX Input 4 Volume */
+       { 0x00000890, 0x0000 },   /* R2192  - EQ3MIX Input 1 Source */
+       { 0x00000891, 0x0080 },   /* R2193  - EQ3MIX Input 1 Volume */
+       { 0x00000892, 0x0000 },   /* R2194  - EQ3MIX Input 2 Source */
+       { 0x00000893, 0x0080 },   /* R2195  - EQ3MIX Input 2 Volume */
+       { 0x00000894, 0x0000 },   /* R2196  - EQ3MIX Input 3 Source */
+       { 0x00000895, 0x0080 },   /* R2197  - EQ3MIX Input 3 Volume */
+       { 0x00000896, 0x0000 },   /* R2198  - EQ3MIX Input 4 Source */
+       { 0x00000897, 0x0080 },   /* R2199  - EQ3MIX Input 4 Volume */
+       { 0x00000898, 0x0000 },   /* R2200  - EQ4MIX Input 1 Source */
+       { 0x00000899, 0x0080 },   /* R2201  - EQ4MIX Input 1 Volume */
+       { 0x0000089A, 0x0000 },   /* R2202  - EQ4MIX Input 2 Source */
+       { 0x0000089B, 0x0080 },   /* R2203  - EQ4MIX Input 2 Volume */
+       { 0x0000089C, 0x0000 },   /* R2204  - EQ4MIX Input 3 Source */
+       { 0x0000089D, 0x0080 },   /* R2205  - EQ4MIX Input 3 Volume */
+       { 0x0000089E, 0x0000 },   /* R2206  - EQ4MIX Input 4 Source */
+       { 0x0000089F, 0x0080 },   /* R2207  - EQ4MIX Input 4 Volume */
+       { 0x000008C0, 0x0000 },   /* R2240  - DRC1LMIX Input 1 Source */
+       { 0x000008C1, 0x0080 },   /* R2241  - DRC1LMIX Input 1 Volume */
+       { 0x000008C2, 0x0000 },   /* R2242  - DRC1LMIX Input 2 Source */
+       { 0x000008C3, 0x0080 },   /* R2243  - DRC1LMIX Input 2 Volume */
+       { 0x000008C4, 0x0000 },   /* R2244  - DRC1LMIX Input 3 Source */
+       { 0x000008C5, 0x0080 },   /* R2245  - DRC1LMIX Input 3 Volume */
+       { 0x000008C6, 0x0000 },   /* R2246  - DRC1LMIX Input 4 Source */
+       { 0x000008C7, 0x0080 },   /* R2247  - DRC1LMIX Input 4 Volume */
+       { 0x000008C8, 0x0000 },   /* R2248  - DRC1RMIX Input 1 Source */
+       { 0x000008C9, 0x0080 },   /* R2249  - DRC1RMIX Input 1 Volume */
+       { 0x000008CA, 0x0000 },   /* R2250  - DRC1RMIX Input 2 Source */
+       { 0x000008CB, 0x0080 },   /* R2251  - DRC1RMIX Input 2 Volume */
+       { 0x000008CC, 0x0000 },   /* R2252  - DRC1RMIX Input 3 Source */
+       { 0x000008CD, 0x0080 },   /* R2253  - DRC1RMIX Input 3 Volume */
+       { 0x000008CE, 0x0000 },   /* R2254  - DRC1RMIX Input 4 Source */
+       { 0x000008CF, 0x0080 },   /* R2255  - DRC1RMIX Input 4 Volume */
+       { 0x00000900, 0x0000 },   /* R2304  - HPLP1MIX Input 1 Source */
+       { 0x00000901, 0x0080 },   /* R2305  - HPLP1MIX Input 1 Volume */
+       { 0x00000902, 0x0000 },   /* R2306  - HPLP1MIX Input 2 Source */
+       { 0x00000903, 0x0080 },   /* R2307  - HPLP1MIX Input 2 Volume */
+       { 0x00000904, 0x0000 },   /* R2308  - HPLP1MIX Input 3 Source */
+       { 0x00000905, 0x0080 },   /* R2309  - HPLP1MIX Input 3 Volume */
+       { 0x00000906, 0x0000 },   /* R2310  - HPLP1MIX Input 4 Source */
+       { 0x00000907, 0x0080 },   /* R2311  - HPLP1MIX Input 4 Volume */
+       { 0x00000908, 0x0000 },   /* R2312  - HPLP2MIX Input 1 Source */
+       { 0x00000909, 0x0080 },   /* R2313  - HPLP2MIX Input 1 Volume */
+       { 0x0000090A, 0x0000 },   /* R2314  - HPLP2MIX Input 2 Source */
+       { 0x0000090B, 0x0080 },   /* R2315  - HPLP2MIX Input 2 Volume */
+       { 0x0000090C, 0x0000 },   /* R2316  - HPLP2MIX Input 3 Source */
+       { 0x0000090D, 0x0080 },   /* R2317  - HPLP2MIX Input 3 Volume */
+       { 0x0000090E, 0x0000 },   /* R2318  - HPLP2MIX Input 4 Source */
+       { 0x0000090F, 0x0080 },   /* R2319  - HPLP2MIX Input 4 Volume */
+       { 0x00000910, 0x0000 },   /* R2320  - HPLP3MIX Input 1 Source */
+       { 0x00000911, 0x0080 },   /* R2321  - HPLP3MIX Input 1 Volume */
+       { 0x00000912, 0x0000 },   /* R2322  - HPLP3MIX Input 2 Source */
+       { 0x00000913, 0x0080 },   /* R2323  - HPLP3MIX Input 2 Volume */
+       { 0x00000914, 0x0000 },   /* R2324  - HPLP3MIX Input 3 Source */
+       { 0x00000915, 0x0080 },   /* R2325  - HPLP3MIX Input 3 Volume */
+       { 0x00000916, 0x0000 },   /* R2326  - HPLP3MIX Input 4 Source */
+       { 0x00000917, 0x0080 },   /* R2327  - HPLP3MIX Input 4 Volume */
+       { 0x00000918, 0x0000 },   /* R2328  - HPLP4MIX Input 1 Source */
+       { 0x00000919, 0x0080 },   /* R2329  - HPLP4MIX Input 1 Volume */
+       { 0x0000091A, 0x0000 },   /* R2330  - HPLP4MIX Input 2 Source */
+       { 0x0000091B, 0x0080 },   /* R2331  - HPLP4MIX Input 2 Volume */
+       { 0x0000091C, 0x0000 },   /* R2332  - HPLP4MIX Input 3 Source */
+       { 0x0000091D, 0x0080 },   /* R2333  - HPLP4MIX Input 3 Volume */
+       { 0x0000091E, 0x0000 },   /* R2334  - HPLP4MIX Input 4 Source */
+       { 0x0000091F, 0x0080 },   /* R2335  - HPLP4MIX Input 4 Volume */
+       { 0x00000940, 0x0000 },   /* R2368  - DSP1LMIX Input 1 Source */
+       { 0x00000941, 0x0080 },   /* R2369  - DSP1LMIX Input 1 Volume */
+       { 0x00000942, 0x0000 },   /* R2370  - DSP1LMIX Input 2 Source */
+       { 0x00000943, 0x0080 },   /* R2371  - DSP1LMIX Input 2 Volume */
+       { 0x00000944, 0x0000 },   /* R2372  - DSP1LMIX Input 3 Source */
+       { 0x00000945, 0x0080 },   /* R2373  - DSP1LMIX Input 3 Volume */
+       { 0x00000946, 0x0000 },   /* R2374  - DSP1LMIX Input 4 Source */
+       { 0x00000947, 0x0080 },   /* R2375  - DSP1LMIX Input 4 Volume */
+       { 0x00000948, 0x0000 },   /* R2376  - DSP1RMIX Input 1 Source */
+       { 0x00000949, 0x0080 },   /* R2377  - DSP1RMIX Input 1 Volume */
+       { 0x0000094A, 0x0000 },   /* R2378  - DSP1RMIX Input 2 Source */
+       { 0x0000094B, 0x0080 },   /* R2379  - DSP1RMIX Input 2 Volume */
+       { 0x0000094C, 0x0000 },   /* R2380  - DSP1RMIX Input 3 Source */
+       { 0x0000094D, 0x0080 },   /* R2381  - DSP1RMIX Input 3 Volume */
+       { 0x0000094E, 0x0000 },   /* R2382  - DSP1RMIX Input 4 Source */
+       { 0x0000094F, 0x0080 },   /* R2383  - DSP1RMIX Input 4 Volume */
+       { 0x00000950, 0x0000 },   /* R2384  - DSP1AUX1MIX Input 1 Source */
+       { 0x00000958, 0x0000 },   /* R2392  - DSP1AUX2MIX Input 1 Source */
+       { 0x00000960, 0x0000 },   /* R2400  - DSP1AUX3MIX Input 1 Source */
+       { 0x00000968, 0x0000 },   /* R2408  - DSP1AUX4MIX Input 1 Source */
+       { 0x00000970, 0x0000 },   /* R2416  - DSP1AUX5MIX Input 1 Source */
+       { 0x00000978, 0x0000 },   /* R2424  - DSP1AUX6MIX Input 1 Source */
+       { 0x00000A80, 0x0000 },   /* R2688  - ASRC1LMIX Input 1 Source */
+       { 0x00000A88, 0x0000 },   /* R2696  - ASRC1RMIX Input 1 Source */
+       { 0x00000A90, 0x0000 },   /* R2704  - ASRC2LMIX Input 1 Source */
+       { 0x00000A98, 0x0000 },   /* R2712  - ASRC2RMIX Input 1 Source */
+       { 0x00000B00, 0x0000 },   /* R2816  - ISRC1DEC1MIX Input 1 Source */
+       { 0x00000B08, 0x0000 },   /* R2824  - ISRC1DEC2MIX Input 1 Source */
+       { 0x00000B20, 0x0000 },   /* R2848  - ISRC1INT1MIX Input 1 Source */
+       { 0x00000B28, 0x0000 },   /* R2856  - ISRC1INT2MIX Input 1 Source */
+       { 0x00000B40, 0x0000 },   /* R2880  - ISRC2DEC1MIX Input 1 Source */
+       { 0x00000B48, 0x0000 },   /* R2888  - ISRC2DEC2MIX Input 1 Source */
+       { 0x00000B60, 0x0000 },   /* R2912  - ISRC2INT1MIX Input 1 Source */
+       { 0x00000B68, 0x0000 },   /* R2920  - ISRC2INT2MIX Input 1 Source */
+       { 0x00000C00, 0xA101 },   /* R3072  - GPIO1 CTRL */
+       { 0x00000C01, 0xA101 },   /* R3073  - GPIO2 CTRL */
+       { 0x00000C02, 0xA101 },   /* R3074  - GPIO3 CTRL */
+       { 0x00000C03, 0xA101 },   /* R3075  - GPIO4 CTRL */
+       { 0x00000C04, 0xA101 },   /* R3076  - GPIO5 CTRL */
+       { 0x00000C0F, 0x0400 },   /* R3087  - IRQ CTRL 1 */
+       { 0x00000C10, 0x1000 },   /* R3088  - GPIO Debounce Config */
+       { 0x00000C20, 0x8002 },   /* R3104  - Misc Pad Ctrl 1 */
        { 0x00000C21, 0x0001 },   /* R3105  - Misc Pad Ctrl 2 */
-       { 0x00000C22, 0x0000 },   /* R3106  - Misc Pad Ctrl 3 */ 
-       { 0x00000C23, 0x0000 },   /* R3107  - Misc Pad Ctrl 4 */ 
-       { 0x00000C24, 0x0000 },   /* R3108  - Misc Pad Ctrl 5 */ 
-       { 0x00000C25, 0x0000 },   /* R3109  - Misc Pad Ctrl 6 */ 
-       { 0x00000D08, 0xFFFF },   /* R3336  - Interrupt Status 1 Mask */ 
-       { 0x00000D09, 0xFFFF },   /* R3337  - Interrupt Status 2 Mask */ 
-       { 0x00000D0A, 0xFFFF },   /* R3338  - Interrupt Status 3 Mask */ 
-       { 0x00000D0B, 0xFFFF },   /* R3339  - Interrupt Status 4 Mask */ 
-       { 0x00000D0C, 0xFEFF },   /* R3340  - Interrupt Status 5 Mask */ 
-       { 0x00000D0F, 0x0000 },   /* R3343  - Interrupt Control */ 
-       { 0x00000D18, 0xFFFF },   /* R3352  - IRQ2 Status 1 Mask */ 
-       { 0x00000D19, 0xFFFF },   /* R3353  - IRQ2 Status 2 Mask */ 
-       { 0x00000D1A, 0xFFFF },   /* R3354  - IRQ2 Status 3 Mask */ 
-       { 0x00000D1B, 0xFFFF },   /* R3355  - IRQ2 Status 4 Mask */ 
-       { 0x00000D1C, 0xFFFF },   /* R3356  - IRQ2 Status 5 Mask */ 
-       { 0x00000D1F, 0x0000 },   /* R3359  - IRQ2 Control */ 
+       { 0x00000C22, 0x0000 },   /* R3106  - Misc Pad Ctrl 3 */
+       { 0x00000C23, 0x0000 },   /* R3107  - Misc Pad Ctrl 4 */
+       { 0x00000C24, 0x0000 },   /* R3108  - Misc Pad Ctrl 5 */
+       { 0x00000C25, 0x0000 },   /* R3109  - Misc Pad Ctrl 6 */
+       { 0x00000D08, 0xFFFF },   /* R3336  - Interrupt Status 1 Mask */
+       { 0x00000D09, 0xFFFF },   /* R3337  - Interrupt Status 2 Mask */
+       { 0x00000D0A, 0xFFFF },   /* R3338  - Interrupt Status 3 Mask */
+       { 0x00000D0B, 0xFFFF },   /* R3339  - Interrupt Status 4 Mask */
+       { 0x00000D0C, 0xFEFF },   /* R3340  - Interrupt Status 5 Mask */
+       { 0x00000D0F, 0x0000 },   /* R3343  - Interrupt Control */
+       { 0x00000D18, 0xFFFF },   /* R3352  - IRQ2 Status 1 Mask */
+       { 0x00000D19, 0xFFFF },   /* R3353  - IRQ2 Status 2 Mask */
+       { 0x00000D1A, 0xFFFF },   /* R3354  - IRQ2 Status 3 Mask */
+       { 0x00000D1B, 0xFFFF },   /* R3355  - IRQ2 Status 4 Mask */
+       { 0x00000D1C, 0xFFFF },   /* R3356  - IRQ2 Status 5 Mask */
+       { 0x00000D1F, 0x0000 },   /* R3359  - IRQ2 Control */
        { 0x00000D41, 0x0000 },   /* R3393  - ADSP2 IRQ0 */
-       { 0x00000D53, 0xFFFF },   /* R3411  - AOD IRQ Mask IRQ1 */ 
-       { 0x00000D54, 0xFFFF },   /* R3412  - AOD IRQ Mask IRQ2 */ 
-       { 0x00000D56, 0x0000 },   /* R3414  - Jack detect debounce */ 
-       { 0x00000E00, 0x0000 },   /* R3584  - FX_Ctrl1 */ 
-       { 0x00000E10, 0x6318 },   /* R3600  - EQ1_1 */ 
-       { 0x00000E11, 0x6300 },   /* R3601  - EQ1_2 */ 
-       { 0x00000E12, 0x0FC8 },   /* R3602  - EQ1_3 */ 
-       { 0x00000E13, 0x03FE },   /* R3603  - EQ1_4 */ 
-       { 0x00000E14, 0x00E0 },   /* R3604  - EQ1_5 */ 
-       { 0x00000E15, 0x1EC4 },   /* R3605  - EQ1_6 */ 
-       { 0x00000E16, 0xF136 },   /* R3606  - EQ1_7 */ 
-       { 0x00000E17, 0x0409 },   /* R3607  - EQ1_8 */ 
-       { 0x00000E18, 0x04CC },   /* R3608  - EQ1_9 */ 
-       { 0x00000E19, 0x1C9B },   /* R3609  - EQ1_10 */ 
-       { 0x00000E1A, 0xF337 },   /* R3610  - EQ1_11 */ 
-       { 0x00000E1B, 0x040B },   /* R3611  - EQ1_12 */ 
-       { 0x00000E1C, 0x0CBB },   /* R3612  - EQ1_13 */ 
-       { 0x00000E1D, 0x16F8 },   /* R3613  - EQ1_14 */ 
-       { 0x00000E1E, 0xF7D9 },   /* R3614  - EQ1_15 */ 
-       { 0x00000E1F, 0x040A },   /* R3615  - EQ1_16 */ 
-       { 0x00000E20, 0x1F14 },   /* R3616  - EQ1_17 */ 
-       { 0x00000E21, 0x058C },   /* R3617  - EQ1_18 */ 
-       { 0x00000E22, 0x0563 },   /* R3618  - EQ1_19 */ 
-       { 0x00000E23, 0x4000 },   /* R3619  - EQ1_20 */ 
-       { 0x00000E24, 0x0B75 },   /* R3620  - EQ1_21 */ 
-       { 0x00000E26, 0x6318 },   /* R3622  - EQ2_1 */ 
-       { 0x00000E27, 0x6300 },   /* R3623  - EQ2_2 */ 
-       { 0x00000E28, 0x0FC8 },   /* R3624  - EQ2_3 */ 
-       { 0x00000E29, 0x03FE },   /* R3625  - EQ2_4 */ 
-       { 0x00000E2A, 0x00E0 },   /* R3626  - EQ2_5 */ 
-       { 0x00000E2B, 0x1EC4 },   /* R3627  - EQ2_6 */ 
-       { 0x00000E2C, 0xF136 },   /* R3628  - EQ2_7 */ 
-       { 0x00000E2D, 0x0409 },   /* R3629  - EQ2_8 */ 
-       { 0x00000E2E, 0x04CC },   /* R3630  - EQ2_9 */ 
-       { 0x00000E2F, 0x1C9B },   /* R3631  - EQ2_10 */ 
-       { 0x00000E30, 0xF337 },   /* R3632  - EQ2_11 */ 
-       { 0x00000E31, 0x040B },   /* R3633  - EQ2_12 */ 
-       { 0x00000E32, 0x0CBB },   /* R3634  - EQ2_13 */ 
-       { 0x00000E33, 0x16F8 },   /* R3635  - EQ2_14 */ 
-       { 0x00000E34, 0xF7D9 },   /* R3636  - EQ2_15 */ 
-       { 0x00000E35, 0x040A },   /* R3637  - EQ2_16 */ 
-       { 0x00000E36, 0x1F14 },   /* R3638  - EQ2_17 */ 
-       { 0x00000E37, 0x058C },   /* R3639  - EQ2_18 */ 
-       { 0x00000E38, 0x0563 },   /* R3640  - EQ2_19 */ 
-       { 0x00000E39, 0x4000 },   /* R3641  - EQ2_20 */ 
-       { 0x00000E3A, 0x0B75 },   /* R3642  - EQ2_21 */ 
-       { 0x00000E3C, 0x6318 },   /* R3644  - EQ3_1 */ 
-       { 0x00000E3D, 0x6300 },   /* R3645  - EQ3_2 */ 
-       { 0x00000E3E, 0x0FC8 },   /* R3646  - EQ3_3 */ 
-       { 0x00000E3F, 0x03FE },   /* R3647  - EQ3_4 */ 
-       { 0x00000E40, 0x00E0 },   /* R3648  - EQ3_5 */ 
-       { 0x00000E41, 0x1EC4 },   /* R3649  - EQ3_6 */ 
-       { 0x00000E42, 0xF136 },   /* R3650  - EQ3_7 */ 
-       { 0x00000E43, 0x0409 },   /* R3651  - EQ3_8 */ 
-       { 0x00000E44, 0x04CC },   /* R3652  - EQ3_9 */ 
-       { 0x00000E45, 0x1C9B },   /* R3653  - EQ3_10 */ 
-       { 0x00000E46, 0xF337 },   /* R3654  - EQ3_11 */ 
-       { 0x00000E47, 0x040B },   /* R3655  - EQ3_12 */ 
-       { 0x00000E48, 0x0CBB },   /* R3656  - EQ3_13 */ 
-       { 0x00000E49, 0x16F8 },   /* R3657  - EQ3_14 */ 
-       { 0x00000E4A, 0xF7D9 },   /* R3658  - EQ3_15 */ 
-       { 0x00000E4B, 0x040A },   /* R3659  - EQ3_16 */ 
-       { 0x00000E4C, 0x1F14 },   /* R3660  - EQ3_17 */ 
-       { 0x00000E4D, 0x058C },   /* R3661  - EQ3_18 */ 
-       { 0x00000E4E, 0x0563 },   /* R3662  - EQ3_19 */ 
-       { 0x00000E4F, 0x4000 },   /* R3663  - EQ3_20 */ 
-       { 0x00000E50, 0x0B75 },   /* R3664  - EQ3_21 */ 
-       { 0x00000E52, 0x6318 },   /* R3666  - EQ4_1 */ 
-       { 0x00000E53, 0x6300 },   /* R3667  - EQ4_2 */ 
-       { 0x00000E54, 0x0FC8 },   /* R3668  - EQ4_3 */ 
-       { 0x00000E55, 0x03FE },   /* R3669  - EQ4_4 */ 
-       { 0x00000E56, 0x00E0 },   /* R3670  - EQ4_5 */ 
-       { 0x00000E57, 0x1EC4 },   /* R3671  - EQ4_6 */ 
-       { 0x00000E58, 0xF136 },   /* R3672  - EQ4_7 */ 
-       { 0x00000E59, 0x0409 },   /* R3673  - EQ4_8 */ 
-       { 0x00000E5A, 0x04CC },   /* R3674  - EQ4_9 */ 
-       { 0x00000E5B, 0x1C9B },   /* R3675  - EQ4_10 */ 
-       { 0x00000E5C, 0xF337 },   /* R3676  - EQ4_11 */ 
-       { 0x00000E5D, 0x040B },   /* R3677  - EQ4_12 */ 
-       { 0x00000E5E, 0x0CBB },   /* R3678  - EQ4_13 */ 
-       { 0x00000E5F, 0x16F8 },   /* R3679  - EQ4_14 */ 
-       { 0x00000E60, 0xF7D9 },   /* R3680  - EQ4_15 */ 
-       { 0x00000E61, 0x040A },   /* R3681  - EQ4_16 */ 
-       { 0x00000E62, 0x1F14 },   /* R3682  - EQ4_17 */ 
-       { 0x00000E63, 0x058C },   /* R3683  - EQ4_18 */ 
-       { 0x00000E64, 0x0563 },   /* R3684  - EQ4_19 */ 
-       { 0x00000E65, 0x4000 },   /* R3685  - EQ4_20 */ 
-       { 0x00000E66, 0x0B75 },   /* R3686  - EQ4_21 */ 
-       { 0x00000E80, 0x0018 },   /* R3712  - DRC1 ctrl1 */ 
-       { 0x00000E81, 0x0933 },   /* R3713  - DRC1 ctrl2 */ 
-       { 0x00000E82, 0x0018 },   /* R3714  - DRC1 ctrl3 */ 
-       { 0x00000E83, 0x0000 },   /* R3715  - DRC1 ctrl4 */ 
-       { 0x00000E84, 0x0000 },   /* R3716  - DRC1 ctrl5 */ 
-       { 0x00000EC0, 0x0000 },   /* R3776  - HPLPF1_1 */ 
-       { 0x00000EC1, 0x0000 },   /* R3777  - HPLPF1_2 */ 
-       { 0x00000EC4, 0x0000 },   /* R3780  - HPLPF2_1 */ 
-       { 0x00000EC5, 0x0000 },   /* R3781  - HPLPF2_2 */ 
-       { 0x00000EC8, 0x0000 },   /* R3784  - HPLPF3_1 */ 
-       { 0x00000EC9, 0x0000 },   /* R3785  - HPLPF3_2 */ 
-       { 0x00000ECC, 0x0000 },   /* R3788  - HPLPF4_1 */ 
-       { 0x00000ECD, 0x0000 },   /* R3789  - HPLPF4_2 */ 
-       { 0x00000EE0, 0x0000 },   /* R3808  - ASRC_ENABLE */ 
-       { 0x00000EE2, 0x0000 },   /* R3810  - ASRC_RATE1 */ 
+       { 0x00000D53, 0xFFFF },   /* R3411  - AOD IRQ Mask IRQ1 */
+       { 0x00000D54, 0xFFFF },   /* R3412  - AOD IRQ Mask IRQ2 */
+       { 0x00000D56, 0x0000 },   /* R3414  - Jack detect debounce */
+       { 0x00000E00, 0x0000 },   /* R3584  - FX_Ctrl1 */
+       { 0x00000E10, 0x6318 },   /* R3600  - EQ1_1 */
+       { 0x00000E11, 0x6300 },   /* R3601  - EQ1_2 */
+       { 0x00000E12, 0x0FC8 },   /* R3602  - EQ1_3 */
+       { 0x00000E13, 0x03FE },   /* R3603  - EQ1_4 */
+       { 0x00000E14, 0x00E0 },   /* R3604  - EQ1_5 */
+       { 0x00000E15, 0x1EC4 },   /* R3605  - EQ1_6 */
+       { 0x00000E16, 0xF136 },   /* R3606  - EQ1_7 */
+       { 0x00000E17, 0x0409 },   /* R3607  - EQ1_8 */
+       { 0x00000E18, 0x04CC },   /* R3608  - EQ1_9 */
+       { 0x00000E19, 0x1C9B },   /* R3609  - EQ1_10 */
+       { 0x00000E1A, 0xF337 },   /* R3610  - EQ1_11 */
+       { 0x00000E1B, 0x040B },   /* R3611  - EQ1_12 */
+       { 0x00000E1C, 0x0CBB },   /* R3612  - EQ1_13 */
+       { 0x00000E1D, 0x16F8 },   /* R3613  - EQ1_14 */
+       { 0x00000E1E, 0xF7D9 },   /* R3614  - EQ1_15 */
+       { 0x00000E1F, 0x040A },   /* R3615  - EQ1_16 */
+       { 0x00000E20, 0x1F14 },   /* R3616  - EQ1_17 */
+       { 0x00000E21, 0x058C },   /* R3617  - EQ1_18 */
+       { 0x00000E22, 0x0563 },   /* R3618  - EQ1_19 */
+       { 0x00000E23, 0x4000 },   /* R3619  - EQ1_20 */
+       { 0x00000E24, 0x0B75 },   /* R3620  - EQ1_21 */
+       { 0x00000E26, 0x6318 },   /* R3622  - EQ2_1 */
+       { 0x00000E27, 0x6300 },   /* R3623  - EQ2_2 */
+       { 0x00000E28, 0x0FC8 },   /* R3624  - EQ2_3 */
+       { 0x00000E29, 0x03FE },   /* R3625  - EQ2_4 */
+       { 0x00000E2A, 0x00E0 },   /* R3626  - EQ2_5 */
+       { 0x00000E2B, 0x1EC4 },   /* R3627  - EQ2_6 */
+       { 0x00000E2C, 0xF136 },   /* R3628  - EQ2_7 */
+       { 0x00000E2D, 0x0409 },   /* R3629  - EQ2_8 */
+       { 0x00000E2E, 0x04CC },   /* R3630  - EQ2_9 */
+       { 0x00000E2F, 0x1C9B },   /* R3631  - EQ2_10 */
+       { 0x00000E30, 0xF337 },   /* R3632  - EQ2_11 */
+       { 0x00000E31, 0x040B },   /* R3633  - EQ2_12 */
+       { 0x00000E32, 0x0CBB },   /* R3634  - EQ2_13 */
+       { 0x00000E33, 0x16F8 },   /* R3635  - EQ2_14 */
+       { 0x00000E34, 0xF7D9 },   /* R3636  - EQ2_15 */
+       { 0x00000E35, 0x040A },   /* R3637  - EQ2_16 */
+       { 0x00000E36, 0x1F14 },   /* R3638  - EQ2_17 */
+       { 0x00000E37, 0x058C },   /* R3639  - EQ2_18 */
+       { 0x00000E38, 0x0563 },   /* R3640  - EQ2_19 */
+       { 0x00000E39, 0x4000 },   /* R3641  - EQ2_20 */
+       { 0x00000E3A, 0x0B75 },   /* R3642  - EQ2_21 */
+       { 0x00000E3C, 0x6318 },   /* R3644  - EQ3_1 */
+       { 0x00000E3D, 0x6300 },   /* R3645  - EQ3_2 */
+       { 0x00000E3E, 0x0FC8 },   /* R3646  - EQ3_3 */
+       { 0x00000E3F, 0x03FE },   /* R3647  - EQ3_4 */
+       { 0x00000E40, 0x00E0 },   /* R3648  - EQ3_5 */
+       { 0x00000E41, 0x1EC4 },   /* R3649  - EQ3_6 */
+       { 0x00000E42, 0xF136 },   /* R3650  - EQ3_7 */
+       { 0x00000E43, 0x0409 },   /* R3651  - EQ3_8 */
+       { 0x00000E44, 0x04CC },   /* R3652  - EQ3_9 */
+       { 0x00000E45, 0x1C9B },   /* R3653  - EQ3_10 */
+       { 0x00000E46, 0xF337 },   /* R3654  - EQ3_11 */
+       { 0x00000E47, 0x040B },   /* R3655  - EQ3_12 */
+       { 0x00000E48, 0x0CBB },   /* R3656  - EQ3_13 */
+       { 0x00000E49, 0x16F8 },   /* R3657  - EQ3_14 */
+       { 0x00000E4A, 0xF7D9 },   /* R3658  - EQ3_15 */
+       { 0x00000E4B, 0x040A },   /* R3659  - EQ3_16 */
+       { 0x00000E4C, 0x1F14 },   /* R3660  - EQ3_17 */
+       { 0x00000E4D, 0x058C },   /* R3661  - EQ3_18 */
+       { 0x00000E4E, 0x0563 },   /* R3662  - EQ3_19 */
+       { 0x00000E4F, 0x4000 },   /* R3663  - EQ3_20 */
+       { 0x00000E50, 0x0B75 },   /* R3664  - EQ3_21 */
+       { 0x00000E52, 0x6318 },   /* R3666  - EQ4_1 */
+       { 0x00000E53, 0x6300 },   /* R3667  - EQ4_2 */
+       { 0x00000E54, 0x0FC8 },   /* R3668  - EQ4_3 */
+       { 0x00000E55, 0x03FE },   /* R3669  - EQ4_4 */
+       { 0x00000E56, 0x00E0 },   /* R3670  - EQ4_5 */
+       { 0x00000E57, 0x1EC4 },   /* R3671  - EQ4_6 */
+       { 0x00000E58, 0xF136 },   /* R3672  - EQ4_7 */
+       { 0x00000E59, 0x0409 },   /* R3673  - EQ4_8 */
+       { 0x00000E5A, 0x04CC },   /* R3674  - EQ4_9 */
+       { 0x00000E5B, 0x1C9B },   /* R3675  - EQ4_10 */
+       { 0x00000E5C, 0xF337 },   /* R3676  - EQ4_11 */
+       { 0x00000E5D, 0x040B },   /* R3677  - EQ4_12 */
+       { 0x00000E5E, 0x0CBB },   /* R3678  - EQ4_13 */
+       { 0x00000E5F, 0x16F8 },   /* R3679  - EQ4_14 */
+       { 0x00000E60, 0xF7D9 },   /* R3680  - EQ4_15 */
+       { 0x00000E61, 0x040A },   /* R3681  - EQ4_16 */
+       { 0x00000E62, 0x1F14 },   /* R3682  - EQ4_17 */
+       { 0x00000E63, 0x058C },   /* R3683  - EQ4_18 */
+       { 0x00000E64, 0x0563 },   /* R3684  - EQ4_19 */
+       { 0x00000E65, 0x4000 },   /* R3685  - EQ4_20 */
+       { 0x00000E66, 0x0B75 },   /* R3686  - EQ4_21 */
+       { 0x00000E80, 0x0018 },   /* R3712  - DRC1 ctrl1 */
+       { 0x00000E81, 0x0933 },   /* R3713  - DRC1 ctrl2 */
+       { 0x00000E82, 0x0018 },   /* R3714  - DRC1 ctrl3 */
+       { 0x00000E83, 0x0000 },   /* R3715  - DRC1 ctrl4 */
+       { 0x00000E84, 0x0000 },   /* R3716  - DRC1 ctrl5 */
+       { 0x00000EC0, 0x0000 },   /* R3776  - HPLPF1_1 */
+       { 0x00000EC1, 0x0000 },   /* R3777  - HPLPF1_2 */
+       { 0x00000EC4, 0x0000 },   /* R3780  - HPLPF2_1 */
+       { 0x00000EC5, 0x0000 },   /* R3781  - HPLPF2_2 */
+       { 0x00000EC8, 0x0000 },   /* R3784  - HPLPF3_1 */
+       { 0x00000EC9, 0x0000 },   /* R3785  - HPLPF3_2 */
+       { 0x00000ECC, 0x0000 },   /* R3788  - HPLPF4_1 */
+       { 0x00000ECD, 0x0000 },   /* R3789  - HPLPF4_2 */
+       { 0x00000EE0, 0x0000 },   /* R3808  - ASRC_ENABLE */
+       { 0x00000EE2, 0x0000 },   /* R3810  - ASRC_RATE1 */
        { 0x00000EE3, 0x4000 },   /* R3811  - ASRC_RATE2 */
-       { 0x00000EF0, 0x0000 },   /* R3824  - ISRC 1 CTRL 1 */ 
-       { 0x00000EF1, 0x0000 },   /* R3825  - ISRC 1 CTRL 2 */ 
-       { 0x00000EF2, 0x0000 },   /* R3826  - ISRC 1 CTRL 3 */ 
-       { 0x00000EF3, 0x0000 },   /* R3827  - ISRC 2 CTRL 1 */ 
-       { 0x00000EF4, 0x0000 },   /* R3828  - ISRC 2 CTRL 2 */ 
-       { 0x00000EF5, 0x0000 },   /* R3829  - ISRC 2 CTRL 3 */ 
-       { 0x00001100, 0x0010 },   /* R4352  - DSP1 Control 1 */ 
+       { 0x00000EF0, 0x0000 },   /* R3824  - ISRC 1 CTRL 1 */
+       { 0x00000EF1, 0x0000 },   /* R3825  - ISRC 1 CTRL 2 */
+       { 0x00000EF2, 0x0000 },   /* R3826  - ISRC 1 CTRL 3 */
+       { 0x00000EF3, 0x0000 },   /* R3827  - ISRC 2 CTRL 1 */
+       { 0x00000EF4, 0x0000 },   /* R3828  - ISRC 2 CTRL 2 */
+       { 0x00000EF5, 0x0000 },   /* R3829  - ISRC 2 CTRL 3 */
+       { 0x00001100, 0x0010 },   /* R4352  - DSP1 Control 1 */
 };
 
 static bool wm5102_readable_register(struct device *dev, unsigned int reg)
index 8588dbad330119149ad112c0bf493e1c979d59a3..953d0790ffd566e967058f7eeb640ff51377cf45 100644 (file)
@@ -406,8 +406,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                goto err;
        }
 
-       ret = regulator_bulk_enable(wm8994->num_supplies,
-                                   wm8994->supplies);
+       ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
                goto err_regulator_free;
@@ -612,8 +611,7 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
 {
        pm_runtime_disable(wm8994->dev);
        wm8994_irq_exit(wm8994);
-       regulator_bulk_disable(wm8994->num_supplies,
-                              wm8994->supplies);
+       regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies);
        regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
        mfd_remove_devices(wm8994->dev);
 }
index 377947580203d295553029097607964ec850551c..283ff7e17a0febd24de519fdd1991ce351d214e7 100644 (file)
@@ -229,12 +229,10 @@ static int bcm47xxpart_parse(struct mtd_info *master,
 
                        last_trx_part = curr_part - 1;
 
-                       /*
-                        * We have whole TRX scanned, skip to the next part. Use
-                        * roundown (not roundup), as the loop will increase
-                        * offset in next step.
-                        */
-                       offset = rounddown(offset + trx->length, blocksize);
+                       /* Jump to the end of TRX */
+                       offset = roundup(offset + trx->length, blocksize);
+                       /* Next loop iteration will increase the offset */
+                       offset -= blocksize;
                        continue;
                }
 
index 1c65c15b31a1aaed713363d5430c917754b13f13..514be04c0b6cc64962c1c4a4b2947346c5fa05dd 100644 (file)
@@ -296,16 +296,30 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
                dev_err(dev, "can't request region for resource %pR\n", res);
                return -EBUSY;
        }
-       b47s->window = ioremap_cache(res->start, resource_size(res));
-       if (!b47s->window) {
-               dev_err(dev, "ioremap failed for resource %pR\n", res);
-               return -ENOMEM;
-       }
 
        b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
        b47s->cc_read = bcm47xxsflash_bcma_cc_read;
        b47s->cc_write = bcm47xxsflash_bcma_cc_write;
 
+       /*
+        * On old MIPS devices cache was magically invalidated when needed,
+        * allowing us to use cached access and gain some performance. Trying
+        * the same on ARM based BCM53573 results in flash corruptions, we need
+        * to use uncached access for it.
+        *
+        * It may be arch specific, but right now there is only 1 ARM SoC using
+        * this driver, so let's follow Broadcom's reference code and check
+        * ChipCommon revision.
+        */
+       if (b47s->bcma_cc->core->id.rev == 54)
+               b47s->window = ioremap_nocache(res->start, resource_size(res));
+       else
+               b47s->window = ioremap_cache(res->start, resource_size(res));
+       if (!b47s->window) {
+               dev_err(dev, "ioremap failed for resource %pR\n", res);
+               return -ENOMEM;
+       }
+
        switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
        case BCMA_CC_FLASHT_STSER:
                b47s->type = BCM47XXSFLASH_TYPE_ST;
index 093edd51bdc7becfad25574b107064f3e5365c12..9b1c13aa9f20e907475ad11453da112bca6a86d4 100644 (file)
@@ -227,7 +227,7 @@ static void sc520cdp_setup_par(void)
 
 static int __init init_sc520cdp(void)
 {
-       int i, devices_found = 0;
+       int i, j, devices_found = 0;
 
 #ifdef REPROGRAM_PAR
        /* reprogram PAR registers so flash appears at the desired addresses */
@@ -243,6 +243,12 @@ static int __init init_sc520cdp(void)
 
                if (!sc520cdp_map[i].virt) {
                        printk("Failed to ioremap_nocache\n");
+                       for (j = 0; j < i; j++) {
+                               if (mymtd[j]) {
+                                       map_destroy(mymtd[j]);
+                                       iounmap(sc520cdp_map[j].virt);
+                               }
+                       }
                        return -EIO;
                }
 
index d46e4adf6d2baa681ba782706615daa47d60b0cf..052772f7caef739714b87b4f6a41b76963cb0e02 100644 (file)
@@ -46,8 +46,7 @@
 
 #include "mtdcore.h"
 
-static struct backing_dev_info mtd_bdi = {
-};
+static struct backing_dev_info *mtd_bdi;
 
 #ifdef CONFIG_PM_SLEEP
 
@@ -500,7 +499,7 @@ int add_mtd_device(struct mtd_info *mtd)
        if (WARN_ONCE(mtd->backing_dev_info, "MTD already registered\n"))
                return -EEXIST;
 
-       mtd->backing_dev_info = &mtd_bdi;
+       mtd->backing_dev_info = mtd_bdi;
 
        BUG_ON(mtd->writesize == 0);
        mutex_lock(&mtd_table_mutex);
@@ -1274,8 +1273,8 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
                                            int section,
                                            struct mtd_oob_region *oobregion))
 {
-       struct mtd_oob_region oobregion = { };
-       int section = 0, ret;
+       struct mtd_oob_region oobregion;
+       int section, ret;
 
        ret = mtd_ooblayout_find_region(mtd, start, &section,
                                        &oobregion, iter);
@@ -1283,7 +1282,7 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
        while (!ret) {
                int cnt;
 
-               cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
+               cnt = min_t(int, nbytes, oobregion.length);
                memcpy(buf, oobbuf + oobregion.offset, cnt);
                buf += cnt;
                nbytes -= cnt;
@@ -1317,8 +1316,8 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
                                            int section,
                                            struct mtd_oob_region *oobregion))
 {
-       struct mtd_oob_region oobregion = { };
-       int section = 0, ret;
+       struct mtd_oob_region oobregion;
+       int section, ret;
 
        ret = mtd_ooblayout_find_region(mtd, start, &section,
                                        &oobregion, iter);
@@ -1326,7 +1325,7 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
        while (!ret) {
                int cnt;
 
-               cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
+               cnt = min_t(int, nbytes, oobregion.length);
                memcpy(oobbuf + oobregion.offset, buf, cnt);
                buf += cnt;
                nbytes -= cnt;
@@ -1354,7 +1353,7 @@ static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
                                            int section,
                                            struct mtd_oob_region *oobregion))
 {
-       struct mtd_oob_region oobregion = { };
+       struct mtd_oob_region oobregion;
        int section = 0, ret, nbytes = 0;
 
        while (1) {
@@ -1771,18 +1770,20 @@ static const struct file_operations mtd_proc_ops = {
 /*====================================================================*/
 /* Init code */
 
-static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
+static struct backing_dev_info * __init mtd_bdi_init(char *name)
 {
+       struct backing_dev_info *bdi;
        int ret;
 
-       ret = bdi_init(bdi);
-       if (!ret)
-               ret = bdi_register(bdi, NULL, "%s", name);
+       bdi = kzalloc(sizeof(*bdi), GFP_KERNEL);
+       if (!bdi)
+               return ERR_PTR(-ENOMEM);
 
+       ret = bdi_setup_and_register(bdi, name);
        if (ret)
-               bdi_destroy(bdi);
+               kfree(bdi);
 
-       return ret;
+       return ret ? ERR_PTR(ret) : bdi;
 }
 
 static struct proc_dir_entry *proc_mtd;
@@ -1795,9 +1796,11 @@ static int __init init_mtd(void)
        if (ret)
                goto err_reg;
 
-       ret = mtd_bdi_init(&mtd_bdi, "mtd");
-       if (ret)
+       mtd_bdi = mtd_bdi_init("mtd");
+       if (IS_ERR(mtd_bdi)) {
+               ret = PTR_ERR(mtd_bdi);
                goto err_bdi;
+       }
 
        proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
 
@@ -1810,6 +1813,8 @@ static int __init init_mtd(void)
 out_procfs:
        if (proc_mtd)
                remove_proc_entry("mtd", NULL);
+       bdi_destroy(mtd_bdi);
+       kfree(mtd_bdi);
 err_bdi:
        class_unregister(&mtd_class);
 err_reg:
@@ -1823,7 +1828,8 @@ static void __exit cleanup_mtd(void)
        if (proc_mtd)
                remove_proc_entry("mtd", NULL);
        class_unregister(&mtd_class);
-       bdi_destroy(&mtd_bdi);
+       bdi_destroy(mtd_bdi);
+       kfree(mtd_bdi);
        idr_destroy(&mtd_idr);
 }
 
index cb06bdd21a1b57ef73e0d6e3034870bd95d51962..c40e2c951758ee0bf880159bfda32f35e67c2253 100644 (file)
@@ -587,7 +587,7 @@ retry:
        ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE ||
                                           erase.state == MTD_ERASE_FAILED);
        if (ret) {
-               dev_err(d->dev, "Interrupted erase block %#llx erassure on %s",
+               dev_err(d->dev, "Interrupted erase block %#llx erasure on %s\n",
                        erase.addr, mtd->name);
                return -EINTR;
        }
index 7b7a887b4709f0122f32b60833d8c2e36bc4dead..353a9ddf6b975d48d522da646761660b35b44d4c 100644 (file)
@@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
        help
          Enable debugging of the S3C NAND driver
 
-config MTD_NAND_S3C2410_HWECC
-       bool "Samsung S3C NAND Hardware ECC"
-       depends on MTD_NAND_S3C2410
-       help
-         Enable the use of the controller's internal ECC generator when
-         using NAND. Early versions of the chips have had problems with
-         incorrect ECC generation, and if using these, the default of
-         software ECC is preferable.
-
 config MTD_NAND_NDFC
        tristate "NDFC NanD Flash Controller"
        depends on 4xx
@@ -205,6 +196,13 @@ config MTD_NAND_S3C2410_CLKSTOP
          when the is NAND chip selected or released, but will save
          approximately 5mA of power when there is nothing happening.
 
+config MTD_NAND_TANGO
+       tristate "NAND Flash support for Tango chips"
+       depends on ARCH_TANGO || COMPILE_TEST
+       depends on HAS_DMA
+       help
+         Enables the NAND Flash controller on Tango chips.
+
 config MTD_NAND_DISKONCHIP
        tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
        depends on HAS_IOMEM
@@ -426,6 +424,11 @@ config MTD_NAND_ORION
          No board specific support is done by this driver, each board
          must advertise a platform_device for the driver to attach.
 
+config MTD_NAND_OXNAS
+       tristate "NAND Flash support for Oxford Semiconductor SoC"
+       help
+         This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
 config MTD_NAND_FSL_ELBC
        tristate "NAND support for Freescale eLBC controllers"
        depends on FSL_SOC
index cafde6f3d95761263d4c5af1395b11bfc000ca9b..19a66e404d5ba949a16a7ba358df25f033e7a51c 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT)      += denali_dt.o
 obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)           += bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_S3C2410)         += s3c2410.o
+obj-$(CONFIG_MTD_NAND_TANGO)           += tango_nand.o
 obj-$(CONFIG_MTD_NAND_DAVINCI)         += davinci_nand.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)      += diskonchip.o
 obj-$(CONFIG_MTD_NAND_DOCG4)           += docg4.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)           += tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
 obj-$(CONFIG_MTD_NAND_PASEMI)          += pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)           += orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS)           += oxnas_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)                += fsl_elbc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_IFC)         += fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)         += fsl_upm.o
index 78e12cc8bac2f5bc43cc54a7a809c8734571bad1..5d6c26f3cf7fc1115821133b82a2972075791e7c 100644 (file)
@@ -234,10 +234,9 @@ static int ams_delta_init(struct platform_device *pdev)
                goto out_gpio;
 
        /* Scan to find existence of the device */
-       if (nand_scan(ams_delta_mtd, 1)) {
-               err = -ENXIO;
+       err = nand_scan(ams_delta_mtd, 1);
+       if (err)
                goto out_mtd;
-       }
 
        /* Register the partitions */
        mtd_device_register(ams_delta_mtd, partition_info,
index 68b9160108c9f114f6ea83e1cda5892923d0433d..9ebd5ecefea605f1e5965ffa0f2f12395565ff16 100644 (file)
@@ -2267,10 +2267,9 @@ static int atmel_nand_probe(struct platform_device *pdev)
                dev_info(host->dev, "No DMA support for NAND access.\n");
 
        /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               res = -ENXIO;
+       res = nand_scan_ident(mtd, 1, NULL);
+       if (res)
                goto err_scan_ident;
-       }
 
        if (host->board.on_flash_bbt || on_flash_bbt)
                nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
@@ -2304,10 +2303,9 @@ static int atmel_nand_probe(struct platform_device *pdev)
        }
 
        /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
+       res = nand_scan_tail(mtd);
+       if (res)
                goto err_scan_tail;
-       }
 
        mtd->name = "atmel_nand";
        res = mtd_device_register(mtd, host->board.parts,
index 9d2424bfdbf55e221290591372ead4fbcf02ee3c..42ebd73f821dd47b9346113d06375af31b68f68c 100644 (file)
@@ -2209,8 +2209,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
        nand_writereg(ctrl, cfg_offs,
                      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
 
-       if (nand_scan_ident(mtd, 1, NULL))
-               return -ENXIO;
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret)
+               return ret;
 
        chip->options |= NAND_NO_SUBPAGE_WRITE;
        /*
@@ -2234,8 +2235,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
        if (ret)
                return ret;
 
-       if (nand_scan_tail(mtd))
-               return -ENXIO;
+       ret = nand_scan_tail(mtd);
+       if (ret)
+               return ret;
 
        return mtd_device_register(mtd, NULL, 0);
 }
index 0b0c93702abbd43c96b4e48eda148db9d36ddbee..d40c32d311d8f9cb95ca20fd07cee000d7b69956 100644 (file)
@@ -725,10 +725,9 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        usedma = 0;
 
        /* Scan to find existence of the device */
-       if (nand_scan_ident(mtd, 2, NULL)) {
-               err = -ENXIO;
+       err = nand_scan_ident(mtd, 2, NULL);
+       if (err)
                goto out_irq;
-       }
 
        cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev,
                                2112 + sizeof(struct nand_buffers) +
index 49133783ca5363f723cb2b9983f02e6ef9ba6b40..226ac0bcafc6539ba6389cf1170f05ee05a2acc6 100644 (file)
@@ -195,9 +195,9 @@ static int __init cmx270_init(void)
        this->write_buf = cmx270_write_buf;
 
        /* Scan to find existence of the device */
-       if (nand_scan (cmx270_nand_mtd, 1)) {
+       ret = nand_scan(cmx270_nand_mtd, 1);
+       if (ret) {
                pr_notice("No NAND device\n");
-               ret = -ENXIO;
                goto err_scan;
        }
 
index a65e4e0f57a1c87b7eee27ea98992ed8ff0a5c57..594b28684138f1e25f5949214ffc5a68202506a0 100644 (file)
@@ -242,10 +242,9 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        }
 
        /* Scan to find existence of the device */
-       if (nand_scan(new_mtd, 1)) {
-               err = -ENXIO;
+       err = nand_scan(new_mtd, 1);
+       if (err)
                goto out_free;
-       }
 
        cs553x_mtd[cs] = new_mtd;
        goto out;
index 0476ae8776d938b09e09371d73cca855b85d4665..73b9d4e2dca0a4c7b7f198cb6fdae0922cfb864f 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
-#include <linux/slab.h>
 #include <linux/mtd/mtd.h>
 #include <linux/module.h>
 
@@ -182,9 +181,6 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
 {
        int i;
 
-       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
-               __FILE__, __LINE__, __func__);
-
        for (i = 0; i < denali->max_banks; i++)
                iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
                denali->flash_reg + INTR_STATUS(i));
@@ -234,9 +230,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
        uint16_t acc_clks;
        uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
 
-       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
-               __FILE__, __LINE__, __func__);
-
        en_lo = CEIL_DIV(Trp[mode], CLK_X);
        en_hi = CEIL_DIV(Treh[mode], CLK_X);
 #if ONFI_BLOOM_TIME
@@ -403,7 +396,7 @@ static void get_hynix_nand_para(struct denali_nand_info *denali,
                break;
        default:
                dev_warn(denali->dev,
-                        "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n"
+                        "Unknown Hynix NAND (Device ID: 0x%x).\n"
                         "Will use default parameter values instead.\n",
                         device_id);
        }
@@ -474,33 +467,6 @@ static void detect_max_banks(struct denali_nand_info *denali)
                denali->max_banks = 1 << (features & FEATURES__N_BANKS);
 }
 
-static void detect_partition_feature(struct denali_nand_info *denali)
-{
-       /*
-        * For MRST platform, denali->fwblks represent the
-        * number of blocks firmware is taken,
-        * FW is in protect partition and MTD driver has no
-        * permission to access it. So let driver know how many
-        * blocks it can't touch.
-        */
-       if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) {
-               if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) &
-                       PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) {
-                       denali->fwblks =
-                           ((ioread32(denali->flash_reg + MIN_MAX_BANK(1)) &
-                             MIN_MAX_BANK__MIN_VALUE) *
-                            denali->blksperchip)
-                           +
-                           (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) &
-                           MIN_BLK_ADDR__VALUE);
-               } else {
-                       denali->fwblks = SPECTRA_START_BLOCK;
-               }
-       } else {
-               denali->fwblks = SPECTRA_START_BLOCK;
-       }
-}
-
 static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
 {
        uint16_t status = PASS;
@@ -508,9 +474,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
        uint8_t maf_id, device_id;
        int i;
 
-       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
-                       __FILE__, __LINE__, __func__);
-
        /*
         * Use read id method to get device ID and other params.
         * For some NAND chips, controller can't report the correct
@@ -552,8 +515,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
 
        find_valid_banks(denali);
 
-       detect_partition_feature(denali);
-
        /*
         * If the user specified to override the default timings
         * with a specific ONFI mode, we apply those changes here.
@@ -567,9 +528,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
 static void denali_set_intr_modes(struct denali_nand_info *denali,
                                        uint16_t INT_ENABLE)
 {
-       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
-               __FILE__, __LINE__, __func__);
-
        if (INT_ENABLE)
                iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE);
        else
@@ -605,7 +563,6 @@ static void denali_irq_init(struct denali_nand_info *denali)
 static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali)
 {
        denali_set_intr_modes(denali, false);
-       free_irq(irqnum, denali);
 }
 
 static void denali_irq_enable(struct denali_nand_info *denali,
@@ -1437,9 +1394,6 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 /* initialize driver data structures */
 static void denali_drv_init(struct denali_nand_info *denali)
 {
-       denali->idx = 0;
-
-       /* setup interrupt handler */
        /*
         * the completion object will be used to notify
         * the callee that the interrupt is done
@@ -1485,14 +1439,12 @@ int denali_init(struct denali_nand_info *denali)
        denali_hw_init(denali);
        denali_drv_init(denali);
 
-       /*
-        * denali_isr register is done after all the hardware
-        * initilization is finished
-        */
-       if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
-                       DENALI_NAND_NAME, denali)) {
-               pr_err("Spectra: Unable to allocate IRQ\n");
-               return -ENODEV;
+       /* Request IRQ after all the hardware initialization is finished */
+       ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+                              IRQF_SHARED, DENALI_NAND_NAME, denali);
+       if (ret) {
+               dev_err(denali->dev, "Unable to request IRQ\n");
+               return ret;
        }
 
        /* now that our ISR is registered, we can enable interrupts */
@@ -1510,10 +1462,9 @@ int denali_init(struct denali_nand_info *denali)
         * this is the first stage in a two step process to register
         * with the nand subsystem
         */
-       if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
-               ret = -ENXIO;
+       ret = nand_scan_ident(mtd, denali->max_banks, NULL);
+       if (ret)
                goto failed_req_irq;
-       }
 
        /* allocate the right size buffer now */
        devm_kfree(denali->dev, denali->buf.buf);
@@ -1528,7 +1479,7 @@ int denali_init(struct denali_nand_info *denali)
        /* Is 32-bit DMA supported? */
        ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
        if (ret) {
-               pr_err("Spectra: no usable DMA configuration\n");
+               dev_err(denali->dev, "No usable DMA configuration\n");
                goto failed_req_irq;
        }
 
@@ -1536,7 +1487,7 @@ int denali_init(struct denali_nand_info *denali)
                             mtd->writesize + mtd->oobsize,
                             DMA_BIDIRECTIONAL);
        if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
-               dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
+               dev_err(denali->dev, "Failed to map DMA buffer\n");
                ret = -EIO;
                goto failed_req_irq;
        }
@@ -1547,16 +1498,16 @@ int denali_init(struct denali_nand_info *denali)
         * the real pagesize and anything necessery
         */
        denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
-       denali->nand.chipsize <<= (denali->devnum - 1);
-       denali->nand.page_shift += (denali->devnum - 1);
+       denali->nand.chipsize <<= denali->devnum - 1;
+       denali->nand.page_shift += denali->devnum - 1;
        denali->nand.pagemask = (denali->nand.chipsize >>
                                                denali->nand.page_shift) - 1;
-       denali->nand.bbt_erase_shift += (denali->devnum - 1);
+       denali->nand.bbt_erase_shift += denali->devnum - 1;
        denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift;
-       denali->nand.chip_shift += (denali->devnum - 1);
-       mtd->writesize <<= (denali->devnum - 1);
-       mtd->oobsize <<= (denali->devnum - 1);
-       mtd->erasesize <<= (denali->devnum - 1);
+       denali->nand.chip_shift += denali->devnum - 1;
+       mtd->writesize <<= denali->devnum - 1;
+       mtd->oobsize <<= denali->devnum - 1;
+       mtd->erasesize <<= denali->devnum - 1;
        mtd->size = denali->nand.numchips * denali->nand.chipsize;
        denali->bbtskipbytes *= denali->devnum;
 
@@ -1606,14 +1557,6 @@ int denali_init(struct denali_nand_info *denali)
        denali->nand.ecc.bytes *= denali->devnum;
        denali->nand.ecc.strength *= denali->devnum;
 
-       /*
-        * Let driver know the total blocks number and how many blocks
-        * contained by each nand chip. blksperchip will help driver to
-        * know how many blocks is taken by FW.
-        */
-       denali->totalblks = mtd->size >> denali->nand.phys_erase_shift;
-       denali->blksperchip = denali->totalblks / denali->nand.numchips;
-
        /* override the default read operations */
        denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
        denali->nand.ecc.read_page = denali_read_page;
@@ -1624,15 +1567,13 @@ int denali_init(struct denali_nand_info *denali)
        denali->nand.ecc.write_oob = denali_write_oob;
        denali->nand.erase = denali_erase;
 
-       if (nand_scan_tail(mtd)) {
-               ret = -ENXIO;
+       ret = nand_scan_tail(mtd);
+       if (ret)
                goto failed_req_irq;
-       }
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
-               dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
-                               ret);
+               dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
                goto failed_req_irq;
        }
        return 0;
index e7ab4866a5da8a8edb76e0385312a979e30b3000..ea22191e85157c1603c798fef6147a4934c9f50a 100644 (file)
 #define CLK_X  5
 #define CLK_MULTI 4
 
-/* spectraswconfig.h */
-#define CMD_DMA 0
-
-#define SPECTRA_PARTITION_ID    0
-/**** Block Table and Reserved Block Parameters *****/
-#define SPECTRA_START_BLOCK     3
-#define NUM_FREE_BLOCKS_GATE    30
-
 /* KBV - Updated to LNW scratch register address */
 #define SCRATCH_REG_ADDR    CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
 #define SCRATCH_REG_SIZE    64
@@ -467,13 +459,9 @@ struct denali_nand_info {
        spinlock_t irq_lock;
        uint32_t irq_status;
        int irq_debug_array[32];
-       int idx;
        int irq;
 
        uint32_t devnum;        /* represent how many nands connected */
-       uint32_t fwblks; /* represent how many blocks FW used */
-       uint32_t totalblks;
-       uint32_t blksperchip;
        uint32_t bbtskipbytes;
        uint32_t max_banks;
 };
index 0cb1e8d9fbfcfe6b0d45965b87eff0d9a3c5d6a9..5607fcd3b8ed5f765219ca5bfb084290d18a962b 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/slab.h>
 
 #include "denali.h"
 
@@ -110,7 +109,7 @@ static int denali_dt_remove(struct platform_device *ofdev)
        struct denali_dt *dt = platform_get_drvdata(ofdev);
 
        denali_remove(&dt->denali);
-       clk_disable(dt->clk);
+       clk_disable_unprepare(dt->clk);
 
        return 0;
 }
index de31514df282223ba1c61f13a68631609fbe9b8d..ac843238b77e72f846c63d2eb9a8299a2d3aceb5 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/slab.h>
 
 #include "denali.h"
 
index d4f454a4b35e7e5ed8aff7a6d5a326c86d62032f..4924b43977ef8b1e2781dee0f980b5bf10950737 100644 (file)
@@ -926,8 +926,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        /*
         * Scan to find existence of the device
         */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               ret = -ENXIO;
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret) {
                dev_err(&pdev->dev, "No NAND Device found!\n");
                goto err_scan_ident;
        }
@@ -992,10 +992,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        }
 
        /* Second stage of scan to fill MTD data-structures */
-       if (nand_scan_tail(mtd)) {
-               ret = -ENXIO;
+       ret = nand_scan_tail(mtd);
+       if (ret)
                goto err_probe;
-       }
 
        /*
         * The partition information can is accessed by (in the same precedence)
index 6317f6836022e8cbcd144b8df10fc698524d793b..0d24857469ab396ac10c165076fd380639aa4463 100644 (file)
@@ -286,10 +286,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
 
-       if (nand_scan(mtd, 1)) {
-               ret = -ENXIO;
+       ret = nand_scan(mtd, 1);
+       if (ret)
                goto err_wp;
-       }
 
        if (gpiomtd->plat.adjust_parts)
                gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
index 9432546f4cd47051e742f03699c4f6058b4915c4..e40364eeb556bd23e0341a8a089d85047282acd1 100644 (file)
@@ -774,10 +774,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
        }
 
        ret = nand_scan_ident(mtd, max_chips, NULL);
-       if (ret) {
-               ret = -ENODEV;
+       if (ret)
                goto err_res;
-       }
 
        host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
                &host->dma_buffer, GFP_KERNEL);
index 852388171f2033320e7cba102c3be24d312c0f03..5553a5d9efd1144b276a20290f5cb2be9fc302f0 100644 (file)
@@ -747,10 +747,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
         * Scan to find existance of the device and
         * Get the type of NAND device SMALL block or LARGE block
         */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               res = -ENXIO;
+       res = nand_scan_ident(mtd, 1, NULL);
+       if (res)
                goto err_exit3;
-       }
 
        host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
        if (!host->dma_buf) {
@@ -793,10 +792,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
         * Fills out all the uninitialized function pointers with the defaults
         * And scans for a bad block table if appropriate.
         */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
+       res = nand_scan_tail(mtd);
+       if (res)
                goto err_exit4;
-       }
 
        mtd->name = DRV_NAME;
 
index 8d3edc34958e7b356431c92b0b9ad43c89ac062c..53bafe23ab39eeffb1c51858ac9acd19cf8ca01b 100644 (file)
@@ -894,10 +894,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        /* Find NAND device */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               res = -ENXIO;
+       res = nand_scan_ident(mtd, 1, NULL);
+       if (res)
                goto err_exit3;
-       }
 
        /* OOB and ECC CPU and DMA work areas */
        host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
@@ -929,10 +928,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        /*
         * Fills out all the uninitialized function pointers with the defaults
         */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
+       res = nand_scan_tail(mtd);
+       if (res)
                goto err_exit3;
-       }
 
        mtd->name = "nxp_lpc3220_slc";
        res = mtd_device_register(mtd, host->ncfg->parts,
index 7eacb2f545f50366cc8996d48d3f46aaf9ed195c..6d6eaed2d20c281321df7e3245ab525866eeca80 100644 (file)
@@ -777,9 +777,9 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        }
 
        /* Detect NAND chips */
-       if (nand_scan(mtd, be32_to_cpup(chips_no))) {
+       retval = nand_scan(mtd, be32_to_cpup(chips_no));
+       if (retval) {
                dev_err(dev, "NAND Flash not found !\n");
-               retval = -ENXIO;
                goto error;
        }
 
index 5223a2182ee44dfbfbda6f578266390f52d4f8b6..6c3eed3c20941c0f9ab0ddb5f7ec86ad623a9b7e 100644 (file)
@@ -1297,7 +1297,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
 
        ret = nand_scan_ident(mtd, nsels, NULL);
        if (ret)
-               return -ENODEV;
+               return ret;
 
        /* store bbt magic in page, cause OOB is not protected */
        if (nand->bbt_options & NAND_BBT_USE_FLASH)
@@ -1323,7 +1323,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
 
        ret = nand_scan_tail(mtd);
        if (ret)
-               return -ENODEV;
+               return ret;
 
        ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
        if (ret) {
index d7f724b24fd70afa37a049ec39df98a4fe510250..61ca020c527295950241c0982b990af5967c9078 100644 (file)
@@ -1747,10 +1747,9 @@ static int mxcnd_probe(struct platform_device *pdev)
        }
 
        /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) {
-               err = -ENXIO;
+       err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
+       if (err)
                goto escan;
-       }
 
        switch (this->ecc.mode) {
        case NAND_ECC_HW:
@@ -1808,10 +1807,9 @@ static int mxcnd_probe(struct platform_device *pdev)
        }
 
        /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               err = -ENXIO;
+       err = nand_scan_tail(mtd);
+       if (err)
                goto escan;
-       }
 
        /* Register the partitions */
        mtd_device_parse_register(mtd, part_probes,
index 3bde96a3f7bfd5b8f066fc56af91fb1983279cdf..ec1c28aaaf23c4bb509a9710121224e46e358dde 100644 (file)
@@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
        nand_wait_ready(mtd);
 }
 
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+       /*
+        * The controller already takes care of waiting for tCCS when the RNDIN
+        * or RNDOUT command is sent, return directly.
+        */
+       if (!(chip->options & NAND_WAIT_TCCS))
+               return;
+
+       /*
+        * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+        * (which should be safe for all NANDs).
+        */
+       if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min)
+               ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000);
+       else
+               ndelay(500);
+}
+
 /**
  * nand_command_lp - [DEFAULT] Send command to NAND large page device
  * @mtd: MTD device structure
@@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
        case NAND_CMD_ERASE1:
        case NAND_CMD_ERASE2:
        case NAND_CMD_SEQIN:
-       case NAND_CMD_RNDIN:
        case NAND_CMD_STATUS:
                return;
 
+       case NAND_CMD_RNDIN:
+               nand_ccs_delay(chip);
+               return;
+
        case NAND_CMD_RESET:
                if (chip->dev_ready)
                        break;
@@ -795,6 +817,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
                               NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
                chip->cmd_ctrl(mtd, NAND_CMD_NONE,
                               NAND_NCE | NAND_CTRL_CHANGE);
+
+               nand_ccs_delay(chip);
                return;
 
        case NAND_CMD_READ0:
@@ -1946,7 +1970,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                                 __func__, buf);
 
 read_retry:
-                       chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+                       if (nand_standard_page_accessors(&chip->ecc))
+                               chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
 
                        /*
                         * Now read the page into the buffer.  Absent an error,
@@ -2634,7 +2659,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        else
                subpage = 0;
 
-       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+       if (nand_standard_page_accessors(&chip->ecc))
+               chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
        if (unlikely(raw))
                status = chip->ecc.write_page_raw(mtd, chip, buf,
@@ -2657,7 +2683,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        if (!cached || !NAND_HAS_CACHEPROG(chip)) {
 
-               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+               if (nand_standard_page_accessors(&chip->ecc))
+                       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
                status = chip->waitfunc(mtd, chip);
                /*
                 * See if operation failed and additional status checks are
@@ -3985,10 +4012,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
 /*
  * Get the flash and manufacturer id and lookup if the type is supported.
  */
-static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
-                                                 struct nand_chip *chip,
-                                                 int *maf_id, int *dev_id,
-                                                 struct nand_flash_dev *type)
+static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
+                              int *maf_id, int *dev_id,
+                              struct nand_flash_dev *type)
 {
        int busw;
        int i, maf_idx;
@@ -4026,7 +4052,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
                pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
                        *maf_id, *dev_id, id_data[0], id_data[1]);
-               return ERR_PTR(-ENODEV);
+               return -ENODEV;
        }
 
        if (!type)
@@ -4053,7 +4079,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        }
 
        if (!type->name)
-               return ERR_PTR(-ENODEV);
+               return -ENODEV;
 
        if (!mtd->name)
                mtd->name = type->name;
@@ -4098,7 +4124,7 @@ ident_done:
                pr_warn("bus width %d instead %d bit\n",
                           (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
                           busw ? 16 : 8);
-               return ERR_PTR(-EINVAL);
+               return -EINVAL;
        }
 
        nand_decode_bbm_options(mtd, chip, id_data);
@@ -4140,7 +4166,7 @@ ident_done:
        pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
                (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
                mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
-       return type;
+       return 0;
 }
 
 static const char * const nand_ecc_modes[] = {
@@ -4306,7 +4332,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 {
        int i, nand_maf_id, nand_dev_id;
        struct nand_chip *chip = mtd_to_nand(mtd);
-       struct nand_flash_dev *type;
        int ret;
 
        ret = nand_dt_init(chip);
@@ -4329,14 +4354,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
 
        /* Read the flash type */
-       type = nand_get_flash_type(mtd, chip, &nand_maf_id,
-                                  &nand_dev_id, table);
-
-       if (IS_ERR(type)) {
+       ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
+       if (ret) {
                if (!(chip->options & NAND_SCAN_SILENT_NODEV))
                        pr_warn("No NAND device found\n");
                chip->select_chip(mtd, -1);
-               return PTR_ERR(type);
+               return ret;
        }
 
        /* Initialize the ->data_interface field. */
@@ -4515,6 +4538,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
        return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
 }
 
+static bool invalid_ecc_page_accessors(struct nand_chip *chip)
+{
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (nand_standard_page_accessors(ecc))
+               return false;
+
+       /*
+        * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
+        * controller driver implements all the page accessors because
+        * default helpers are not suitable when the core does not
+        * send the READ0/PAGEPROG commands.
+        */
+       return (!ecc->read_page || !ecc->write_page ||
+               !ecc->read_page_raw || !ecc->write_page_raw ||
+               (NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
+               (NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
+                ecc->hwctl && ecc->calculate));
+}
+
 /**
  * nand_scan_tail - [NAND Interface] Scan for the NAND device
  * @mtd: MTD device structure
@@ -4535,6 +4578,11 @@ int nand_scan_tail(struct mtd_info *mtd)
                   !(chip->bbt_options & NAND_BBT_USE_FLASH)))
                return -EINVAL;
 
+       if (invalid_ecc_page_accessors(chip)) {
+               pr_err("Invalid ECC page accessors setup\n");
+               return -EINVAL;
+       }
+
        if (!(chip->options & NAND_OWN_BUFFERS)) {
                nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
                                + mtd->oobsize * 3, GFP_KERNEL);
index 2af9869a115e97fb72f34e19ce0b6751b30ddd11..b3a332f37e145044b7b47f999b20382648d16b3e 100644 (file)
@@ -36,6 +36,9 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"TC58NVG2S0F 4G 3.3V 8-bit",
                { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
                  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
+       {"TC58NVG2S0H 4G 3.3V 8-bit",
+               { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
+                 SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
        {"TC58NVG3S0F 8G 3.3V 8-bit",
                { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
                  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
index 13a587407be320e72147bafdc3bf641bbf0da747..f06312df3669c18cb788fc033acf6b5811db8d0a 100644 (file)
@@ -18,6 +18,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 20000,
                        .tALS_min = 50000,
@@ -58,6 +60,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 10000,
                        .tALS_min = 25000,
@@ -98,6 +102,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 10000,
                        .tALS_min = 15000,
@@ -138,6 +144,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 5000,
                        .tALS_min = 10000,
@@ -178,6 +186,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 5000,
                        .tALS_min = 10000,
@@ -218,6 +228,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 5000,
                        .tALS_min = 10000,
@@ -290,10 +302,22 @@ int onfi_init_data_interface(struct nand_chip *chip,
        *iface = onfi_sdr_timings[timing_mode];
 
        /*
-        * TODO: initialize timings that cannot be deduced from timing mode:
+        * Initialize timings that cannot be deduced from timing mode:
         * tR, tPROG, tCCS, ...
         * These information are part of the ONFI parameter page.
         */
+       if (chip->onfi_version) {
+               struct nand_onfi_params *params = &chip->onfi_params;
+               struct nand_sdr_timings *timings = &iface->timings.sdr;
+
+               /* microseconds -> picoseconds */
+               timings->tPROG_max = 1000000UL * le16_to_cpu(params->t_prog);
+               timings->tBERS_max = 1000000UL * le16_to_cpu(params->t_bers);
+               timings->tR_max = 1000000UL * le16_to_cpu(params->t_r);
+
+               /* nanoseconds -> picoseconds */
+               timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
+       }
 
        return 0;
 }
index 1eb934414eb5804978994a382dbb1d782ca59e53..c84742671a5f9782a23bec53b0182de0e8871289 100644 (file)
@@ -525,24 +525,20 @@ static int nandsim_debugfs_create(struct nandsim *dev)
 {
        struct nandsim_debug_info *dbg = &dev->dbg;
        struct dentry *dent;
-       int err;
 
        if (!IS_ENABLED(CONFIG_DEBUG_FS))
                return 0;
 
        dent = debugfs_create_dir("nandsim", NULL);
-       if (IS_ERR_OR_NULL(dent)) {
-               int err = dent ? -ENODEV : PTR_ERR(dent);
-
-               NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
-                       err);
-               return err;
+       if (!dent) {
+               NS_ERR("cannot create \"nandsim\" debugfs directory\n");
+               return -ENODEV;
        }
        dbg->dfs_root = dent;
 
        dent = debugfs_create_file("wear_report", S_IRUSR,
                                   dbg->dfs_root, dev, &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
+       if (!dent)
                goto out_remove;
        dbg->dfs_wear_report = dent;
 
@@ -550,8 +546,7 @@ static int nandsim_debugfs_create(struct nandsim *dev)
 
 out_remove:
        debugfs_remove_recursive(dbg->dfs_root);
-       err = dent ? PTR_ERR(dent) : -ENODEV;
-       return err;
+       return -ENODEV;
 }
 
 /**
@@ -2313,8 +2308,6 @@ static int __init ns_init_module(void)
        retval = nand_scan_ident(nsmtd, 1, NULL);
        if (retval) {
                NS_ERR("cannot scan NAND Simulator device\n");
-               if (retval > 0)
-                       retval = -ENXIO;
                goto error;
        }
 
@@ -2350,8 +2343,6 @@ static int __init ns_init_module(void)
        retval = nand_scan_tail(nsmtd);
        if (retval) {
                NS_ERR("can't register NAND Simulator\n");
-               if (retval > 0)
-                       retval = -ENXIO;
                goto error;
        }
 
index 5513bfd9cdc90ed8e2628e311b7a92e02bfe0cd7..2a52101120d466dc81d27eb8ac2c9fd10b19fb5e 100644 (file)
@@ -1895,10 +1895,10 @@ static int omap_nand_probe(struct platform_device *pdev)
 
        /* scan NAND device connected to chip controller */
        nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
-       if (nand_scan_ident(mtd, 1, NULL)) {
+       err = nand_scan_ident(mtd, 1, NULL);
+       if (err) {
                dev_err(&info->pdev->dev,
                        "scan failed, may be bus-width mismatch\n");
-               err = -ENXIO;
                goto return_error;
        }
 
@@ -2154,10 +2154,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 scan_tail:
        /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               err = -ENXIO;
+       err = nand_scan_tail(mtd);
+       if (err)
                goto return_error;
-       }
 
        if (dev->of_node)
                mtd_device_register(mtd, NULL, 0);
@@ -2197,6 +2196,7 @@ static const struct of_device_id omap_nand_ids[] = {
        { .compatible = "ti,omap2-nand", },
        {},
 };
+MODULE_DEVICE_TABLE(of, omap_nand_ids);
 
 static struct platform_driver omap_nand_driver = {
        .probe          = omap_nand_probe,
index 40a7c4a2cf0d44c8f407dc6c170d44cc8d768510..4a91c5d000be790bc6200a50a9d00f80f4de9bc4 100644 (file)
@@ -155,10 +155,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
                clk_put(clk);
        }
 
-       if (nand_scan(mtd, 1)) {
-               ret = -ENXIO;
+       ret = nand_scan(mtd, 1);
+       if (ret)
                goto no_dev;
-       }
 
        mtd->name = "orion_nand";
        ret = mtd_device_register(mtd, board->parts, board->nr_parts);
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644 (file)
index 0000000..3e3bf3b
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+/* Nand commands */
+#define OXNAS_NAND_CMD_ALE             BIT(18)
+#define OXNAS_NAND_CMD_CLE             BIT(19)
+
+#define OXNAS_NAND_MAX_CHIPS   1
+
+struct oxnas_nand_ctrl {
+       struct nand_hw_control base;
+       void __iomem *io_base;
+       struct clk *clk;
+       struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
+};
+
+static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+       return readb(oxnas->io_base);
+}
+
+static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+       ioread8_rep(oxnas->io_base, buf, len);
+}
+
+static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+       iowrite8_rep(oxnas->io_base, buf, len);
+}
+
+/* Single CS command control */
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+                               unsigned int ctrl)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+       if (ctrl & NAND_CLE)
+               writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
+       else if (ctrl & NAND_ALE)
+               writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *nand_np;
+       struct oxnas_nand_ctrl *oxnas;
+       struct nand_chip *chip;
+       struct mtd_info *mtd;
+       struct resource *res;
+       int nchips = 0;
+       int count = 0;
+       int err = 0;
+
+       /* Allocate memory for the device structure (and zero it) */
+       oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+                            GFP_KERNEL);
+       if (!oxnas)
+               return -ENOMEM;
+
+       nand_hw_control_init(&oxnas->base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(oxnas->io_base))
+               return PTR_ERR(oxnas->io_base);
+
+       oxnas->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(oxnas->clk))
+               oxnas->clk = NULL;
+
+       /* Only a single chip node is supported */
+       count = of_get_child_count(np);
+       if (count > 1)
+               return -EINVAL;
+
+       clk_prepare_enable(oxnas->clk);
+       device_reset_optional(&pdev->dev);
+
+       for_each_child_of_node(np, nand_np) {
+               chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+                                   GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+
+               chip->controller = &oxnas->base;
+
+               nand_set_flash_node(chip, nand_np);
+               nand_set_controller_data(chip, oxnas);
+
+               mtd = nand_to_mtd(chip);
+               mtd->dev.parent = &pdev->dev;
+               mtd->priv = chip;
+
+               chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
+               chip->read_buf = oxnas_nand_read_buf;
+               chip->read_byte = oxnas_nand_read_byte;
+               chip->write_buf = oxnas_nand_write_buf;
+               chip->chip_delay = 30;
+
+               /* Scan to find existence of the device */
+               err = nand_scan(mtd, 1);
+               if (err)
+                       return err;
+
+               err = mtd_device_register(mtd, NULL, 0);
+               if (err) {
+                       nand_release(mtd);
+                       return err;
+               }
+
+               oxnas->chips[nchips] = chip;
+               ++nchips;
+       }
+
+       /* Exit if no chips found */
+       if (!nchips)
+               return -ENODEV;
+
+       platform_set_drvdata(pdev, oxnas);
+
+       return 0;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+       struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
+
+       if (oxnas->chips[0])
+               nand_release(nand_to_mtd(oxnas->chips[0]));
+
+       clk_disable_unprepare(oxnas->clk);
+
+       return 0;
+}
+
+static const struct of_device_id oxnas_nand_match[] = {
+       { .compatible = "oxsemi,ox820-nand" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, oxnas_nand_match);
+
+static struct platform_driver oxnas_nand_driver = {
+       .probe  = oxnas_nand_probe,
+       .remove = oxnas_nand_remove,
+       .driver = {
+               .name           = "oxnas_nand",
+               .of_match_table = oxnas_nand_match,
+       },
+};
+
+module_platform_driver(oxnas_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
index 5de7591b05106bcbf172ad3bc3c6c8013c8b4c32..074b8b01289e185bc153135ee9be79c933920bcc 100644 (file)
@@ -156,10 +156,9 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
        chip->bbt_options = NAND_BBT_USE_FLASH;
 
        /* Scan to find existence of the device */
-       if (nand_scan(pasemi_nand_mtd, 1)) {
-               err = -ENXIO;
+       err = nand_scan(pasemi_nand_mtd, 1);
+       if (err)
                goto out_lpc;
-       }
 
        if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
                dev_err(dev, "Unable to register MTD device\n");
index 415a53a0deeb306bb5baeaf3f5ad6638fd41d103..791de3e4bbb681392a50c510883f00c95cdd47cd 100644 (file)
@@ -86,10 +86,9 @@ static int plat_nand_probe(struct platform_device *pdev)
        }
 
        /* Scan to find existence of the device */
-       if (nand_scan(mtd, pdata->chip.nr_chips)) {
-               err = -ENXIO;
+       err = nand_scan(mtd, pdata->chip.nr_chips);
+       if (err)
                goto out;
-       }
 
        part_types = pdata->chip.part_probe_types;
 
index b121bf4ed73a2d50aca1935cffe2e6bf3639c26d..649ba8200832d5ba3d237327fd3861d9844c2149 100644 (file)
@@ -1680,8 +1680,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
        chip->ecc.strength = pdata->ecc_strength;
        chip->ecc.size = pdata->ecc_step_size;
 
-       if (nand_scan_ident(mtd, 1, NULL))
-               return -ENODEV;
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret)
+               return ret;
 
        if (!pdata->keep_config) {
                ret = pxa3xx_nand_init(host);
@@ -1774,8 +1775,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
        int ret, irq, cs;
 
        pdata = dev_get_platdata(&pdev->dev);
-       if (pdata->num_cs <= 0)
+       if (pdata->num_cs <= 0) {
+               dev_err(&pdev->dev, "invalid number of chip selects\n");
                return -ENODEV;
+       }
+
        info = devm_kzalloc(&pdev->dev,
                            sizeof(*info) + sizeof(*host) * pdata->num_cs,
                            GFP_KERNEL);
@@ -1813,8 +1817,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
        nand_hw_control_init(chip->controller);
        info->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(info->clk)) {
-               dev_err(&pdev->dev, "failed to get nand clock\n");
-               return PTR_ERR(info->clk);
+               ret = PTR_ERR(info->clk);
+               dev_err(&pdev->dev, "failed to get nand clock: %d\n", ret);
+               return ret;
        }
        ret = clk_prepare_enable(info->clk);
        if (ret < 0)
@@ -1842,6 +1847,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
        info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(info->mmio_base)) {
                ret = PTR_ERR(info->mmio_base);
+               dev_err(&pdev->dev, "failed to map register space: %d\n", ret);
                goto fail_disable_clk;
        }
        info->mmio_phys = r->start;
@@ -1861,7 +1867,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
                                   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
                                   pdev->name, info);
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to request IRQ\n");
+               dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
                goto fail_free_buf;
        }
 
@@ -1960,10 +1966,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        }
 
        ret = alloc_nand_resource(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "alloc nand resource failed\n");
+       if (ret)
                return ret;
-       }
 
        info = platform_get_drvdata(pdev);
        probe_success = 0;
index d459c19d78de383c1c2a88a1bcda0d1301b3c003..f0b030d44f71ff2add4383196fba0c9e02350277 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -185,6 +187,22 @@ struct s3c2410_nand_info {
 #endif
 };
 
+struct s3c24XX_nand_devtype_data {
+       enum s3c_cpu_type type;
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
+       .type = TYPE_S3C2410,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
+       .type = TYPE_S3C2412,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
+       .type = TYPE_S3C2440,
+};
+
 /* conversion functions */
 
 static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
@@ -497,7 +515,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
 
 /* ECC handling functions */
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
                                     u_char *read_ecc, u_char *calc_ecc)
 {
@@ -649,7 +666,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 
        return 0;
 }
-#endif
 
 /* over-ride the standard functions for a little more speed. We can
  * use read/write block to move the data buffers to/from the controller
@@ -796,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
        return -ENODEV;
 }
 
+static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
+                                       const struct nand_data_interface *conf,
+                                       bool check_only)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       struct s3c2410_platform_nand *pdata = info->platform;
+       const struct nand_sdr_timings *timings;
+       int tacls;
+
+       timings = nand_get_sdr_timings(conf);
+       if (IS_ERR(timings))
+               return -ENOTSUPP;
+
+       tacls = timings->tCLS_min - timings->tWP_min;
+       if (tacls < 0)
+               tacls = 0;
+
+       pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
+       pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
+       pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
+
+       return s3c2410_nand_setrate(info);
+}
+
 /**
  * s3c2410_nand_init_chip - initialise a single instance of an chip
  * @info: The base NAND controller the chip is on.
@@ -810,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
                                   struct s3c2410_nand_mtd *nmtd,
                                   struct s3c2410_nand_set *set)
 {
+       struct device_node *np = info->device->of_node;
        struct nand_chip *chip = &nmtd->chip;
        void __iomem *regs = info->regs;
 
+       nand_set_flash_node(chip, set->of_node);
+
        chip->write_buf    = s3c2410_nand_write_buf;
        chip->read_buf     = s3c2410_nand_read_buf;
        chip->select_chip  = s3c2410_nand_select_chip;
@@ -821,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        chip->options      = set->options;
        chip->controller   = &info->controller;
 
+       /*
+        * let's keep behavior unchanged for legacy boards booting via pdata and
+        * auto-detect timings only when booting with a device tree.
+        */
+       if (np)
+               chip->setup_data_interface = s3c2410_nand_setup_data_interface;
+
        switch (info->cpu_type) {
        case TYPE_S3C2410:
                chip->IO_ADDR_W = regs + S3C2410_NFDATA;
@@ -858,58 +908,14 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        nmtd->info         = info;
        nmtd->set          = set;
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
-       chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-       chip->ecc.correct   = s3c2410_nand_correct_data;
-       chip->ecc.mode      = NAND_ECC_HW;
-       chip->ecc.strength  = 1;
+       chip->ecc.mode = info->platform->ecc_mode;
 
-       switch (info->cpu_type) {
-       case TYPE_S3C2410:
-               chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
-               chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-               break;
-
-       case TYPE_S3C2412:
-               chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
-               chip->ecc.calculate = s3c2412_nand_calculate_ecc;
-               break;
-
-       case TYPE_S3C2440:
-               chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-               chip->ecc.calculate = s3c2440_nand_calculate_ecc;
-               break;
-       }
-#else
-       chip->ecc.mode      = NAND_ECC_SOFT;
-       chip->ecc.algo  = NAND_ECC_HAMMING;
-#endif
-
-       if (set->disable_ecc)
-               chip->ecc.mode  = NAND_ECC_NONE;
-
-       switch (chip->ecc.mode) {
-       case NAND_ECC_NONE:
-               dev_info(info->device, "NAND ECC disabled\n");
-               break;
-       case NAND_ECC_SOFT:
-               dev_info(info->device, "NAND soft ECC\n");
-               break;
-       case NAND_ECC_HW:
-               dev_info(info->device, "NAND hardware ECC\n");
-               break;
-       default:
-               dev_info(info->device, "NAND ECC UNKNOWN\n");
-               break;
-       }
-
-       /* If you use u-boot BBT creation code, specifying this flag will
-        * let the kernel fish out the BBT from the NAND, and also skip the
-        * full NAND scan that can take 1/2s or so. Little things... */
-       if (set->flash_bbt) {
+       /*
+        * If you use u-boot BBT creation code, specifying this flag will
+        * let the kernel fish out the BBT from the NAND.
+        */
+       if (set->flash_bbt)
                chip->bbt_options |= NAND_BBT_USE_FLASH;
-               chip->options |= NAND_SKIP_BBTSCAN;
-       }
 }
 
 /**
@@ -923,28 +929,146 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
  *
  * The internal state is currently limited to the ECC state information.
 */
-static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
-                                    struct s3c2410_nand_mtd *nmtd)
+static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+                                   struct s3c2410_nand_mtd *nmtd)
 {
        struct nand_chip *chip = &nmtd->chip;
 
-       dev_dbg(info->device, "chip %p => page shift %d\n",
-               chip, chip->page_shift);
+       switch (chip->ecc.mode) {
 
-       if (chip->ecc.mode != NAND_ECC_HW)
-               return;
+       case NAND_ECC_NONE:
+               dev_info(info->device, "ECC disabled\n");
+               break;
+
+       case NAND_ECC_SOFT:
+               /*
+                * This driver expects Hamming based ECC when ecc_mode is set
+                * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+                * avoid adding an extra ecc_algo field to
+                * s3c2410_platform_nand.
+                */
+               chip->ecc.algo = NAND_ECC_HAMMING;
+               dev_info(info->device, "soft ECC\n");
+               break;
+
+       case NAND_ECC_HW:
+               chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+               chip->ecc.correct   = s3c2410_nand_correct_data;
+               chip->ecc.strength  = 1;
+
+               switch (info->cpu_type) {
+               case TYPE_S3C2410:
+                       chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+                       break;
+
+               case TYPE_S3C2412:
+                       chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+                       break;
+
+               case TYPE_S3C2440:
+                       chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+                       break;
+               }
+
+               dev_dbg(info->device, "chip %p => page shift %d\n",
+                       chip, chip->page_shift);
 
                /* change the behaviour depending on whether we are using
                 * the large or small page nand device */
+               if (chip->page_shift > 10) {
+                       chip->ecc.size      = 256;
+                       chip->ecc.bytes     = 3;
+               } else {
+                       chip->ecc.size      = 512;
+                       chip->ecc.bytes     = 3;
+                       mtd_set_ooblayout(nand_to_mtd(chip),
+                                         &s3c2410_ooblayout_ops);
+               }
 
-       if (chip->page_shift > 10) {
-               chip->ecc.size      = 256;
-               chip->ecc.bytes     = 3;
-       } else {
-               chip->ecc.size      = 512;
-               chip->ecc.bytes     = 3;
-               mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+               dev_info(info->device, "hardware ECC\n");
+               break;
+
+       default:
+               dev_err(info->device, "invalid ECC mode!\n");
+               return -EINVAL;
        }
+
+       if (chip->bbt_options & NAND_BBT_USE_FLASH)
+               chip->options |= NAND_SKIP_BBTSCAN;
+
+       return 0;
+}
+
+static const struct of_device_id s3c24xx_nand_dt_ids[] = {
+       {
+               .compatible = "samsung,s3c2410-nand",
+               .data = &s3c2410_nand_devtype_data,
+       }, {
+               /* also compatible with s3c6400 */
+               .compatible = "samsung,s3c2412-nand",
+               .data = &s3c2412_nand_devtype_data,
+       }, {
+               .compatible = "samsung,s3c2440-nand",
+               .data = &s3c2440_nand_devtype_data,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
+
+static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
+{
+       const struct s3c24XX_nand_devtype_data *devtype_data;
+       struct s3c2410_platform_nand *pdata;
+       struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+       struct device_node *np = pdev->dev.of_node, *child;
+       struct s3c2410_nand_set *sets;
+
+       devtype_data = of_device_get_match_data(&pdev->dev);
+       if (!devtype_data)
+               return -ENODEV;
+
+       info->cpu_type = devtype_data->type;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       pdev->dev.platform_data = pdata;
+
+       pdata->nr_sets = of_get_child_count(np);
+       if (!pdata->nr_sets)
+               return 0;
+
+       sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets,
+                           GFP_KERNEL);
+       if (!sets)
+               return -ENOMEM;
+
+       pdata->sets = sets;
+
+       for_each_available_child_of_node(np, child) {
+               sets->name = (char *)child->name;
+               sets->of_node = child;
+               sets->nr_chips = 1;
+
+               of_node_get(child);
+
+               sets++;
+       }
+
+       return 0;
+}
+
+static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
+{
+       struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+
+       info->cpu_type = platform_get_device_id(pdev)->driver_data;
+
+       return 0;
 }
 
 /* s3c24xx_nand_probe
@@ -956,8 +1080,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 */
 static int s3c24xx_nand_probe(struct platform_device *pdev)
 {
-       struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
-       enum s3c_cpu_type cpu_type;
+       struct s3c2410_platform_nand *plat;
        struct s3c2410_nand_info *info;
        struct s3c2410_nand_mtd *nmtd;
        struct s3c2410_nand_set *sets;
@@ -967,8 +1090,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
        int nr_sets;
        int setno;
 
-       cpu_type = platform_get_device_id(pdev)->driver_data;
-
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (info == NULL) {
                err = -ENOMEM;
@@ -990,6 +1111,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
        s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
 
+       if (pdev->dev.of_node)
+               err = s3c24xx_nand_probe_dt(pdev);
+       else
+               err = s3c24xx_nand_probe_pdata(pdev);
+
+       if (err)
+               goto exit_error;
+
+       plat = to_nand_plat(pdev);
+
        /* allocate and map the resource */
 
        /* currently we assume we have the one resource */
@@ -998,7 +1129,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
        info->device    = &pdev->dev;
        info->platform  = plat;
-       info->cpu_type  = cpu_type;
 
        info->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(info->regs)) {
@@ -1008,12 +1138,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
 
-       /* initialise the hardware */
-
-       err = s3c2410_nand_inithw(info);
-       if (err != 0)
-               goto exit_error;
-
        sets = (plat != NULL) ? plat->sets : NULL;
        nr_sets = (plat != NULL) ? plat->nr_sets : 1;
 
@@ -1046,7 +1170,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
                                                 NULL);
 
                if (nmtd->scan_res == 0) {
-                       s3c2410_nand_update_chip(info, nmtd);
+                       err = s3c2410_nand_update_chip(info, nmtd);
+                       if (err < 0)
+                               goto exit_error;
                        nand_scan_tail(mtd);
                        s3c2410_nand_add_partition(info, nmtd, sets);
                }
@@ -1055,6 +1181,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
                        sets++;
        }
 
+       /* initialise the hardware */
+       err = s3c2410_nand_inithw(info);
+       if (err != 0)
+               goto exit_error;
+
        err = s3c2410_nand_cpufreq_register(info);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to init cpufreq support\n");
@@ -1155,6 +1286,7 @@ static struct platform_driver s3c24xx_nand_driver = {
        .id_table       = s3c24xx_driver_ids,
        .driver         = {
                .name   = "s3c24xx-nand",
+               .of_match_table = s3c24xx_nand_dt_ids,
        },
 };
 
index 888fd314c62a234b7a43e3c922a3d4dbb14e36c9..72369bd079af2afc216a21a1da6fc3b1fd857462 100644 (file)
@@ -187,17 +187,9 @@ static int socrates_nand_probe(struct platform_device *ofdev)
 
        dev_set_drvdata(&ofdev->dev, host);
 
-       /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               res = -ENXIO;
+       res = nand_scan(mtd, 1);
+       if (res)
                goto out;
-       }
-
-       /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
-               goto out;
-       }
 
        res = mtd_device_register(mtd, NULL, 0);
        if (!res)
index 8b8470c4e6d02d2058264cd2a74847ce343df129..e40482a65de6683264950a0caeba55484b1ffedf 100644 (file)
 #define NFC_ECC_PIPELINE       BIT(3)
 #define NFC_ECC_EXCEPTION      BIT(4)
 #define NFC_ECC_BLOCK_SIZE_MSK BIT(5)
+#define NFC_ECC_BLOCK_512      BIT(5)
 #define NFC_RANDOM_EN          BIT(9)
 #define NFC_RANDOM_DIRECTION   BIT(10)
 #define NFC_ECC_MODE_MSK       GENMASK(15, 12)
@@ -817,6 +818,9 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
        ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
                   NFC_ECC_PIPELINE;
 
+       if (nand->ecc.size == 512)
+               ecc_ctl |= NFC_ECC_BLOCK_512;
+
        writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
 }
 
diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
new file mode 100644 (file)
index 0000000..28c7f47
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2016 Sigma Designs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+/* Offsets relative to chip->base */
+#define PBUS_CMD       0
+#define PBUS_ADDR      4
+#define PBUS_DATA      8
+
+/* Offsets relative to reg_base */
+#define NFC_STATUS     0x00
+#define NFC_FLASH_CMD  0x04
+#define NFC_DEVICE_CFG 0x08
+#define NFC_TIMING1    0x0c
+#define NFC_TIMING2    0x10
+#define NFC_XFER_CFG   0x14
+#define NFC_PKT_0_CFG  0x18
+#define NFC_PKT_N_CFG  0x1c
+#define NFC_BB_CFG     0x20
+#define NFC_ADDR_PAGE  0x24
+#define NFC_ADDR_OFFSET        0x28
+#define NFC_XFER_STATUS        0x2c
+
+/* NFC_STATUS values */
+#define CMD_READY      BIT(31)
+
+/* NFC_FLASH_CMD values */
+#define NFC_READ       1
+#define NFC_WRITE      2
+
+/* NFC_XFER_STATUS values */
+#define PAGE_IS_EMPTY  BIT(16)
+
+/* Offsets relative to mem_base */
+#define METADATA       0x000
+#define ERROR_REPORT   0x1c0
+
+/*
+ * Error reports are split in two bytes:
+ * byte 0 for the first packet in the page (PKT_0)
+ * byte 1 for other packets in the page (PKT_N, for N > 0)
+ * ERR_COUNT_PKT_N is the max error count over all but the first packet.
+ */
+#define DECODE_OK_PKT_0(v)     ((v) & BIT(7))
+#define DECODE_OK_PKT_N(v)     ((v) & BIT(15))
+#define ERR_COUNT_PKT_0(v)     (((v) >> 0) & 0x3f)
+#define ERR_COUNT_PKT_N(v)     (((v) >> 8) & 0x3f)
+
+/* Offsets relative to pbus_base */
+#define PBUS_CS_CTRL   0x83c
+#define PBUS_PAD_MODE  0x8f0
+
+/* PBUS_CS_CTRL values */
+#define PBUS_IORDY     BIT(31)
+
+/*
+ * PBUS_PAD_MODE values
+ * In raw mode, the driver communicates directly with the NAND chips.
+ * In NFC mode, the NAND Flash controller manages the communication.
+ * We use NFC mode for read and write; raw mode for everything else.
+ */
+#define MODE_RAW       0
+#define MODE_NFC       BIT(31)
+
+#define METADATA_SIZE  4
+#define BBM_SIZE       6
+#define FIELD_ORDER    15
+
+#define MAX_CS         4
+
+struct tango_nfc {
+       struct nand_hw_control hw;
+       void __iomem *reg_base;
+       void __iomem *mem_base;
+       void __iomem *pbus_base;
+       struct tango_chip *chips[MAX_CS];
+       struct dma_chan *chan;
+       int freq_kHz;
+};
+
+#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
+
+struct tango_chip {
+       struct nand_chip nand_chip;
+       void __iomem *base;
+       u32 timing1;
+       u32 timing2;
+       u32 xfer_cfg;
+       u32 pkt_0_cfg;
+       u32 pkt_n_cfg;
+       u32 bb_cfg;
+};
+
+#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
+
+#define XFER_CFG(cs, page_count, steps, metadata_size) \
+       ((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size))
+
+#define PKT_CFG(size, strength) ((size) << 16 | (strength))
+
+#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size))
+
+#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
+
+static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+       if (ctrl & NAND_CLE)
+               writeb_relaxed(dat, tchip->base + PBUS_CMD);
+
+       if (ctrl & NAND_ALE)
+               writeb_relaxed(dat, tchip->base + PBUS_ADDR);
+}
+
+static int tango_dev_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+
+       return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
+}
+
+static u8 tango_read_byte(struct mtd_info *mtd)
+{
+       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+       return readb_relaxed(tchip->base + PBUS_DATA);
+}
+
+static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+       ioread8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+       iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_select_chip(struct mtd_info *mtd, int idx)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+       struct tango_chip *tchip = to_tango_chip(chip);
+
+       if (idx < 0)
+               return; /* No "chip unselect" function */
+
+       writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
+       writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
+       writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
+       writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
+       writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
+       writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *meta = chip->oob_poi + BBM_SIZE;
+       u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
+       const int ecc_size = chip->ecc.bytes;
+       const int pkt_size = chip->ecc.size;
+       int i, res, meta_len, bitflips = 0;
+
+       for (i = 0; i < chip->ecc.steps; ++i) {
+               meta_len = i ? 0 : METADATA_SIZE;
+               res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+                                                 meta, meta_len,
+                                                 chip->ecc.strength);
+               if (res < 0)
+                       mtd->ecc_stats.failed++;
+
+               bitflips = max(res, bitflips);
+               buf += pkt_size;
+               ecc += ecc_size;
+       }
+
+       return bitflips;
+}
+
+static int decode_error_report(struct tango_nfc *nfc)
+{
+       u32 status, res;
+
+       status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
+       if (status & PAGE_IS_EMPTY)
+               return 0;
+
+       res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
+
+       if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res))
+               return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
+
+       return -EBADMSG;
+}
+
+static void tango_dma_callback(void *arg)
+{
+       complete(arg);
+}
+
+static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf,
+                 int len, int page)
+{
+       void __iomem *addr = nfc->reg_base + NFC_STATUS;
+       struct dma_chan *chan = nfc->chan;
+       struct dma_async_tx_descriptor *desc;
+       struct scatterlist sg;
+       struct completion tx_done;
+       int err = -EIO;
+       u32 res, val;
+
+       sg_init_one(&sg, buf, len);
+       if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
+               return -EIO;
+
+       desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
+       if (!desc)
+               goto dma_unmap;
+
+       desc->callback = tango_dma_callback;
+       desc->callback_param = &tx_done;
+       init_completion(&tx_done);
+
+       writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
+
+       writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
+       writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET);
+       writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD);
+
+       dmaengine_submit(desc);
+       dma_async_issue_pending(chan);
+
+       res = wait_for_completion_timeout(&tx_done, HZ);
+       if (res > 0)
+               err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
+
+       writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
+dma_unmap:
+       dma_unmap_sg(chan->device->dev, &sg, 1, dir);
+
+       return err;
+}
+
+static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                          u8 *buf, int oob_required, int page)
+{
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+       int err, res, len = mtd->writesize;
+
+       if (oob_required)
+               chip->ecc.read_oob(mtd, chip, page);
+
+       err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
+       if (err)
+               return err;
+
+       res = decode_error_report(nfc);
+       if (res < 0) {
+               chip->ecc.read_oob_raw(mtd, chip, page);
+               res = check_erased_page(chip, buf);
+       }
+
+       return res;
+}
+
+static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                           const u8 *buf, int oob_required, int page)
+{
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+       int err, len = mtd->writesize;
+
+       /* Calling tango_write_oob() would send PAGEPROG twice */
+       if (oob_required)
+               return -ENOTSUPP;
+
+       writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
+       err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       *pos += len;
+
+       if (!*buf) {
+               /* skip over "len" bytes */
+               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1);
+       } else {
+               tango_read_buf(mtd, *buf, len);
+               *buf += len;
+       }
+}
+
+static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       *pos += len;
+
+       if (!*buf) {
+               /* skip over "len" bytes */
+               chip->cmdfunc(mtd, NAND_CMD_SEQIN, *pos, -1);
+       } else {
+               tango_write_buf(mtd, *buf, len);
+               *buf += len;
+       }
+}
+
+/*
+ * Physical page layout (not drawn to scale)
+ *
+ * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
+ *
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ * | M |      PKT_0      | ECC_0 | ... |     N1    | BBM | N2 | ECC_N |
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ *
+ * Logical page layout:
+ *
+ *       +-----+---+-------+-----+-------+
+ * oob = | BBM | M | ECC_0 | ... | ECC_N |
+ *       +-----+---+-------+-----+-------+
+ *
+ *       +-----------------+-----+-----------------+
+ * buf = |      PKT_0      | ... |      PKT_N      |
+ *       +-----------------+-----+-----------------+
+ */
+static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *oob_orig = oob;
+       const int page_size = mtd->writesize;
+       const int ecc_size = chip->ecc.bytes;
+       const int pkt_size = chip->ecc.size;
+       int pos = 0; /* position within physical page */
+       int rem = page_size; /* bytes remaining until BBM area */
+
+       if (oob)
+               oob += BBM_SIZE;
+
+       aux_read(chip, &oob, METADATA_SIZE, &pos);
+
+       while (rem > pkt_size) {
+               aux_read(chip, &buf, pkt_size, &pos);
+               aux_read(chip, &oob, ecc_size, &pos);
+               rem = page_size - pos;
+       }
+
+       aux_read(chip, &buf, rem, &pos);
+       aux_read(chip, &oob_orig, BBM_SIZE, &pos);
+       aux_read(chip, &buf, pkt_size - rem, &pos);
+       aux_read(chip, &oob, ecc_size, &pos);
+}
+
+static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       const u8 *oob_orig = oob;
+       const int page_size = mtd->writesize;
+       const int ecc_size = chip->ecc.bytes;
+       const int pkt_size = chip->ecc.size;
+       int pos = 0; /* position within physical page */
+       int rem = page_size; /* bytes remaining until BBM area */
+
+       if (oob)
+               oob += BBM_SIZE;
+
+       aux_write(chip, &oob, METADATA_SIZE, &pos);
+
+       while (rem > pkt_size) {
+               aux_write(chip, &buf, pkt_size, &pos);
+               aux_write(chip, &oob, ecc_size, &pos);
+               rem = page_size - pos;
+       }
+
+       aux_write(chip, &buf, rem, &pos);
+       aux_write(chip, &oob_orig, BBM_SIZE, &pos);
+       aux_write(chip, &buf, pkt_size - rem, &pos);
+       aux_write(chip, &oob, ecc_size, &pos);
+}
+
+static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                              u8 *buf, int oob_required, int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+       raw_read(chip, buf, chip->oob_poi);
+       return 0;
+}
+
+static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                               const u8 *buf, int oob_required, int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+       raw_write(chip, buf, chip->oob_poi);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       return 0;
+}
+
+static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                         int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+       raw_read(chip, NULL, chip->oob_poi);
+       return 0;
+}
+
+static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                          int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+       raw_write(chip, NULL, chip->oob_poi);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       chip->waitfunc(mtd, chip);
+       return 0;
+}
+
+static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (idx >= ecc->steps)
+               return -ERANGE;
+
+       res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
+       res->length = ecc->bytes;
+
+       return 0;
+}
+
+static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+       return -ERANGE; /* no free space in spare area */
+}
+
+static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
+       .ecc    = oob_ecc,
+       .free   = oob_free,
+};
+
+static u32 to_ticks(int kHz, int ps)
+{
+       return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
+}
+
+static int tango_set_timings(struct mtd_info *mtd,
+                            const struct nand_data_interface *conf,
+                            bool check_only)
+{
+       const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+       struct tango_chip *tchip = to_tango_chip(chip);
+       u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
+       int kHz = nfc->freq_kHz;
+
+       if (IS_ERR(sdr))
+               return PTR_ERR(sdr);
+
+       if (check_only)
+               return 0;
+
+       Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
+       Textw = to_ticks(kHz, sdr->tWB_max);
+       Twc = to_ticks(kHz, sdr->tWC_min);
+       Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
+
+       Tacc = to_ticks(kHz, sdr->tREA_max);
+       Thold = to_ticks(kHz, sdr->tREH_min);
+       Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
+       Textr = to_ticks(kHz, sdr->tRHZ_max);
+
+       tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
+       tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
+
+       return 0;
+}
+
+static int chip_init(struct device *dev, struct device_node *np)
+{
+       u32 cs;
+       int err, res;
+       struct mtd_info *mtd;
+       struct nand_chip *chip;
+       struct tango_chip *tchip;
+       struct nand_ecc_ctrl *ecc;
+       struct tango_nfc *nfc = dev_get_drvdata(dev);
+
+       tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
+       if (!tchip)
+               return -ENOMEM;
+
+       res = of_property_count_u32_elems(np, "reg");
+       if (res < 0)
+               return res;
+
+       if (res != 1)
+               return -ENOTSUPP; /* Multi-CS chips are not supported */
+
+       err = of_property_read_u32_index(np, "reg", 0, &cs);
+       if (err)
+               return err;
+
+       if (cs >= MAX_CS)
+               return -EINVAL;
+
+       chip = &tchip->nand_chip;
+       ecc = &chip->ecc;
+       mtd = nand_to_mtd(chip);
+
+       chip->read_byte = tango_read_byte;
+       chip->write_buf = tango_write_buf;
+       chip->read_buf = tango_read_buf;
+       chip->select_chip = tango_select_chip;
+       chip->cmd_ctrl = tango_cmd_ctrl;
+       chip->dev_ready = tango_dev_ready;
+       chip->setup_data_interface = tango_set_timings;
+       chip->options = NAND_USE_BOUNCE_BUFFER |
+                       NAND_NO_SUBPAGE_WRITE |
+                       NAND_WAIT_TCCS;
+       chip->controller = &nfc->hw;
+       tchip->base = nfc->pbus_base + (cs * 256);
+
+       nand_set_flash_node(chip, np);
+       mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
+       mtd->dev.parent = dev;
+
+       err = nand_scan_ident(mtd, 1, NULL);
+       if (err)
+               return err;
+
+       ecc->mode = NAND_ECC_HW;
+       ecc->algo = NAND_ECC_BCH;
+       ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
+
+       ecc->read_page_raw = tango_read_page_raw;
+       ecc->write_page_raw = tango_write_page_raw;
+       ecc->read_page = tango_read_page;
+       ecc->write_page = tango_write_page;
+       ecc->read_oob = tango_read_oob;
+       ecc->write_oob = tango_write_oob;
+       ecc->options = NAND_ECC_CUSTOM_PAGE_ACCESS;
+
+       err = nand_scan_tail(mtd);
+       if (err)
+               return err;
+
+       tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
+       tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
+       tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
+       tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
+
+       err = mtd_device_register(mtd, NULL, 0);
+       if (err)
+               return err;
+
+       nfc->chips[cs] = tchip;
+
+       return 0;
+}
+
+static int tango_nand_remove(struct platform_device *pdev)
+{
+       int cs;
+       struct tango_nfc *nfc = platform_get_drvdata(pdev);
+
+       dma_release_channel(nfc->chan);
+
+       for (cs = 0; cs < MAX_CS; ++cs) {
+               if (nfc->chips[cs])
+                       nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
+       }
+
+       return 0;
+}
+
+static int tango_nand_probe(struct platform_device *pdev)
+{
+       int err;
+       struct clk *clk;
+       struct resource *res;
+       struct tango_nfc *nfc;
+       struct device_node *np;
+
+       nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+       if (!nfc)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nfc->reg_base))
+               return PTR_ERR(nfc->reg_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nfc->mem_base))
+               return PTR_ERR(nfc->mem_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nfc->pbus_base))
+               return PTR_ERR(nfc->pbus_base);
+
+       clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
+       if (IS_ERR(nfc->chan))
+               return PTR_ERR(nfc->chan);
+
+       platform_set_drvdata(pdev, nfc);
+       nand_hw_control_init(&nfc->hw);
+       nfc->freq_kHz = clk_get_rate(clk) / 1000;
+
+       for_each_child_of_node(pdev->dev.of_node, np) {
+               err = chip_init(&pdev->dev, np);
+               if (err) {
+                       tango_nand_remove(pdev);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static const struct of_device_id tango_nand_ids[] = {
+       { .compatible = "sigma,smp8758-nand" },
+       { /* sentinel */ }
+};
+
+static struct platform_driver tango_nand_driver = {
+       .probe  = tango_nand_probe,
+       .remove = tango_nand_remove,
+       .driver = {
+               .name           = "tango-nand",
+               .of_match_table = tango_nand_ids,
+       },
+};
+
+module_platform_driver(tango_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sigma Designs");
+MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
index 08b30549ec0a0e61f3cd236102f77f6ad9e16097..fc5e773f8b6015955bed0737116cbf532a299ecb 100644 (file)
@@ -435,10 +435,10 @@ static int tmio_probe(struct platform_device *dev)
        nand_chip->waitfunc = tmio_nand_wait;
 
        /* Scan to find existence of the device */
-       if (nand_scan(mtd, 1)) {
-               retval = -ENODEV;
+       retval = nand_scan(mtd, 1);
+       if (retval)
                goto err_irq;
-       }
+
        /* Register the partitions */
        retval = mtd_device_parse_register(mtd, NULL, NULL,
                                           data ? data->partition : NULL,
index 3ad514c44dcb71a008e816a37e53af8183d6295a..3ea4bb19e12d9de9a52ba8c1479ea925d250e9eb 100644 (file)
@@ -717,10 +717,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
        vf610_nfc_preinit_controller(nfc);
 
        /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               err = -ENXIO;
+       err = nand_scan_ident(mtd, 1, NULL);
+       if (err)
                goto error;
-       }
 
        vf610_nfc_init_controller(nfc);
 
@@ -775,10 +774,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
        }
 
        /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               err = -ENXIO;
+       err = nand_scan_tail(mtd);
+       if (err)
                goto error;
-       }
 
        platform_set_drvdata(pdev, mtd);
 
index d403ba7b8f432ea45690767e334b6d6d8f8016bb..d489fbd07c12b6e73bf0f73e5f3de2696d4da3c4 100644 (file)
@@ -1077,12 +1077,14 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 
        /* Get flash device data */
        for_each_available_child_of_node(dev->of_node, np) {
-               if (of_property_read_u32(np, "reg", &cs)) {
+               ret = of_property_read_u32(np, "reg", &cs);
+               if (ret) {
                        dev_err(dev, "Couldn't determine chip select.\n");
                        goto err;
                }
 
-               if (cs > CQSPI_MAX_CHIPSELECT) {
+               if (cs >= CQSPI_MAX_CHIPSELECT) {
+                       ret = -EINVAL;
                        dev_err(dev, "Chip select %d out of range.\n", cs);
                        goto err;
                }
index 5c82e4ef1904b3bebcdd6fae8fc23bb37768df52..b4d8953fb30a4cc7efe59e62e2eadff3d60a2c9e 100644 (file)
@@ -224,7 +224,7 @@ struct fsl_qspi_devtype_data {
        int driver_data;
 };
 
-static struct fsl_qspi_devtype_data vybrid_data = {
+static const struct fsl_qspi_devtype_data vybrid_data = {
        .devtype = FSL_QUADSPI_VYBRID,
        .rxfifo = 128,
        .txfifo = 64,
@@ -232,7 +232,7 @@ static struct fsl_qspi_devtype_data vybrid_data = {
        .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
 };
 
-static struct fsl_qspi_devtype_data imx6sx_data = {
+static const struct fsl_qspi_devtype_data imx6sx_data = {
        .devtype = FSL_QUADSPI_IMX6SX,
        .rxfifo = 128,
        .txfifo = 512,
@@ -241,7 +241,7 @@ static struct fsl_qspi_devtype_data imx6sx_data = {
                       | QUADSPI_QUIRK_TKT245618,
 };
 
-static struct fsl_qspi_devtype_data imx7d_data = {
+static const struct fsl_qspi_devtype_data imx7d_data = {
        .devtype = FSL_QUADSPI_IMX7D,
        .rxfifo = 512,
        .txfifo = 512,
@@ -250,7 +250,7 @@ static struct fsl_qspi_devtype_data imx7d_data = {
                       | QUADSPI_QUIRK_4X_INT_CLK,
 };
 
-static struct fsl_qspi_devtype_data imx6ul_data = {
+static const struct fsl_qspi_devtype_data imx6ul_data = {
        .devtype = FSL_QUADSPI_IMX6UL,
        .rxfifo = 128,
        .txfifo = 512,
index d0fc165d7d666cac0ffc69b6c68fbdd49bc2b29c..da7cd69d4857282d80c88b57e887294407ccc6e8 100644 (file)
@@ -799,6 +799,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },
 
        { "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, SECT_4K) },
+       { "at25df321",  INFO(0x1f4700, 0, 64 * 1024,  64, SECT_4K) },
        { "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, SECT_4K) },
        { "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
 
@@ -825,6 +826,7 @@ static const struct flash_info spi_nor_ids[] = {
        /* Everspin */
        { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
        { "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+       { "mr25h40",  CAT25_INFO(512 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 
        /* Fujitsu */
        { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
@@ -872,11 +874,13 @@ static const struct flash_info spi_nor_ids[] = {
        { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
        { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
        { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
+       { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) },
        { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
        { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
        { "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 
        /* Micron */
+       { "n25q016a",    INFO(0x20bb15, 0, 64 * 1024,   32, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q032",     INFO(0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
        { "n25q032a",    INFO(0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
        { "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
@@ -905,7 +909,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
        { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
        { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
-       { "s25fl128s",  INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
+       { "s25fl128s",  INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
@@ -921,6 +925,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "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) },
+       { "s25fl208k",  INFO(0x014014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ) },
 
        /* SST -- large erase sizes are "overlays", "sectors" are 4K */
        { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
@@ -1255,6 +1260,13 @@ static int spansion_quad_enable(struct spi_nor *nor)
                return -EINVAL;
        }
 
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret) {
+               dev_err(nor->dev,
+                       "timeout while writing configuration register\n");
+               return ret;
+       }
+
        /* read back and check it */
        ret = read_cr(nor);
        if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
index 4da379f28d5d1b798ca09ddb0f71ca42ad18ccd0..f7222dc6581de1e75d439550520f8108b1d2744e 100644 (file)
@@ -1775,6 +1775,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
                        if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
                                continue;
 
+                       if (!ds->ports[port].netdev)
+                               continue;
+
                        if (vlan.data[i] ==
                            GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
                                continue;
@@ -1783,6 +1786,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
                            chip->ports[port].bridge_dev)
                                break; /* same bridge, check next VLAN */
 
+                       if (!chip->ports[i].bridge_dev)
+                               continue;
+
                        netdev_warn(ds->ports[port].netdev,
                                    "hardware VLAN %d already used by %s\n",
                                    vlan.vid,
index b9f4c463e516c34e538e78ccce5a7c0efcf7c818..be5b80103bec8a7805405b0b5f82e53c9aa9c535 100644 (file)
@@ -627,6 +627,8 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
 
        spin_lock_init(&vp->lock);
 
+       setup_timer(&vp->timer, corkscrew_timer, (unsigned long) dev);
+
        /* Read the station address from the EEPROM. */
        EL3WINDOW(0);
        for (i = 0; i < 0x18; i++) {
@@ -707,6 +709,7 @@ static int corkscrew_open(struct net_device *dev)
 {
        int ioaddr = dev->base_addr;
        struct corkscrew_private *vp = netdev_priv(dev);
+       bool armtimer = false;
        __u32 config;
        int i;
 
@@ -731,12 +734,7 @@ static int corkscrew_open(struct net_device *dev)
                if (corkscrew_debug > 1)
                        pr_debug("%s: Initial media type %s.\n",
                               dev->name, media_tbl[dev->if_port].name);
-
-               init_timer(&vp->timer);
-               vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
-               vp->timer.data = (unsigned long) dev;
-               vp->timer.function = corkscrew_timer;   /* timer handler */
-               add_timer(&vp->timer);
+               armtimer = true;
        } else
                dev->if_port = vp->default_media;
 
@@ -776,6 +774,9 @@ static int corkscrew_open(struct net_device *dev)
                return -EAGAIN;
        }
 
+       if (armtimer)
+               mod_timer(&vp->timer, jiffies + media_tbl[dev->if_port].wait);
+
        if (corkscrew_debug > 1) {
                EL3WINDOW(4);
                pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n",
@@ -1426,7 +1427,7 @@ static int corkscrew_close(struct net_device *dev)
                        dev->name, rx_nocopy, rx_copy, queued_packet);
        }
 
-       del_timer(&vp->timer);
+       del_timer_sync(&vp->timer);
 
        /* Turn off statistics ASAP.  We update lp->stats below. */
        outw(StatsDisable, ioaddr + EL3_CMD);
index 4e5c3874a50ff7e0b2b2ec30bdee7f39f5f017ce..bba81735ce875ba88884101091de9de004e729db 100644 (file)
@@ -1676,10 +1676,10 @@ bna_cb_ioceth_reset(void *arg)
 }
 
 static struct bfa_ioc_cbfn bna_ioceth_cbfn = {
-       bna_cb_ioceth_enable,
-       bna_cb_ioceth_disable,
-       bna_cb_ioceth_hbfail,
-       bna_cb_ioceth_reset
+       .enable_cbfn = bna_cb_ioceth_enable,
+       .disable_cbfn = bna_cb_ioceth_disable,
+       .hbfail_cbfn = bna_cb_ioceth_hbfail,
+       .reset_cbfn = bna_cb_ioceth_reset
 };
 
 static void bna_attr_init(struct bna_ioceth *ioceth)
index f0bcb15d3fec0c86e8258ffd614d0a098a44706d..608bea171956873508256e024c11e0de2396c119 100644 (file)
@@ -31,4 +31,13 @@ config MACB
          To compile this driver as a module, choose M here: the module
          will be called macb.
 
+config MACB_PCI
+       tristate "Cadence PCI MACB/GEM support"
+       depends on MACB && PCI && COMMON_CLK
+       ---help---
+         This is PCI wrapper for MACB driver.
+
+         To compile this driver as a module, choose M here: the module
+         will be called macb_pci.
+
 endif # NET_CADENCE
index 91f79b1f0505d25beb9935790f47146c555024cf..4ba75594d5c55cdec41bb1a805317b4af0fdf0a1 100644 (file)
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MACB_PCI) += macb_pci.o
index 538544a7c642f6cf1ca19c0d9222ec1c928077dd..c0fb80acc2dad4b91d3b3cb8198be50dc9597fbd 100644 (file)
@@ -404,6 +404,8 @@ static int macb_mii_probe(struct net_device *dev)
                        phy_irq = gpio_to_irq(pdata->phy_irq_pin);
                        phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
                }
+       } else {
+               phydev->irq = PHY_POLL;
        }
 
        /* attach the mac to the phy */
@@ -482,6 +484,9 @@ static int macb_mii_init(struct macb *bp)
                                goto err_out_unregister_bus;
                }
        } else {
+               for (i = 0; i < PHY_MAX_ADDR; i++)
+                       bp->mii_bus->irq[i] = PHY_POLL;
+
                if (pdata)
                        bp->mii_bus->phy_mask = pdata->phy_mask;
 
@@ -2523,16 +2528,24 @@ static int macb_clk_init(struct platform_device *pdev, struct clk **pclk,
                         struct clk **hclk, struct clk **tx_clk,
                         struct clk **rx_clk)
 {
+       struct macb_platform_data *pdata;
        int err;
 
-       *pclk = devm_clk_get(&pdev->dev, "pclk");
+       pdata = dev_get_platdata(&pdev->dev);
+       if (pdata) {
+               *pclk = pdata->pclk;
+               *hclk = pdata->hclk;
+       } else {
+               *pclk = devm_clk_get(&pdev->dev, "pclk");
+               *hclk = devm_clk_get(&pdev->dev, "hclk");
+       }
+
        if (IS_ERR(*pclk)) {
                err = PTR_ERR(*pclk);
                dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err);
                return err;
        }
 
-       *hclk = devm_clk_get(&pdev->dev, "hclk");
        if (IS_ERR(*hclk)) {
                err = PTR_ERR(*hclk);
                dev_err(&pdev->dev, "failed to get hclk (%u)\n", err);
@@ -3107,15 +3120,23 @@ static const struct of_device_id macb_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, macb_dt_ids);
 #endif /* CONFIG_OF */
 
+static const struct macb_config default_gem_config = {
+       .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO,
+       .dma_burst_length = 16,
+       .clk_init = macb_clk_init,
+       .init = macb_init,
+       .jumbo_max_len = 10240,
+};
+
 static int macb_probe(struct platform_device *pdev)
 {
+       const struct macb_config *macb_config = &default_gem_config;
        int (*clk_init)(struct platform_device *, struct clk **,
                        struct clk **, struct clk **,  struct clk **)
-                                             = macb_clk_init;
-       int (*init)(struct platform_device *) = macb_init;
+                                             = macb_config->clk_init;
+       int (*init)(struct platform_device *) = macb_config->init;
        struct device_node *np = pdev->dev.of_node;
        struct device_node *phy_node;
-       const struct macb_config *macb_config = NULL;
        struct clk *pclk, *hclk = NULL, *tx_clk = NULL, *rx_clk = NULL;
        unsigned int queue_mask, num_queues;
        struct macb_platform_data *pdata;
diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
new file mode 100644 (file)
index 0000000..92be2cd
--- /dev/null
@@ -0,0 +1,153 @@
+/**
+ * macb_pci.c - Cadence GEM PCI wrapper.
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ *
+ * Authors: Rafal Ozieblo <rafalo@cadence.com>
+ *         Bartosz Folta <bfolta@cadence.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_data/macb.h>
+#include <linux/platform_device.h>
+#include "macb.h"
+
+#define PCI_DRIVER_NAME "macb_pci"
+#define PLAT_DRIVER_NAME "macb"
+
+#define CDNS_VENDOR_ID 0x17cd
+#define CDNS_DEVICE_ID 0xe007
+
+#define GEM_PCLK_RATE 50000000
+#define GEM_HCLK_RATE 50000000
+
+static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       int err;
+       struct platform_device *plat_dev;
+       struct platform_device_info plat_info;
+       struct macb_platform_data plat_data;
+       struct resource res[2];
+
+       /* sanity check */
+       if (!id)
+               return -EINVAL;
+
+       /* enable pci device */
+       err = pci_enable_device(pdev);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Enabling PCI device has failed: 0x%04X",
+                       err);
+               return -EACCES;
+       }
+
+       pci_set_master(pdev);
+
+       /* set up resources */
+       memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+       res[0].start = pdev->resource[0].start;
+       res[0].end = pdev->resource[0].end;
+       res[0].name = PCI_DRIVER_NAME;
+       res[0].flags = IORESOURCE_MEM;
+       res[1].start = pdev->irq;
+       res[1].name = PCI_DRIVER_NAME;
+       res[1].flags = IORESOURCE_IRQ;
+
+       dev_info(&pdev->dev, "EMAC physical base addr = 0x%p\n",
+                (void *)(uintptr_t)pci_resource_start(pdev, 0));
+
+       /* set up macb platform data */
+       memset(&plat_data, 0, sizeof(plat_data));
+
+       /* initialize clocks */
+       plat_data.pclk = clk_register_fixed_rate(&pdev->dev, "pclk", NULL, 0,
+                                                GEM_PCLK_RATE);
+       if (IS_ERR(plat_data.pclk)) {
+               err = PTR_ERR(plat_data.pclk);
+               goto err_pclk_register;
+       }
+
+       plat_data.hclk = clk_register_fixed_rate(&pdev->dev, "hclk", NULL, 0,
+                                                GEM_HCLK_RATE);
+       if (IS_ERR(plat_data.hclk)) {
+               err = PTR_ERR(plat_data.hclk);
+               goto err_hclk_register;
+       }
+
+       /* set up platform device info */
+       memset(&plat_info, 0, sizeof(plat_info));
+       plat_info.parent = &pdev->dev;
+       plat_info.fwnode = pdev->dev.fwnode;
+       plat_info.name = PLAT_DRIVER_NAME;
+       plat_info.id = pdev->devfn;
+       plat_info.res = res;
+       plat_info.num_res = ARRAY_SIZE(res);
+       plat_info.data = &plat_data;
+       plat_info.size_data = sizeof(plat_data);
+       plat_info.dma_mask = DMA_BIT_MASK(32);
+
+       /* register platform device */
+       plat_dev = platform_device_register_full(&plat_info);
+       if (IS_ERR(plat_dev)) {
+               err = PTR_ERR(plat_dev);
+               goto err_plat_dev_register;
+       }
+
+       pci_set_drvdata(pdev, plat_dev);
+
+       return 0;
+
+err_plat_dev_register:
+       clk_unregister(plat_data.hclk);
+
+err_hclk_register:
+       clk_unregister(plat_data.pclk);
+
+err_pclk_register:
+       pci_disable_device(pdev);
+       return err;
+}
+
+static void macb_remove(struct pci_dev *pdev)
+{
+       struct platform_device *plat_dev = pci_get_drvdata(pdev);
+       struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
+
+       platform_device_unregister(plat_dev);
+       pci_disable_device(pdev);
+       clk_unregister(plat_data->pclk);
+       clk_unregister(plat_data->hclk);
+}
+
+static struct pci_device_id dev_id_table[] = {
+       { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), },
+       { 0, }
+};
+
+static struct pci_driver macb_pci_driver = {
+       .name     = PCI_DRIVER_NAME,
+       .id_table = dev_id_table,
+       .probe    = macb_probe,
+       .remove   = macb_remove,
+};
+
+module_pci_driver(macb_pci_driver);
+MODULE_DEVICE_TABLE(pci, dev_id_table);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence NIC PCI wrapper");
index 81d1d0bc7553bfc907e32bf5e42618ab57b68911..3a05f9098e759653b671be72e73135d04491a984 100644 (file)
@@ -568,28 +568,33 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
        reg_block_dump(ap, buf, A_MC5_CONFIG, A_MC5_MASK_WRITE_CMD);
 }
 
-static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int get_link_ksettings(struct net_device *dev,
+                             struct ethtool_link_ksettings *cmd)
 {
        struct adapter *adapter = dev->ml_priv;
        struct port_info *p = &adapter->port[dev->if_port];
+       u32 supported, advertising;
 
-       cmd->supported = p->link_config.supported;
-       cmd->advertising = p->link_config.advertising;
+       supported = p->link_config.supported;
+       advertising = p->link_config.advertising;
 
        if (netif_carrier_ok(dev)) {
-               ethtool_cmd_speed_set(cmd, p->link_config.speed);
-               cmd->duplex = p->link_config.duplex;
+               cmd->base.speed = p->link_config.speed;
+               cmd->base.duplex = p->link_config.duplex;
        } else {
-               ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
-               cmd->duplex = DUPLEX_UNKNOWN;
+               cmd->base.speed = SPEED_UNKNOWN;
+               cmd->base.duplex = DUPLEX_UNKNOWN;
        }
 
-       cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
-       cmd->phy_address = p->phy->mdio.prtad;
-       cmd->transceiver = XCVR_EXTERNAL;
-       cmd->autoneg = p->link_config.autoneg;
-       cmd->maxtxpkt = 0;
-       cmd->maxrxpkt = 0;
+       cmd->base.port = (supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+       cmd->base.phy_address = p->phy->mdio.prtad;
+       cmd->base.autoneg = p->link_config.autoneg;
+
+       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+                                               supported);
+       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+                                               advertising);
+
        return 0;
 }
 
@@ -628,36 +633,41 @@ static int speed_duplex_to_caps(int speed, int duplex)
                      ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
                      ADVERTISED_10000baseT_Full)
 
-static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int set_link_ksettings(struct net_device *dev,
+                             const struct ethtool_link_ksettings *cmd)
 {
        struct adapter *adapter = dev->ml_priv;
        struct port_info *p = &adapter->port[dev->if_port];
        struct link_config *lc = &p->link_config;
+       u32 advertising;
+
+       ethtool_convert_link_mode_to_legacy_u32(&advertising,
+                                               cmd->link_modes.advertising);
 
        if (!(lc->supported & SUPPORTED_Autoneg))
                return -EOPNOTSUPP;             /* can't change speed/duplex */
 
-       if (cmd->autoneg == AUTONEG_DISABLE) {
-               u32 speed = ethtool_cmd_speed(cmd);
-               int cap = speed_duplex_to_caps(speed, cmd->duplex);
+       if (cmd->base.autoneg == AUTONEG_DISABLE) {
+               u32 speed = cmd->base.speed;
+               int cap = speed_duplex_to_caps(speed, cmd->base.duplex);
 
                if (!(lc->supported & cap) || (speed == SPEED_1000))
                        return -EINVAL;
                lc->requested_speed = speed;
-               lc->requested_duplex = cmd->duplex;
+               lc->requested_duplex = cmd->base.duplex;
                lc->advertising = 0;
        } else {
-               cmd->advertising &= ADVERTISED_MASK;
-               if (cmd->advertising & (cmd->advertising - 1))
-                       cmd->advertising = lc->supported;
-               cmd->advertising &= lc->supported;
-               if (!cmd->advertising)
+               advertising &= ADVERTISED_MASK;
+               if (advertising & (advertising - 1))
+                       advertising = lc->supported;
+               advertising &= lc->supported;
+               if (!advertising)
                        return -EINVAL;
                lc->requested_speed = SPEED_INVALID;
                lc->requested_duplex = DUPLEX_INVALID;
-               lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+               lc->advertising = advertising | ADVERTISED_Autoneg;
        }
-       lc->autoneg = cmd->autoneg;
+       lc->autoneg = cmd->base.autoneg;
        if (netif_running(dev))
                t1_link_start(p->phy, p->mac, lc);
        return 0;
@@ -788,8 +798,6 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
 }
 
 static const struct ethtool_ops t1_ethtool_ops = {
-       .get_settings      = get_settings,
-       .set_settings      = set_settings,
        .get_drvinfo       = get_drvinfo,
        .get_msglevel      = get_msglevel,
        .set_msglevel      = set_msglevel,
@@ -807,6 +815,8 @@ static const struct ethtool_ops t1_ethtool_ops = {
        .get_ethtool_stats = get_stats,
        .get_regs_len      = get_regs_len,
        .get_regs          = get_regs,
+       .get_link_ksettings = get_link_ksettings,
+       .set_link_ksettings = set_link_ksettings,
 };
 
 static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
index 092b3c16440bcf2f4f6186cb8af0e1eed8ca1354..7b2224ae72f238bed5325325bc965726474f7e70 100644 (file)
@@ -1801,27 +1801,31 @@ static int set_phys_id(struct net_device *dev,
        return 0;
 }
 
-static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int get_link_ksettings(struct net_device *dev,
+                             struct ethtool_link_ksettings *cmd)
 {
        struct port_info *p = netdev_priv(dev);
+       u32 supported;
 
-       cmd->supported = p->link_config.supported;
-       cmd->advertising = p->link_config.advertising;
+       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+                                               p->link_config.supported);
+       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+                                               p->link_config.advertising);
 
        if (netif_carrier_ok(dev)) {
-               ethtool_cmd_speed_set(cmd, p->link_config.speed);
-               cmd->duplex = p->link_config.duplex;
+               cmd->base.speed = p->link_config.speed;
+               cmd->base.duplex = p->link_config.duplex;
        } else {
-               ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
-               cmd->duplex = DUPLEX_UNKNOWN;
+               cmd->base.speed = SPEED_UNKNOWN;
+               cmd->base.duplex = DUPLEX_UNKNOWN;
        }
 
-       cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
-       cmd->phy_address = p->phy.mdio.prtad;
-       cmd->transceiver = XCVR_EXTERNAL;
-       cmd->autoneg = p->link_config.autoneg;
-       cmd->maxtxpkt = 0;
-       cmd->maxrxpkt = 0;
+       ethtool_convert_link_mode_to_legacy_u32(&supported,
+                                               cmd->link_modes.supported);
+
+       cmd->base.port = (supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+       cmd->base.phy_address = p->phy.mdio.prtad;
+       cmd->base.autoneg = p->link_config.autoneg;
        return 0;
 }
 
@@ -1860,44 +1864,49 @@ static int speed_duplex_to_caps(int speed, int duplex)
                      ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
                      ADVERTISED_10000baseT_Full)
 
-static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int set_link_ksettings(struct net_device *dev,
+                             const struct ethtool_link_ksettings *cmd)
 {
        struct port_info *p = netdev_priv(dev);
        struct link_config *lc = &p->link_config;
+       u32 advertising;
+
+       ethtool_convert_link_mode_to_legacy_u32(&advertising,
+                                               cmd->link_modes.advertising);
 
        if (!(lc->supported & SUPPORTED_Autoneg)) {
                /*
                 * PHY offers a single speed/duplex.  See if that's what's
                 * being requested.
                 */
-               if (cmd->autoneg == AUTONEG_DISABLE) {
-                       u32 speed = ethtool_cmd_speed(cmd);
-                       int cap = speed_duplex_to_caps(speed, cmd->duplex);
+               if (cmd->base.autoneg == AUTONEG_DISABLE) {
+                       u32 speed = cmd->base.speed;
+                       int cap = speed_duplex_to_caps(speed, cmd->base.duplex);
                        if (lc->supported & cap)
                                return 0;
                }
                return -EINVAL;
        }
 
-       if (cmd->autoneg == AUTONEG_DISABLE) {
-               u32 speed = ethtool_cmd_speed(cmd);
-               int cap = speed_duplex_to_caps(speed, cmd->duplex);
+       if (cmd->base.autoneg == AUTONEG_DISABLE) {
+               u32 speed = cmd->base.speed;
+               int cap = speed_duplex_to_caps(speed, cmd->base.duplex);
 
                if (!(lc->supported & cap) || (speed == SPEED_1000))
                        return -EINVAL;
                lc->requested_speed = speed;
-               lc->requested_duplex = cmd->duplex;
+               lc->requested_duplex = cmd->base.duplex;
                lc->advertising = 0;
        } else {
-               cmd->advertising &= ADVERTISED_MASK;
-               cmd->advertising &= lc->supported;
-               if (!cmd->advertising)
+               advertising &= ADVERTISED_MASK;
+               advertising &= lc->supported;
+               if (!advertising)
                        return -EINVAL;
                lc->requested_speed = SPEED_INVALID;
                lc->requested_duplex = DUPLEX_INVALID;
-               lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+               lc->advertising = advertising | ADVERTISED_Autoneg;
        }
-       lc->autoneg = cmd->autoneg;
+       lc->autoneg = cmd->base.autoneg;
        if (netif_running(dev))
                t3_link_start(&p->phy, &p->mac, lc);
        return 0;
@@ -2097,8 +2106,6 @@ static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 }
 
 static const struct ethtool_ops cxgb_ethtool_ops = {
-       .get_settings = get_settings,
-       .set_settings = set_settings,
        .get_drvinfo = get_drvinfo,
        .get_msglevel = get_msglevel,
        .set_msglevel = set_msglevel,
@@ -2120,6 +2127,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
        .get_regs_len = get_regs_len,
        .get_regs = get_regs,
        .get_wol = get_wol,
+       .get_link_ksettings = get_link_ksettings,
+       .set_link_ksettings = set_link_ksettings,
 };
 
 static int in_range(int val, int lo, int hi)
index a1de0d12927d2ac5757e2f321f6b918f802db734..396c88678eabfec556536ca4a81f862245632d76 100644 (file)
@@ -715,16 +715,18 @@ static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
        strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
-static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int ep93xx_get_link_ksettings(struct net_device *dev,
+                                    struct ethtool_link_ksettings *cmd)
 {
        struct ep93xx_priv *ep = netdev_priv(dev);
-       return mii_ethtool_gset(&ep->mii, cmd);
+       return mii_ethtool_get_link_ksettings(&ep->mii, cmd);
 }
 
-static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int ep93xx_set_link_ksettings(struct net_device *dev,
+                                    const struct ethtool_link_ksettings *cmd)
 {
        struct ep93xx_priv *ep = netdev_priv(dev);
-       return mii_ethtool_sset(&ep->mii, cmd);
+       return mii_ethtool_set_link_ksettings(&ep->mii, cmd);
 }
 
 static int ep93xx_nway_reset(struct net_device *dev)
@@ -741,10 +743,10 @@ static u32 ep93xx_get_link(struct net_device *dev)
 
 static const struct ethtool_ops ep93xx_ethtool_ops = {
        .get_drvinfo            = ep93xx_get_drvinfo,
-       .get_settings           = ep93xx_get_settings,
-       .set_settings           = ep93xx_set_settings,
        .nway_reset             = ep93xx_nway_reset,
        .get_link               = ep93xx_get_link,
+       .get_link_ksettings     = ep93xx_get_link_ksettings,
+       .set_link_ksettings     = ep93xx_set_link_ksettings,
 };
 
 static const struct net_device_ops ep93xx_netdev_ops = {
index f1a81c52afe38783aad3d4c5ab43f3fdfaaacf08..008dc8161775cc920160a200cc480e06dc054733 100644 (file)
@@ -570,19 +570,21 @@ static void dm9000_set_msglevel(struct net_device *dev, u32 value)
        dm->msg_enable = value;
 }
 
-static int dm9000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int dm9000_get_link_ksettings(struct net_device *dev,
+                                    struct ethtool_link_ksettings *cmd)
 {
        struct board_info *dm = to_dm9000_board(dev);
 
-       mii_ethtool_gset(&dm->mii, cmd);
+       mii_ethtool_get_link_ksettings(&dm->mii, cmd);
        return 0;
 }
 
-static int dm9000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int dm9000_set_link_ksettings(struct net_device *dev,
+                                    const struct ethtool_link_ksettings *cmd)
 {
        struct board_info *dm = to_dm9000_board(dev);
 
-       return mii_ethtool_sset(&dm->mii, cmd);
+       return mii_ethtool_set_link_ksettings(&dm->mii, cmd);
 }
 
 static int dm9000_nway_reset(struct net_device *dev)
@@ -741,8 +743,6 @@ static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
 
 static const struct ethtool_ops dm9000_ethtool_ops = {
        .get_drvinfo            = dm9000_get_drvinfo,
-       .get_settings           = dm9000_get_settings,
-       .set_settings           = dm9000_set_settings,
        .get_msglevel           = dm9000_get_msglevel,
        .set_msglevel           = dm9000_set_msglevel,
        .nway_reset             = dm9000_nway_reset,
@@ -752,6 +752,8 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
        .get_eeprom_len         = dm9000_get_eeprom_len,
        .get_eeprom             = dm9000_get_eeprom,
        .set_eeprom             = dm9000_set_eeprom,
+       .get_link_ksettings     = dm9000_get_link_ksettings,
+       .set_link_ksettings     = dm9000_set_link_ksettings,
 };
 
 static void dm9000_show_carrier(struct board_info *db,
index f3a3454805f9f148ded65ef5d5342ca42a870abf..a654736237a9c250bf4ac39d6237c2bd1f154744 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig FSL_DPAA_ETH
        tristate "DPAA Ethernet"
-       depends on FSL_SOC && FSL_DPAA && FSL_FMAN
+       depends on FSL_DPAA && FSL_FMAN
        select PHYLIB
        select FSL_FMAN_MAC
        ---help---
index 3c48a84dec8638d29d84c26ca20976c19201ce5a..624ba9058dc46bd369f7be872b040aee1e814696 100644 (file)
@@ -733,7 +733,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
        priv->cgr_data.cgr.cb = dpaa_eth_cgscn;
 
        /* Enable Congestion State Change Notifications and CS taildrop */
-       initcgr.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES;
+       initcgr.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES);
        initcgr.cgr.cscn_en = QM_CGR_EN;
 
        /* Set different thresholds based on the MAC speed.
@@ -747,7 +747,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
                cs_th = DPAA_CS_THRESHOLD_1G;
        qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
 
-       initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
+       initcgr.we_mask |= cpu_to_be16(QM_CGR_WE_CSTD_EN);
        initcgr.cgr.cstd_en = QM_CGR_EN;
 
        err = qman_create_cgr(&priv->cgr_data.cgr, QMAN_CGR_FLAG_USE_INIT,
@@ -896,18 +896,18 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
        if (dpaa_fq->init) {
                memset(&initfq, 0, sizeof(initfq));
 
-               initfq.we_mask = QM_INITFQ_WE_FQCTRL;
+               initfq.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL);
                /* Note: we may get to keep an empty FQ in cache */
-               initfq.fqd.fq_ctrl = QM_FQCTRL_PREFERINCACHE;
+               initfq.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_PREFERINCACHE);
 
                /* Try to reduce the number of portal interrupts for
                 * Tx Confirmation FQs.
                 */
                if (dpaa_fq->fq_type == FQ_TYPE_TX_CONFIRM)
-                       initfq.fqd.fq_ctrl |= QM_FQCTRL_HOLDACTIVE;
+                       initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_HOLDACTIVE);
 
                /* FQ placement */
-               initfq.we_mask |= QM_INITFQ_WE_DESTWQ;
+               initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_DESTWQ);
 
                qm_fqd_set_destwq(&initfq.fqd, dpaa_fq->channel, dpaa_fq->wq);
 
@@ -920,8 +920,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
                if (dpaa_fq->fq_type == FQ_TYPE_TX ||
                    dpaa_fq->fq_type == FQ_TYPE_TX_CONFIRM ||
                    dpaa_fq->fq_type == FQ_TYPE_TX_CONF_MQ) {
-                       initfq.we_mask |= QM_INITFQ_WE_CGID;
-                       initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE;
+                       initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CGID);
+                       initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_CGE);
                        initfq.fqd.cgid = (u8)priv->cgr_data.cgr.cgrid;
                        /* Set a fixed overhead accounting, in an attempt to
                         * reduce the impact of fixed-size skb shells and the
@@ -932,7 +932,7 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
                         * insufficient value, but even that is better than
                         * no overhead accounting at all.
                         */
-                       initfq.we_mask |= QM_INITFQ_WE_OAC;
+                       initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_OAC);
                        qm_fqd_set_oac(&initfq.fqd, QM_OAC_CG);
                        qm_fqd_set_oal(&initfq.fqd,
                                       min(sizeof(struct sk_buff) +
@@ -941,9 +941,9 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
                }
 
                if (td_enable) {
-                       initfq.we_mask |= QM_INITFQ_WE_TDTHRESH;
+                       initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_TDTHRESH);
                        qm_fqd_set_taildrop(&initfq.fqd, DPAA_FQ_TD, 1);
-                       initfq.fqd.fq_ctrl = QM_FQCTRL_TDE;
+                       initfq.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_TDE);
                }
 
                if (dpaa_fq->fq_type == FQ_TYPE_TX) {
@@ -951,7 +951,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
                        if (queue_id >= 0)
                                confq = priv->conf_fqs[queue_id];
                        if (confq) {
-                               initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
+                               initfq.we_mask |=
+                                       cpu_to_be16(QM_INITFQ_WE_CONTEXTA);
                        /* ContextA: OVOM=1(use contextA2 bits instead of ICAD)
                         *           A2V=1 (contextA A2 field is valid)
                         *           A0V=1 (contextA A0 field is valid)
@@ -959,8 +960,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
                         * ContextA A2: EBD=1 (deallocate buffers inside FMan)
                         * ContextB B0(ASPID): 0 (absolute Virtual Storage ID)
                         */
-                               initfq.fqd.context_a.hi = 0x1e000000;
-                               initfq.fqd.context_a.lo = 0x80000000;
+                               qm_fqd_context_a_set64(&initfq.fqd,
+                                                      0x1e00000080000000ULL);
                        }
                }
 
@@ -968,13 +969,13 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
                if (priv->use_ingress_cgr &&
                    (dpaa_fq->fq_type == FQ_TYPE_RX_DEFAULT ||
                     dpaa_fq->fq_type == FQ_TYPE_RX_ERROR)) {
-                       initfq.we_mask |= QM_INITFQ_WE_CGID;
-                       initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE;
+                       initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CGID);
+                       initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_CGE);
                        initfq.fqd.cgid = (u8)priv->ingress_cgr.cgrid;
                        /* Set a fixed overhead accounting, just like for the
                         * egress CGR.
                         */
-                       initfq.we_mask |= QM_INITFQ_WE_OAC;
+                       initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_OAC);
                        qm_fqd_set_oac(&initfq.fqd, QM_OAC_CG);
                        qm_fqd_set_oal(&initfq.fqd,
                                       min(sizeof(struct sk_buff) +
@@ -984,9 +985,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
 
                /* Initialization common to all ingress queues */
                if (dpaa_fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE) {
-                       initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
-                       initfq.fqd.fq_ctrl |=
-                               QM_FQCTRL_HOLDACTIVE;
+                       initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CONTEXTA);
+                       initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_HOLDACTIVE);
                        initfq.fqd.context_a.stashing.exclusive =
                                QM_STASHING_EXCL_DATA | QM_STASHING_EXCL_CTX |
                                QM_STASHING_EXCL_ANNOTATION;
@@ -1350,7 +1350,7 @@ static int dpaa_enable_tx_csum(struct dpaa_priv *priv,
        parse_result->l4_off = (u8)skb_transport_offset(skb);
 
        /* Enable L3 (and L4, if TCP or UDP) HW checksum. */
-       fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC;
+       fd->cmd |= cpu_to_be32(FM_FD_CMD_RPD | FM_FD_CMD_DTC);
 
        /* On P1023 and similar platforms fd->cmd interpretation could
         * be disabled by setting CONTEXT_A bit ICMD; currently this bit
@@ -1732,7 +1732,7 @@ static int skb_to_contig_fd(struct dpaa_priv *priv,
 
        /* Fill in the rest of the FD fields */
        qm_fd_set_contig(fd, priv->tx_headroom, skb->len);
-       fd->cmd |= FM_FD_CMD_FCO;
+       fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO);
 
        /* Map the entire buffer size that may be seen by FMan, but no more */
        addr = dma_map_single(dev, skbh,
@@ -1840,7 +1840,7 @@ static int skb_to_sg_fd(struct dpaa_priv *priv,
        }
 
        fd->bpid = FSL_DPAA_BPID_INV;
-       fd->cmd |= FM_FD_CMD_FCO;
+       fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO);
        qm_fd_addr_set64(fd, addr);
 
        return 0;
@@ -1867,7 +1867,7 @@ static inline int dpaa_xmit(struct dpaa_priv *priv,
 
        egress_fq = priv->egress_fqs[queue];
        if (fd->bpid == FSL_DPAA_BPID_INV)
-               fd->cmd |= qman_fq_fqid(priv->conf_fqs[queue]);
+               fd->cmd |= cpu_to_be32(qman_fq_fqid(priv->conf_fqs[queue]));
 
        /* Trace this Tx fd */
        trace_dpaa_tx_fd(priv->net_dev, egress_fq, fd);
@@ -1960,17 +1960,17 @@ static void dpaa_rx_error(struct net_device *net_dev,
 {
        if (net_ratelimit())
                netif_err(priv, hw, net_dev, "Err FD status = 0x%08x\n",
-                         fd->status & FM_FD_STAT_RX_ERRORS);
+                         be32_to_cpu(fd->status) & FM_FD_STAT_RX_ERRORS);
 
        percpu_priv->stats.rx_errors++;
 
-       if (fd->status & FM_FD_ERR_DMA)
+       if (be32_to_cpu(fd->status) & FM_FD_ERR_DMA)
                percpu_priv->rx_errors.dme++;
-       if (fd->status & FM_FD_ERR_PHYSICAL)
+       if (be32_to_cpu(fd->status) & FM_FD_ERR_PHYSICAL)
                percpu_priv->rx_errors.fpe++;
-       if (fd->status & FM_FD_ERR_SIZE)
+       if (be32_to_cpu(fd->status) & FM_FD_ERR_SIZE)
                percpu_priv->rx_errors.fse++;
-       if (fd->status & FM_FD_ERR_PRS_HDR_ERR)
+       if (be32_to_cpu(fd->status) & FM_FD_ERR_PRS_HDR_ERR)
                percpu_priv->rx_errors.phe++;
 
        dpaa_fd_release(net_dev, fd);
@@ -1986,7 +1986,7 @@ static void dpaa_tx_error(struct net_device *net_dev,
 
        if (net_ratelimit())
                netif_warn(priv, hw, net_dev, "FD status = 0x%08x\n",
-                          fd->status & FM_FD_STAT_TX_ERRORS);
+                          be32_to_cpu(fd->status) & FM_FD_STAT_TX_ERRORS);
 
        percpu_priv->stats.tx_errors++;
 
@@ -2020,10 +2020,11 @@ static void dpaa_tx_conf(struct net_device *net_dev,
 {
        struct sk_buff  *skb;
 
-       if (unlikely(fd->status & FM_FD_STAT_TX_ERRORS) != 0) {
+       if (unlikely(be32_to_cpu(fd->status) & FM_FD_STAT_TX_ERRORS)) {
                if (net_ratelimit())
                        netif_warn(priv, hw, net_dev, "FD status = 0x%08x\n",
-                                  fd->status & FM_FD_STAT_TX_ERRORS);
+                                  be32_to_cpu(fd->status) &
+                                  FM_FD_STAT_TX_ERRORS);
 
                percpu_priv->stats.tx_errors++;
        }
@@ -2100,6 +2101,8 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
        struct sk_buff *skb;
        int *count_ptr;
 
+       fd_status = be32_to_cpu(fd->status);
+       fd_format = qm_fd_get_format(fd);
        net_dev = ((struct dpaa_fq *)fq)->net_dev;
        priv = netdev_priv(net_dev);
        dpaa_bp = dpaa_bpid2pool(dq->fd.bpid);
@@ -2417,12 +2420,12 @@ static int dpaa_ingress_cgr_init(struct dpaa_priv *priv)
        }
 
        /* Enable CS TD, but disable Congestion State Change Notifications. */
-       initcgr.we_mask = QM_CGR_WE_CS_THRES;
+       initcgr.we_mask = cpu_to_be16(QM_CGR_WE_CS_THRES);
        initcgr.cgr.cscn_en = QM_CGR_EN;
        cs_th = DPAA_INGRESS_CS_THRESHOLD;
        qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
 
-       initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
+       initcgr.we_mask |= cpu_to_be16(QM_CGR_WE_CSTD_EN);
        initcgr.cgr.cstd_en = QM_CGR_EN;
 
        /* This CGR will be associated with the SWP affined to the current CPU.
index 854befde0a08c9031df92a69c5c9e3709062c188..97b184774784beb603c27d62486e771f3a8af80b 100644 (file)
@@ -828,6 +828,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
        priv = netdev_priv(ndev);
        priv->ndev = ndev;
        platform_set_drvdata(pdev, ndev);
+       SET_NETDEV_DEV(ndev, &pdev->dev);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        priv->base = devm_ioremap_resource(d, res);
@@ -903,7 +904,6 @@ static int hip04_mac_probe(struct platform_device *pdev)
        ndev->priv_flags |= IFF_UNICAST_FLT;
        ndev->irq = irq;
        netif_napi_add(ndev, &priv->napi, hip04_rx_poll, NAPI_POLL_WEIGHT);
-       SET_NETDEV_DEV(ndev, &pdev->dev);
 
        hip04_reset_ppe(priv);
        if (priv->phy_mode == PHY_INTERFACE_MODE_MII)
index 49863068c59e3cb4ecb4c24128326cbd4c42e37a..979852d56f31ddb7301c7be19f2f91d922ef5e33 100644 (file)
@@ -805,6 +805,7 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, ndev);
+       SET_NETDEV_DEV(ndev, &pdev->dev);
 
        priv = netdev_priv(ndev);
        priv->dev = dev;
@@ -882,7 +883,6 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
        ndev->netdev_ops = &hisi_femac_netdev_ops;
        ndev->ethtool_ops = &hisi_femac_ethtools_ops;
        netif_napi_add(ndev, &priv->napi, hisi_femac_poll, FEMAC_POLL_WEIGHT);
-       SET_NETDEV_DEV(ndev, &pdev->dev);
 
        hisi_femac_port_init(priv);
 
index fbece63395a888fdaaabeda3eeb63e3fb1f5377f..a831f947ca8c1157737a18b69c611105442f9276 100644 (file)
@@ -1181,7 +1181,9 @@ map_failed:
 
 static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
 {
+       struct tcphdr *tcph;
        int offset = 0;
+       int hdr_len;
 
        /* only TCP packets will be aggregated */
        if (skb->protocol == htons(ETH_P_IP)) {
@@ -1208,14 +1210,20 @@ static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
        /* if mss is not set through Large Packet bit/mss in rx buffer,
         * expect that the mss will be written to the tcp header checksum.
         */
+       tcph = (struct tcphdr *)(skb->data + offset);
        if (lrg_pkt) {
                skb_shinfo(skb)->gso_size = mss;
        } else if (offset) {
-               struct tcphdr *tcph = (struct tcphdr *)(skb->data + offset);
-
                skb_shinfo(skb)->gso_size = ntohs(tcph->check);
                tcph->check = 0;
        }
+
+       if (skb_shinfo(skb)->gso_size) {
+               hdr_len = offset + tcph->doff * 4;
+               skb_shinfo(skb)->gso_segs =
+                               DIV_ROUND_UP(skb->len - hdr_len,
+                                            skb_shinfo(skb)->gso_size);
+       }
 }
 
 static int ibmveth_poll(struct napi_struct *napi, int budget)
index 5f62c3d70df9d46ff2411220948ab87bc42f4d11..1fa7c03edec2fd0aa91f93dd86d7705f4a273a4b 100644 (file)
@@ -2713,7 +2713,7 @@ static const struct of_device_id mv643xx_eth_shared_ids[] = {
 MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids);
 #endif
 
-#if defined(CONFIG_OF) && !defined(CONFIG_MV64X60)
+#if defined(CONFIG_OF_IRQ) && !defined(CONFIG_MV64X60)
 #define mv643xx_eth_property(_np, _name, _v)                           \
        do {                                                            \
                u32 tmp;                                                \
index fece974b4edd7fe8f49a98baf75e462b445b6c04..d768c7b6c6d6688c46077c48e25df45cdf9ad7dc 100644 (file)
@@ -2404,7 +2404,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                        local_port);
                return err;
        }
-       err = __mlxsw_sp_port_create(mlxsw_sp, local_port, false,
+       err = __mlxsw_sp_port_create(mlxsw_sp, local_port, split,
                                     module, width, lane);
        if (err)
                goto err_port_create;
index f3bb9055a29274c951776e09b134a57b00971d14..44bb04d4d21b58cd878e7bfb4c24a690e959157d 100644 (file)
@@ -26,11 +26,11 @@ static inline bool is_bits_set(int value, int mask)
 }
 
 static int encx24j600_switch_bank(struct encx24j600_context *ctx,
-                                        int bank)
+                                 int bank)
 {
        int ret = 0;
-
        int bank_opcode = BANK_SELECT(bank);
+
        ret = spi_write(ctx->spi, &bank_opcode, 1);
        if (ret == 0)
                ctx->bank = bank;
@@ -39,7 +39,7 @@ static int encx24j600_switch_bank(struct encx24j600_context *ctx,
 }
 
 static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode,
-                           const void *buf, size_t len)
+                          const void *buf, size_t len)
 {
        struct spi_message m;
        struct spi_transfer t[2] = { { .tx_buf = &opcode, .len = 1, },
@@ -54,12 +54,14 @@ static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode,
 static void regmap_lock_mutex(void *context)
 {
        struct encx24j600_context *ctx = context;
+
        mutex_lock(&ctx->mutex);
 }
 
 static void regmap_unlock_mutex(void *context)
 {
        struct encx24j600_context *ctx = context;
+
        mutex_unlock(&ctx->mutex);
 }
 
@@ -128,6 +130,7 @@ static int regmap_encx24j600_sfr_update(struct encx24j600_context *ctx,
 
        if (reg < 0x80) {
                int ret = 0;
+
                cmd = banked_code | banked_reg;
                if ((banked_reg < 0x16) && (ctx->bank != bank))
                        ret = encx24j600_switch_bank(ctx, bank);
@@ -174,6 +177,7 @@ static int regmap_encx24j600_sfr_write(void *context, u8 reg, u8 *val,
                                       size_t len)
 {
        struct encx24j600_context *ctx = context;
+
        return regmap_encx24j600_sfr_update(ctx, reg, val, len, WCRU, WCRCODE);
 }
 
@@ -228,9 +232,9 @@ int regmap_encx24j600_spi_write(void *context, u8 reg, const u8 *data,
 
        if (reg < 0xc0)
                return encx24j600_cmdn(ctx, reg, data, count);
-       else
-               /* SPI 1-byte command. Ignore data */
-               return spi_write(ctx->spi, &reg, 1);
+
+       /* SPI 1-byte command. Ignore data */
+       return spi_write(ctx->spi, &reg, 1);
 }
 EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_write);
 
@@ -495,6 +499,7 @@ static struct regmap_config phycfg = {
        .writeable_reg = encx24j600_phymap_writeable,
        .volatile_reg = encx24j600_phymap_volatile,
 };
+
 static struct regmap_bus phymap_encx24j600 = {
        .reg_write = regmap_encx24j600_phy_reg_write,
        .reg_read = regmap_encx24j600_phy_reg_read,
index b14f0305aa318023a530856ad03a04b962cfd539..fbce6166504e480949f46982390668dff9af4659 100644 (file)
@@ -30,7 +30,7 @@
 
 #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
 static int debug = -1;
-module_param(debug, int, 0);
+module_param(debug, int, 0000);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
 /* SRAM memory layout:
@@ -105,6 +105,7 @@ static u16 encx24j600_read_reg(struct encx24j600_priv *priv, u8 reg)
        struct net_device *dev = priv->ndev;
        unsigned int val = 0;
        int ret = regmap_read(priv->ctx.regmap, reg, &val);
+
        if (unlikely(ret))
                netif_err(priv, drv, dev, "%s: error %d reading reg %02x\n",
                          __func__, ret, reg);
@@ -115,6 +116,7 @@ static void encx24j600_write_reg(struct encx24j600_priv *priv, u8 reg, u16 val)
 {
        struct net_device *dev = priv->ndev;
        int ret = regmap_write(priv->ctx.regmap, reg, val);
+
        if (unlikely(ret))
                netif_err(priv, drv, dev, "%s: error %d writing reg %02x=%04x\n",
                          __func__, ret, reg, val);
@@ -125,6 +127,7 @@ static void encx24j600_update_reg(struct encx24j600_priv *priv, u8 reg,
 {
        struct net_device *dev = priv->ndev;
        int ret = regmap_update_bits(priv->ctx.regmap, reg, mask, val);
+
        if (unlikely(ret))
                netif_err(priv, drv, dev, "%s: error %d updating reg %02x=%04x~%04x\n",
                          __func__, ret, reg, val, mask);
@@ -135,6 +138,7 @@ static u16 encx24j600_read_phy(struct encx24j600_priv *priv, u8 reg)
        struct net_device *dev = priv->ndev;
        unsigned int val = 0;
        int ret = regmap_read(priv->ctx.phymap, reg, &val);
+
        if (unlikely(ret))
                netif_err(priv, drv, dev, "%s: error %d reading %02x\n",
                          __func__, ret, reg);
@@ -145,6 +149,7 @@ static void encx24j600_write_phy(struct encx24j600_priv *priv, u8 reg, u16 val)
 {
        struct net_device *dev = priv->ndev;
        int ret = regmap_write(priv->ctx.phymap, reg, val);
+
        if (unlikely(ret))
                netif_err(priv, drv, dev, "%s: error %d writing reg %02x=%04x\n",
                          __func__, ret, reg, val);
@@ -164,6 +169,7 @@ static void encx24j600_cmd(struct encx24j600_priv *priv, u8 cmd)
 {
        struct net_device *dev = priv->ndev;
        int ret = regmap_write(priv->ctx.regmap, cmd, 0);
+
        if (unlikely(ret))
                netif_err(priv, drv, dev, "%s: error %d with cmd %02x\n",
                          __func__, ret, cmd);
@@ -173,6 +179,7 @@ static int encx24j600_raw_read(struct encx24j600_priv *priv, u8 reg, u8 *data,
                               size_t count)
 {
        int ret;
+
        mutex_lock(&priv->ctx.mutex);
        ret = regmap_encx24j600_spi_read(&priv->ctx, reg, data, count);
        mutex_unlock(&priv->ctx.mutex);
@@ -184,6 +191,7 @@ static int encx24j600_raw_write(struct encx24j600_priv *priv, u8 reg,
                                const u8 *data, size_t count)
 {
        int ret;
+
        mutex_lock(&priv->ctx.mutex);
        ret = regmap_encx24j600_spi_write(&priv->ctx, reg, data, count);
        mutex_unlock(&priv->ctx.mutex);
@@ -194,6 +202,7 @@ static int encx24j600_raw_write(struct encx24j600_priv *priv, u8 reg,
 static void encx24j600_update_phcon1(struct encx24j600_priv *priv)
 {
        u16 phcon1 = encx24j600_read_phy(priv, PHCON1);
+
        if (priv->autoneg == AUTONEG_ENABLE) {
                phcon1 |= ANEN | RENEG;
        } else {
@@ -328,6 +337,7 @@ static int encx24j600_receive_packet(struct encx24j600_priv *priv,
 {
        struct net_device *dev = priv->ndev;
        struct sk_buff *skb = netdev_alloc_skb(dev, rsv->len + NET_IP_ALIGN);
+
        if (!skb) {
                pr_err_ratelimited("RX: OOM: packet dropped\n");
                dev->stats.rx_dropped++;
@@ -346,7 +356,6 @@ static int encx24j600_receive_packet(struct encx24j600_priv *priv,
        /* Maintain stats */
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += rsv->len;
-       priv->next_packet = rsv->next_packet;
 
        netif_rx(skb);
 
@@ -383,6 +392,8 @@ static void encx24j600_rx_packets(struct encx24j600_priv *priv, u8 packet_count)
                        encx24j600_receive_packet(priv, &rsv);
                }
 
+               priv->next_packet = rsv.next_packet;
+
                newrxtail = priv->next_packet - 2;
                if (newrxtail == ENC_RX_BUF_START)
                        newrxtail = SRAM_SIZE - 2;
@@ -827,6 +838,7 @@ static void encx24j600_set_multicast_list(struct net_device *dev)
 static void encx24j600_hw_tx(struct encx24j600_priv *priv)
 {
        struct net_device *dev = priv->ndev;
+
        netif_info(priv, tx_queued, dev, "TX Packet Len:%d\n",
                   priv->tx_skb->len);
 
@@ -894,7 +906,6 @@ static void encx24j600_tx_timeout(struct net_device *dev)
 
        dev->stats.tx_errors++;
        netif_wake_queue(dev);
-       return;
 }
 
 static int encx24j600_get_regs_len(struct net_device *dev)
@@ -957,12 +968,14 @@ static int encx24j600_set_settings(struct net_device *dev,
 static u32 encx24j600_get_msglevel(struct net_device *dev)
 {
        struct encx24j600_priv *priv = netdev_priv(dev);
+
        return priv->msg_enable;
 }
 
 static void encx24j600_set_msglevel(struct net_device *dev, u32 val)
 {
        struct encx24j600_priv *priv = netdev_priv(dev);
+
        priv->msg_enable = val;
 }
 
index 00efb1c4c57e842f653fb6dc36a314a894dc1770..17a70122df05c93bec01f13dc48e3924b4868acf 100644 (file)
@@ -1265,7 +1265,7 @@ static const struct qed_iscsi_ops qed_iscsi_ops_pass = {
        .get_stats = &qed_iscsi_stats,
 };
 
-const struct qed_iscsi_ops *qed_get_iscsi_ops()
+const struct qed_iscsi_ops *qed_get_iscsi_ops(void)
 {
        return &qed_iscsi_ops_pass;
 }
index ae32f855e31b845617f8d70dc127cdb177cc361a..422289c232bc77b2c08c49e5646967b94aeedff8 100644 (file)
@@ -460,6 +460,12 @@ static int emac_clks_phase1_init(struct platform_device *pdev,
 {
        int ret;
 
+       /* On ACPI platforms, clocks are controlled by firmware and/or
+        * ACPI, not by drivers.
+        */
+       if (has_acpi_companion(&pdev->dev))
+               return 0;
+
        ret = emac_clks_get(pdev, adpt);
        if (ret)
                return ret;
@@ -485,6 +491,9 @@ static int emac_clks_phase2_init(struct platform_device *pdev,
 {
        int ret;
 
+       if (has_acpi_companion(&pdev->dev))
+               return 0;
+
        ret = clk_set_rate(adpt->clk[EMAC_CLK_TX], 125000000);
        if (ret)
                return ret;
index 4ff4e0491406b1b2a06d5e05b9b4871bebc203e6..aa11b70b9ca48081bf2e78604d2d2ccad36a84cb 100644 (file)
@@ -472,8 +472,6 @@ static void r6040_down(struct net_device *dev)
        iowrite16(adrp[0], ioaddr + MID_0L);
        iowrite16(adrp[1], ioaddr + MID_0M);
        iowrite16(adrp[2], ioaddr + MID_0H);
-
-       phy_stop(dev->phydev);
 }
 
 static int r6040_close(struct net_device *dev)
@@ -481,12 +479,12 @@ static int r6040_close(struct net_device *dev)
        struct r6040_private *lp = netdev_priv(dev);
        struct pci_dev *pdev = lp->pdev;
 
-       spin_lock_irq(&lp->lock);
+       phy_stop(dev->phydev);
        napi_disable(&lp->napi);
        netif_stop_queue(dev);
-       r6040_down(dev);
 
-       free_irq(dev->irq, dev);
+       spin_lock_irq(&lp->lock);
+       r6040_down(dev);
 
        /* Free RX buffer */
        r6040_free_rxbufs(dev);
@@ -496,6 +494,8 @@ static int r6040_close(struct net_device *dev)
 
        spin_unlock_irq(&lp->lock);
 
+       free_irq(dev->irq, dev);
+
        /* Free Descriptor memory */
        if (lp->rx_ring) {
                pci_free_consistent(pdev,
index f644216eda1b5c5d1d925cf8427c0e29c87c6616..87bdc56b4e3a636450e4f39e49b37606332d8268 100644 (file)
@@ -120,44 +120,53 @@ static int efx_ethtool_phys_id(struct net_device *net_dev,
 }
 
 /* This must be called with rtnl_lock held. */
-static int efx_ethtool_get_settings(struct net_device *net_dev,
-                                   struct ethtool_cmd *ecmd)
+static int
+efx_ethtool_get_link_ksettings(struct net_device *net_dev,
+                              struct ethtool_link_ksettings *cmd)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_link_state *link_state = &efx->link_state;
+       u32 supported;
 
        mutex_lock(&efx->mac_lock);
-       efx->phy_op->get_settings(efx, ecmd);
+       efx->phy_op->get_link_ksettings(efx, cmd);
        mutex_unlock(&efx->mac_lock);
 
        /* Both MACs support pause frames (bidirectional and respond-only) */
-       ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+       ethtool_convert_link_mode_to_legacy_u32(&supported,
+                                               cmd->link_modes.supported);
+
+       supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
+       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+                                               supported);
 
        if (LOOPBACK_INTERNAL(efx)) {
-               ethtool_cmd_speed_set(ecmd, link_state->speed);
-               ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
+               cmd->base.speed = link_state->speed;
+               cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
        }
 
        return 0;
 }
 
 /* This must be called with rtnl_lock held. */
-static int efx_ethtool_set_settings(struct net_device *net_dev,
-                                   struct ethtool_cmd *ecmd)
+static int
+efx_ethtool_set_link_ksettings(struct net_device *net_dev,
+                              const struct ethtool_link_ksettings *cmd)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
        int rc;
 
        /* GMAC does not support 1000Mbps HD */
-       if ((ethtool_cmd_speed(ecmd) == SPEED_1000) &&
-           (ecmd->duplex != DUPLEX_FULL)) {
+       if ((cmd->base.speed == SPEED_1000) &&
+           (cmd->base.duplex != DUPLEX_FULL)) {
                netif_dbg(efx, drv, efx->net_dev,
                          "rejecting unsupported 1000Mbps HD setting\n");
                return -EINVAL;
        }
 
        mutex_lock(&efx->mac_lock);
-       rc = efx->phy_op->set_settings(efx, ecmd);
+       rc = efx->phy_op->set_link_ksettings(efx, cmd);
        mutex_unlock(&efx->mac_lock);
        return rc;
 }
@@ -1342,8 +1351,6 @@ static int efx_ethtool_get_module_info(struct net_device *net_dev,
 }
 
 const struct ethtool_ops efx_ethtool_ops = {
-       .get_settings           = efx_ethtool_get_settings,
-       .set_settings           = efx_ethtool_set_settings,
        .get_drvinfo            = efx_ethtool_get_drvinfo,
        .get_regs_len           = efx_ethtool_get_regs_len,
        .get_regs               = efx_ethtool_get_regs,
@@ -1373,4 +1380,6 @@ const struct ethtool_ops efx_ethtool_ops = {
        .get_ts_info            = efx_ethtool_get_ts_info,
        .get_module_info        = efx_ethtool_get_module_info,
        .get_module_eeprom      = efx_ethtool_get_module_eeprom,
+       .get_link_ksettings     = efx_ethtool_get_link_ksettings,
+       .set_link_ksettings     = efx_ethtool_set_link_ksettings,
 };
index 9dcd396784ae72f7f1959463fe3086c2f504e143..c905971c5f3a2849262dcf3ce220de93e32e4bd2 100644 (file)
@@ -503,45 +503,59 @@ static void efx_mcdi_phy_remove(struct efx_nic *efx)
        kfree(phy_data);
 }
 
-static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+static void efx_mcdi_phy_get_link_ksettings(struct efx_nic *efx,
+                                           struct ethtool_link_ksettings *cmd)
 {
        struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
        MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);
        int rc;
-
-       ecmd->supported =
-               mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap);
-       ecmd->advertising = efx->link_advertising;
-       ethtool_cmd_speed_set(ecmd, efx->link_state.speed);
-       ecmd->duplex = efx->link_state.fd;
-       ecmd->port = mcdi_to_ethtool_media(phy_cfg->media);
-       ecmd->phy_address = phy_cfg->port;
-       ecmd->transceiver = XCVR_INTERNAL;
-       ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg);
-       ecmd->mdio_support = (efx->mdio.mode_support &
+       u32 supported, advertising, lp_advertising;
+
+       supported = mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap);
+       advertising = efx->link_advertising;
+       cmd->base.speed = efx->link_state.speed;
+       cmd->base.duplex = efx->link_state.fd;
+       cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media);
+       cmd->base.phy_address = phy_cfg->port;
+       cmd->base.autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg);
+       cmd->base.mdio_support = (efx->mdio.mode_support &
                              (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22));
 
+       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+                                               supported);
+       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+                                               advertising);
+
        BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
        rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
                          outbuf, sizeof(outbuf), NULL);
        if (rc)
                return;
-       ecmd->lp_advertising =
+       lp_advertising =
                mcdi_to_ethtool_cap(phy_cfg->media,
                                    MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP));
+
+       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
+                                               lp_advertising);
 }
 
-static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+static int
+efx_mcdi_phy_set_link_ksettings(struct efx_nic *efx,
+                               const struct ethtool_link_ksettings *cmd)
 {
        struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
        u32 caps;
        int rc;
+       u32 advertising;
+
+       ethtool_convert_link_mode_to_legacy_u32(&advertising,
+                                               cmd->link_modes.advertising);
 
-       if (ecmd->autoneg) {
-               caps = (ethtool_to_mcdi_cap(ecmd->advertising) |
+       if (cmd->base.autoneg) {
+               caps = (ethtool_to_mcdi_cap(advertising) |
                         1 << MC_CMD_PHY_CAP_AN_LBN);
-       } else if (ecmd->duplex) {
-               switch (ethtool_cmd_speed(ecmd)) {
+       } else if (cmd->base.duplex) {
+               switch (cmd->base.speed) {
                case 10:    caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN;    break;
                case 100:   caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN;   break;
                case 1000:  caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN;  break;
@@ -550,7 +564,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
                default:    return -EINVAL;
                }
        } else {
-               switch (ethtool_cmd_speed(ecmd)) {
+               switch (cmd->base.speed) {
                case 10:    caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN;    break;
                case 100:   caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN;   break;
                case 1000:  caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN;  break;
@@ -563,9 +577,9 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
        if (rc)
                return rc;
 
-       if (ecmd->autoneg) {
+       if (cmd->base.autoneg) {
                efx_link_set_advertising(
-                       efx, ecmd->advertising | ADVERTISED_Autoneg);
+                       efx, advertising | ADVERTISED_Autoneg);
                phy_cfg->forced_cap = 0;
        } else {
                efx_link_set_advertising(efx, 0);
@@ -812,8 +826,8 @@ static const struct efx_phy_operations efx_mcdi_phy_ops = {
        .poll           = efx_mcdi_phy_poll,
        .fini           = efx_port_dummy_op_void,
        .remove         = efx_mcdi_phy_remove,
-       .get_settings   = efx_mcdi_phy_get_settings,
-       .set_settings   = efx_mcdi_phy_set_settings,
+       .get_link_ksettings = efx_mcdi_phy_get_link_ksettings,
+       .set_link_ksettings = efx_mcdi_phy_set_link_ksettings,
        .test_alive     = efx_mcdi_phy_test_alive,
        .run_tests      = efx_mcdi_phy_run_tests,
        .test_name      = efx_mcdi_phy_test_name,
index 8692e829b40f0402cd6f3e85dd836dfd724cfb41..1a635ced62d0581634748d4b8bdcb15a2e0da69c 100644 (file)
@@ -720,8 +720,8 @@ static inline bool efx_link_state_equal(const struct efx_link_state *left,
  * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
  * @poll: Update @link_state and report whether it changed.
  *     Serialised by the mac_lock.
- * @get_settings: Get ethtool settings. Serialised by the mac_lock.
- * @set_settings: Set ethtool settings. Serialised by the mac_lock.
+ * @get_link_ksettings: Get ethtool settings. Serialised by the mac_lock.
+ * @set_link_ksettings: Set ethtool settings. Serialised by the mac_lock.
  * @set_npage_adv: Set abilities advertised in (Extended) Next Page
  *     (only needed where AN bit is set in mmds)
  * @test_alive: Test that PHY is 'alive' (online)
@@ -736,10 +736,10 @@ struct efx_phy_operations {
        void (*remove) (struct efx_nic *efx);
        int (*reconfigure) (struct efx_nic *efx);
        bool (*poll) (struct efx_nic *efx);
-       void (*get_settings) (struct efx_nic *efx,
-                             struct ethtool_cmd *ecmd);
-       int (*set_settings) (struct efx_nic *efx,
-                            struct ethtool_cmd *ecmd);
+       void (*get_link_ksettings)(struct efx_nic *efx,
+                                  struct ethtool_link_ksettings *cmd);
+       int (*set_link_ksettings)(struct efx_nic *efx,
+                                 const struct ethtool_link_ksettings *cmd);
        void (*set_npage_adv) (struct efx_nic *efx, u32);
        int (*test_alive) (struct efx_nic *efx);
        const char *(*test_name) (struct efx_nic *efx, unsigned int index);
index 98f10c21652140a57cf2ee89ee1ff3b25a7802ba..8b6810bad54b73fc90da579521e1e20050933aac 100644 (file)
@@ -158,9 +158,9 @@ static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx,
        if (!pskb_may_pull(skb, hdrlen + sizeof(struct iphdr)))
                return false;
 
-       iph = (struct iphdr *)(skb->data + hdrlen + sizeof(struct iphdr));
+       iph = (struct iphdr *)(skb->data + hdrlen);
 
-       return iph->saddr != pctx->ms_addr_ip4.s_addr;
+       return iph->saddr == pctx->ms_addr_ip4.s_addr;
 }
 
 /* Check if the inner IP source address in this packet is assigned to any
@@ -423,11 +423,11 @@ static inline void gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
 
        /* Bits    8  7  6  5  4  3  2  1
         *        +--+--+--+--+--+--+--+--+
-        *        |version |PT| 1| E| S|PN|
+        *        |version |PT| 0| E| S|PN|
         *        +--+--+--+--+--+--+--+--+
         *          0  0  1  1  1  0  0  0
         */
-       gtp1->flags     = 0x38; /* v1, GTP-non-prime. */
+       gtp1->flags     = 0x30; /* v1, GTP-non-prime. */
        gtp1->type      = GTP_TPDU;
        gtp1->length    = htons(payload_len);
        gtp1->tid       = htonl(pctx->u.v1.o_tei);
index f293d33fb28fc8e77c66aa44bf8842645611a988..8d5b903d1d9dcd1f0f783f470b6fdbe482d6bbee 100644 (file)
@@ -517,9 +517,9 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
 
                mtt = irda_get_mtt(skb);
                pr_debug("%s: %ld, mtt=%d\n", __func__, jiffies, mtt);
-                       if (mtt > 1000)
-                               mdelay(mtt / 1000);
-                       else if (mtt)
+               if (mtt > 1000)
+                       mdelay(mtt / 1000);
+               else if (mtt)
                        udelay(mtt);
 
                /* Enable DMA interrupt */
index b425fa1013af918529f9d66e54652308dd06361a..08327e005cccf27fc18db64d234aaefd0dcd1a1f 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/virtio.h>
 #include <linux/virtio_net.h>
+#include <linux/bpf.h>
 #include <linux/scatterlist.h>
 #include <linux/if_vlan.h>
 #include <linux/slab.h>
@@ -81,6 +82,8 @@ struct receive_queue {
 
        struct napi_struct napi;
 
+       struct bpf_prog __rcu *xdp_prog;
+
        /* Chain pages by the private ptr. */
        struct page *pages;
 
@@ -111,6 +114,9 @@ struct virtnet_info {
        /* # of queue pairs currently used by the driver */
        u16 curr_queue_pairs;
 
+       /* # of XDP queue pairs currently used by the driver */
+       u16 xdp_queue_pairs;
+
        /* I like... big packets and I cannot lie! */
        bool big_packets;
 
@@ -324,6 +330,90 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
        return skb;
 }
 
+static void virtnet_xdp_xmit(struct virtnet_info *vi,
+                            struct receive_queue *rq,
+                            struct send_queue *sq,
+                            struct xdp_buff *xdp)
+{
+       struct page *page = virt_to_head_page(xdp->data);
+       struct virtio_net_hdr_mrg_rxbuf *hdr;
+       unsigned int num_sg, len;
+       void *xdp_sent;
+       int err;
+
+       /* Free up any pending old buffers before queueing new ones. */
+       while ((xdp_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) {
+               struct page *sent_page = virt_to_head_page(xdp_sent);
+
+               if (vi->mergeable_rx_bufs)
+                       put_page(sent_page);
+               else
+                       give_pages(rq, sent_page);
+       }
+
+       /* Zero header and leave csum up to XDP layers */
+       hdr = xdp->data;
+       memset(hdr, 0, vi->hdr_len);
+
+       num_sg = 1;
+       sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data);
+       err = virtqueue_add_outbuf(sq->vq, sq->sg, num_sg,
+                                  xdp->data, GFP_ATOMIC);
+       if (unlikely(err)) {
+               if (vi->mergeable_rx_bufs)
+                       put_page(page);
+               else
+                       give_pages(rq, page);
+               return; // On error abort to avoid unnecessary kick
+       } else if (!vi->mergeable_rx_bufs) {
+               /* If not mergeable bufs must be big packets so cleanup pages */
+               give_pages(rq, (struct page *)page->private);
+               page->private = 0;
+       }
+
+       virtqueue_kick(sq->vq);
+}
+
+static u32 do_xdp_prog(struct virtnet_info *vi,
+                      struct receive_queue *rq,
+                      struct bpf_prog *xdp_prog,
+                      struct page *page, int offset, int len)
+{
+       int hdr_padded_len;
+       struct xdp_buff xdp;
+       unsigned int qp;
+       u32 act;
+       u8 *buf;
+
+       buf = page_address(page) + offset;
+
+       if (vi->mergeable_rx_bufs)
+               hdr_padded_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+       else
+               hdr_padded_len = sizeof(struct padded_vnet_hdr);
+
+       xdp.data = buf + hdr_padded_len;
+       xdp.data_end = xdp.data + (len - vi->hdr_len);
+
+       act = bpf_prog_run_xdp(xdp_prog, &xdp);
+       switch (act) {
+       case XDP_PASS:
+               return XDP_PASS;
+       case XDP_TX:
+               qp = vi->curr_queue_pairs -
+                       vi->xdp_queue_pairs +
+                       smp_processor_id();
+               xdp.data = buf + (vi->mergeable_rx_bufs ? 0 : 4);
+               virtnet_xdp_xmit(vi, rq, &vi->sq[qp], &xdp);
+               return XDP_TX;
+       default:
+               bpf_warn_invalid_xdp_action(act);
+       case XDP_ABORTED:
+       case XDP_DROP:
+               return XDP_DROP;
+       }
+}
+
 static struct sk_buff *receive_small(struct virtnet_info *vi, void *buf, unsigned int len)
 {
        struct sk_buff * skb = buf;
@@ -340,17 +430,102 @@ static struct sk_buff *receive_big(struct net_device *dev,
                                   void *buf,
                                   unsigned int len)
 {
+       struct bpf_prog *xdp_prog;
        struct page *page = buf;
-       struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE);
+       struct sk_buff *skb;
 
+       rcu_read_lock();
+       xdp_prog = rcu_dereference(rq->xdp_prog);
+       if (xdp_prog) {
+               struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
+               u32 act;
+
+               if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags))
+                       goto err_xdp;
+               act = do_xdp_prog(vi, rq, xdp_prog, page, 0, len);
+               switch (act) {
+               case XDP_PASS:
+                       break;
+               case XDP_TX:
+                       rcu_read_unlock();
+                       goto xdp_xmit;
+               case XDP_DROP:
+               default:
+                       goto err_xdp;
+               }
+       }
+       rcu_read_unlock();
+
+       skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE);
        if (unlikely(!skb))
                goto err;
 
        return skb;
 
+err_xdp:
+       rcu_read_unlock();
 err:
        dev->stats.rx_dropped++;
        give_pages(rq, page);
+xdp_xmit:
+       return NULL;
+}
+
+/* The conditions to enable XDP should preclude the underlying device from
+ * sending packets across multiple buffers (num_buf > 1). However per spec
+ * it does not appear to be illegal to do so but rather just against convention.
+ * So in order to avoid making a system unresponsive the packets are pushed
+ * into a page and the XDP program is run. This will be extremely slow and we
+ * push a warning to the user to fix this as soon as possible. Fixing this may
+ * require resolving the underlying hardware to determine why multiple buffers
+ * are being received or simply loading the XDP program in the ingress stack
+ * after the skb is built because there is no advantage to running it here
+ * anymore.
+ */
+static struct page *xdp_linearize_page(struct receive_queue *rq,
+                                      u16 num_buf,
+                                      struct page *p,
+                                      int offset,
+                                      unsigned int *len)
+{
+       struct page *page = alloc_page(GFP_ATOMIC);
+       unsigned int page_off = 0;
+
+       if (!page)
+               return NULL;
+
+       memcpy(page_address(page) + page_off, page_address(p) + offset, *len);
+       page_off += *len;
+
+       while (--num_buf) {
+               unsigned int buflen;
+               unsigned long ctx;
+               void *buf;
+               int off;
+
+               ctx = (unsigned long)virtqueue_get_buf(rq->vq, &buflen);
+               if (unlikely(!ctx))
+                       goto err_buf;
+
+               /* guard against a misconfigured or uncooperative backend that
+                * is sending packet larger than the MTU.
+                */
+               if ((page_off + buflen) > PAGE_SIZE)
+                       goto err_buf;
+
+               buf = mergeable_ctx_to_buf_address(ctx);
+               p = virt_to_head_page(buf);
+               off = buf - page_address(p);
+
+               memcpy(page_address(page) + page_off,
+                      page_address(p) + off, buflen);
+               page_off += buflen;
+       }
+
+       *len = page_off;
+       return page;
+err_buf:
+       __free_pages(page, 0);
        return NULL;
 }
 
@@ -365,11 +540,67 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
        u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
        struct page *page = virt_to_head_page(buf);
        int offset = buf - page_address(page);
-       unsigned int truesize = max(len, mergeable_ctx_to_buf_truesize(ctx));
+       struct sk_buff *head_skb, *curr_skb;
+       struct bpf_prog *xdp_prog;
+       unsigned int truesize;
+
+       head_skb = NULL;
+
+       rcu_read_lock();
+       xdp_prog = rcu_dereference(rq->xdp_prog);
+       if (xdp_prog) {
+               struct page *xdp_page;
+               u32 act;
+
+               /* No known backend devices should send packets with
+                * more than a single buffer when XDP conditions are
+                * met. However it is not strictly illegal so the case
+                * is handled as an exception and a warning is thrown.
+                */
+               if (unlikely(num_buf > 1)) {
+                       bpf_warn_invalid_xdp_buffer();
+
+                       /* linearize data for XDP */
+                       xdp_page = xdp_linearize_page(rq, num_buf,
+                                                     page, offset, &len);
+                       if (!xdp_page)
+                               goto err_xdp;
+                       offset = 0;
+               } else {
+                       xdp_page = page;
+               }
+
+               /* Transient failure which in theory could occur if
+                * in-flight packets from before XDP was enabled reach
+                * the receive path after XDP is loaded. In practice I
+                * was not able to create this condition.
+                */
+               if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags))
+                       goto err_xdp;
+
+               act = do_xdp_prog(vi, rq, xdp_prog, page, offset, len);
+               switch (act) {
+               case XDP_PASS:
+                       if (unlikely(xdp_page != page))
+                               __free_pages(xdp_page, 0);
+                       break;
+               case XDP_TX:
+                       if (unlikely(xdp_page != page))
+                               goto err_xdp;
+                       rcu_read_unlock();
+                       goto xdp_xmit;
+               case XDP_DROP:
+               default:
+                       if (unlikely(xdp_page != page))
+                               __free_pages(xdp_page, 0);
+                       goto err_xdp;
+               }
+       }
+       rcu_read_unlock();
 
-       struct sk_buff *head_skb = page_to_skb(vi, rq, page, offset, len,
-                                              truesize);
-       struct sk_buff *curr_skb = head_skb;
+       truesize = max(len, mergeable_ctx_to_buf_truesize(ctx));
+       head_skb = page_to_skb(vi, rq, page, offset, len, truesize);
+       curr_skb = head_skb;
 
        if (unlikely(!curr_skb))
                goto err_skb;
@@ -423,6 +654,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
        ewma_pkt_len_add(&rq->mrg_avg_pkt_len, head_skb->len);
        return head_skb;
 
+err_xdp:
+       rcu_read_unlock();
 err_skb:
        put_page(page);
        while (--num_buf) {
@@ -439,6 +672,7 @@ err_skb:
 err_buf:
        dev->stats.rx_dropped++;
        dev_kfree_skb(head_skb);
+xdp_xmit:
        return NULL;
 }
 
@@ -1337,6 +1571,13 @@ static int virtnet_set_channels(struct net_device *dev,
        if (queue_pairs > vi->max_queue_pairs || queue_pairs == 0)
                return -EINVAL;
 
+       /* For now we don't support modifying channels while XDP is loaded
+        * also when XDP is loaded all RX queues have XDP programs so we only
+        * need to check a single RX queue.
+        */
+       if (vi->rq[0].xdp_prog)
+               return -EINVAL;
+
        get_online_cpus();
        err = virtnet_set_queues(vi, queue_pairs);
        if (!err) {
@@ -1428,6 +1669,93 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
        .set_settings = virtnet_set_settings,
 };
 
+static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog)
+{
+       unsigned long int max_sz = PAGE_SIZE - sizeof(struct padded_vnet_hdr);
+       struct virtnet_info *vi = netdev_priv(dev);
+       struct bpf_prog *old_prog;
+       u16 xdp_qp = 0, curr_qp;
+       int i, err;
+
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
+           virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6)) {
+               netdev_warn(dev, "can't set XDP while host is implementing LRO, disable LRO first\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (vi->mergeable_rx_bufs && !vi->any_header_sg) {
+               netdev_warn(dev, "XDP expects header/data in single page, any_header_sg required\n");
+               return -EINVAL;
+       }
+
+       if (dev->mtu > max_sz) {
+               netdev_warn(dev, "XDP requires MTU less than %lu\n", max_sz);
+               return -EINVAL;
+       }
+
+       curr_qp = vi->curr_queue_pairs - vi->xdp_queue_pairs;
+       if (prog)
+               xdp_qp = nr_cpu_ids;
+
+       /* XDP requires extra queues for XDP_TX */
+       if (curr_qp + xdp_qp > vi->max_queue_pairs) {
+               netdev_warn(dev, "request %i queues but max is %i\n",
+                           curr_qp + xdp_qp, vi->max_queue_pairs);
+               return -ENOMEM;
+       }
+
+       err = virtnet_set_queues(vi, curr_qp + xdp_qp);
+       if (err) {
+               dev_warn(&dev->dev, "XDP Device queue allocation failure.\n");
+               return err;
+       }
+
+       if (prog) {
+               prog = bpf_prog_add(prog, vi->max_queue_pairs - 1);
+               if (IS_ERR(prog)) {
+                       virtnet_set_queues(vi, curr_qp);
+                       return PTR_ERR(prog);
+               }
+       }
+
+       vi->xdp_queue_pairs = xdp_qp;
+       netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp);
+
+       for (i = 0; i < vi->max_queue_pairs; i++) {
+               old_prog = rtnl_dereference(vi->rq[i].xdp_prog);
+               rcu_assign_pointer(vi->rq[i].xdp_prog, prog);
+               if (old_prog)
+                       bpf_prog_put(old_prog);
+       }
+
+       return 0;
+}
+
+static bool virtnet_xdp_query(struct net_device *dev)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < vi->max_queue_pairs; i++) {
+               if (vi->rq[i].xdp_prog)
+                       return true;
+       }
+       return false;
+}
+
+static int virtnet_xdp(struct net_device *dev, struct netdev_xdp *xdp)
+{
+       switch (xdp->command) {
+       case XDP_SETUP_PROG:
+               return virtnet_xdp_set(dev, xdp->prog);
+       case XDP_QUERY_PROG:
+               xdp->prog_attached = virtnet_xdp_query(dev);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 static const struct net_device_ops virtnet_netdev = {
        .ndo_open            = virtnet_open,
        .ndo_stop            = virtnet_close,
@@ -1444,6 +1772,7 @@ static const struct net_device_ops virtnet_netdev = {
 #ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = virtnet_busy_poll,
 #endif
+       .ndo_xdp                = virtnet_xdp,
 };
 
 static void virtnet_config_changed_work(struct work_struct *work)
@@ -1505,12 +1834,20 @@ static void virtnet_free_queues(struct virtnet_info *vi)
 
 static void free_receive_bufs(struct virtnet_info *vi)
 {
+       struct bpf_prog *old_prog;
        int i;
 
+       rtnl_lock();
        for (i = 0; i < vi->max_queue_pairs; i++) {
                while (vi->rq[i].pages)
                        __free_pages(get_a_page(&vi->rq[i], GFP_KERNEL), 0);
+
+               old_prog = rtnl_dereference(vi->rq[i].xdp_prog);
+               RCU_INIT_POINTER(vi->rq[i].xdp_prog, NULL);
+               if (old_prog)
+                       bpf_prog_put(old_prog);
        }
+       rtnl_unlock();
 }
 
 static void free_receive_page_frags(struct virtnet_info *vi)
@@ -1521,6 +1858,16 @@ static void free_receive_page_frags(struct virtnet_info *vi)
                        put_page(vi->rq[i].alloc_frag.page);
 }
 
+static bool is_xdp_queue(struct virtnet_info *vi, int q)
+{
+       if (q < (vi->curr_queue_pairs - vi->xdp_queue_pairs))
+               return false;
+       else if (q < vi->curr_queue_pairs)
+               return true;
+       else
+               return false;
+}
+
 static void free_unused_bufs(struct virtnet_info *vi)
 {
        void *buf;
@@ -1528,8 +1875,12 @@ static void free_unused_bufs(struct virtnet_info *vi)
 
        for (i = 0; i < vi->max_queue_pairs; i++) {
                struct virtqueue *vq = vi->sq[i].vq;
-               while ((buf = virtqueue_detach_unused_buf(vq)) != NULL)
-                       dev_kfree_skb(buf);
+               while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
+                       if (!is_xdp_queue(vi, i))
+                               dev_kfree_skb(buf);
+                       else
+                               put_page(virt_to_head_page(buf));
+               }
        }
 
        for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -1930,7 +2281,9 @@ static int virtnet_probe(struct virtio_device *vdev)
                goto free_unregister_netdev;
        }
 
-       virtnet_set_affinity(vi);
+       rtnl_lock();
+       virtnet_set_queues(vi, vi->curr_queue_pairs);
+       rtnl_unlock();
 
        /* Assume link up if device can't report link status,
           otherwise get link status from config. */
index 3bca24651dc0a1c5121348a21d7431d8384d2024..7532646c3b7bedb89c2cbe95e84f09e32e0a8391 100644 (file)
@@ -366,6 +366,8 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
        struct in6_addr *nexthop;
        int ret;
 
+       nf_reset(skb);
+
        skb->protocol = htons(ETH_P_IPV6);
        skb->dev = dev;
 
@@ -547,6 +549,8 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
        u32 nexthop;
        int ret = -EINVAL;
 
+       nf_reset(skb);
+
        /* Be paranoid, rather than too clever. */
        if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
                struct sk_buff *skb2;
@@ -849,8 +853,6 @@ static struct sk_buff *vrf_rcv_nfhook(u8 pf, unsigned int hook,
 {
        struct net *net = dev_net(dev);
 
-       nf_reset(skb);
-
        if (NF_HOOK(pf, hook, net, NULL, skb, dev, NULL, vrf_rcv_finish) < 0)
                skb = NULL;    /* kfree_skb(skb) handled by nf code */
 
index 5920c996fcdf24679944920fac6e577c0c4c472b..ff2e4a5654c7cb29a907d39603b68760123c33f8 100644 (file)
@@ -95,62 +95,63 @@ static inline void write_av9110_bit (lmc_softc_t *, int);
 static void write_av9110(lmc_softc_t *, u32, u32, u32, u32, u32);
 
 lmc_media_t lmc_ds3_media = {
-  lmc_ds3_init,                        /* special media init stuff */
-  lmc_ds3_default,             /* reset to default state */
-  lmc_ds3_set_status,          /* reset status to state provided */
-  lmc_dummy_set_1,             /* set clock source */
-  lmc_dummy_set2_1,            /* set line speed */
-  lmc_ds3_set_100ft,           /* set cable length */
-  lmc_ds3_set_scram,           /* set scrambler */
-  lmc_ds3_get_link_status,     /* get link status */
-  lmc_dummy_set_1,             /* set link status */
-  lmc_ds3_set_crc_length,      /* set CRC length */
-  lmc_dummy_set_1,             /* set T1 or E1 circuit type */
-  lmc_ds3_watchdog
+  .init = lmc_ds3_init,                                /* special media init stuff */
+  .defaults = lmc_ds3_default,                 /* reset to default state */
+  .set_status = lmc_ds3_set_status,            /* reset status to state provided */
+  .set_clock_source = lmc_dummy_set_1,         /* set clock source */
+  .set_speed = lmc_dummy_set2_1,               /* set line speed */
+  .set_cable_length = lmc_ds3_set_100ft,       /* set cable length */
+  .set_scrambler = lmc_ds3_set_scram,          /* set scrambler */
+  .get_link_status = lmc_ds3_get_link_status,  /* get link status */
+  .set_link_status = lmc_dummy_set_1,          /* set link status */
+  .set_crc_length = lmc_ds3_set_crc_length,    /* set CRC length */
+  .set_circuit_type = lmc_dummy_set_1,         /* set T1 or E1 circuit type */
+  .watchdog = lmc_ds3_watchdog
 };
 
 lmc_media_t lmc_hssi_media = {
-  lmc_hssi_init,               /* special media init stuff */
-  lmc_hssi_default,            /* reset to default state */
-  lmc_hssi_set_status,         /* reset status to state provided */
-  lmc_hssi_set_clock,          /* set clock source */
-  lmc_dummy_set2_1,            /* set line speed */
-  lmc_dummy_set_1,             /* set cable length */
-  lmc_dummy_set_1,             /* set scrambler */
-  lmc_hssi_get_link_status,    /* get link status */
-  lmc_hssi_set_link_status,    /* set link status */
-  lmc_hssi_set_crc_length,     /* set CRC length */
-  lmc_dummy_set_1,             /* set T1 or E1 circuit type */
-  lmc_hssi_watchdog
+  .init = lmc_hssi_init,                       /* special media init stuff */
+  .defaults = lmc_hssi_default,                        /* reset to default state */
+  .set_status = lmc_hssi_set_status,           /* reset status to state provided */
+  .set_clock_source = lmc_hssi_set_clock,      /* set clock source */
+  .set_speed = lmc_dummy_set2_1,               /* set line speed */
+  .set_cable_length = lmc_dummy_set_1,         /* set cable length */
+  .set_scrambler = lmc_dummy_set_1,            /* set scrambler */
+  .get_link_status = lmc_hssi_get_link_status, /* get link status */
+  .set_link_status = lmc_hssi_set_link_status, /* set link status */
+  .set_crc_length = lmc_hssi_set_crc_length,   /* set CRC length */
+  .set_circuit_type = lmc_dummy_set_1,         /* set T1 or E1 circuit type */
+  .watchdog = lmc_hssi_watchdog
 };
 
-lmc_media_t lmc_ssi_media = { lmc_ssi_init,    /* special media init stuff */
-  lmc_ssi_default,             /* reset to default state */
-  lmc_ssi_set_status,          /* reset status to state provided */
-  lmc_ssi_set_clock,           /* set clock source */
-  lmc_ssi_set_speed,           /* set line speed */
-  lmc_dummy_set_1,             /* set cable length */
-  lmc_dummy_set_1,             /* set scrambler */
-  lmc_ssi_get_link_status,     /* get link status */
-  lmc_ssi_set_link_status,     /* set link status */
-  lmc_ssi_set_crc_length,      /* set CRC length */
-  lmc_dummy_set_1,             /* set T1 or E1 circuit type */
-  lmc_ssi_watchdog
+lmc_media_t lmc_ssi_media = {
+  .init = lmc_ssi_init,                                /* special media init stuff */
+  .defaults = lmc_ssi_default,                 /* reset to default state */
+  .set_status = lmc_ssi_set_status,            /* reset status to state provided */
+  .set_clock_source = lmc_ssi_set_clock,       /* set clock source */
+  .set_speed = lmc_ssi_set_speed,              /* set line speed */
+  .set_cable_length = lmc_dummy_set_1,         /* set cable length */
+  .set_scrambler = lmc_dummy_set_1,            /* set scrambler */
+  .get_link_status = lmc_ssi_get_link_status,  /* get link status */
+  .set_link_status = lmc_ssi_set_link_status,  /* set link status */
+  .set_crc_length = lmc_ssi_set_crc_length,    /* set CRC length */
+  .set_circuit_type = lmc_dummy_set_1,         /* set T1 or E1 circuit type */
+  .watchdog = lmc_ssi_watchdog
 };
 
 lmc_media_t lmc_t1_media = {
-  lmc_t1_init,                 /* special media init stuff */
-  lmc_t1_default,              /* reset to default state */
-  lmc_t1_set_status,           /* reset status to state provided */
-  lmc_t1_set_clock,            /* set clock source */
-  lmc_dummy_set2_1,            /* set line speed */
-  lmc_dummy_set_1,             /* set cable length */
-  lmc_dummy_set_1,             /* set scrambler */
-  lmc_t1_get_link_status,      /* get link status */
-  lmc_dummy_set_1,             /* set link status */
-  lmc_t1_set_crc_length,       /* set CRC length */
-  lmc_t1_set_circuit_type,     /* set T1 or E1 circuit type */
-  lmc_t1_watchdog
+  .init = lmc_t1_init,                         /* special media init stuff */
+  .defaults = lmc_t1_default,                  /* reset to default state */
+  .set_status = lmc_t1_set_status,             /* reset status to state provided */
+  .set_clock_source = lmc_t1_set_clock,                /* set clock source */
+  .set_speed = lmc_dummy_set2_1,               /* set line speed */
+  .set_cable_length = lmc_dummy_set_1,         /* set cable length */
+  .set_scrambler = lmc_dummy_set_1,            /* set scrambler */
+  .get_link_status = lmc_t1_get_link_status,   /* get link status */
+  .set_link_status = lmc_dummy_set_1,          /* set link status */
+  .set_crc_length = lmc_t1_set_crc_length,     /* set CRC length */
+  .set_circuit_type = lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
+  .watchdog = lmc_t1_watchdog
 };
 
 static void
index d5dc80c48b4cb36a55c54a2383ce9812ae068260..b3323c0697f6239ebbfe757137cde8352fe3c480 100644 (file)
@@ -22,9 +22,8 @@ void __nd_detach_ndns(struct device *dev, struct nd_namespace_common **_ndns)
 {
        struct nd_namespace_common *ndns = *_ndns;
 
-       dev_WARN_ONCE(dev, !mutex_is_locked(&ndns->dev.mutex)
-                       || ndns->claim != dev,
-                       "%s: invalid claim\n", __func__);
+       lockdep_assert_held(&ndns->dev.mutex);
+       dev_WARN_ONCE(dev, ndns->claim != dev, "%s: invalid claim\n", __func__);
        ndns->claim = NULL;
        *_ndns = NULL;
        put_device(&ndns->dev);
@@ -49,9 +48,8 @@ bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach,
 {
        if (attach->claim)
                return false;
-       dev_WARN_ONCE(dev, !mutex_is_locked(&attach->dev.mutex)
-                       || *_ndns,
-                       "%s: invalid claim\n", __func__);
+       lockdep_assert_held(&attach->dev.mutex);
+       dev_WARN_ONCE(dev, *_ndns, "%s: invalid claim\n", __func__);
        attach->claim = dev;
        *_ndns = attach;
        get_device(&attach->dev);
@@ -226,6 +224,12 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
                resource_size_t offset, void *buf, size_t size, int rw)
 {
        struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+       unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
+       sector_t sector = offset >> 9;
+       int rc = 0;
+
+       if (unlikely(!size))
+               return 0;
 
        if (unlikely(offset + size > nsio->size)) {
                dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
@@ -233,17 +237,31 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
        }
 
        if (rw == READ) {
-               unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
-
-               if (unlikely(is_bad_pmem(&nsio->bb, offset / 512, sz_align)))
+               if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align)))
                        return -EIO;
                return memcpy_from_pmem(buf, nsio->addr + offset, size);
-       } else {
-               memcpy_to_pmem(nsio->addr + offset, buf, size);
-               nvdimm_flush(to_nd_region(ndns->dev.parent));
        }
 
-       return 0;
+       if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) {
+               if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) {
+                       long cleared;
+
+                       cleared = nvdimm_clear_poison(&ndns->dev, offset, size);
+                       if (cleared < size)
+                               rc = -EIO;
+                       if (cleared > 0 && cleared / 512) {
+                               cleared /= 512;
+                               badblocks_clear(&nsio->bb, sector, cleared);
+                       }
+                       invalidate_pmem(nsio->addr + offset, size);
+               } else
+                       rc = -EIO;
+       }
+
+       memcpy_to_pmem(nsio->addr + offset, buf, size);
+       nvdimm_flush(to_nd_region(ndns->dev.parent));
+
+       return rc;
 }
 
 int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
@@ -253,7 +271,7 @@ int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
 
        nsio->size = resource_size(res);
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
-                               dev_name(dev))) {
+                               dev_name(&ndns->dev))) {
                dev_warn(dev, "could not reserve region %pR\n", res);
                return -EBUSY;
        }
index 7ceba08774b690dbda57f667e223b3b0a180dd09..9303cfeb8bee507c171c2060fb7602e7b0519267 100644 (file)
@@ -317,35 +317,6 @@ ssize_t nd_sector_size_store(struct device *dev, const char *buf,
        }
 }
 
-void __nd_iostat_start(struct bio *bio, unsigned long *start)
-{
-       struct gendisk *disk = bio->bi_bdev->bd_disk;
-       const int rw = bio_data_dir(bio);
-       int cpu = part_stat_lock();
-
-       *start = jiffies;
-       part_round_stats(cpu, &disk->part0);
-       part_stat_inc(cpu, &disk->part0, ios[rw]);
-       part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio));
-       part_inc_in_flight(&disk->part0, rw);
-       part_stat_unlock();
-}
-EXPORT_SYMBOL(__nd_iostat_start);
-
-void nd_iostat_end(struct bio *bio, unsigned long start)
-{
-       struct gendisk *disk = bio->bi_bdev->bd_disk;
-       unsigned long duration = jiffies - start;
-       const int rw = bio_data_dir(bio);
-       int cpu = part_stat_lock();
-
-       part_stat_add(cpu, &disk->part0, ticks[rw], duration);
-       part_round_stats(cpu, &disk->part0);
-       part_dec_in_flight(&disk->part0, rw);
-       part_stat_unlock();
-}
-EXPORT_SYMBOL(nd_iostat_end);
-
 static ssize_t commands_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
index 619834e144d1e65e2314cde9356c86cff44d5053..ee0b412827bfb43fc739d5e03e873f12254517fa 100644 (file)
@@ -64,6 +64,8 @@ static int nvdimm_probe(struct device *dev)
        nd_label_copy(ndd, to_next_namespace_index(ndd),
                        to_current_namespace_index(ndd));
        rc = nd_label_reserve_dpa(ndd);
+       if (ndd->ns_current >= 0)
+               nvdimm_set_aliasing(dev);
        nvdimm_bus_unlock(dev);
 
        if (rc)
index d614493ad5acb849037d22bcc44fd78c0e80e1a3..0eedc49e0d473ed36b5ef9832760aa8498b9f146 100644 (file)
@@ -184,6 +184,13 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
        return rc;
 }
 
+void nvdimm_set_aliasing(struct device *dev)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+
+       nvdimm->flags |= NDD_ALIASING;
+}
+
 static void nvdimm_release(struct device *dev)
 {
        struct nvdimm *nvdimm = to_nvdimm(dev);
index 11ea90120542dcbec8410147efca7a502eea9a77..6f9a6ffd7cde25f3e4714b2035eb519db1099fd8 100644 (file)
@@ -84,18 +84,8 @@ static struct platform_driver e820_pmem_driver = {
        },
 };
 
-static __init int e820_pmem_init(void)
-{
-       return platform_driver_register(&e820_pmem_driver);
-}
-
-static __exit void e820_pmem_exit(void)
-{
-       platform_driver_unregister(&e820_pmem_driver);
-}
+module_platform_driver(e820_pmem_driver);
 
 MODULE_ALIAS("platform:e820_pmem*");
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Intel Corporation");
-module_init(e820_pmem_init);
-module_exit(e820_pmem_exit);
index fac7cabe8f563e8e0e08b97f79aeb4f86174f66f..dd615345699fddf38f9117344278bf9364afe547 100644 (file)
@@ -938,7 +938,7 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
                }
 
                for_each_dpa_resource(ndd, res)
-                       if (strncmp(res->name, "pmem", 3) == 0)
+                       if (strncmp(res->name, "pmem", 4) == 0)
                                count++;
                WARN_ON_ONCE(!count);
 
index abe5c6bc756c255193d803039973971368b9471d..6307088b375f2d899002f9fc9fae16c387357598 100644 (file)
@@ -1132,7 +1132,7 @@ static ssize_t size_show(struct device *dev,
        return sprintf(buf, "%llu\n", (unsigned long long)
                        nvdimm_namespace_capacity(to_ndns(dev)));
 }
-static DEVICE_ATTR(size, S_IRUGO, size_show, size_store);
+static DEVICE_ATTR(size, 0444, size_show, size_store);
 
 static u8 *namespace_to_uuid(struct device *dev)
 {
@@ -1456,7 +1456,7 @@ static umode_t namespace_visible(struct kobject *kobj,
 
        if (is_namespace_pmem(dev) || is_namespace_blk(dev)) {
                if (a == &dev_attr_size.attr)
-                       return S_IWUSR | S_IRUGO;
+                       return 0644;
 
                if (is_namespace_pmem(dev) && a == &dev_attr_sector_size.attr)
                        return 0;
@@ -1653,7 +1653,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
                u64 hw_start, hw_end, pmem_start, pmem_end;
                struct nd_label_ent *label_ent;
 
-               WARN_ON(!mutex_is_locked(&nd_mapping->lock));
+               lockdep_assert_held(&nd_mapping->lock);
                list_for_each_entry(label_ent, &nd_mapping->labels, list) {
                        nd_label = label_ent->label;
                        if (!nd_label)
@@ -1997,7 +1997,7 @@ struct device *create_namespace_blk(struct nd_region *nd_region,
        struct nd_mapping *nd_mapping = &nd_region->mapping[0];
        struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
        struct nd_namespace_blk *nsblk;
-       char *name[NSLABEL_NAME_LEN];
+       char name[NSLABEL_NAME_LEN];
        struct device *dev = NULL;
        struct resource *res;
 
index d3b2fca8deec20b930ca55e025c7f116b30f9199..35dd75057e1697f2e03de12c62cf3f6cabb69aec 100644 (file)
@@ -238,6 +238,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
                void *buf, size_t len);
 long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
                unsigned int len);
+void nvdimm_set_aliasing(struct device *dev);
 struct nd_btt *to_nd_btt(struct device *dev);
 
 struct nd_gen_sb {
@@ -377,10 +378,17 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
        if (!blk_queue_io_stat(disk->queue))
                return false;
 
-       __nd_iostat_start(bio, start);
+       *start = jiffies;
+       generic_start_io_acct(bio_data_dir(bio),
+                             bio_sectors(bio), &disk->part0);
        return true;
 }
-void nd_iostat_end(struct bio *bio, unsigned long start);
+static inline void nd_iostat_end(struct bio *bio, unsigned long start)
+{
+       struct gendisk *disk = bio->bi_bdev->bd_disk;
+
+       generic_end_io_acct(bio_data_dir(bio), &disk->part0, start);
+}
 static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector,
                unsigned int len)
 {
index cea8350fbc7ec2f2e617199fd2bc8b8cb1df2fbb..a2ac9e641aa9341f2fcca9fa8b968fd874e80a90 100644 (file)
@@ -108,7 +108,7 @@ static ssize_t align_show(struct device *dev,
 {
        struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
 
-       return sprintf(buf, "%lx\n", nd_pfn->align);
+       return sprintf(buf, "%ld\n", nd_pfn->align);
 }
 
 static ssize_t __align_store(struct nd_pfn *nd_pfn, const char *buf)
index 24618431a14bae7e891438b3601d017d1d34db4d..7282d7495bf1f0a1bf6685012dafb1d9cc60bfa4 100644 (file)
@@ -53,21 +53,24 @@ static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
        struct device *dev = to_dev(pmem);
        sector_t sector;
        long cleared;
+       int rc = 0;
 
        sector = (offset - pmem->data_offset) / 512;
-       cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
 
+       cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
+       if (cleared < len)
+               rc = -EIO;
        if (cleared > 0 && cleared / 512) {
-               dev_dbg(dev, "%s: %#llx clear %ld sector%s\n",
-                               __func__, (unsigned long long) sector,
-                               cleared / 512, cleared / 512 > 1 ? "s" : "");
-               badblocks_clear(&pmem->bb, sector, cleared / 512);
-       } else {
-               return -EIO;
+               cleared /= 512;
+               dev_dbg(dev, "%s: %#llx clear %ld sector%s\n", __func__,
+                               (unsigned long long) sector, cleared,
+                               cleared > 1 ? "s" : "");
+               badblocks_clear(&pmem->bb, sector, cleared);
        }
 
        invalidate_pmem(pmem->virt_addr + offset, len);
-       return 0;
+
+       return rc;
 }
 
 static void write_pmem(void *pmem_addr, struct page *page,
@@ -270,7 +273,7 @@ static int pmem_attach_disk(struct device *dev,
                dev_warn(dev, "unable to guarantee persistence of writes\n");
 
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
-                               dev_name(dev))) {
+                               dev_name(&ndns->dev))) {
                dev_warn(dev, "could not reserve region %pR\n", res);
                return -EBUSY;
        }
index 6af5e629140cd3336d590c6ec24783ebd6e3d78d..7cd705f3247c341160a6b2ad7d1827c1604f34ce 100644 (file)
@@ -509,7 +509,7 @@ void nd_mapping_free_labels(struct nd_mapping *nd_mapping)
 {
        struct nd_label_ent *label_ent, *e;
 
-       WARN_ON(!mutex_is_locked(&nd_mapping->lock));
+       lockdep_assert_held(&nd_mapping->lock);
        list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
                list_del(&label_ent->list);
                kfree(label_ent);
index 82f7000a285d3780229a0ac5d49bac5618176f1d..642478d35e99a5c023a03a2d8f9593c8e4fbbde2 100644 (file)
@@ -206,7 +206,7 @@ void sync_stop(void)
  * because we cannot reach this code without at least one
  * dcookie user still being registered (namely, the reader
  * of the event buffer). */
-static inline unsigned long fast_get_dcookie(struct path *path)
+static inline unsigned long fast_get_dcookie(const struct path *path)
 {
        unsigned long cookie;
 
index 185376901d9c7412d434152e7fec31600da9f20b..5fe8be089b8b2dc51ced608e0790c7ce05b8dd18 100644 (file)
@@ -363,6 +363,18 @@ config IDEAPAD_LAPTOP
          This is a driver for Lenovo IdeaPad netbooks contains drivers for
          rfkill switch, hotkey, fan control and backlight control.
 
+config SURFACE3_WMI
+       tristate "Surface 3 WMI Driver"
+       depends on ACPI_WMI
+       depends on DMI
+       depends on INPUT
+       depends on SPI
+       ---help---
+         Say Y here if you have a Surface 3.
+
+         To compile this driver as a module, choose M here: the module will
+         be called surface3-wmi.
+
 config THINKPAD_ACPI
        tristate "ThinkPad ACPI Laptop Extras"
        depends on ACPI
@@ -1005,12 +1017,27 @@ config INTEL_PMC_IPC
        The PMC is an ARC processor which defines IPC commands for communication
        with other entities in the CPU.
 
+config INTEL_BXTWC_PMIC_TMU
+       tristate "Intel BXT Whiskey Cove TMU Driver"
+       depends on REGMAP
+       depends on INTEL_SOC_PMIC && INTEL_PMC_IPC
+       ---help---
+         Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature.
+         This driver enables the alarm wakeup functionality in the TMU unit
+         of Whiskey Cove PMIC.
+
 config SURFACE_PRO3_BUTTON
        tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
        depends on ACPI && INPUT
        ---help---
          This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
 
+config SURFACE_3_BUTTON
+       tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet"
+       depends on ACPI && KEYBOARD_GPIO
+       ---help---
+         This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
+
 config INTEL_PUNIT_IPC
        tristate "Intel P-Unit IPC Driver"
        ---help---
@@ -1028,10 +1055,21 @@ config INTEL_TELEMETRY
          directly via debugfs files. Various tools may use
          this interface for SoC state monitoring.
 
+config MLX_PLATFORM
+       tristate "Mellanox Technologies platform support"
+       depends on X86_64
+       ---help---
+         This option enables system support for the Mellanox Technologies
+         platform. The Mellanox systems provide data center networking
+         solutions based on Virtual Protocol Interconnect (VPI) technology
+         enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE
+         connection.
+
+         If you have a Mellanox system, say Y or M here.
+
 config MLX_CPLD_PLATFORM
        tristate "Mellanox platform hotplug driver support"
        default n
-       depends on MLX_PLATFORM
        select HWMON
        select I2C
        ---help---
index 1f06b6339cf73cbb832518fe89cb95552a06e499..d4111f0f8a78fdbcc7a10ef5e236bdda1cdffc15 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP)        += panasonic-laptop.o
 obj-$(CONFIG_INTEL_MENLOW)     += intel_menlow.o
 obj-$(CONFIG_ACPI_WMI)         += wmi.o
 obj-$(CONFIG_MSI_WMI)          += msi-wmi.o
+obj-$(CONFIG_SURFACE3_WMI)     += surface3-wmi.o
 obj-$(CONFIG_TOPSTAR_LAPTOP)   += topstar-laptop.o
 
 # toshiba_acpi must link after wmi to ensure that wmi devices are found
@@ -66,9 +67,12 @@ obj-$(CONFIG_PVPANIC)           += pvpanic.o
 obj-$(CONFIG_ALIENWARE_WMI)    += alienware-wmi.o
 obj-$(CONFIG_INTEL_PMC_IPC)    += intel_pmc_ipc.o
 obj-$(CONFIG_SURFACE_PRO3_BUTTON)      += surfacepro3_button.o
+obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
 obj-$(CONFIG_INTEL_PUNIT_IPC)  += intel_punit_ipc.o
+obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU)     += intel_bxtwc_tmu.o
 obj-$(CONFIG_INTEL_TELEMETRY)  += intel_telemetry_core.o \
                                   intel_telemetry_pltdrv.o \
                                   intel_telemetry_debugfs.o
 obj-$(CONFIG_INTEL_PMC_CORE)    += intel_pmc_core.o
+obj-$(CONFIG_MLX_PLATFORM)     += mlx-platform.o
 obj-$(CONFIG_MLX_CPLD_PLATFORM)        += mlxcpld-hotplug.o
index a7614fc542b52aaaa4f58d91ea43bd9625e8de32..410741acb3c92dabe36417800f564a943c5d42ec 100644 (file)
@@ -870,6 +870,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
                },
        },
+       {
+               .ident = "Lenovo ideapad Y700-15ACZ",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"),
+               },
+       },
        {
                .ident = "Lenovo ideapad Y700-15ISK",
                .matches = {
diff --git a/drivers/platform/x86/intel_bxtwc_tmu.c b/drivers/platform/x86/intel_bxtwc_tmu.c
new file mode 100644 (file)
index 0000000..e202abd
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * intel_bxtwc_tmu.c - Intel BXT Whiskey Cove PMIC TMU driver
+ *
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ *
+ * This driver adds TMU (Time Management Unit) support for Intel BXT platform.
+ * It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove
+ * PMIC.
+ *
+ * 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/intel_soc_pmic.h>
+
+#define BXTWC_TMUIRQ           0x4fb6
+#define BXTWC_MIRQLVL1         0x4e0e
+#define BXTWC_MTMUIRQ_REG      0x4fb7
+#define BXTWC_MIRQLVL1_MTMU    BIT(1)
+#define BXTWC_TMU_WK_ALRM      BIT(1)
+#define BXTWC_TMU_SYS_ALRM     BIT(2)
+#define BXTWC_TMU_ALRM_MASK    (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
+#define BXTWC_TMU_ALRM_IRQ     (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
+
+struct wcove_tmu {
+       int irq;
+       struct device *dev;
+       struct regmap *regmap;
+};
+
+static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data)
+{
+       struct wcove_tmu *wctmu = data;
+       unsigned int tmu_irq;
+
+       /* Read TMU interrupt reg */
+       regmap_read(wctmu->regmap, BXTWC_TMUIRQ, &tmu_irq);
+       if (tmu_irq & BXTWC_TMU_ALRM_IRQ) {
+               /* clear TMU irq */
+               regmap_write(wctmu->regmap, BXTWC_TMUIRQ, tmu_irq);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+static int bxt_wcove_tmu_probe(struct platform_device *pdev)
+{
+       struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+       struct regmap_irq_chip_data *regmap_irq_chip;
+       struct wcove_tmu *wctmu;
+       int ret, virq, irq;
+
+       wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL);
+       if (!wctmu)
+               return -ENOMEM;
+
+       wctmu->dev = &pdev->dev;
+       wctmu->regmap = pmic->regmap;
+
+       irq = platform_get_irq(pdev, 0);
+
+       if (irq < 0) {
+               dev_err(&pdev->dev, "invalid irq %d\n", irq);
+               return irq;
+       }
+
+       regmap_irq_chip = pmic->irq_chip_data_tmu;
+       virq = regmap_irq_get_virq(regmap_irq_chip, irq);
+       if (virq < 0) {
+               dev_err(&pdev->dev,
+                       "failed to get virtual interrupt=%d\n", irq);
+               return virq;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, virq,
+                                       NULL, bxt_wcove_tmu_irq_handler,
+                                       IRQF_ONESHOT, "bxt_wcove_tmu", wctmu);
+       if (ret) {
+               dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n",
+                                                       ret, virq);
+               return ret;
+       }
+       wctmu->irq = virq;
+
+       /* Enable TMU interrupts */
+       regmap_update_bits(wctmu->regmap, BXTWC_MIRQLVL1,
+                                 BXTWC_MIRQLVL1_MTMU, 0);
+
+       /* Unmask TMU second level Wake & System alarm */
+       regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG,
+                                 BXTWC_TMU_ALRM_MASK, 0);
+
+       platform_set_drvdata(pdev, wctmu);
+       return 0;
+}
+
+static int bxt_wcove_tmu_remove(struct platform_device *pdev)
+{
+       struct wcove_tmu *wctmu = platform_get_drvdata(pdev);
+       unsigned int val;
+
+       /* Mask TMU interrupts */
+       regmap_read(wctmu->regmap, BXTWC_MIRQLVL1, &val);
+       regmap_write(wctmu->regmap, BXTWC_MIRQLVL1,
+                       val | BXTWC_MIRQLVL1_MTMU);
+       regmap_read(wctmu->regmap, BXTWC_MTMUIRQ_REG, &val);
+       regmap_write(wctmu->regmap, BXTWC_MTMUIRQ_REG,
+                       val | BXTWC_TMU_ALRM_MASK);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bxtwc_tmu_suspend(struct device *dev)
+{
+       struct wcove_tmu *wctmu = dev_get_drvdata(dev);
+
+       enable_irq_wake(wctmu->irq);
+       return 0;
+}
+
+static int bxtwc_tmu_resume(struct device *dev)
+{
+       struct wcove_tmu *wctmu = dev_get_drvdata(dev);
+
+       disable_irq_wake(wctmu->irq);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(bxtwc_tmu_pm_ops, bxtwc_tmu_suspend, bxtwc_tmu_resume);
+
+static const struct platform_device_id bxt_wcove_tmu_id_table[] = {
+       { .name = "bxt_wcove_tmu" },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table);
+
+static struct platform_driver bxt_wcove_tmu_driver = {
+       .probe = bxt_wcove_tmu_probe,
+       .remove = bxt_wcove_tmu_remove,
+       .driver = {
+               .name = "bxt_wcove_tmu",
+               .pm     = &bxtwc_tmu_pm_ops,
+       },
+       .id_table = bxt_wcove_tmu_id_table,
+};
+
+module_platform_driver(bxt_wcove_tmu_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Nilesh Bacchewar <nilesh.bacchewar@intel.com>");
+MODULE_DESCRIPTION("BXT Whiskey Cove TMU Driver");
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
new file mode 100644 (file)
index 0000000..97b4c3a
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/i2c-mux-reg.h>
+#include <linux/platform_data/mlxcpld-hotplug.h>
+
+#define MLX_PLAT_DEVICE_NAME           "mlxplat"
+
+/* LPC bus IO offsets */
+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR         0x2000
+#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR         0x2500
+#define MLXPLAT_CPLD_LPC_IO_RANGE              0x100
+#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF           0xdb
+#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF           0xda
+#define MLXPLAT_CPLD_LPC_PIO_OFFSET            0x10000UL
+#define MLXPLAT_CPLD_LPC_REG1  ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
+                                 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
+                                 MLXPLAT_CPLD_LPC_PIO_OFFSET)
+#define MLXPLAT_CPLD_LPC_REG2  ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
+                                 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
+                                 MLXPLAT_CPLD_LPC_PIO_OFFSET)
+
+/* Start channel numbers */
+#define MLXPLAT_CPLD_CH1                       2
+#define MLXPLAT_CPLD_CH2                       10
+
+/* Number of LPC attached MUX platform devices */
+#define MLXPLAT_CPLD_LPC_MUX_DEVS              2
+
+/* mlxplat_priv - platform private data
+ * @pdev_i2c - i2c controller platform device
+ * @pdev_mux - array of mux platform devices
+ */
+struct mlxplat_priv {
+       struct platform_device *pdev_i2c;
+       struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
+       struct platform_device *pdev_hotplug;
+};
+
+/* Regions for LPC I2C controller and LPC base register space */
+static const struct resource mlxplat_lpc_resources[] = {
+       [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
+                              MLXPLAT_CPLD_LPC_IO_RANGE,
+                              "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
+       [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
+                              MLXPLAT_CPLD_LPC_IO_RANGE,
+                              "mlxplat_cpld_lpc_regs",
+                              IORESOURCE_IO),
+};
+
+/* Platform default channels */
+static const int mlxplat_default_channels[][8] = {
+       {
+               MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
+               MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
+               5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
+       },
+       {
+               MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
+               MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
+               5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
+       },
+};
+
+/* Platform channels for MSN21xx system family */
+static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+/* Platform mux data */
+static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
+       {
+               .parent = 1,
+               .base_nr = MLXPLAT_CPLD_CH1,
+               .write_only = 1,
+               .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
+               .reg_size = 1,
+               .idle_in_use = 1,
+       },
+       {
+               .parent = 1,
+               .base_nr = MLXPLAT_CPLD_CH2,
+               .write_only = 1,
+               .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
+               .reg_size = 1,
+               .idle_in_use = 1,
+       },
+
+};
+
+/* Platform hotplug devices */
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = {
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
+               .bus = 10,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
+               .bus = 10,
+       },
+};
+
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = {
+       {
+               .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
+               .bus = 10,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
+               .bus = 10,
+       },
+};
+
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = {
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+               .bus = 11,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+               .bus = 12,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+               .bus = 13,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+               .bus = 14,
+       },
+};
+
+/* Platform hotplug default data */
+static
+struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_default_data = {
+       .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
+       .top_aggr_mask = 0x48,
+       .top_aggr_psu_mask = 0x08,
+       .psu_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x58),
+       .psu_mask = 0x03,
+       .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_psu),
+       .psu = mlxplat_mlxcpld_hotplug_psu,
+       .top_aggr_pwr_mask = 0x08,
+       .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
+       .pwr_mask = 0x03,
+       .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
+       .pwr = mlxplat_mlxcpld_hotplug_pwr,
+       .top_aggr_fan_mask = 0x40,
+       .fan_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x88),
+       .fan_mask = 0x0f,
+       .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_fan),
+       .fan = mlxplat_mlxcpld_hotplug_fan,
+};
+
+/* Platform hotplug MSN21xx system family data */
+static
+struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_msn21xx_data = {
+       .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
+       .top_aggr_mask = 0x04,
+       .top_aggr_pwr_mask = 0x04,
+       .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
+       .pwr_mask = 0x03,
+       .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
+};
+
+static struct resource mlxplat_mlxcpld_hotplug_resources[] = {
+       [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
+};
+
+struct platform_device *mlxplat_dev;
+struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
+
+static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+               mlxplat_mux_data[i].values = mlxplat_default_channels[i];
+               mlxplat_mux_data[i].n_values =
+                               ARRAY_SIZE(mlxplat_default_channels[i]);
+       }
+       mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_default_data;
+
+       return 1;
+};
+
+static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+               mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
+               mlxplat_mux_data[i].n_values =
+                               ARRAY_SIZE(mlxplat_msn21xx_channels);
+       }
+       mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_msn21xx_data;
+
+       return 1;
+};
+
+static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_msn21xx_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
+               },
+       },
+       { }
+};
+
+static int __init mlxplat_init(void)
+{
+       struct mlxplat_priv *priv;
+       int i, err;
+
+       if (!dmi_check_system(mlxplat_dmi_table))
+               return -ENODEV;
+
+       mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
+                                       mlxplat_lpc_resources,
+                                       ARRAY_SIZE(mlxplat_lpc_resources));
+
+       if (IS_ERR(mlxplat_dev))
+               return PTR_ERR(mlxplat_dev);
+
+       priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
+                           GFP_KERNEL);
+       if (!priv) {
+               err = -ENOMEM;
+               goto fail_alloc;
+       }
+       platform_set_drvdata(mlxplat_dev, priv);
+
+       priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
+                                                        NULL, 0);
+       if (IS_ERR(priv->pdev_i2c)) {
+               err = PTR_ERR(priv->pdev_i2c);
+               goto fail_alloc;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+               priv->pdev_mux[i] = platform_device_register_resndata(
+                                               &mlxplat_dev->dev,
+                                               "i2c-mux-reg", i, NULL,
+                                               0, &mlxplat_mux_data[i],
+                                               sizeof(mlxplat_mux_data[i]));
+               if (IS_ERR(priv->pdev_mux[i])) {
+                       err = PTR_ERR(priv->pdev_mux[i]);
+                       goto fail_platform_mux_register;
+               }
+       }
+
+       priv->pdev_hotplug = platform_device_register_resndata(
+                               &mlxplat_dev->dev, "mlxcpld-hotplug", -1,
+                               mlxplat_mlxcpld_hotplug_resources,
+                               ARRAY_SIZE(mlxplat_mlxcpld_hotplug_resources),
+                               mlxplat_hotplug, sizeof(*mlxplat_hotplug));
+       if (IS_ERR(priv->pdev_hotplug)) {
+               err = PTR_ERR(priv->pdev_hotplug);
+               goto fail_platform_mux_register;
+       }
+
+       return 0;
+
+fail_platform_mux_register:
+       for (i--; i > 0 ; i--)
+               platform_device_unregister(priv->pdev_mux[i]);
+       platform_device_unregister(priv->pdev_i2c);
+fail_alloc:
+       platform_device_unregister(mlxplat_dev);
+
+       return err;
+}
+module_init(mlxplat_init);
+
+static void __exit mlxplat_exit(void)
+{
+       struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
+       int i;
+
+       platform_device_unregister(priv->pdev_hotplug);
+
+       for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
+               platform_device_unregister(priv->pdev_mux[i]);
+
+       platform_device_unregister(priv->pdev_i2c);
+       platform_device_unregister(mlxplat_dev);
+}
+module_exit(mlxplat_exit);
+
+MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
+MODULE_DESCRIPTION("Mellanox platform driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c
new file mode 100644 (file)
index 0000000..cbf4d83
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  Driver for the LID cover switch of the Surface 3
+ *
+ *  Copyright (c) 2016 Red Hat 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; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/input.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("Surface 3 platform driver");
+MODULE_LICENSE("GPL");
+
+#define ACPI_BUTTON_HID_LID            "PNP0C0D"
+#define SPI_CTL_OBJ_NAME               "SPI"
+#define SPI_TS_OBJ_NAME                        "NTRG"
+
+#define SURFACE3_LID_GUID "F7CC25EC-D20B-404C-8903-0ED4359C18AE"
+
+MODULE_ALIAS("wmi:" SURFACE3_LID_GUID);
+
+static const struct dmi_system_id surface3_dmi_table[] = {
+#if defined(CONFIG_X86)
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+               },
+       },
+#endif
+       { }
+};
+
+struct surface3_wmi {
+       struct acpi_device *touchscreen_adev;
+       struct acpi_device *pnp0c0d_adev;
+       struct acpi_hotplug_context hp;
+       struct input_dev *input;
+};
+
+static struct platform_device *s3_wmi_pdev;
+
+static struct surface3_wmi s3_wmi;
+
+static DEFINE_MUTEX(s3_wmi_lock);
+
+static int s3_wmi_query_block(const char *guid, int instance, int *ret)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+       union acpi_object *obj;
+       int error = 0;
+
+       mutex_lock(&s3_wmi_lock);
+       status = wmi_query_block(guid, instance, &output);
+
+       obj = output.pointer;
+
+       if (!obj || obj->type != ACPI_TYPE_INTEGER) {
+               if (obj) {
+                       pr_err("query block returned object type: %d - buffer length:%d\n",
+                              obj->type,
+                              obj->type == ACPI_TYPE_BUFFER ?
+                                               obj->buffer.length : 0);
+               }
+               error = -EINVAL;
+               goto out_free_unlock;
+       }
+       *ret = obj->integer.value;
+ out_free_unlock:
+       kfree(obj);
+       mutex_unlock(&s3_wmi_lock);
+       return error;
+}
+
+static inline int s3_wmi_query_lid(int *ret)
+{
+       return s3_wmi_query_block(SURFACE3_LID_GUID, 0, ret);
+}
+
+static int s3_wmi_send_lid_state(void)
+{
+       int ret, lid_sw;
+
+       ret = s3_wmi_query_lid(&lid_sw);
+       if (ret)
+               return ret;
+
+       input_report_switch(s3_wmi.input, SW_LID, lid_sw);
+       input_sync(s3_wmi.input);
+
+       return 0;
+}
+
+static int s3_wmi_hp_notify(struct acpi_device *adev, u32 value)
+{
+       return s3_wmi_send_lid_state();
+}
+
+static acpi_status s3_wmi_attach_spi_device(acpi_handle handle,
+                                           u32 level,
+                                           void *data,
+                                           void **return_value)
+{
+       struct acpi_device *adev, **ts_adev;
+
+       if (acpi_bus_get_device(handle, &adev))
+               return AE_OK;
+
+       ts_adev = data;
+
+       if (strncmp(acpi_device_bid(adev), SPI_TS_OBJ_NAME,
+           strlen(SPI_TS_OBJ_NAME)))
+               return AE_OK;
+
+       if (*ts_adev) {
+               pr_err("duplicate entry %s\n", SPI_TS_OBJ_NAME);
+               return AE_OK;
+       }
+
+       *ts_adev = adev;
+
+       return AE_OK;
+}
+
+static int s3_wmi_check_platform_device(struct device *dev, void *data)
+{
+       struct acpi_device *adev, *ts_adev;
+       acpi_handle handle;
+       acpi_status status;
+
+       /* ignore non ACPI devices */
+       handle = ACPI_HANDLE(dev);
+       if (!handle || acpi_bus_get_device(handle, &adev))
+               return 0;
+
+       /* check for LID ACPI switch */
+       if (!strcmp(ACPI_BUTTON_HID_LID, acpi_device_hid(adev))) {
+               s3_wmi.pnp0c0d_adev = adev;
+               return 0;
+       }
+
+       /* ignore non SPI controllers */
+       if (strncmp(acpi_device_bid(adev), SPI_CTL_OBJ_NAME,
+           strlen(SPI_CTL_OBJ_NAME)))
+               return 0;
+
+       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+                                    s3_wmi_attach_spi_device, NULL,
+                                    &ts_adev, NULL);
+       if (ACPI_FAILURE(status))
+               dev_warn(dev, "failed to enumerate SPI slaves\n");
+
+       if (!ts_adev)
+               return 0;
+
+       s3_wmi.touchscreen_adev = ts_adev;
+
+       return 0;
+}
+
+static int s3_wmi_create_and_register_input(struct platform_device *pdev)
+{
+       struct input_dev *input;
+       int error;
+
+       input = devm_input_allocate_device(&pdev->dev);
+       if (!input)
+               return -ENOMEM;
+
+       input->name = "Lid Switch";
+       input->phys = "button/input0";
+       input->id.bustype = BUS_HOST;
+       input->id.product = 0x0005;
+
+       input_set_capability(input, EV_SW, SW_LID);
+
+       error = input_register_device(input);
+       if (error)
+               goto out_err;
+
+       s3_wmi.input = input;
+
+       return 0;
+ out_err:
+       input_free_device(s3_wmi.input);
+       return error;
+}
+
+static int __init s3_wmi_probe(struct platform_device *pdev)
+{
+       int error;
+
+       if (!dmi_check_system(surface3_dmi_table))
+               return -ENODEV;
+
+       memset(&s3_wmi, 0, sizeof(s3_wmi));
+
+       bus_for_each_dev(&platform_bus_type, NULL, NULL,
+                        s3_wmi_check_platform_device);
+
+       if (!s3_wmi.touchscreen_adev)
+               return -ENODEV;
+
+       acpi_bus_trim(s3_wmi.pnp0c0d_adev);
+
+       error = s3_wmi_create_and_register_input(pdev);
+       if (error)
+               goto restore_acpi_lid;
+
+       acpi_initialize_hp_context(s3_wmi.touchscreen_adev, &s3_wmi.hp,
+                                  s3_wmi_hp_notify, NULL);
+
+       s3_wmi_send_lid_state();
+
+       return 0;
+
+ restore_acpi_lid:
+       acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
+       return error;
+}
+
+static int s3_wmi_remove(struct platform_device *device)
+{
+       /* remove the hotplug context from the acpi device */
+       s3_wmi.touchscreen_adev->hp = NULL;
+
+       /* reinstall the actual PNPC0C0D LID default handle */
+       acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3_wmi_resume(struct device *dev)
+{
+       s3_wmi_send_lid_state();
+       return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(s3_wmi_pm, NULL, s3_wmi_resume);
+
+static struct platform_driver s3_wmi_driver = {
+       .driver = {
+               .name = "surface3-wmi",
+               .pm = &s3_wmi_pm,
+       },
+       .remove = s3_wmi_remove,
+};
+
+static int __init s3_wmi_init(void)
+{
+       int error;
+
+       s3_wmi_pdev = platform_device_alloc("surface3-wmi", -1);
+       if (!s3_wmi_pdev)
+               return -ENOMEM;
+
+       error = platform_device_add(s3_wmi_pdev);
+       if (error)
+               goto err_device_put;
+
+       error = platform_driver_probe(&s3_wmi_driver, s3_wmi_probe);
+       if (error)
+               goto err_device_del;
+
+       pr_info("Surface 3 WMI Extras loaded\n");
+       return 0;
+
+ err_device_del:
+       platform_device_del(s3_wmi_pdev);
+ err_device_put:
+       platform_device_put(s3_wmi_pdev);
+       return error;
+}
+
+static void __exit s3_wmi_exit(void)
+{
+       platform_device_unregister(s3_wmi_pdev);
+       platform_driver_unregister(&s3_wmi_driver);
+}
+
+module_init(s3_wmi_init);
+module_exit(s3_wmi_exit);
diff --git a/drivers/platform/x86/surface3_button.c b/drivers/platform/x86/surface3_button.c
new file mode 100644 (file)
index 0000000..8bfd7f6
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Supports for the button array on the Surface tablets.
+ *
+ * (C) Copyright 2016 Red Hat, Inc
+ *
+ * Based on soc_button_array.c:
+ *
+ * {C} Copyright 2014 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+
+
+#define SURFACE_BUTTON_OBJ_NAME                "TEV2"
+#define MAX_NBUTTONS                   4
+
+/*
+ * Some of the buttons like volume up/down are auto repeat, while others
+ * are not. To support both, we register two platform devices, and put
+ * buttons into them based on whether the key should be auto repeat.
+ */
+#define BUTTON_TYPES                   2
+
+/*
+ * Power button, Home button, Volume buttons support is supposed to
+ * be covered by drivers/input/misc/soc_button_array.c, which is implemented
+ * according to "Windows ACPI Design Guide for SoC Platforms".
+ * However surface 3 seems not to obey the specs, instead it uses
+ * device TEV2(MSHW0028) for declaring the GPIOs. The gpios are also slightly
+ * different in which the Home button is active high.
+ * Compared to surfacepro3_button.c which also handles MSHW0028, the Surface 3
+ * is a reduce platform and thus uses GPIOs, not ACPI events.
+ * We choose an I2C driver here because we need to access the resources
+ * declared under the device node, while surfacepro3_button.c only needs
+ * the ACPI companion node.
+ */
+static const struct acpi_device_id surface3_acpi_match[] = {
+       { "MSHW0028", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, surface3_acpi_match);
+
+struct surface3_button_info {
+       const char *name;
+       int acpi_index;
+       unsigned int event_type;
+       unsigned int event_code;
+       bool autorepeat;
+       bool wakeup;
+       bool active_low;
+};
+
+struct surface3_button_data {
+       struct platform_device *children[BUTTON_TYPES];
+};
+
+/*
+ * Get the Nth GPIO number from the ACPI object.
+ */
+static int surface3_button_lookup_gpio(struct device *dev, int acpi_index)
+{
+       struct gpio_desc *desc;
+       int gpio;
+
+       desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       gpio = desc_to_gpio(desc);
+
+       gpiod_put(desc);
+
+       return gpio;
+}
+
+static struct platform_device *
+surface3_button_device_create(struct i2c_client *client,
+                             const struct surface3_button_info *button_info,
+                             bool autorepeat)
+{
+       const struct surface3_button_info *info;
+       struct platform_device *pd;
+       struct gpio_keys_button *gpio_keys;
+       struct gpio_keys_platform_data *gpio_keys_pdata;
+       int n_buttons = 0;
+       int gpio;
+       int error;
+
+       gpio_keys_pdata = devm_kzalloc(&client->dev,
+                                      sizeof(*gpio_keys_pdata) +
+                                      sizeof(*gpio_keys) * MAX_NBUTTONS,
+                                      GFP_KERNEL);
+       if (!gpio_keys_pdata)
+               return ERR_PTR(-ENOMEM);
+
+       gpio_keys = (void *)(gpio_keys_pdata + 1);
+
+       for (info = button_info; info->name; info++) {
+               if (info->autorepeat != autorepeat)
+                       continue;
+
+               gpio = surface3_button_lookup_gpio(&client->dev,
+                                                  info->acpi_index);
+               if (!gpio_is_valid(gpio))
+                       continue;
+
+               gpio_keys[n_buttons].type = info->event_type;
+               gpio_keys[n_buttons].code = info->event_code;
+               gpio_keys[n_buttons].gpio = gpio;
+               gpio_keys[n_buttons].active_low = info->active_low;
+               gpio_keys[n_buttons].desc = info->name;
+               gpio_keys[n_buttons].wakeup = info->wakeup;
+               n_buttons++;
+       }
+
+       if (n_buttons == 0) {
+               error = -ENODEV;
+               goto err_free_mem;
+       }
+
+       gpio_keys_pdata->buttons = gpio_keys;
+       gpio_keys_pdata->nbuttons = n_buttons;
+       gpio_keys_pdata->rep = autorepeat;
+
+       pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
+       if (!pd) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       error = platform_device_add_data(pd, gpio_keys_pdata,
+                                        sizeof(*gpio_keys_pdata));
+       if (error)
+               goto err_free_pdev;
+
+       error = platform_device_add(pd);
+       if (error)
+               goto err_free_pdev;
+
+       return pd;
+
+err_free_pdev:
+       platform_device_put(pd);
+err_free_mem:
+       devm_kfree(&client->dev, gpio_keys_pdata);
+       return ERR_PTR(error);
+}
+
+static int surface3_button_remove(struct i2c_client *client)
+{
+       struct surface3_button_data *priv = i2c_get_clientdata(client);
+
+       int i;
+
+       for (i = 0; i < BUTTON_TYPES; i++)
+               if (priv->children[i])
+                       platform_device_unregister(priv->children[i]);
+
+       return 0;
+}
+
+static struct surface3_button_info surface3_button_surface3[] = {
+       { "power", 0, EV_KEY, KEY_POWER, false, true, true },
+       { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
+       { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
+       { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
+       { }
+};
+
+static int surface3_button_probe(struct i2c_client *client,
+                                const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct surface3_button_data *priv;
+       struct platform_device *pd;
+       int i;
+       int error;
+
+       if (strncmp(acpi_device_bid(ACPI_COMPANION(&client->dev)),
+                   SURFACE_BUTTON_OBJ_NAME,
+                   strlen(SURFACE_BUTTON_OBJ_NAME)))
+               return -ENODEV;
+
+       if (gpiod_count(dev, KBUILD_MODNAME) <= 0) {
+               dev_dbg(dev, "no GPIO attached, ignoring...\n");
+               return -ENODEV;
+       }
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, priv);
+
+       for (i = 0; i < BUTTON_TYPES; i++) {
+               pd = surface3_button_device_create(client,
+                                                  surface3_button_surface3,
+                                                  i == 0);
+               if (IS_ERR(pd)) {
+                       error = PTR_ERR(pd);
+                       if (error != -ENODEV) {
+                               surface3_button_remove(client);
+                               return error;
+                       }
+                       continue;
+               }
+
+               priv->children[i] = pd;
+       }
+
+       if (!priv->children[0] && !priv->children[1])
+               return -ENODEV;
+
+       return 0;
+}
+
+static const struct i2c_device_id surface3_id[] = {
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, surface3_id);
+
+static struct i2c_driver surface3_driver = {
+       .probe = surface3_button_probe,
+       .remove = surface3_button_remove,
+       .id_table = surface3_id,
+       .driver = {
+               .name = "surface3",
+               .acpi_match_table = ACPI_PTR(surface3_acpi_match),
+       },
+};
+module_i2c_driver(surface3_driver);
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_DESCRIPTION("surface3 button array driver");
+MODULE_LICENSE("GPL v2");
index eb0f5b13841a505ea4157e949cf179d71d26175e..9aafbb03482d735fcc55bdfab3df83249900a024 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
                           DCDC5, DCDC6, LDO1, LS3 };
 
-#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \
-                          _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \
+#define TPS65218_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
+                          _em, _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \
        {                                                       \
                .name                   = _name,                \
+               .of_match               = _of,                  \
                .id                     = _id,                  \
                .ops                    = &_ops,                \
                .n_voltages             = _n,                   \
@@ -54,14 +56,6 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
                .bypass_mask    = _sm,                          \
        }                                                       \
 
-#define TPS65218_INFO(_id, _nm, _min, _max)    \
-       [_id] = {                                       \
-               .id             = _id,                  \
-               .name           = _nm,                  \
-               .min_uV         = _min,                 \
-               .max_uV         = _max,                 \
-       }
-
 static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = {
        REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000),
        REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000),
@@ -77,36 +71,6 @@ static const struct regulator_linear_range dcdc4_ranges[] = {
        REGULATOR_LINEAR_RANGE(1600000, 0x10, 0x34, 50000),
 };
 
-static struct tps_info tps65218_pmic_regs[] = {
-       TPS65218_INFO(DCDC1, "DCDC1", 850000, 1675000),
-       TPS65218_INFO(DCDC2, "DCDC2", 850000, 1675000),
-       TPS65218_INFO(DCDC3, "DCDC3", 900000, 3400000),
-       TPS65218_INFO(DCDC4, "DCDC4", 1175000, 3400000),
-       TPS65218_INFO(DCDC5, "DCDC5", 1000000, 1000000),
-       TPS65218_INFO(DCDC6, "DCDC6", 1800000, 1800000),
-       TPS65218_INFO(LDO1, "LDO1", 900000, 3400000),
-       TPS65218_INFO(LS3, "LS3", -1, -1),
-};
-
-#define TPS65218_OF_MATCH(comp, label) \
-       { \
-               .compatible = comp, \
-               .data = &label, \
-       }
-
-static const struct of_device_id tps65218_of_match[] = {
-       TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
-       TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
-       TPS65218_OF_MATCH("ti,tps65218-ls3", tps65218_pmic_regs[LS3]),
-       { }
-};
-MODULE_DEVICE_TABLE(of, tps65218_of_match);
-
 static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev,
                                         unsigned selector)
 {
@@ -188,7 +152,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev)
        if (rid == TPS65218_DCDC_3 && tps->rev == TPS65218_REV_2_1)
                return 0;
 
-       if (!tps->info[rid]->strobe) {
+       if (!tps->strobes[rid]) {
                if (rid == TPS65218_DCDC_3)
                        tps->info[rid]->strobe = 3;
                else
@@ -197,8 +161,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev)
 
        return tps65218_set_bits(tps, dev->desc->bypass_reg,
                                 dev->desc->bypass_mask,
-                                tps->info[rid]->strobe,
-                                TPS65218_PROTECT_L1);
+                                tps->strobes[rid], TPS65218_PROTECT_L1);
 }
 
 /* Operations permitted on DCDC1, DCDC2 */
@@ -272,7 +235,7 @@ static int tps65218_pmic_get_current_limit(struct regulator_dev *dev)
        unsigned int index;
        struct tps65218 *tps = rdev_get_drvdata(dev);
 
-       retval = tps65218_reg_read(tps, dev->desc->csel_reg, &index);
+       retval = regmap_read(tps->regmap, dev->desc->csel_reg, &index);
        if (retval < 0)
                return retval;
 
@@ -300,104 +263,104 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = {
 };
 
 static const struct regulator_desc regulators[] = {
-       TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, REGULATOR_VOLTAGE,
-                          tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1,
+       TPS65218_REGULATOR("DCDC1", "regulator-dcdc1", TPS65218_DCDC_1,
+                          REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64,
+                          TPS65218_REG_CONTROL_DCDC1,
                           TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1,
                           TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges,
                           2, 4000, 0, TPS65218_REG_SEQ3,
                           TPS65218_SEQ3_DC1_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE,
-                          tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2,
+       TPS65218_REGULATOR("DCDC2", "regulator-dcdc2", TPS65218_DCDC_2,
+                          REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64,
+                          TPS65218_REG_CONTROL_DCDC2,
                           TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1,
                           TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges,
                           2, 4000, 0, TPS65218_REG_SEQ3,
                           TPS65218_SEQ3_DC2_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE,
-                          tps65218_ldo1_dcdc34_ops, 64,
+       TPS65218_REGULATOR("DCDC3", "regulator-dcdc3", TPS65218_DCDC_3,
+                          REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64,
                           TPS65218_REG_CONTROL_DCDC3,
                           TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
                           TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2,
                           0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC3_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE,
-                          tps65218_ldo1_dcdc34_ops, 53,
+       TPS65218_REGULATOR("DCDC4", "regulator-dcdc4", TPS65218_DCDC_4,
+                          REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 53,
                           TPS65218_REG_CONTROL_DCDC4,
                           TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1,
                           TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2,
                           0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC4_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE,
-                          tps65218_dcdc56_pmic_ops, 1, -1, -1,
-                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0,
-                          NULL, 0, 0, 1000000, TPS65218_REG_SEQ5,
+       TPS65218_REGULATOR("DCDC5", "regulator-dcdc5", TPS65218_DCDC_5,
+                          REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1,
+                          -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0,
+                          0, NULL, 0, 0, 1000000, TPS65218_REG_SEQ5,
                           TPS65218_SEQ5_DC5_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE,
-                          tps65218_dcdc56_pmic_ops, 1, -1, -1,
-                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0,
-                          NULL, 0, 0, 1800000, TPS65218_REG_SEQ5,
+       TPS65218_REGULATOR("DCDC6", "regulator-dcdc6", TPS65218_DCDC_6,
+                          REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1,
+                          -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0,
+                          0, NULL, 0, 0, 1800000, TPS65218_REG_SEQ5,
                           TPS65218_SEQ5_DC6_SEQ_MASK),
-       TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE,
-                          tps65218_ldo1_dcdc34_ops, 64,
+       TPS65218_REGULATOR("LDO1", "regulator-ldo1", TPS65218_LDO_1,
+                          REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64,
                           TPS65218_REG_CONTROL_LDO1,
                           TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
                           TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges,
                           2, 0, 0, TPS65218_REG_SEQ6,
                           TPS65218_SEQ6_LDO1_SEQ_MASK),
-       TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT,
-                          tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2,
-                          TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2,
-                          TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0),
+       TPS65218_REGULATOR("LS3", "regulator-ls3", TPS65218_LS_3,
+                          REGULATOR_CURRENT, tps65218_ls3_ops, 0, 0, 0,
+                          TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS3_EN,
+                          TPS65218_REG_CONFIG2, TPS65218_CONFIG2_LS3ILIM_MASK,
+                          NULL, 0, 0, 0, 0, 0),
 };
 
 static int tps65218_regulator_probe(struct platform_device *pdev)
 {
        struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
-       struct regulator_init_data *init_data;
-       const struct tps_info   *template;
        struct regulator_dev *rdev;
-       const struct of_device_id       *match;
        struct regulator_config config = { };
-       int id, ret;
+       int i, ret;
        unsigned int val;
 
-       match = of_match_device(tps65218_of_match, &pdev->dev);
-       if (!match)
-               return -ENODEV;
-
-       template = match->data;
-       id = template->id;
-       init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
-                                              &regulators[id]);
-
-       platform_set_drvdata(pdev, tps);
-
-       tps->info[id] = &tps65218_pmic_regs[id];
        config.dev = &pdev->dev;
-       config.init_data = init_data;
+       config.dev->of_node = tps->dev->of_node;
        config.driver_data = tps;
        config.regmap = tps->regmap;
-       config.of_node = pdev->dev.of_node;
 
-       rdev = devm_regulator_register(&pdev->dev, &regulators[id], &config);
-       if (IS_ERR(rdev)) {
-               dev_err(tps->dev, "failed to register %s regulator\n",
-                       pdev->name);
-               return PTR_ERR(rdev);
-       }
+       /* Allocate memory for strobes */
+       tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) *
+                                   TPS65218_NUM_REGULATOR, GFP_KERNEL);
 
-       ret = tps65218_reg_read(tps, regulators[id].bypass_reg, &val);
-       if (ret)
-               return ret;
+       for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+               rdev = devm_regulator_register(&pdev->dev, &regulators[i],
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(tps->dev, "failed to register %s regulator\n",
+                               pdev->name);
+                       return PTR_ERR(rdev);
+               }
 
-       tps->info[id]->strobe = val & regulators[id].bypass_mask;
+               ret = regmap_read(tps->regmap, regulators[i].bypass_reg, &val);
+               if (ret)
+                       return ret;
+
+               tps->strobes[i] = val & regulators[i].bypass_mask;
+       }
 
        return 0;
 }
 
+static const struct platform_device_id tps65218_regulator_id_table[] = {
+       { "tps65218-regulator", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps65218_regulator_id_table);
+
 static struct platform_driver tps65218_regulator_driver = {
        .driver = {
                .name = "tps65218-pmic",
-               .of_match_table = tps65218_of_match,
        },
        .probe = tps65218_regulator_probe,
+       .id_table = tps65218_regulator_id_table,
 };
 
 module_platform_driver(tps65218_regulator_driver);
index e859d148aba9ecdbcecc47e745209b94ed83dd67..c93c5a8fba32925584dbc28c60610786328d09ff 100644 (file)
@@ -303,7 +303,7 @@ config RTC_DRV_MAX6900
 
 config RTC_DRV_MAX8907
        tristate "Maxim MAX8907"
-       depends on MFD_MAX8907
+       depends on MFD_MAX8907 || COMPILE_TEST
        help
          If you say yes here you will get support for the
          RTC of Maxim MAX8907 PMIC.
@@ -343,7 +343,7 @@ config RTC_DRV_MAX8997
 
 config RTC_DRV_MAX77686
        tristate "Maxim MAX77686"
-       depends on MFD_MAX77686 || MFD_MAX77620
+       depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
        help
          If you say yes here you will get support for the
          RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC.
@@ -481,6 +481,7 @@ config RTC_DRV_TWL92330
 config RTC_DRV_TWL4030
        tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"
        depends on TWL4030_CORE
+       depends on OF
        help
          If you say yes here you get support for the RTC on the
          TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.
@@ -602,7 +603,8 @@ config RTC_DRV_RV8803
 
 config RTC_DRV_S5M
        tristate "Samsung S2M/S5M series"
-       depends on MFD_SEC_CORE
+       depends on MFD_SEC_CORE || COMPILE_TEST
+       select REGMAP_IRQ
        help
          If you say yes here you will get support for the
          RTC of Samsung S2MPS14 and S5M PMIC series.
@@ -820,8 +822,8 @@ config RTC_DRV_RV3029_HWMON
 
 comment "Platform RTC drivers"
 
-# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
-# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
+# this 'CMOS' RTC driver is arch dependent because it requires
+# <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
 # global rtc_lock ... it's not yet just another platform_device.
 
 config RTC_DRV_CMOS
@@ -1549,14 +1551,11 @@ config RTC_DRV_MPC5121
          will be called rtc-mpc5121.
 
 config RTC_DRV_JZ4740
-       tristate "Ingenic JZ4740 SoC"
-       depends on MACH_JZ4740 || COMPILE_TEST
+       bool "Ingenic JZ4740 SoC"
+       depends on MACH_INGENIC || COMPILE_TEST
        help
-         If you say yes here you get support for the Ingenic JZ4740 SoC RTC
-         controller.
-
-         This driver can also be buillt as a module. If so, the module
-         will be called rtc-jz4740.
+         If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
+         controllers.
 
 config RTC_DRV_LPC24XX
        tristate "NXP RTC for LPC178x/18xx/408x/43xx"
@@ -1567,7 +1566,7 @@ config RTC_DRV_LPC24XX
          NXP LPC178x/18xx/408x/43xx devices.
 
          If you have one of the devices above enable this driver to use
-         the hardware RTC. This driver can also be buillt as a module. If
+         the hardware RTC. This driver can also be built as a module. If
          so, the module will be called rtc-lpc24xx.
 
 config RTC_DRV_LPC32XX
@@ -1576,7 +1575,7 @@ config RTC_DRV_LPC32XX
        help
          This enables support for the NXP RTC in the LPC32XX
 
-         This driver can also be buillt as a module. If so, the module
+         This driver can also be built as a module. If so, the module
          will be called rtc-lpc32xx.
 
 config RTC_DRV_PM8XXX
@@ -1706,6 +1705,17 @@ config RTC_DRV_PIC32
           This driver can also be built as a module. If so, the module
           will be called rtc-pic32
 
+config RTC_DRV_R7301
+       tristate "EPSON TOYOCOM RTC-7301SF/DG"
+       select REGMAP_MMIO
+       depends on OF && HAS_IOMEM
+       help
+          If you say yes here you get support for the EPSON TOYOCOM
+          RTC-7301SF/DG chips.
+
+          This driver can also be built as a module. If so, the module
+          will be called rtc-r7301.
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
index 1ac694a330c8dadc0cbe78a4f6cd8d7359de2ecc..f13ab1c5c222c269e711786e74f5a99a258150a5 100644 (file)
@@ -120,6 +120,7 @@ obj-$(CONFIG_RTC_DRV_PM8XXX)        += rtc-pm8xxx.o
 obj-$(CONFIG_RTC_DRV_PS3)      += rtc-ps3.o
 obj-$(CONFIG_RTC_DRV_PUV3)     += rtc-puv3.o
 obj-$(CONFIG_RTC_DRV_PXA)      += rtc-pxa.o
+obj-$(CONFIG_RTC_DRV_R7301)    += rtc-r7301.o
 obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RC5T583)  += rtc-rc5t583.o
 obj-$(CONFIG_RTC_DRV_RK808)    += rtc-rk808.o
index 38aa8e1906c262dc9f367d94230422fb5a2be82c..f4a96dbdabf21ec4bdf8017e524ea42b9b0ce5c7 100644 (file)
@@ -332,14 +332,86 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
        cmos_checkintr(cmos, rtc_control);
 }
 
+static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct cmos_rtc *cmos = dev_get_drvdata(dev);
+       struct rtc_time now;
+
+       cmos_read_time(dev, &now);
+
+       if (!cmos->day_alrm) {
+               time64_t t_max_date;
+               time64_t t_alrm;
+
+               t_max_date = rtc_tm_to_time64(&now);
+               t_max_date += 24 * 60 * 60 - 1;
+               t_alrm = rtc_tm_to_time64(&t->time);
+               if (t_alrm > t_max_date) {
+                       dev_err(dev,
+                               "Alarms can be up to one day in the future\n");
+                       return -EINVAL;
+               }
+       } else if (!cmos->mon_alrm) {
+               struct rtc_time max_date = now;
+               time64_t t_max_date;
+               time64_t t_alrm;
+               int max_mday;
+
+               if (max_date.tm_mon == 11) {
+                       max_date.tm_mon = 0;
+                       max_date.tm_year += 1;
+               } else {
+                       max_date.tm_mon += 1;
+               }
+               max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
+               if (max_date.tm_mday > max_mday)
+                       max_date.tm_mday = max_mday;
+
+               t_max_date = rtc_tm_to_time64(&max_date);
+               t_max_date -= 1;
+               t_alrm = rtc_tm_to_time64(&t->time);
+               if (t_alrm > t_max_date) {
+                       dev_err(dev,
+                               "Alarms can be up to one month in the future\n");
+                       return -EINVAL;
+               }
+       } else {
+               struct rtc_time max_date = now;
+               time64_t t_max_date;
+               time64_t t_alrm;
+               int max_mday;
+
+               max_date.tm_year += 1;
+               max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
+               if (max_date.tm_mday > max_mday)
+                       max_date.tm_mday = max_mday;
+
+               t_max_date = rtc_tm_to_time64(&max_date);
+               t_max_date -= 1;
+               t_alrm = rtc_tm_to_time64(&t->time);
+               if (t_alrm > t_max_date) {
+                       dev_err(dev,
+                               "Alarms can be up to one year in the future\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
        unsigned char mon, mday, hrs, min, sec, rtc_control;
+       int ret;
 
        if (!is_valid_irq(cmos->irq))
                return -EIO;
 
+       ret = cmos_validate_alarm(dev, t);
+       if (ret < 0)
+               return ret;
+
        mon = t->time.tm_mon + 1;
        mday = t->time.tm_mday;
        hrs = t->time.tm_hour;
@@ -707,9 +779,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 
        spin_unlock_irq(&rtc_lock);
 
-       /* FIXME:
-        * <asm-generic/rtc.h> doesn't know 12-hour mode either.
-        */
        if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
                dev_warn(dev, "only 24-hr supported\n");
                retval = -ENXIO;
index 4e31036ee2596dec93accd26f627c5b95591ae9f..4ad97be480430babc3321075f2739114eaad8f04 100644 (file)
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/acpi.h>
 #include <linux/bcd.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
@@ -191,6 +192,26 @@ static const struct i2c_device_id ds1307_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ds1307_id);
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ds1307_acpi_ids[] = {
+       { .id = "DS1307", .driver_data = ds_1307 },
+       { .id = "DS1337", .driver_data = ds_1337 },
+       { .id = "DS1338", .driver_data = ds_1338 },
+       { .id = "DS1339", .driver_data = ds_1339 },
+       { .id = "DS1388", .driver_data = ds_1388 },
+       { .id = "DS1340", .driver_data = ds_1340 },
+       { .id = "DS3231", .driver_data = ds_3231 },
+       { .id = "M41T00", .driver_data = m41t00 },
+       { .id = "MCP7940X", .driver_data = mcp794xx },
+       { .id = "MCP7941X", .driver_data = mcp794xx },
+       { .id = "PT7C4338", .driver_data = ds_1307 },
+       { .id = "RX8025", .driver_data = rx_8025 },
+       { .id = "ISL12057", .driver_data = ds_1337 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
+#endif
+
 /*----------------------------------------------------------------------*/
 
 #define BLOCK_DATA_MAX_TRIES 10
@@ -874,17 +895,17 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client,
        return setup;
 }
 
-static void ds1307_trickle_of_init(struct i2c_client *client,
-                                  struct chip_desc *chip)
+static void ds1307_trickle_init(struct i2c_client *client,
+                               struct chip_desc *chip)
 {
        uint32_t ohms = 0;
        bool diode = true;
 
        if (!chip->do_trickle_setup)
                goto out;
-       if (of_property_read_u32(client->dev.of_node, "trickle-resistor-ohms" , &ohms))
+       if (device_property_read_u32(&client->dev, "trickle-resistor-ohms", &ohms))
                goto out;
-       if (of_property_read_bool(client->dev.of_node, "trickle-diode-disable"))
+       if (device_property_read_bool(&client->dev, "trickle-diode-disable"))
                diode = false;
        chip->trickle_charger_setup = chip->do_trickle_setup(client,
                                                             ohms, diode);
@@ -1268,7 +1289,7 @@ static int ds1307_probe(struct i2c_client *client,
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
        int                     tmp, wday;
-       struct chip_desc        *chip = &chips[id->driver_data];
+       struct chip_desc        *chip;
        struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
        bool                    want_irq = false;
        bool                    ds1307_can_wakeup_device = false;
@@ -1297,11 +1318,23 @@ static int ds1307_probe(struct i2c_client *client,
        i2c_set_clientdata(client, ds1307);
 
        ds1307->client  = client;
-       ds1307->type    = id->driver_data;
+       if (id) {
+               chip = &chips[id->driver_data];
+               ds1307->type = id->driver_data;
+       } else {
+               const struct acpi_device_id *acpi_id;
+
+               acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids),
+                                           &client->dev);
+               if (!acpi_id)
+                       return -ENODEV;
+               chip = &chips[acpi_id->driver_data];
+               ds1307->type = acpi_id->driver_data;
+       }
 
-       if (!pdata && client->dev.of_node)
-               ds1307_trickle_of_init(client, chip);
-       else if (pdata && pdata->trickle_charger_setup)
+       if (!pdata)
+               ds1307_trickle_init(client, chip);
+       else if (pdata->trickle_charger_setup)
                chip->trickle_charger_setup = pdata->trickle_charger_setup;
 
        if (chip->trickle_charger_setup && chip->trickle_charger_reg) {
@@ -1678,6 +1711,7 @@ static int ds1307_remove(struct i2c_client *client)
 static struct i2c_driver ds1307_driver = {
        .driver = {
                .name   = "rtc-ds1307",
+               .acpi_match_table = ACPI_PTR(ds1307_acpi_ids),
        },
        .probe          = ds1307_probe,
        .remove         = ds1307_remove,
index 3b3049c8c9e04ddb8ebfb3c391eba41b320286f3..52429f0a57cc2125e428aa88be917a4268f44b35 100644 (file)
@@ -89,10 +89,8 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
        int ret;
        int i;
 
-       if (nbytes > 4) {
-               WARN_ON(1);
+       if (WARN_ON(nbytes > 4))
                return -EINVAL;
-       }
 
        ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf);
 
index 8d8049bdfaf613a83336fd22ed326ddfe9717716..67b56b80dc7097049dbf20f0ea8d0e908a231b5f 100644 (file)
@@ -67,7 +67,7 @@
 #define DSR_ETAD  (1 << 21)      /* External tamper A detected */
 #define DSR_EBD   (1 << 20)      /* External boot detected */
 #define DSR_SAD   (1 << 19)      /* SCC alarm detected */
-#define DSR_TTD   (1 << 18)      /* Temperatur tamper detected */
+#define DSR_TTD   (1 << 18)      /* Temperature tamper detected */
 #define DSR_CTD   (1 << 17)      /* Clock tamper detected */
 #define DSR_VTD   (1 << 16)      /* Voltage tamper detected */
 #define DSR_WBF   (1 << 10)      /* Write Busy Flag (synchronous) */
index 5e14651b71a89a2327a2f1fe175cc56156d6a880..72918c1ba0928d4fc78d921db621c489fafb9701 100644 (file)
  *
  */
 
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/reboot.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #define JZ_REG_RTC_SEC_ALARM   0x08
 #define JZ_REG_RTC_REGULATOR   0x0C
 #define JZ_REG_RTC_HIBERNATE   0x20
+#define JZ_REG_RTC_WAKEUP_FILTER       0x24
+#define JZ_REG_RTC_RESET_COUNTER       0x28
 #define JZ_REG_RTC_SCRATCHPAD  0x34
 
+/* The following are present on the jz4780 */
+#define JZ_REG_RTC_WENR        0x3C
+#define JZ_RTC_WENR_WEN        BIT(31)
+
 #define JZ_RTC_CTRL_WRDY       BIT(7)
 #define JZ_RTC_CTRL_1HZ                BIT(6)
 #define JZ_RTC_CTRL_1HZ_IRQ    BIT(5)
 #define JZ_RTC_CTRL_AE         BIT(2)
 #define JZ_RTC_CTRL_ENABLE     BIT(0)
 
+/* Magic value to enable writes on jz4780 */
+#define JZ_RTC_WENR_MAGIC      0xA55A
+
+#define JZ_RTC_WAKEUP_FILTER_MASK      0x0000FFE0
+#define JZ_RTC_RESET_COUNTER_MASK      0x00000FE0
+
+enum jz4740_rtc_type {
+       ID_JZ4740,
+       ID_JZ4780,
+};
+
 struct jz4740_rtc {
        void __iomem *base;
+       enum jz4740_rtc_type type;
 
        struct rtc_device *rtc;
+       struct clk *clk;
 
        int irq;
 
        spinlock_t lock;
+
+       unsigned int min_wakeup_pin_assert_time;
+       unsigned int reset_pin_assert_time;
 };
 
+static struct device *dev_for_power_off;
+
 static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
 {
        return readl(rtc->base + reg);
@@ -64,11 +90,33 @@ static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
        return timeout ? 0 : -EIO;
 }
 
+static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
+{
+       uint32_t ctrl;
+       int ret, timeout = 1000;
+
+       ret = jz4740_rtc_wait_write_ready(rtc);
+       if (ret != 0)
+               return ret;
+
+       writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR);
+
+       do {
+               ctrl = readl(rtc->base + JZ_REG_RTC_WENR);
+       } while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout);
+
+       return timeout ? 0 : -EIO;
+}
+
 static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
        uint32_t val)
 {
-       int ret;
-       ret = jz4740_rtc_wait_write_ready(rtc);
+       int ret = 0;
+
+       if (rtc->type >= ID_JZ4780)
+               ret = jz4780_rtc_enable_write(rtc);
+       if (ret == 0)
+               ret = jz4740_rtc_wait_write_ready(rtc);
        if (ret == 0)
                writel(val, rtc->base + reg);
 
@@ -203,12 +251,57 @@ static irqreturn_t jz4740_rtc_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-void jz4740_rtc_poweroff(struct device *dev)
+static void jz4740_rtc_poweroff(struct device *dev)
 {
        struct jz4740_rtc *rtc = dev_get_drvdata(dev);
        jz4740_rtc_reg_write(rtc, JZ_REG_RTC_HIBERNATE, 1);
 }
-EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff);
+
+static void jz4740_rtc_power_off(void)
+{
+       struct jz4740_rtc *rtc = dev_get_drvdata(dev_for_power_off);
+       unsigned long rtc_rate;
+       unsigned long wakeup_filter_ticks;
+       unsigned long reset_counter_ticks;
+
+       clk_prepare_enable(rtc->clk);
+
+       rtc_rate = clk_get_rate(rtc->clk);
+
+       /*
+        * Set minimum wakeup pin assertion time: 100 ms.
+        * Range is 0 to 2 sec if RTC is clocked at 32 kHz.
+        */
+       wakeup_filter_ticks =
+               (rtc->min_wakeup_pin_assert_time * rtc_rate) / 1000;
+       if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
+               wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
+       else
+               wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
+       jz4740_rtc_reg_write(rtc,
+                            JZ_REG_RTC_WAKEUP_FILTER, wakeup_filter_ticks);
+
+       /*
+        * Set reset pin low-level assertion time after wakeup: 60 ms.
+        * Range is 0 to 125 ms if RTC is clocked at 32 kHz.
+        */
+       reset_counter_ticks = (rtc->reset_pin_assert_time * rtc_rate) / 1000;
+       if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
+               reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
+       else
+               reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
+       jz4740_rtc_reg_write(rtc,
+                            JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks);
+
+       jz4740_rtc_poweroff(dev_for_power_off);
+       machine_halt();
+}
+
+static const struct of_device_id jz4740_rtc_of_match[] = {
+       { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
+       { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
+       {},
+};
 
 static int jz4740_rtc_probe(struct platform_device *pdev)
 {
@@ -216,11 +309,20 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
        struct jz4740_rtc *rtc;
        uint32_t scratchpad;
        struct resource *mem;
+       const struct platform_device_id *id = platform_get_device_id(pdev);
+       const struct of_device_id *of_id = of_match_device(
+                       jz4740_rtc_of_match, &pdev->dev);
+       struct device_node *np = pdev->dev.of_node;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
+       if (of_id)
+               rtc->type = (enum jz4740_rtc_type)of_id->data;
+       else
+               rtc->type = id->driver_data;
+
        rtc->irq = platform_get_irq(pdev, 0);
        if (rtc->irq < 0) {
                dev_err(&pdev->dev, "Failed to get platform irq\n");
@@ -232,6 +334,12 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
        if (IS_ERR(rtc->base))
                return PTR_ERR(rtc->base);
 
+       rtc->clk = devm_clk_get(&pdev->dev, "rtc");
+       if (IS_ERR(rtc->clk)) {
+               dev_err(&pdev->dev, "Failed to get RTC clock\n");
+               return PTR_ERR(rtc->clk);
+       }
+
        spin_lock_init(&rtc->lock);
 
        platform_set_drvdata(pdev, rtc);
@@ -263,6 +371,27 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
                }
        }
 
+       if (np && of_device_is_system_power_controller(np)) {
+               if (!pm_power_off) {
+                       /* Default: 60ms */
+                       rtc->reset_pin_assert_time = 60;
+                       of_property_read_u32(np, "reset-pin-assert-time-ms",
+                                            &rtc->reset_pin_assert_time);
+
+                       /* Default: 100ms */
+                       rtc->min_wakeup_pin_assert_time = 100;
+                       of_property_read_u32(np,
+                                            "min-wakeup-pin-assert-time-ms",
+                                            &rtc->min_wakeup_pin_assert_time);
+
+                       dev_for_power_off = &pdev->dev;
+                       pm_power_off = jz4740_rtc_power_off;
+               } else {
+                       dev_warn(&pdev->dev,
+                                "Poweroff handler already present!\n");
+               }
+       }
+
        return 0;
 }
 
@@ -295,17 +424,20 @@ static const struct dev_pm_ops jz4740_pm_ops = {
 #define JZ4740_RTC_PM_OPS NULL
 #endif  /* CONFIG_PM */
 
+static const struct platform_device_id jz4740_rtc_ids[] = {
+       { "jz4740-rtc", ID_JZ4740 },
+       { "jz4780-rtc", ID_JZ4780 },
+       {}
+};
+
 static struct platform_driver jz4740_rtc_driver = {
        .probe   = jz4740_rtc_probe,
        .driver  = {
                .name  = "jz4740-rtc",
                .pm    = JZ4740_RTC_PM_OPS,
+               .of_match_table = of_match_ptr(jz4740_rtc_of_match),
        },
+       .id_table = jz4740_rtc_ids,
 };
 
-module_platform_driver(jz4740_rtc_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
-MODULE_ALIAS("platform:jz4740-rtc");
+builtin_platform_driver(jz4740_rtc_driver);
index e6bfb9c42a10b08948910345e34f1b3b83057e82..1ae7da5cfc608f6c4bcb3764b00683e2a54b7919 100644 (file)
@@ -11,7 +11,7 @@
  * published by the Free Software Foundation.
 */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/rtc.h>
 
 static const unsigned char rtc_days_in_month[] = {
@@ -148,5 +148,3 @@ struct rtc_time rtc_ktime_to_tm(ktime_t kt)
        return ret;
 }
 EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
-
-MODULE_LICENSE("GPL");
index 4021fd04cb0ac847c955c4de79e283a97b73ff17..ce75e421ba001fce02c7f7afce57c310af012001 100644 (file)
@@ -12,7 +12,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * */
+ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -21,6 +21,8 @@
 #include <linux/spi/spi.h>
 #include <linux/rtc.h>
 #include <linux/of.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
 
 /* MCP795 Instructions, see datasheet table 3-1 */
 #define MCP795_EEREAD  0x03
@@ -29,7 +31,7 @@
 #define MCP795_EEWREN  0x06
 #define MCP795_SRREAD  0x05
 #define MCP795_SRWRITE 0x01
-#define MCP795_READ            0x13
+#define MCP795_READ    0x13
 #define MCP795_WRITE   0x12
 #define MCP795_UNLOCK  0x14
 #define MCP795_IDWRITE 0x32
 #define MCP795_CLRWDT  0x44
 #define MCP795_CLRRAM  0x54
 
-#define MCP795_ST_BIT  0x80
-#define MCP795_24_BIT  0x40
+/* MCP795 RTCC registers, see datasheet table 4-1 */
+#define MCP795_REG_SECONDS     0x01
+#define MCP795_REG_DAY         0x04
+#define MCP795_REG_MONTH       0x06
+#define MCP795_REG_CONTROL     0x08
+
+#define MCP795_ST_BIT          BIT(7)
+#define MCP795_24_BIT          BIT(6)
+#define MCP795_LP_BIT          BIT(5)
+#define MCP795_EXTOSC_BIT      BIT(3)
+#define MCP795_OSCON_BIT       BIT(5)
 
 static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count)
 {
@@ -93,30 +104,97 @@ static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state)
        return ret;
 }
 
+static int mcp795_stop_oscillator(struct device *dev, bool *extosc)
+{
+       int retries = 5;
+       int ret;
+       u8 data;
+
+       ret = mcp795_rtcc_set_bits(dev, MCP795_REG_SECONDS, MCP795_ST_BIT, 0);
+       if (ret)
+               return ret;
+       ret = mcp795_rtcc_read(dev, MCP795_REG_CONTROL, &data, 1);
+       if (ret)
+               return ret;
+       *extosc = !!(data & MCP795_EXTOSC_BIT);
+       ret = mcp795_rtcc_set_bits(
+                               dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, 0);
+       if (ret)
+               return ret;
+       /* wait for the OSCON bit to clear */
+       do {
+               usleep_range(700, 800);
+               ret = mcp795_rtcc_read(dev, MCP795_REG_DAY, &data, 1);
+               if (ret)
+                       break;
+               if (!(data & MCP795_OSCON_BIT))
+                       break;
+
+       } while (--retries);
+
+       return !retries ? -EIO : ret;
+}
+
+static int mcp795_start_oscillator(struct device *dev, bool *extosc)
+{
+       if (extosc) {
+               u8 data = *extosc ? MCP795_EXTOSC_BIT : 0;
+               int ret;
+
+               ret = mcp795_rtcc_set_bits(
+                       dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, data);
+               if (ret)
+                       return ret;
+       }
+       return mcp795_rtcc_set_bits(
+                       dev, MCP795_REG_SECONDS, MCP795_ST_BIT, MCP795_ST_BIT);
+}
+
 static int mcp795_set_time(struct device *dev, struct rtc_time *tim)
 {
        int ret;
        u8 data[7];
+       bool extosc;
+
+       /* Stop RTC and store current value of EXTOSC bit */
+       ret = mcp795_stop_oscillator(dev, &extosc);
+       if (ret)
+               return ret;
 
        /* Read first, so we can leave config bits untouched */
-       ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data));
+       ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data));
 
        if (ret)
                return ret;
 
-       data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10);
-       data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10);
-       data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10);
-       data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10);
-       data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10);
+       data[0] = (data[0] & 0x80) | bin2bcd(tim->tm_sec);
+       data[1] = (data[1] & 0x80) | bin2bcd(tim->tm_min);
+       data[2] = bin2bcd(tim->tm_hour);
+       data[4] = bin2bcd(tim->tm_mday);
+       data[5] = (data[5] & MCP795_LP_BIT) | bin2bcd(tim->tm_mon + 1);
 
        if (tim->tm_year > 100)
                tim->tm_year -= 100;
 
-       data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10);
+       data[6] = bin2bcd(tim->tm_year);
+
+       /* Always write the date and month using a separate Write command.
+        * This is a workaround for a know silicon issue that some combinations
+        * of date and month values may result in the date being reset to 1.
+        */
+       ret = mcp795_rtcc_write(dev, MCP795_REG_SECONDS, data, 5);
+       if (ret)
+               return ret;
 
-       ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data));
+       ret = mcp795_rtcc_write(dev, MCP795_REG_MONTH, &data[5], 2);
+       if (ret)
+               return ret;
 
+       /* Start back RTC and restore previous value of EXTOSC bit.
+        * There is no need to clear EXTOSC bit when the previous value was 0
+        * because it was already cleared when stopping the RTC oscillator.
+        */
+       ret = mcp795_start_oscillator(dev, extosc ? &extosc : NULL);
        if (ret)
                return ret;
 
@@ -132,17 +210,17 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim)
        int ret;
        u8 data[7];
 
-       ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data));
+       ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data));
 
        if (ret)
                return ret;
 
-       tim->tm_sec             = ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f);
-       tim->tm_min             = ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f);
-       tim->tm_hour    = ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f);
-       tim->tm_mday    = ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f);
-       tim->tm_mon             = ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f);
-       tim->tm_year    = ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */
+       tim->tm_sec     = bcd2bin(data[0] & 0x7F);
+       tim->tm_min     = bcd2bin(data[1] & 0x7F);
+       tim->tm_hour    = bcd2bin(data[2] & 0x3F);
+       tim->tm_mday    = bcd2bin(data[4] & 0x3F);
+       tim->tm_mon     = bcd2bin(data[5] & 0x1F) - 1;
+       tim->tm_year    = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */
 
        dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n",
                                tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
@@ -169,13 +247,13 @@ static int mcp795_probe(struct spi_device *spi)
                return ret;
        }
 
-       /* Start the oscillator */
-       mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT);
+       /* Start the oscillator but don't set the value of EXTOSC bit */
+       mcp795_start_oscillator(&spi->dev, NULL);
        /* Clear the 12 hour mode flag*/
        mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0);
 
        rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795",
-                                                               &mcp795_rtc_ops, THIS_MODULE);
+                                       &mcp795_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc))
                return PTR_ERR(rtc);
 
index efb0a08ac1175182a07ef9d63a49184a20698bd4..a06dff994c8316c0062b39d3704055a1305584a8 100644 (file)
@@ -191,12 +191,19 @@ static int pcf85063_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
        struct rtc_device *rtc;
+       int err;
 
        dev_dbg(&client->dev, "%s\n", __func__);
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
                return -ENODEV;
 
+       err = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
+       if (err < 0) {
+               dev_err(&client->dev, "RTC chip is not present\n");
+               return err;
+       }
+
        rtc = devm_rtc_device_register(&client->dev,
                                       pcf85063_driver.driver.name,
                                       &pcf85063_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c
new file mode 100644 (file)
index 0000000..28d5408
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * EPSON TOYOCOM RTC-7301SF/DG Driver
+ *
+ * Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
+ *
+ * Based on rtc-rp5c01.c
+ *
+ * Datasheet: http://www5.epsondevice.com/en/products/parallel/rtc7301sf.html
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define DRV_NAME "rtc-r7301"
+
+#define RTC7301_1_SEC          0x0     /* Bank 0 and Band 1 */
+#define RTC7301_10_SEC         0x1     /* Bank 0 and Band 1 */
+#define RTC7301_AE             BIT(3)
+#define RTC7301_1_MIN          0x2     /* Bank 0 and Band 1 */
+#define RTC7301_10_MIN         0x3     /* Bank 0 and Band 1 */
+#define RTC7301_1_HOUR         0x4     /* Bank 0 and Band 1 */
+#define RTC7301_10_HOUR                0x5     /* Bank 0 and Band 1 */
+#define RTC7301_DAY_OF_WEEK    0x6     /* Bank 0 and Band 1 */
+#define RTC7301_1_DAY          0x7     /* Bank 0 and Band 1 */
+#define RTC7301_10_DAY         0x8     /* Bank 0 and Band 1 */
+#define RTC7301_1_MONTH                0x9     /* Bank 0 */
+#define RTC7301_10_MONTH       0xa     /* Bank 0 */
+#define RTC7301_1_YEAR         0xb     /* Bank 0 */
+#define RTC7301_10_YEAR                0xc     /* Bank 0 */
+#define RTC7301_100_YEAR       0xd     /* Bank 0 */
+#define RTC7301_1000_YEAR      0xe     /* Bank 0 */
+#define RTC7301_ALARM_CONTROL  0xe     /* Bank 1 */
+#define RTC7301_ALARM_CONTROL_AIE      BIT(0)
+#define RTC7301_ALARM_CONTROL_AF       BIT(1)
+#define RTC7301_TIMER_CONTROL  0xe     /* Bank 2 */
+#define RTC7301_TIMER_CONTROL_TIE      BIT(0)
+#define RTC7301_TIMER_CONTROL_TF       BIT(1)
+#define RTC7301_CONTROL                0xf     /* All banks */
+#define RTC7301_CONTROL_BUSY           BIT(0)
+#define RTC7301_CONTROL_STOP           BIT(1)
+#define RTC7301_CONTROL_BANK_SEL_0     BIT(2)
+#define RTC7301_CONTROL_BANK_SEL_1     BIT(3)
+
+struct rtc7301_priv {
+       struct regmap *regmap;
+       int irq;
+       spinlock_t lock;
+       u8 bank;
+};
+
+static const struct regmap_config rtc7301_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 8,
+       .reg_stride = 4,
+};
+
+static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg)
+{
+       int reg_stride = regmap_get_reg_stride(priv->regmap);
+       unsigned int val;
+
+       regmap_read(priv->regmap, reg_stride * reg, &val);
+
+       return val & 0xf;
+}
+
+static void rtc7301_write(struct rtc7301_priv *priv, u8 val, unsigned int reg)
+{
+       int reg_stride = regmap_get_reg_stride(priv->regmap);
+
+       regmap_write(priv->regmap, reg_stride * reg, val);
+}
+
+static void rtc7301_update_bits(struct rtc7301_priv *priv, unsigned int reg,
+                               u8 mask, u8 val)
+{
+       int reg_stride = regmap_get_reg_stride(priv->regmap);
+
+       regmap_update_bits(priv->regmap, reg_stride * reg, mask, val);
+}
+
+static int rtc7301_wait_while_busy(struct rtc7301_priv *priv)
+{
+       int retries = 100;
+
+       while (retries-- > 0) {
+               u8 val;
+
+               val = rtc7301_read(priv, RTC7301_CONTROL);
+               if (!(val & RTC7301_CONTROL_BUSY))
+                       return 0;
+
+               usleep_range(200, 300);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static void rtc7301_stop(struct rtc7301_priv *priv)
+{
+       rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP,
+                           RTC7301_CONTROL_STOP);
+}
+
+static void rtc7301_start(struct rtc7301_priv *priv)
+{
+       rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP, 0);
+}
+
+static void rtc7301_select_bank(struct rtc7301_priv *priv, u8 bank)
+{
+       u8 val = 0;
+
+       if (bank == priv->bank)
+               return;
+
+       if (bank & BIT(0))
+               val |= RTC7301_CONTROL_BANK_SEL_0;
+       if (bank & BIT(1))
+               val |= RTC7301_CONTROL_BANK_SEL_1;
+
+       rtc7301_update_bits(priv, RTC7301_CONTROL,
+                           RTC7301_CONTROL_BANK_SEL_0 |
+                           RTC7301_CONTROL_BANK_SEL_1, val);
+
+       priv->bank = bank;
+}
+
+static void rtc7301_get_time(struct rtc7301_priv *priv, struct rtc_time *tm,
+                            bool alarm)
+{
+       int year;
+
+       tm->tm_sec = rtc7301_read(priv, RTC7301_1_SEC);
+       tm->tm_sec += (rtc7301_read(priv, RTC7301_10_SEC) & ~RTC7301_AE) * 10;
+       tm->tm_min = rtc7301_read(priv, RTC7301_1_MIN);
+       tm->tm_min += (rtc7301_read(priv, RTC7301_10_MIN) & ~RTC7301_AE) * 10;
+       tm->tm_hour = rtc7301_read(priv, RTC7301_1_HOUR);
+       tm->tm_hour += (rtc7301_read(priv, RTC7301_10_HOUR) & ~RTC7301_AE) * 10;
+       tm->tm_mday = rtc7301_read(priv, RTC7301_1_DAY);
+       tm->tm_mday += (rtc7301_read(priv, RTC7301_10_DAY) & ~RTC7301_AE) * 10;
+
+       if (alarm) {
+               tm->tm_wday = -1;
+               tm->tm_mon = -1;
+               tm->tm_year = -1;
+               tm->tm_yday = -1;
+               tm->tm_isdst = -1;
+               return;
+       }
+
+       tm->tm_wday = (rtc7301_read(priv, RTC7301_DAY_OF_WEEK) & ~RTC7301_AE);
+       tm->tm_mon = rtc7301_read(priv, RTC7301_10_MONTH) * 10 +
+                    rtc7301_read(priv, RTC7301_1_MONTH) - 1;
+       year = rtc7301_read(priv, RTC7301_1000_YEAR) * 1000 +
+              rtc7301_read(priv, RTC7301_100_YEAR) * 100 +
+              rtc7301_read(priv, RTC7301_10_YEAR) * 10 +
+              rtc7301_read(priv, RTC7301_1_YEAR);
+
+       tm->tm_year = year - 1900;
+}
+
+static void rtc7301_write_time(struct rtc7301_priv *priv, struct rtc_time *tm,
+                              bool alarm)
+{
+       int year;
+
+       rtc7301_write(priv, tm->tm_sec % 10, RTC7301_1_SEC);
+       rtc7301_write(priv, tm->tm_sec / 10, RTC7301_10_SEC);
+
+       rtc7301_write(priv, tm->tm_min % 10, RTC7301_1_MIN);
+       rtc7301_write(priv, tm->tm_min / 10, RTC7301_10_MIN);
+
+       rtc7301_write(priv, tm->tm_hour % 10, RTC7301_1_HOUR);
+       rtc7301_write(priv, tm->tm_hour / 10, RTC7301_10_HOUR);
+
+       rtc7301_write(priv, tm->tm_mday % 10, RTC7301_1_DAY);
+       rtc7301_write(priv, tm->tm_mday / 10, RTC7301_10_DAY);
+
+       /* Don't care for alarm register */
+       rtc7301_write(priv, alarm ? RTC7301_AE : tm->tm_wday,
+                     RTC7301_DAY_OF_WEEK);
+
+       if (alarm)
+               return;
+
+       rtc7301_write(priv, (tm->tm_mon + 1) % 10, RTC7301_1_MONTH);
+       rtc7301_write(priv, (tm->tm_mon + 1) / 10, RTC7301_10_MONTH);
+
+       year = tm->tm_year + 1900;
+
+       rtc7301_write(priv, year % 10, RTC7301_1_YEAR);
+       rtc7301_write(priv, (year / 10) % 10, RTC7301_10_YEAR);
+       rtc7301_write(priv, (year / 100) % 10, RTC7301_100_YEAR);
+       rtc7301_write(priv, year / 1000, RTC7301_1000_YEAR);
+}
+
+static void rtc7301_alarm_irq(struct rtc7301_priv *priv, unsigned int enabled)
+{
+       rtc7301_update_bits(priv, RTC7301_ALARM_CONTROL,
+                           RTC7301_ALARM_CONTROL_AF |
+                           RTC7301_ALARM_CONTROL_AIE,
+                           enabled ? RTC7301_ALARM_CONTROL_AIE : 0);
+}
+
+static int rtc7301_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 0);
+
+       err = rtc7301_wait_while_busy(priv);
+       if (!err)
+               rtc7301_get_time(priv, tm, false);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return err ? err : rtc_valid_tm(tm);
+}
+
+static int rtc7301_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_stop(priv);
+       usleep_range(200, 300);
+       rtc7301_select_bank(priv, 0);
+       rtc7301_write_time(priv, tm, false);
+       rtc7301_start(priv);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int rtc7301_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+       u8 alrm_ctrl;
+
+       if (priv->irq <= 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 1);
+       rtc7301_get_time(priv, &alarm->time, true);
+
+       alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL);
+
+       alarm->enabled = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AIE);
+       alarm->pending = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AF);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int rtc7301_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       if (priv->irq <= 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 1);
+       rtc7301_write_time(priv, &alarm->time, true);
+       rtc7301_alarm_irq(priv, alarm->enabled);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int rtc7301_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       if (priv->irq <= 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 1);
+       rtc7301_alarm_irq(priv, enabled);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static const struct rtc_class_ops rtc7301_rtc_ops = {
+       .read_time      = rtc7301_read_time,
+       .set_time       = rtc7301_set_time,
+       .read_alarm     = rtc7301_read_alarm,
+       .set_alarm      = rtc7301_set_alarm,
+       .alarm_irq_enable = rtc7301_alarm_irq_enable,
+};
+
+static irqreturn_t rtc7301_irq_handler(int irq, void *dev_id)
+{
+       struct rtc_device *rtc = dev_id;
+       struct rtc7301_priv *priv = dev_get_drvdata(rtc->dev.parent);
+       unsigned long flags;
+       irqreturn_t ret = IRQ_NONE;
+       u8 alrm_ctrl;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 1);
+
+       alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL);
+       if (alrm_ctrl & RTC7301_ALARM_CONTROL_AF) {
+               ret = IRQ_HANDLED;
+               rtc7301_alarm_irq(priv, false);
+               rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return ret;
+}
+
+static void rtc7301_init(struct rtc7301_priv *priv)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 2);
+       rtc7301_write(priv, 0, RTC7301_TIMER_CONTROL);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int __init rtc7301_rtc_probe(struct platform_device *dev)
+{
+       struct resource *res;
+       void __iomem *regs;
+       struct rtc7301_priv *priv;
+       struct rtc_device *rtc;
+       int ret;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       regs = devm_ioremap_resource(&dev->dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       priv->regmap = devm_regmap_init_mmio(&dev->dev, regs,
+                                            &rtc7301_regmap_config);
+       if (IS_ERR(priv->regmap))
+               return PTR_ERR(priv->regmap);
+
+       priv->irq = platform_get_irq(dev, 0);
+
+       spin_lock_init(&priv->lock);
+       priv->bank = -1;
+
+       rtc7301_init(priv);
+
+       platform_set_drvdata(dev, priv);
+
+       rtc = devm_rtc_device_register(&dev->dev, DRV_NAME, &rtc7301_rtc_ops,
+                                      THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       if (priv->irq > 0) {
+               ret = devm_request_irq(&dev->dev, priv->irq,
+                                      rtc7301_irq_handler, IRQF_SHARED,
+                                      dev_name(&dev->dev), rtc);
+               if (ret) {
+                       priv->irq = 0;
+                       dev_err(&dev->dev, "unable to request IRQ\n");
+               } else {
+                       device_set_wakeup_capable(&dev->dev, true);
+               }
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int rtc7301_suspend(struct device *dev)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(priv->irq);
+
+       return 0;
+}
+
+static int rtc7301_resume(struct device *dev)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(priv->irq);
+
+       return 0;
+}
+
+#endif
+
+static SIMPLE_DEV_PM_OPS(rtc7301_pm_ops, rtc7301_suspend, rtc7301_resume);
+
+static const struct of_device_id rtc7301_dt_match[] = {
+       { .compatible = "epson,rtc7301sf" },
+       { .compatible = "epson,rtc7301dg" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, rtc7301_dt_match);
+
+static struct platform_driver rtc7301_rtc_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = rtc7301_dt_match,
+               .pm = &rtc7301_pm_ops,
+       },
+};
+
+module_platform_driver_probe(rtc7301_rtc_driver, rtc7301_rtc_probe);
+
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EPSON TOYOCOM RTC-7301SF/DG Driver");
+MODULE_ALIAS("platform:rtc-r7301");
index 83a057a0306072ff5efc4beebbcc6f5727b30307..7fc36973fa330e4845b84f688800d6903556de38 100644 (file)
@@ -1,20 +1,18 @@
 /* rtc-starfire.c: Starfire platform RTC driver.
+ *
+ * Author: David S. Miller
+ * License: GPL
  *
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
 
 #include <asm/oplib.h>
 
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_DESCRIPTION("Starfire RTC driver");
-MODULE_LICENSE("GPL");
-
 static u32 starfire_get_time(void)
 {
        static char obp_gettod[32];
@@ -57,4 +55,4 @@ static struct platform_driver starfire_rtc_driver = {
        },
 };
 
-module_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);
+builtin_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);
index 7c696c12f28f8cf36bdbc281ffcf3d52a68b133d..11bc562eba5dfb7d9aa749ff9e951397b9d6c7a8 100644 (file)
@@ -1,4 +1,7 @@
 /* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems.
+ *
+ * Author: David S. Miller
+ * License: GPL
  *
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
@@ -6,7 +9,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/rtc.h>
@@ -98,8 +100,4 @@ static struct platform_driver sun4v_rtc_driver = {
        },
 };
 
-module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
-
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_DESCRIPTION("SUN4V RTC driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
index 176720b7b9e5083195b3bd789dbf5a8a622cd6c8..c18c39212ce680929b72c07e0ebe6305bb2675d8 100644 (file)
 
 #include <linux/i2c/twl.h>
 
+enum twl_class {
+       TWL_4030 = 0,
+       TWL_6030,
+};
 
 /*
  * RTC block register offsets (use TWL_MODULE_RTC)
@@ -136,16 +140,30 @@ static const u8 twl6030_rtc_reg_map[] = {
 #define ALL_TIME_REGS          6
 
 /*----------------------------------------------------------------------*/
-static u8  *rtc_reg_map;
+struct twl_rtc {
+       struct device *dev;
+       struct rtc_device *rtc;
+       u8 *reg_map;
+       /*
+        * Cache the value for timer/alarm interrupts register; this is
+        * only changed by callers holding rtc ops lock (or resume).
+        */
+       unsigned char rtc_irq_bits;
+       bool wake_enabled;
+#ifdef CONFIG_PM_SLEEP
+       unsigned char irqstat;
+#endif
+       enum twl_class class;
+};
 
 /*
  * Supports 1 byte read from TWL RTC register.
  */
-static int twl_rtc_read_u8(u8 *data, u8 reg)
+static int twl_rtc_read_u8(struct twl_rtc *twl_rtc, u8 *data, u8 reg)
 {
        int ret;
 
-       ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
+       ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
        if (ret < 0)
                pr_err("Could not read TWL register %X - error %d\n", reg, ret);
        return ret;
@@ -154,40 +172,34 @@ static int twl_rtc_read_u8(u8 *data, u8 reg)
 /*
  * Supports 1 byte write to TWL RTC registers.
  */
-static int twl_rtc_write_u8(u8 data, u8 reg)
+static int twl_rtc_write_u8(struct twl_rtc *twl_rtc, u8 data, u8 reg)
 {
        int ret;
 
-       ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
+       ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
        if (ret < 0)
                pr_err("Could not write TWL register %X - error %d\n",
                       reg, ret);
        return ret;
 }
 
-/*
- * Cache the value for timer/alarm interrupts register; this is
- * only changed by callers holding rtc ops lock (or resume).
- */
-static unsigned char rtc_irq_bits;
-
 /*
  * Enable 1/second update and/or alarm interrupts.
  */
-static int set_rtc_irq_bit(unsigned char bit)
+static int set_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
 {
        unsigned char val;
        int ret;
 
        /* if the bit is set, return from here */
-       if (rtc_irq_bits & bit)
+       if (twl_rtc->rtc_irq_bits & bit)
                return 0;
 
-       val = rtc_irq_bits | bit;
+       val = twl_rtc->rtc_irq_bits | bit;
        val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
-       ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+       ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
        if (ret == 0)
-               rtc_irq_bits = val;
+               twl_rtc->rtc_irq_bits = val;
 
        return ret;
 }
@@ -195,19 +207,19 @@ static int set_rtc_irq_bit(unsigned char bit)
 /*
  * Disable update and/or alarm interrupts.
  */
-static int mask_rtc_irq_bit(unsigned char bit)
+static int mask_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
 {
        unsigned char val;
        int ret;
 
        /* if the bit is clear, return from here */
-       if (!(rtc_irq_bits & bit))
+       if (!(twl_rtc->rtc_irq_bits & bit))
                return 0;
 
-       val = rtc_irq_bits & ~bit;
-       ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+       val = twl_rtc->rtc_irq_bits & ~bit;
+       ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
        if (ret == 0)
-               rtc_irq_bits = val;
+               twl_rtc->rtc_irq_bits = val;
 
        return ret;
 }
@@ -215,21 +227,23 @@ static int mask_rtc_irq_bit(unsigned char bit)
 static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
 {
        struct platform_device *pdev = to_platform_device(dev);
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
        int irq = platform_get_irq(pdev, 0);
-       static bool twl_rtc_wake_enabled;
        int ret;
 
        if (enabled) {
-               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-               if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) {
+               ret = set_rtc_irq_bit(twl_rtc,
+                                     BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+               if (device_can_wakeup(dev) && !twl_rtc->wake_enabled) {
                        enable_irq_wake(irq);
-                       twl_rtc_wake_enabled = true;
+                       twl_rtc->wake_enabled = true;
                }
        } else {
-               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-               if (twl_rtc_wake_enabled) {
+               ret = mask_rtc_irq_bit(twl_rtc,
+                                      BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+               if (twl_rtc->wake_enabled) {
                        disable_irq_wake(irq);
-                       twl_rtc_wake_enabled = false;
+                       twl_rtc->wake_enabled = false;
                }
        }
 
@@ -247,21 +261,23 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
  */
 static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
        unsigned char rtc_data[ALL_TIME_REGS];
        int ret;
        u8 save_control;
        u8 rtc_control;
 
-       ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
        if (ret < 0) {
                dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret);
                return ret;
        }
        /* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */
-       if (twl_class_is_6030()) {
+       if (twl_rtc->class == TWL_6030) {
                if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) {
                        save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M;
-                       ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+                       ret = twl_rtc_write_u8(twl_rtc, save_control,
+                                              REG_RTC_CTRL_REG);
                        if (ret < 0) {
                                dev_err(dev, "%s clr GET_TIME, error %d\n",
                                        __func__, ret);
@@ -274,17 +290,17 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
        rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M;
 
        /* for twl6030/32 enable read access to static shadowed registers */
-       if (twl_class_is_6030())
+       if (twl_rtc->class == TWL_6030)
                rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT;
 
-       ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_write_u8(twl_rtc, rtc_control, REG_RTC_CTRL_REG);
        if (ret < 0) {
                dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret);
                return ret;
        }
 
        ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
-                       (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
+                       (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
 
        if (ret < 0) {
                dev_err(dev, "%s: reading data, error %d\n", __func__, ret);
@@ -292,8 +308,8 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
        }
 
        /* for twl6030 restore original state of rtc control register */
-       if (twl_class_is_6030()) {
-               ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       if (twl_rtc->class == TWL_6030) {
+               ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
                if (ret < 0) {
                        dev_err(dev, "%s: restore CTRL_REG, error %d\n",
                                __func__, ret);
@@ -313,6 +329,7 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
 static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
        unsigned char save_control;
        unsigned char rtc_data[ALL_TIME_REGS];
        int ret;
@@ -325,18 +342,18 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
        rtc_data[5] = bin2bcd(tm->tm_year - 100);
 
        /* Stop RTC while updating the TC registers */
-       ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
        if (ret < 0)
                goto out;
 
        save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
-       ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
        if (ret < 0)
                goto out;
 
        /* update all the time registers in one shot */
        ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
-               (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
+               (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
        if (ret < 0) {
                dev_err(dev, "rtc_set_time error %d\n", ret);
                goto out;
@@ -344,7 +361,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
 
        /* Start back RTC */
        save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
-       ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
 
 out:
        return ret;
@@ -355,11 +372,12 @@ out:
  */
 static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
        unsigned char rtc_data[ALL_TIME_REGS];
        int ret;
 
        ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
-                       (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
+                       twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
        if (ret < 0) {
                dev_err(dev, "rtc_read_alarm error %d\n", ret);
                return ret;
@@ -374,7 +392,7 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
        alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
 
        /* report cached alarm enable state */
-       if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
+       if (twl_rtc->rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
                alm->enabled = 1;
 
        return ret;
@@ -382,6 +400,8 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
 static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
        unsigned char alarm_data[ALL_TIME_REGS];
        int ret;
 
@@ -398,7 +418,7 @@ static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
        /* update all the alarm registers in one shot */
        ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
-               (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
+                       twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
        if (ret) {
                dev_err(dev, "rtc_set_alarm error %d\n", ret);
                goto out;
@@ -410,14 +430,15 @@ out:
        return ret;
 }
 
-static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
+static irqreturn_t twl_rtc_interrupt(int irq, void *data)
 {
+       struct twl_rtc *twl_rtc = data;
        unsigned long events;
        int ret = IRQ_NONE;
        int res;
        u8 rd_reg;
 
-       res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+       res = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
        if (res)
                goto out;
        /*
@@ -431,12 +452,12 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
        else
                events = RTC_IRQF | RTC_PF;
 
-       res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M,
-                                  REG_RTC_STATUS_REG);
+       res = twl_rtc_write_u8(twl_rtc, BIT_RTC_STATUS_REG_ALARM_M,
+                              REG_RTC_STATUS_REG);
        if (res)
                goto out;
 
-       if (twl_class_is_4030()) {
+       if (twl_rtc->class == TWL_4030) {
                /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
                 * needs 2 reads to clear the interrupt. One read is done in
                 * do_twl_pwrirq(). Doing the second read, to clear
@@ -455,7 +476,7 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
        }
 
        /* Notify RTC core on event */
-       rtc_update_irq(rtc, 1, events);
+       rtc_update_irq(twl_rtc->rtc, 1, events);
 
        ret = IRQ_HANDLED;
 out:
@@ -474,21 +495,36 @@ static const struct rtc_class_ops twl_rtc_ops = {
 
 static int twl_rtc_probe(struct platform_device *pdev)
 {
-       struct rtc_device *rtc;
+       struct twl_rtc *twl_rtc;
+       struct device_node *np = pdev->dev.of_node;
        int ret = -EINVAL;
        int irq = platform_get_irq(pdev, 0);
        u8 rd_reg;
 
+       if (!np) {
+               dev_err(&pdev->dev, "no DT info\n");
+               return -EINVAL;
+       }
+
        if (irq <= 0)
                return ret;
 
-       /* Initialize the register map */
-       if (twl_class_is_4030())
-               rtc_reg_map = (u8 *)twl4030_rtc_reg_map;
-       else
-               rtc_reg_map = (u8 *)twl6030_rtc_reg_map;
+       twl_rtc = devm_kzalloc(&pdev->dev, sizeof(*twl_rtc), GFP_KERNEL);
+       if (!twl_rtc)
+               return -ENOMEM;
 
-       ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+       if (twl_class_is_4030()) {
+               twl_rtc->class = TWL_4030;
+               twl_rtc->reg_map = (u8 *)twl4030_rtc_reg_map;
+       } else if (twl_class_is_6030()) {
+               twl_rtc->class = TWL_6030;
+               twl_rtc->reg_map = (u8 *)twl6030_rtc_reg_map;
+       } else {
+               dev_err(&pdev->dev, "TWL Class not supported.\n");
+               return -EINVAL;
+       }
+
+       ret = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
        if (ret < 0)
                return ret;
 
@@ -499,11 +535,11 @@ static int twl_rtc_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
 
        /* Clear RTC Power up reset and pending alarm interrupts */
-       ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
+       ret = twl_rtc_write_u8(twl_rtc, rd_reg, REG_RTC_STATUS_REG);
        if (ret < 0)
                return ret;
 
-       if (twl_class_is_6030()) {
+       if (twl_rtc->class == TWL_6030) {
                twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
                        REG_INT_MSK_LINE_A);
                twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
@@ -511,40 +547,42 @@ static int twl_rtc_probe(struct platform_device *pdev)
        }
 
        dev_info(&pdev->dev, "Enabling TWL-RTC\n");
-       ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG);
+       ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M,
+                              REG_RTC_CTRL_REG);
        if (ret < 0)
                return ret;
 
        /* ensure interrupts are disabled, bootloaders can be strange */
-       ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG);
+       ret = twl_rtc_write_u8(twl_rtc, 0, REG_RTC_INTERRUPTS_REG);
        if (ret < 0)
                dev_warn(&pdev->dev, "unable to disable interrupt\n");
 
        /* init cached IRQ enable bits */
-       ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
+       ret = twl_rtc_read_u8(twl_rtc, &twl_rtc->rtc_irq_bits,
+                             REG_RTC_INTERRUPTS_REG);
        if (ret < 0)
                return ret;
 
+       platform_set_drvdata(pdev, twl_rtc);
        device_init_wakeup(&pdev->dev, 1);
 
-       rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+       twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                                        &twl_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
+       if (IS_ERR(twl_rtc->rtc)) {
                dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
-                       PTR_ERR(rtc));
-               return PTR_ERR(rtc);
+                       PTR_ERR(twl_rtc->rtc));
+               return PTR_ERR(twl_rtc->rtc);
        }
 
        ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                                        twl_rtc_interrupt,
                                        IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                       dev_name(&rtc->dev), rtc);
+                                       dev_name(&twl_rtc->rtc->dev), twl_rtc);
        if (ret < 0) {
                dev_err(&pdev->dev, "IRQ is not free.\n");
                return ret;
        }
 
-       platform_set_drvdata(pdev, rtc);
        return 0;
 }
 
@@ -554,10 +592,12 @@ static int twl_rtc_probe(struct platform_device *pdev)
  */
 static int twl_rtc_remove(struct platform_device *pdev)
 {
+       struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
+
        /* leave rtc running, but disable irqs */
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-       if (twl_class_is_6030()) {
+       mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       if (twl_rtc->class == TWL_6030) {
                twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
                        REG_INT_MSK_LINE_A);
                twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
@@ -569,40 +609,40 @@ static int twl_rtc_remove(struct platform_device *pdev)
 
 static void twl_rtc_shutdown(struct platform_device *pdev)
 {
+       struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
+
        /* mask timer interrupts, but leave alarm interrupts on to enable
           power-on when alarm is triggered */
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
 }
 
 #ifdef CONFIG_PM_SLEEP
-static unsigned char irqstat;
-
 static int twl_rtc_suspend(struct device *dev)
 {
-       irqstat = rtc_irq_bits;
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
+       twl_rtc->irqstat = twl_rtc->rtc_irq_bits;
 
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
        return 0;
 }
 
 static int twl_rtc_resume(struct device *dev)
 {
-       set_rtc_irq_bit(irqstat);
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
+       set_rtc_irq_bit(twl_rtc, twl_rtc->irqstat);
        return 0;
 }
 #endif
 
 static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume);
 
-#ifdef CONFIG_OF
 static const struct of_device_id twl_rtc_of_match[] = {
        {.compatible = "ti,twl4030-rtc", },
        { },
 };
 MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
-#endif
-
-MODULE_ALIAS("platform:twl_rtc");
 
 static struct platform_driver twl4030rtc_driver = {
        .probe          = twl_rtc_probe,
@@ -611,7 +651,7 @@ static struct platform_driver twl4030rtc_driver = {
        .driver         = {
                .name           = "twl_rtc",
                .pm             = &twl_rtc_pm_ops,
-               .of_match_table = of_match_ptr(twl_rtc_of_match),
+               .of_match_table = twl_rtc_of_match,
        },
 };
 
index 82c7c48aa619c7090127025664f58eaed769cc5a..cd77b55d3895462e144071651f91ddce2185ef8e 100644 (file)
@@ -149,7 +149,6 @@ static const char *ll_get_link(struct dentry *dentry,
 }
 
 const struct inode_operations ll_fast_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .setattr        = ll_setattr,
        .get_link       = ll_get_link,
        .getattr        = ll_getattr,
index 5ca1fb0043f6505c6958a16bc2c9688d7af6a291..adaf6f6dd858cb9b0a6b0077782d068b3d024e0b 100644 (file)
@@ -310,18 +310,10 @@ static int v9fs_write_end(struct file *filp, struct address_space *mapping,
 
        p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
 
-       if (unlikely(copied < len)) {
-               /*
-                * zero out the rest of the area
-                */
-               unsigned from = pos & (PAGE_SIZE - 1);
-
-               zero_user(page, from + copied, len - copied);
-               flush_dcache_page(page);
+       if (unlikely(copied < len && !PageUptodate(page))) {
+               copied = 0;
+               goto out;
        }
-
-       if (!PageUptodate(page))
-               SetPageUptodate(page);
        /*
         * No need to use i_size_read() here, the i_size
         * cannot change under us because we hold the i_mutex.
@@ -331,6 +323,7 @@ static int v9fs_write_end(struct file *filp, struct address_space *mapping,
                i_size_write(inode, last_pos);
        }
        set_page_dirty(page);
+out:
        unlock_page(page);
        put_page(page);
 
index 30ca770c5e0b854d51abeb5193882a12503c8f8d..f4f4450119e42f74c1bc3269cc07ee798f9bc49b 100644 (file)
@@ -1464,7 +1464,6 @@ static const struct inode_operations v9fs_file_inode_operations = {
 };
 
 static const struct inode_operations v9fs_symlink_inode_operations = {
-       .readlink = generic_readlink,
        .get_link = v9fs_vfs_get_link,
        .getattr = v9fs_vfs_getattr,
        .setattr = v9fs_vfs_setattr,
index afaa4b6de8018f37f6bbc2c8595c0af01d14fdef..5999bd050678cd333ffa0f7e6e88f6a575e5a885 100644 (file)
@@ -979,7 +979,6 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {
 };
 
 const struct inode_operations v9fs_symlink_inode_operations_dotl = {
-       .readlink = generic_readlink,
        .get_link = v9fs_vfs_get_link_dotl,
        .getattr = v9fs_vfs_getattr_dotl,
        .setattr = v9fs_vfs_setattr_dotl,
index 69b03dbb792f7a080abc70f5d45ff4bf50d458b9..ae622cdce142264af53127a8d94730c64a0d74d2 100644 (file)
@@ -70,7 +70,6 @@ const struct address_space_operations affs_symlink_aops = {
 };
 
 const struct inode_operations affs_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .setattr        = affs_notify_change,
 };
index a1fba4285277dde3af647d778b8aefd4c36d2261..c885daae68c8ee9687ea6be1fdb17ce3d3bf603b 100644 (file)
@@ -145,7 +145,7 @@ void autofs4_free_ino(struct autofs_info *);
 
 /* Expiration */
 int is_autofs4_dentry(struct dentry *);
-int autofs4_expire_wait(struct dentry *dentry, int rcu_walk);
+int autofs4_expire_wait(const struct path *path, int rcu_walk);
 int autofs4_expire_run(struct super_block *, struct vfsmount *,
                       struct autofs_sb_info *,
                       struct autofs_packet_expire __user *);
@@ -217,7 +217,8 @@ static inline int autofs_prepare_pipe(struct file *pipe)
 
 /* Queue management functions */
 
-int autofs4_wait(struct autofs_sb_info *, struct dentry *, enum autofs_notify);
+int autofs4_wait(struct autofs_sb_info *,
+                const struct path *, enum autofs_notify);
 int autofs4_wait_release(struct autofs_sb_info *, autofs_wqt_t, int);
 void autofs4_catatonic_mode(struct autofs_sb_info *);
 
index fc09eb77ddf37a4ae27af402553220e4287af92e..6f48d670c9415ce610980e6288d118623cd237d1 100644 (file)
@@ -204,7 +204,7 @@ static int autofs_dev_ioctl_protosubver(struct file *fp,
 /* Find the topmost mount satisfying test() */
 static int find_autofs_mount(const char *pathname,
                             struct path *res,
-                            int test(struct path *path, void *data),
+                            int test(const struct path *path, void *data),
                             void *data)
 {
        struct path path;
@@ -230,12 +230,12 @@ static int find_autofs_mount(const char *pathname,
        return err;
 }
 
-static int test_by_dev(struct path *path, void *p)
+static int test_by_dev(const struct path *path, void *p)
 {
        return path->dentry->d_sb->s_dev == *(dev_t *)p;
 }
 
-static int test_by_type(struct path *path, void *p)
+static int test_by_type(const struct path *path, void *p)
 {
        struct autofs_info *ino = autofs4_dentry_ino(path->dentry);
 
@@ -468,7 +468,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
        ino = autofs4_dentry_ino(path.dentry);
        if (ino) {
                err = 0;
-               autofs4_expire_wait(path.dentry, 0);
+               autofs4_expire_wait(&path, 0);
                spin_lock(&sbi->fs_lock);
                param->requester.uid =
                        from_kuid_munged(current_user_ns(), ino->uid);
@@ -575,7 +575,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
 
                devid = new_encode_dev(dev);
 
-               err = have_submounts(path.dentry);
+               err = path_has_submounts(&path);
 
                if (follow_down_one(&path))
                        magic = path.dentry->d_sb->s_magic;
index d8e6d421c27fb74eed07369e83278183bb394f82..57725d4a8c59e4b9293c29087e71c3d7f7b0d884 100644 (file)
@@ -310,26 +310,29 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
        now = jiffies;
        timeout = sbi->exp_timeout;
 
-       spin_lock(&sbi->fs_lock);
-       ino = autofs4_dentry_ino(root);
-       /* No point expiring a pending mount */
-       if (ino->flags & AUTOFS_INF_PENDING)
-               goto out;
        if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
+               spin_lock(&sbi->fs_lock);
+               ino = autofs4_dentry_ino(root);
+               /* No point expiring a pending mount */
+               if (ino->flags & AUTOFS_INF_PENDING) {
+                       spin_unlock(&sbi->fs_lock);
+                       goto out;
+               }
                ino->flags |= AUTOFS_INF_WANT_EXPIRE;
                spin_unlock(&sbi->fs_lock);
                synchronize_rcu();
-               spin_lock(&sbi->fs_lock);
                if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
+                       spin_lock(&sbi->fs_lock);
                        ino->flags |= AUTOFS_INF_EXPIRING;
                        init_completion(&ino->expire_complete);
                        spin_unlock(&sbi->fs_lock);
                        return root;
                }
+               spin_lock(&sbi->fs_lock);
                ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
+               spin_unlock(&sbi->fs_lock);
        }
 out:
-       spin_unlock(&sbi->fs_lock);
        dput(root);
 
        return NULL;
@@ -495,8 +498,9 @@ found:
        return expired;
 }
 
-int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
+int autofs4_expire_wait(const struct path *path, int rcu_walk)
 {
+       struct dentry *dentry = path->dentry;
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
        int status;
@@ -525,7 +529,7 @@ retry:
 
                pr_debug("waiting for expire %p name=%pd\n", dentry, dentry);
 
-               status = autofs4_wait(sbi, dentry, NFY_NONE);
+               status = autofs4_wait(sbi, path, NFY_NONE);
                wait_for_completion(&ino->expire_complete);
 
                pr_debug("expire done status=%d\n", status);
@@ -592,11 +596,12 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
 
        if (dentry) {
                struct autofs_info *ino = autofs4_dentry_ino(dentry);
+               const struct path path = { .mnt = mnt, .dentry = dentry };
 
                /* This is synchronous because it makes the daemon a
                 * little easier
                 */
-               ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
+               ret = autofs4_wait(sbi, &path, NFY_EXPIRE);
 
                spin_lock(&sbi->fs_lock);
                /* avoid rapid-fire expire attempts if expiry fails */
index a11f7317487773617dd585197e7482f5e22a3045..82e8f6edfb48d0e8670dd58e3fbdcfb4b5ceb85d 100644 (file)
@@ -32,7 +32,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file);
 static struct dentry *autofs4_lookup(struct inode *,
                                     struct dentry *, unsigned int);
 static struct vfsmount *autofs4_d_automount(struct path *);
-static int autofs4_d_manage(struct dentry *, bool);
+static int autofs4_d_manage(const struct path *, bool);
 static void autofs4_dentry_release(struct dentry *);
 
 const struct file_operations autofs4_root_operations = {
@@ -123,7 +123,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
         * it.
         */
        spin_lock(&sbi->lookup_lock);
-       if (!d_mountpoint(dentry) && simple_empty(dentry)) {
+       if (!path_is_mountpoint(&file->f_path) && simple_empty(dentry)) {
                spin_unlock(&sbi->lookup_lock);
                return -ENOENT;
        }
@@ -269,39 +269,41 @@ next:
        return NULL;
 }
 
-static int autofs4_mount_wait(struct dentry *dentry, bool rcu_walk)
+static int autofs4_mount_wait(const struct path *path, bool rcu_walk)
 {
-       struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
-       struct autofs_info *ino = autofs4_dentry_ino(dentry);
+       struct autofs_sb_info *sbi = autofs4_sbi(path->dentry->d_sb);
+       struct autofs_info *ino = autofs4_dentry_ino(path->dentry);
        int status = 0;
 
        if (ino->flags & AUTOFS_INF_PENDING) {
                if (rcu_walk)
                        return -ECHILD;
-               pr_debug("waiting for mount name=%pd\n", dentry);
-               status = autofs4_wait(sbi, dentry, NFY_MOUNT);
+               pr_debug("waiting for mount name=%pd\n", path->dentry);
+               status = autofs4_wait(sbi, path, NFY_MOUNT);
                pr_debug("mount wait done status=%d\n", status);
        }
        ino->last_used = jiffies;
        return status;
 }
 
-static int do_expire_wait(struct dentry *dentry, bool rcu_walk)
+static int do_expire_wait(const struct path *path, bool rcu_walk)
 {
+       struct dentry *dentry = path->dentry;
        struct dentry *expiring;
 
        expiring = autofs4_lookup_expiring(dentry, rcu_walk);
        if (IS_ERR(expiring))
                return PTR_ERR(expiring);
        if (!expiring)
-               return autofs4_expire_wait(dentry, rcu_walk);
+               return autofs4_expire_wait(path, rcu_walk);
        else {
+               const struct path this = { .mnt = path->mnt, .dentry = expiring };
                /*
                 * If we are racing with expire the request might not
                 * be quite complete, but the directory has been removed
                 * so it must have been successful, just wait for it.
                 */
-               autofs4_expire_wait(expiring, 0);
+               autofs4_expire_wait(&this, 0);
                autofs4_del_expiring(expiring);
                dput(expiring);
        }
@@ -354,7 +356,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
         * and the directory was removed, so just go ahead and try
         * the mount.
         */
-       status = do_expire_wait(dentry, 0);
+       status = do_expire_wait(path, 0);
        if (status && status != -EAGAIN)
                return NULL;
 
@@ -362,7 +364,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
        spin_lock(&sbi->fs_lock);
        if (ino->flags & AUTOFS_INF_PENDING) {
                spin_unlock(&sbi->fs_lock);
-               status = autofs4_mount_wait(dentry, 0);
+               status = autofs4_mount_wait(path, 0);
                if (status)
                        return ERR_PTR(status);
                goto done;
@@ -370,28 +372,28 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
 
        /*
         * If the dentry is a symlink it's equivalent to a directory
-        * having d_mountpoint() true, so there's no need to call back
-        * to the daemon.
+        * having path_is_mountpoint() true, so there's no need to call
+        * back to the daemon.
         */
        if (d_really_is_positive(dentry) && d_is_symlink(dentry)) {
                spin_unlock(&sbi->fs_lock);
                goto done;
        }
 
-       if (!d_mountpoint(dentry)) {
+       if (!path_is_mountpoint(path)) {
                /*
                 * It's possible that user space hasn't removed directories
                 * after umounting a rootless multi-mount, although it
-                * should. For v5 have_submounts() is sufficient to handle
-                * this because the leaves of the directory tree under the
-                * mount never trigger mounts themselves (they have an autofs
-                * trigger mount mounted on them). But v4 pseudo direct mounts
-                * do need the leaves to trigger mounts. In this case we
-                * have no choice but to use the list_empty() check and
+                * should. For v5 path_has_submounts() is sufficient to
+                * handle this because the leaves of the directory tree under
+                * the mount never trigger mounts themselves (they have an
+                * autofs trigger mount mounted on them). But v4 pseudo direct
+                * mounts do need the leaves to trigger mounts. In this case
+                * we have no choice but to use the list_empty() check and
                 * require user space behave.
                 */
                if (sbi->version > 4) {
-                       if (have_submounts(dentry)) {
+                       if (path_has_submounts(path)) {
                                spin_unlock(&sbi->fs_lock);
                                goto done;
                        }
@@ -403,7 +405,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
                }
                ino->flags |= AUTOFS_INF_PENDING;
                spin_unlock(&sbi->fs_lock);
-               status = autofs4_mount_wait(dentry, 0);
+               status = autofs4_mount_wait(path, 0);
                spin_lock(&sbi->fs_lock);
                ino->flags &= ~AUTOFS_INF_PENDING;
                if (status) {
@@ -421,8 +423,9 @@ done:
        return NULL;
 }
 
-static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
+static int autofs4_d_manage(const struct path *path, bool rcu_walk)
 {
+       struct dentry *dentry = path->dentry;
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
        int status;
@@ -431,20 +434,20 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
 
        /* The daemon never waits. */
        if (autofs4_oz_mode(sbi)) {
-               if (!d_mountpoint(dentry))
+               if (!path_is_mountpoint(path))
                        return -EISDIR;
                return 0;
        }
 
        /* Wait for pending expires */
-       if (do_expire_wait(dentry, rcu_walk) == -ECHILD)
+       if (do_expire_wait(path, rcu_walk) == -ECHILD)
                return -ECHILD;
 
        /*
         * This dentry may be under construction so wait on mount
         * completion.
         */
-       status = autofs4_mount_wait(dentry, rcu_walk);
+       status = autofs4_mount_wait(path, rcu_walk);
        if (status)
                return status;
 
@@ -460,7 +463,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
 
                if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
                        return 0;
-               if (d_mountpoint(dentry))
+               if (path_is_mountpoint(path))
                        return 0;
                inode = d_inode_rcu(dentry);
                if (inode && S_ISLNK(inode->i_mode))
@@ -487,7 +490,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
                 * we can avoid needless calls ->d_automount() and avoid
                 * an incorrect ELOOP error return.
                 */
-               if ((!d_mountpoint(dentry) && !simple_empty(dentry)) ||
+               if ((!path_is_mountpoint(path) && !simple_empty(dentry)) ||
                    (d_really_is_positive(dentry) && d_is_symlink(dentry)))
                        status = -EISDIR;
        }
index 99aab00dc21763505adbe5a1d8d992a83e131aaf..ab0b4285a202c77ded6ab0c36d75621db281d1bc 100644 (file)
@@ -25,6 +25,5 @@ static const char *autofs4_get_link(struct dentry *dentry,
 }
 
 const struct inode_operations autofs4_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = autofs4_get_link
 };
index e44271dfceb6f8fd0740436d1754821914b7f9bf..1278335ce366da6d899ce76017a6f94fc6b17d78 100644 (file)
@@ -250,8 +250,9 @@ autofs4_find_wait(struct autofs_sb_info *sbi, const struct qstr *qstr)
 static int validate_request(struct autofs_wait_queue **wait,
                            struct autofs_sb_info *sbi,
                            const struct qstr *qstr,
-                           struct dentry *dentry, enum autofs_notify notify)
+                           const struct path *path, enum autofs_notify notify)
 {
+       struct dentry *dentry = path->dentry;
        struct autofs_wait_queue *wq;
        struct autofs_info *ino;
 
@@ -314,6 +315,7 @@ static int validate_request(struct autofs_wait_queue **wait,
         */
        if (notify == NFY_MOUNT) {
                struct dentry *new = NULL;
+               struct path this;
                int valid = 1;
 
                /*
@@ -333,7 +335,9 @@ static int validate_request(struct autofs_wait_queue **wait,
                                        dentry = new;
                        }
                }
-               if (have_submounts(dentry))
+               this.mnt = path->mnt;
+               this.dentry = dentry;
+               if (path_has_submounts(&this))
                        valid = 0;
 
                if (new)
@@ -345,8 +349,9 @@ static int validate_request(struct autofs_wait_queue **wait,
 }
 
 int autofs4_wait(struct autofs_sb_info *sbi,
-                struct dentry *dentry, enum autofs_notify notify)
+                const struct path *path, enum autofs_notify notify)
 {
+       struct dentry *dentry = path->dentry;
        struct autofs_wait_queue *wq;
        struct qstr qstr;
        char *name;
@@ -405,7 +410,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
                return -EINTR;
        }
 
-       ret = validate_request(&wq, sbi, &qstr, dentry, notify);
+       ret = validate_request(&wq, sbi, &qstr, path, notify);
        if (ret <= 0) {
                if (ret != -EINTR)
                        mutex_unlock(&sbi->wq_mutex);
index 8712062275b83fb7f2995106c80b5e7e39292c21..5f685c8192981864c3e273acce95dacc40494367 100644 (file)
@@ -106,6 +106,50 @@ static ssize_t bad_inode_listxattr(struct dentry *dentry, char *buffer,
        return -EIO;
 }
 
+static const char *bad_inode_get_link(struct dentry *dentry,
+                                     struct inode *inode,
+                                     struct delayed_call *done)
+{
+       return ERR_PTR(-EIO);
+}
+
+static struct posix_acl *bad_inode_get_acl(struct inode *inode, int type)
+{
+       return ERR_PTR(-EIO);
+}
+
+static int bad_inode_fiemap(struct inode *inode,
+                           struct fiemap_extent_info *fieinfo, u64 start,
+                           u64 len)
+{
+       return -EIO;
+}
+
+static int bad_inode_update_time(struct inode *inode, struct timespec *time,
+                                int flags)
+{
+       return -EIO;
+}
+
+static int bad_inode_atomic_open(struct inode *inode, struct dentry *dentry,
+                                struct file *file, unsigned int open_flag,
+                                umode_t create_mode, int *opened)
+{
+       return -EIO;
+}
+
+static int bad_inode_tmpfile(struct inode *inode, struct dentry *dentry,
+                            umode_t mode)
+{
+       return -EIO;
+}
+
+static int bad_inode_set_acl(struct inode *inode, struct posix_acl *acl,
+                            int type)
+{
+       return -EIO;
+}
+
 static const struct inode_operations bad_inode_ops =
 {
        .create         = bad_inode_create,
@@ -118,14 +162,17 @@ static const struct inode_operations bad_inode_ops =
        .mknod          = bad_inode_mknod,
        .rename         = bad_inode_rename2,
        .readlink       = bad_inode_readlink,
-       /* follow_link must be no-op, otherwise unmounting this inode
-          won't work */
-       /* put_link returns void */
-       /* truncate returns void */
        .permission     = bad_inode_permission,
        .getattr        = bad_inode_getattr,
        .setattr        = bad_inode_setattr,
        .listxattr      = bad_inode_listxattr,
+       .get_link       = bad_inode_get_link,
+       .get_acl        = bad_inode_get_acl,
+       .fiemap         = bad_inode_fiemap,
+       .update_time    = bad_inode_update_time,
+       .atomic_open    = bad_inode_atomic_open,
+       .tmpfile        = bad_inode_tmpfile,
+       .set_acl        = bad_inode_set_acl,
 };
 
 
index 50bcfb80d33a012e0b0dc0daa6fe1aeb03d5b2cd..6a823719b6c580557cccab3d01123d50857ad334 100644 (file)
@@ -3232,9 +3232,6 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages,
                      size_t num_pages, loff_t pos, size_t write_bytes,
                      struct extent_state **cached);
 int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
-ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
-                             struct file *file_out, loff_t pos_out,
-                             size_t len, unsigned int flags);
 int btrfs_clone_file_range(struct file *file_in, loff_t pos_in,
                           struct file *file_out, loff_t pos_out, u64 len);
 
index 448f57d108d1d93fc35a119b37c87126a399dd5a..b5c5da215d051e2d3ef13673917b2f86b042edc8 100644 (file)
@@ -3033,7 +3033,6 @@ const struct file_operations btrfs_file_operations = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = btrfs_compat_ioctl,
 #endif
-       .copy_file_range = btrfs_copy_file_range,
        .clone_file_range = btrfs_clone_file_range,
        .dedupe_file_range = btrfs_dedupe_file_range,
 };
index c3b6ffa8e39d272981c0f3fe8134e97a93f0b360..f2b281ad7af6b9db26b48c6d4f072a850c19d58a 100644 (file)
@@ -10653,7 +10653,6 @@ static const struct inode_operations btrfs_special_inode_operations = {
        .update_time    = btrfs_update_time,
 };
 static const struct inode_operations btrfs_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .getattr        = btrfs_getattr,
        .setattr        = btrfs_setattr,
index 0a6902555e654e7ff5d99ab1a13d03cbca5ec139..33f967d30b2ad1d555015baea2bccc5eba05d1d5 100644 (file)
@@ -834,7 +834,7 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
  * sys_mkdirat and vfs_mkdir, but we only do a single component lookup
  * inside this filesystem so it's quite a bit simpler.
  */
-static noinline int btrfs_mksubvol(struct path *parent,
+static noinline int btrfs_mksubvol(const struct path *parent,
                                   char *name, int namelen,
                                   struct btrfs_root *snap_src,
                                   u64 *async_transid, bool readonly,
@@ -3987,18 +3987,6 @@ out_unlock:
        return ret;
 }
 
-ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
-                             struct file *file_out, loff_t pos_out,
-                             size_t len, unsigned int flags)
-{
-       ssize_t ret;
-
-       ret = btrfs_clone_files(file_out, file_in, pos_in, len, pos_out);
-       if (ret == 0)
-               ret = len;
-       return ret;
-}
-
 int btrfs_clone_file_range(struct file *src_file, loff_t off,
                struct file *dst_file, loff_t destoff, u64 len)
 {
index a0f1e2b91c8e0f46051e398b663f89220365f187..9cd0c0ea7cdbd5b683ab035927636f9f56b751d3 100644 (file)
@@ -1317,25 +1317,27 @@ static int ceph_write_end(struct file *file, struct address_space *mapping,
                          struct page *page, void *fsdata)
 {
        struct inode *inode = file_inode(file);
-       unsigned from = pos & (PAGE_SIZE - 1);
        int check_cap = 0;
 
        dout("write_end file %p inode %p page %p %d~%d (%d)\n", file,
             inode, page, (int)pos, (int)copied, (int)len);
 
        /* zero the stale part of the page if we did a short copy */
-       if (copied < len)
-               zero_user_segment(page, from+copied, len);
+       if (!PageUptodate(page)) {
+               if (copied < len) {
+                       copied = 0;
+                       goto out;
+               }
+               SetPageUptodate(page);
+       }
 
        /* did file size increase? */
        if (pos+copied > i_size_read(inode))
                check_cap = ceph_inode_set_size(inode, pos+copied);
 
-       if (!PageUptodate(page))
-               SetPageUptodate(page);
-
        set_page_dirty(page);
 
+out:
        unlock_page(page);
        put_page(page);
 
index 284f0d807151e4d28655e0087fa727164b701e64..398e5328b30952410cc503e7e4d20918d3bdc671 100644 (file)
@@ -1869,7 +1869,6 @@ retry:
  * symlinks
  */
 static const struct inode_operations ceph_symlink_iops = {
-       .readlink = generic_readlink,
        .get_link = simple_get_link,
        .setattr = ceph_setattr,
        .getattr = ceph_getattr,
index 15261ba464c5023f82014751fee8efaf09abec5f..e6efb9a8859892df6ded9d58334815439828d2ec 100644 (file)
@@ -914,7 +914,6 @@ const struct inode_operations cifs_file_inode_ops = {
 };
 
 const struct inode_operations cifs_symlink_inode_ops = {
-       .readlink = generic_readlink,
        .get_link = cifs_get_link,
        .permission = cifs_permission,
        .listxattr = cifs_listxattr,
index 1bfb7ba4e85e3ecc05000a3543a01917a7ed40a4..f13e09057c6b8297ce8f8572e880b953c4e4e864 100644 (file)
@@ -17,7 +17,6 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
 }
 
 static const struct inode_operations coda_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .setattr        = coda_setattr,
 };
index db6d692896088ebc9745d9c05c85309280885b38..a6ab012a2c6acf9815bb8d4d1e29fb4568084b08 100644 (file)
@@ -305,7 +305,6 @@ static const char *configfs_get_link(struct dentry *dentry,
 
 const struct inode_operations configfs_symlink_inode_operations = {
        .get_link = configfs_get_link,
-       .readlink = generic_readlink,
        .setattr = configfs_setattr,
 };
 
index 5c7cc953ac8191d80bc899f5bb510e9d71d7d69d..252378359a8f64eb69323dd88efa4747f20b488f 100644 (file)
@@ -1273,38 +1273,44 @@ rename_retry:
        goto again;
 }
 
-/*
- * Search for at least 1 mount point in the dentry's subdirs.
- * We descend to the next level whenever the d_subdirs
- * list is non-empty and continue searching.
- */
+struct check_mount {
+       struct vfsmount *mnt;
+       unsigned int mounted;
+};
 
-static enum d_walk_ret check_mount(void *data, struct dentry *dentry)
+static enum d_walk_ret path_check_mount(void *data, struct dentry *dentry)
 {
-       int *ret = data;
-       if (d_mountpoint(dentry)) {
-               *ret = 1;
+       struct check_mount *info = data;
+       struct path path = { .mnt = info->mnt, .dentry = dentry };
+
+       if (likely(!d_mountpoint(dentry)))
+               return D_WALK_CONTINUE;
+       if (__path_is_mountpoint(&path)) {
+               info->mounted = 1;
                return D_WALK_QUIT;
        }
        return D_WALK_CONTINUE;
 }
 
 /**
- * have_submounts - check for mounts over a dentry
- * @parent: dentry to check.
+ * path_has_submounts - check for mounts over a dentry in the
+ *                      current namespace.
+ * @parent: path to check.
  *
  * Return true if the parent or its subdirectories contain
- * a mount point
+ * a mount point in the current namespace.
  */
-int have_submounts(struct dentry *parent)
+int path_has_submounts(const struct path *parent)
 {
-       int ret = 0;
+       struct check_mount data = { .mnt = parent->mnt, .mounted = 0 };
 
-       d_walk(parent, &ret, check_mount, NULL);
+       read_seqlock_excl(&mount_lock);
+       d_walk(parent->dentry, &data, path_check_mount, NULL);
+       read_sequnlock_excl(&mount_lock);
 
-       return ret;
+       return data.mounted;
 }
-EXPORT_SYMBOL(have_submounts);
+EXPORT_SYMBOL(path_has_submounts);
 
 /*
  * Called by mount code to set a mountpoint and check if the mountpoint is
index ac44a69fbea9a533dbcc27cdc27771f4f7795f1e..a26a701ef512e840d21b9bdd7024ff1574e4b3c6 100644 (file)
@@ -90,7 +90,7 @@ static void hash_dcookie(struct dcookie_struct * dcs)
 }
 
 
-static struct dcookie_struct *alloc_dcookie(struct path *path)
+static struct dcookie_struct *alloc_dcookie(const struct path *path)
 {
        struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache,
                                                        GFP_KERNEL);
@@ -113,7 +113,7 @@ static struct dcookie_struct *alloc_dcookie(struct path *path)
 /* This is the main kernel-side routine that retrieves the cookie
  * value for a dentry/vfsmnt pair.
  */
-int get_dcookie(struct path *path, unsigned long *cookie)
+int get_dcookie(const struct path *path, unsigned long *cookie)
 {
        int err = 0;
        struct dcookie_struct * dcs;
index cf390dceddd29a27708f92f41c727c1c3c99c812..e7413f82d27bf392be10998aa9c8b2ef598a354e 100644 (file)
@@ -631,28 +631,23 @@ out_lock:
 
 static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz)
 {
+       DEFINE_DELAYED_CALL(done);
        struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
-       char *lower_buf;
+       const char *link;
        char *buf;
-       mm_segment_t old_fs;
        int rc;
 
-       lower_buf = kmalloc(PATH_MAX, GFP_KERNEL);
-       if (!lower_buf)
-               return ERR_PTR(-ENOMEM);
-       old_fs = get_fs();
-       set_fs(get_ds());
-       rc = d_inode(lower_dentry)->i_op->readlink(lower_dentry,
-                                                  (char __user *)lower_buf,
-                                                  PATH_MAX);
-       set_fs(old_fs);
-       if (rc < 0)
-               goto out;
+       link = vfs_get_link(lower_dentry, &done);
+       if (IS_ERR(link))
+               return ERR_CAST(link);
+
        rc = ecryptfs_decode_and_decrypt_filename(&buf, bufsiz, dentry->d_sb,
-                                                 lower_buf, rc);
-out:
-       kfree(lower_buf);
-       return rc ? ERR_PTR(rc) : buf;
+                                                 link, strlen(link));
+       do_delayed_call(&done);
+       if (rc)
+               return ERR_PTR(rc);
+
+       return buf;
 }
 
 static const char *ecryptfs_get_link(struct dentry *dentry,
@@ -1089,7 +1084,6 @@ out:
 }
 
 const struct inode_operations ecryptfs_symlink_iops = {
-       .readlink = generic_readlink,
        .get_link = ecryptfs_get_link,
        .permission = ecryptfs_permission,
        .setattr = ecryptfs_setattr,
index d8072bc074a44f74c09c47c2905eb0d1c7ac87dc..0ac62811b34118ab4889d4ee8807706818efadff 100644 (file)
@@ -870,46 +870,31 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
 
        page = *pagep;
        if (page == NULL) {
-               ret = simple_write_begin(file, mapping, pos, len, flags, pagep,
-                                        fsdata);
-               if (ret) {
-                       EXOFS_DBGMSG("simple_write_begin failed\n");
-                       goto out;
+               page = grab_cache_page_write_begin(mapping, pos >> PAGE_SHIFT,
+                                                  flags);
+               if (!page) {
+                       EXOFS_DBGMSG("grab_cache_page_write_begin failed\n");
+                       return -ENOMEM;
                }
-
-               page = *pagep;
+               *pagep = page;
        }
 
         /* read modify write */
        if (!PageUptodate(page) && (len != PAGE_SIZE)) {
                loff_t i_size = i_size_read(mapping->host);
                pgoff_t end_index = i_size >> PAGE_SHIFT;
-               size_t rlen;
 
-               if (page->index < end_index)
-                       rlen = PAGE_SIZE;
-               else if (page->index == end_index)
-                       rlen = i_size & ~PAGE_MASK;
-               else
-                       rlen = 0;
-
-               if (!rlen) {
+               if (page->index > end_index) {
                        clear_highpage(page);
                        SetPageUptodate(page);
-                       goto out;
-               }
-
-               ret = _readpage(page, true);
-               if (ret) {
-                       /*SetPageError was done by _readpage. Is it ok?*/
-                       unlock_page(page);
-                       EXOFS_DBGMSG("__readpage failed\n");
+               } else {
+                       ret = _readpage(page, true);
+                       if (ret) {
+                               unlock_page(page);
+                               EXOFS_DBGMSG("__readpage failed\n");
+                       }
                }
        }
-out:
-       if (unlikely(ret))
-               _write_failed(mapping->host, pos + len);
-
        return ret;
 }
 
@@ -929,18 +914,25 @@ static int exofs_write_end(struct file *file, struct address_space *mapping,
                        struct page *page, void *fsdata)
 {
        struct inode *inode = mapping->host;
-       /* According to comment in simple_write_end i_mutex is held */
-       loff_t i_size = inode->i_size;
-       int ret;
-
-       ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata);
-       if (unlikely(ret))
-               _write_failed(inode, pos + len);
+       loff_t last_pos = pos + copied;
 
-       /* TODO: once simple_write_end marks inode dirty remove */
-       if (i_size != inode->i_size)
+       if (!PageUptodate(page)) {
+               if (copied < len) {
+                       _write_failed(inode, pos + len);
+                       copied = 0;
+                       goto out;
+               }
+               SetPageUptodate(page);
+       }
+       if (last_pos > inode->i_size) {
+               i_size_write(inode, last_pos);
                mark_inode_dirty(inode);
-       return ret;
+       }
+       set_page_dirty(page);
+out:
+       unlock_page(page);
+       put_page(page);
+       return copied;
 }
 
 static int exofs_releasepage(struct page *page, gfp_t gfp)
index e173afe9266109f4e7b948433d4d422e90bacc72..0093ea2512a85809e16605088074a8335513e81c 100644 (file)
@@ -1478,6 +1478,10 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
                inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
        else
                ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+       if (i_size_read(inode) < 0) {
+               ret = -EFSCORRUPTED;
+               goto bad_inode;
+       }
        ei->i_dtime = 0;
        inode->i_generation = le32_to_cpu(raw_inode->i_generation);
        ei->i_state = 0;
index 8437b191bf5de334a5c8908832c0dec0ac1f0fc7..eeffb0138a1744a32466308ed8f39c9151d0bd33 100644 (file)
@@ -21,7 +21,6 @@
 #include "xattr.h"
 
 const struct inode_operations ext2_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .setattr        = ext2_setattr,
 #ifdef CONFIG_EXT2_FS_XATTR
@@ -30,7 +29,6 @@ const struct inode_operations ext2_symlink_inode_operations = {
 };
  
 const struct inode_operations ext2_fast_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = simple_get_link,
        .setattr        = ext2_setattr,
 #ifdef CONFIG_EXT2_FS_XATTR
index dfc8309d7755d55a6e7e73814ede13f204d60cae..63a6b6332682b8865576b7554c63e23d3e2841ae 100644 (file)
@@ -1205,7 +1205,7 @@ static int ext4_release_dquot(struct dquot *dquot);
 static int ext4_mark_dquot_dirty(struct dquot *dquot);
 static int ext4_write_info(struct super_block *sb, int type);
 static int ext4_quota_on(struct super_block *sb, int type, int format_id,
-                        struct path *path);
+                        const struct path *path);
 static int ext4_quota_off(struct super_block *sb, int type);
 static int ext4_quota_on_mount(struct super_block *sb, int type);
 static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
@@ -5293,7 +5293,7 @@ static void lockdep_set_quota_inode(struct inode *inode, int subclass)
  * Standard function to be called on quota_on
  */
 static int ext4_quota_on(struct super_block *sb, int type, int format_id,
-                        struct path *path)
+                        const struct path *path)
 {
        int err;
 
index 557b3b0d668c3f12d458a194d819ecb1da407645..73b184d161fc98dc6c870758243b1a03932cb85f 100644 (file)
@@ -83,21 +83,18 @@ errout:
 }
 
 const struct inode_operations ext4_encrypted_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = ext4_encrypted_get_link,
        .setattr        = ext4_setattr,
        .listxattr      = ext4_listxattr,
 };
 
 const struct inode_operations ext4_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .setattr        = ext4_setattr,
        .listxattr      = ext4_listxattr,
 };
 
 const struct inode_operations ext4_fast_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = simple_get_link,
        .setattr        = ext4_setattr,
        .listxattr      = ext4_listxattr,
index db33b5631dc81d16a88efd4a4f4de3f809be65b9..56c19b0610a899a6351f72a16e26b788f956e3d5 100644 (file)
@@ -1075,7 +1075,6 @@ errout:
 }
 
 const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = f2fs_encrypted_get_link,
        .getattr        = f2fs_getattr,
        .setattr        = f2fs_setattr,
@@ -1105,7 +1104,6 @@ const struct inode_operations f2fs_dir_inode_operations = {
 };
 
 const struct inode_operations f2fs_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = f2fs_get_link,
        .getattr        = f2fs_getattr,
        .setattr        = f2fs_setattr,
index ad17e05ebf95f07888b15f2b09a7b37ac89b9710..6d982b57de9241de853b9ee592ff0564a0bad832 100644 (file)
@@ -155,7 +155,7 @@ over:
  * @mode: the mode with which the new file will be opened
  * @fop: the 'struct file_operations' for the new file
  */
-struct file *alloc_file(struct path *path, fmode_t mode,
+struct file *alloc_file(const struct path *path, fmode_t mode,
                const struct file_operations *fop)
 {
        struct file *file;
index 096f79997f75adf9603c4c6367635588535a8ae3..1f7c732f32b07f1bab9e4961f16cb52ee9f09f70 100644 (file)
@@ -1831,7 +1831,6 @@ static const struct inode_operations fuse_common_inode_operations = {
 static const struct inode_operations fuse_symlink_inode_operations = {
        .setattr        = fuse_setattr,
        .get_link       = fuse_get_link,
-       .readlink       = generic_readlink,
        .getattr        = fuse_getattr,
        .listxattr      = fuse_listxattr,
 };
index 5a6f52ea272282b0c695372f11c8f8512c7ace12..6b039d7ce160fce7677c3e5d702cd27a6299bb59 100644 (file)
@@ -839,12 +839,10 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
        BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
        kaddr = kmap_atomic(page);
        memcpy(buf + pos, kaddr + pos, copied);
-       memset(kaddr + pos + copied, 0, len - copied);
        flush_dcache_page(page);
        kunmap_atomic(kaddr);
 
-       if (!PageUptodate(page))
-               SetPageUptodate(page);
+       WARN_ON(!PageUptodate(page));
        unlock_page(page);
        put_page(page);
 
index fe3f84995c486f139651518e3dd58cc6c447d899..6cd9f84967b8a8b89a446c4a6232c65627233be2 100644 (file)
@@ -2067,7 +2067,6 @@ const struct inode_operations gfs2_dir_iops = {
 };
 
 const struct inode_operations gfs2_symlink_iops = {
-       .readlink = generic_readlink,
        .get_link = gfs2_get_link,
        .permission = gfs2_permission,
        .setattr = gfs2_setattr,
index 23e15ea53e4582fa43cd703ae715de95313c4a25..e61261a7417e57cc49a784c5a54b8a15f92bd352 100644 (file)
@@ -920,7 +920,6 @@ static const char *hostfs_get_link(struct dentry *dentry,
 }
 
 static const struct inode_operations hostfs_link_iops = {
-       .readlink       = generic_readlink,
        .get_link       = hostfs_get_link,
 };
 
index 4fcf51766d4a6b90a48a567f6a5f55d419d76c47..b63cf3af2dc286f210159295c69a97151c36ffaa 100644 (file)
@@ -62,7 +62,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
 extern void *copy_mount_options(const void __user *);
 extern char *copy_mount_string(const void __user *);
 
-extern struct vfsmount *lookup_mnt(struct path *);
+extern struct vfsmount *lookup_mnt(const struct path *);
 extern int finish_automount(struct vfsmount *, struct path *);
 
 extern int sb_prepare_remount_readonly(struct super_block *);
index 8f3f0855fcd230a28563105108c5e0e19cf55b72..d2fa138a868ce2550724e8565881660be4b392e0 100644 (file)
@@ -13,7 +13,6 @@
 
 const struct inode_operations jffs2_symlink_inode_operations =
 {
-       .readlink =     generic_readlink,
        .get_link =     simple_get_link,
        .setattr =      jffs2_setattr,
        .listxattr =    jffs2_listxattr,
index c82404fee6cd3b391de27297996d5bd6246f9960..38320607993e2f5c093b26dcfeb372022aa90dff 100644 (file)
 #include "jfs_xattr.h"
 
 const struct inode_operations jfs_fast_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = simple_get_link,
        .setattr        = jfs_setattr,
        .listxattr      = jfs_listxattr,
 };
 
 const struct inode_operations jfs_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .setattr        = jfs_setattr,
        .listxattr      = jfs_listxattr,
index 9b43ca02b7ab2b28c5a17ea36856b3fa4237a55a..1684af4a8b9b4eaf752dfffc063b3a2cc622d472 100644 (file)
@@ -135,7 +135,6 @@ static const char *kernfs_iop_get_link(struct dentry *dentry,
 
 const struct inode_operations kernfs_symlink_iops = {
        .listxattr      = kernfs_iop_listxattr,
-       .readlink       = generic_readlink,
        .get_link       = kernfs_iop_get_link,
        .setattr        = kernfs_iop_setattr,
        .getattr        = kernfs_iop_getattr,
index 48826d4da189ec0373f24c16a89e4f1066815200..6637aa60c1dac94cea638cc58b1b700bbb25b9c9 100644 (file)
@@ -465,6 +465,8 @@ EXPORT_SYMBOL(simple_write_begin);
  * is not called, so a filesystem that actually does store data in .write_inode
  * should extend on what's done here with a call to mark_inode_dirty() in the
  * case that i_size has changed.
+ *
+ * Use *ONLY* with simple_readpage()
  */
 int simple_write_end(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned copied,
@@ -474,14 +476,14 @@ int simple_write_end(struct file *file, struct address_space *mapping,
        loff_t last_pos = pos + copied;
 
        /* zero the stale part of the page if we did a short copy */
-       if (copied < len) {
-               unsigned from = pos & (PAGE_SIZE - 1);
-
-               zero_user(page, from + copied, len - copied);
-       }
+       if (!PageUptodate(page)) {
+               if (copied < len) {
+                       unsigned from = pos & (PAGE_SIZE - 1);
 
-       if (!PageUptodate(page))
+                       zero_user(page, from + copied, len - copied);
+               }
                SetPageUptodate(page);
+       }
        /*
         * No need to use i_size_read() here, the i_size
         * cannot change under us because we hold the i_mutex.
@@ -1129,7 +1131,6 @@ EXPORT_SYMBOL(simple_get_link);
 
 const struct inode_operations simple_symlink_inode_operations = {
        .get_link = simple_get_link,
-       .readlink = generic_readlink
 };
 EXPORT_SYMBOL(simple_symlink_inode_operations);
 
index f975d667c53900c08526e4774b8f74a96e822dbb..e7d9bf86d97595d1d1fe29bcca7ae5bdeefa0b6a 100644 (file)
@@ -434,7 +434,6 @@ static const struct address_space_operations minix_aops = {
 };
 
 static const struct inode_operations minix_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .getattr        = minix_getattr,
 };
index d2e25d7b64b3073c28f37a339b31ac75d275c6f4..2c856fc47ae309ed88c3ca59302cb1ba660142f2 100644 (file)
@@ -94,6 +94,12 @@ extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
 extern int __legitimize_mnt(struct vfsmount *, unsigned);
 extern bool legitimize_mnt(struct vfsmount *, unsigned);
 
+static inline bool __path_is_mountpoint(const struct path *path)
+{
+       struct mount *m = __lookup_mnt(path->mnt, path->dentry);
+       return m && likely(!(m->mnt.mnt_flags & MNT_SYNC_UMOUNT));
+}
+
 extern void __detach_mounts(struct dentry *dentry);
 
 static inline void detach_mounts(struct dentry *dentry)
index 2b55ea142273e98e5cfc809950295f3cc772e362..d9fc7617b9e48a9225f5a97a752ed3bd5db7b869 100644 (file)
@@ -1200,7 +1200,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
                if (managed & DCACHE_MANAGE_TRANSIT) {
                        BUG_ON(!path->dentry->d_op);
                        BUG_ON(!path->dentry->d_op->d_manage);
-                       ret = path->dentry->d_op->d_manage(path->dentry, false);
+                       ret = path->dentry->d_op->d_manage(path, false);
                        if (ret < 0)
                                break;
                }
@@ -1263,10 +1263,10 @@ int follow_down_one(struct path *path)
 }
 EXPORT_SYMBOL(follow_down_one);
 
-static inline int managed_dentry_rcu(struct dentry *dentry)
+static inline int managed_dentry_rcu(const struct path *path)
 {
-       return (dentry->d_flags & DCACHE_MANAGE_TRANSIT) ?
-               dentry->d_op->d_manage(dentry, true) : 0;
+       return (path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) ?
+               path->dentry->d_op->d_manage(path, true) : 0;
 }
 
 /*
@@ -1282,7 +1282,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                 * Don't forget we might have a non-mountpoint managed dentry
                 * that wants to block transit.
                 */
-               switch (managed_dentry_rcu(path->dentry)) {
+               switch (managed_dentry_rcu(path)) {
                case -ECHILD:
                default:
                        return false;
@@ -1392,8 +1392,7 @@ int follow_down(struct path *path)
                if (managed & DCACHE_MANAGE_TRANSIT) {
                        BUG_ON(!path->dentry->d_op);
                        BUG_ON(!path->dentry->d_op->d_manage);
-                       ret = path->dentry->d_op->d_manage(
-                               path->dentry, false);
+                       ret = path->dentry->d_op->d_manage(path, false);
                        if (ret < 0)
                                return ret == -EISDIR ? 0 : ret;
                }
@@ -2863,7 +2862,7 @@ bool may_open_dev(const struct path *path)
                !(path->mnt->mnt_sb->s_iflags & SB_I_NODEV);
 }
 
-static int may_open(struct path *path, int acc_mode, int flag)
+static int may_open(const struct path *path, int acc_mode, int flag)
 {
        struct dentry *dentry = path->dentry;
        struct inode *inode = dentry->d_inode;
@@ -2913,7 +2912,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
 
 static int handle_truncate(struct file *filp)
 {
-       struct path *path = &filp->f_path;
+       const struct path *path = &filp->f_path;
        struct inode *inode = path->dentry->d_inode;
        int error = get_write_access(inode);
        if (error)
@@ -4607,7 +4606,8 @@ out:
  * have ->get_link() not calling nd_jump_link().  Using (or not using) it
  * for any given inode is up to filesystem.
  */
-int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+static int generic_readlink(struct dentry *dentry, char __user *buffer,
+                           int buflen)
 {
        DEFINE_DELAYED_CALL(done);
        struct inode *inode = d_inode(dentry);
@@ -4623,7 +4623,36 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
        do_delayed_call(&done);
        return res;
 }
-EXPORT_SYMBOL(generic_readlink);
+
+/**
+ * vfs_readlink - copy symlink body into userspace buffer
+ * @dentry: dentry on which to get symbolic link
+ * @buffer: user memory pointer
+ * @buflen: size of buffer
+ *
+ * Does not touch atime.  That's up to the caller if necessary
+ *
+ * Does not call security hook.
+ */
+int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+{
+       struct inode *inode = d_inode(dentry);
+
+       if (unlikely(!(inode->i_opflags & IOP_DEFAULT_READLINK))) {
+               if (unlikely(inode->i_op->readlink))
+                       return inode->i_op->readlink(dentry, buffer, buflen);
+
+               if (!d_is_symlink(dentry))
+                       return -EINVAL;
+
+               spin_lock(&inode->i_lock);
+               inode->i_opflags |= IOP_DEFAULT_READLINK;
+               spin_unlock(&inode->i_lock);
+       }
+
+       return generic_readlink(dentry, buffer, buflen);
+}
+EXPORT_SYMBOL(vfs_readlink);
 
 /**
  * vfs_get_link - get symlink body
@@ -4740,7 +4769,6 @@ int page_symlink(struct inode *inode, const char *symname, int len)
 EXPORT_SYMBOL(page_symlink);
 
 const struct inode_operations page_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
 };
 EXPORT_SYMBOL(page_symlink_inode_operations);
index e6c234b1a6456c1364bcc06b029f3cc4a155d5bd..f7e28f8ea04d2a629ae7c5ead8b84ca71913cc8a 100644 (file)
@@ -678,7 +678,7 @@ out:
  *
  * lookup_mnt takes a reference to the found vfsmount.
  */
-struct vfsmount *lookup_mnt(struct path *path)
+struct vfsmount *lookup_mnt(const struct path *path)
 {
        struct mount *child_mnt;
        struct vfsmount *m;
@@ -1159,7 +1159,36 @@ struct vfsmount *mntget(struct vfsmount *mnt)
 }
 EXPORT_SYMBOL(mntget);
 
-struct vfsmount *mnt_clone_internal(struct path *path)
+/* path_is_mountpoint() - Check if path is a mount in the current
+ *                          namespace.
+ *
+ *  d_mountpoint() can only be used reliably to establish if a dentry is
+ *  not mounted in any namespace and that common case is handled inline.
+ *  d_mountpoint() isn't aware of the possibility there may be multiple
+ *  mounts using a given dentry in a different namespace. This function
+ *  checks if the passed in path is a mountpoint rather than the dentry
+ *  alone.
+ */
+bool path_is_mountpoint(const struct path *path)
+{
+       unsigned seq;
+       bool res;
+
+       if (!d_mountpoint(path->dentry))
+               return false;
+
+       rcu_read_lock();
+       do {
+               seq = read_seqbegin(&mount_lock);
+               res = __path_is_mountpoint(path);
+       } while (read_seqretry(&mount_lock, seq));
+       rcu_read_unlock();
+
+       return res;
+}
+EXPORT_SYMBOL(path_is_mountpoint);
+
+struct vfsmount *mnt_clone_internal(const struct path *path)
 {
        struct mount *p;
        p = clone_mnt(real_mount(path->mnt), path->dentry, CL_PRIVATE);
@@ -1758,7 +1787,7 @@ out:
 
 /* Caller should check returned pointer for errors */
 
-struct vfsmount *collect_mounts(struct path *path)
+struct vfsmount *collect_mounts(const struct path *path)
 {
        struct mount *tree;
        namespace_lock();
@@ -1791,7 +1820,7 @@ void drop_collected_mounts(struct vfsmount *mnt)
  *
  * Release with mntput().
  */
-struct vfsmount *clone_private_mount(struct path *path)
+struct vfsmount *clone_private_mount(const struct path *path)
 {
        struct mount *old_mnt = real_mount(path->mnt);
        struct mount *new_mnt;
@@ -2997,7 +3026,7 @@ bool is_path_reachable(struct mount *mnt, struct dentry *dentry,
        return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry);
 }
 
-bool path_is_under(struct path *path1, struct path *path2)
+bool path_is_under(const struct path *path1, const struct path *path2)
 {
        bool res;
        read_seqlock_excl(&mount_lock);
index f6cf4c7e92b1b8c3cf7e7846aa4c968a24829b03..ba611bf1aff3bcfb3837257a86610431bf425d26 100644 (file)
@@ -243,7 +243,6 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
 
 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
 static const struct inode_operations ncp_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .setattr        = ncp_notify_change,
 };
index 64c11f399b3d4edfb0b9416550e5391277cf5a3e..55208b9b3c110b1bf9ded64a90a93c196c0fa160 100644 (file)
@@ -377,7 +377,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
         */
        if (!PageUptodate(page)) {
                unsigned pglen = nfs_page_length(page);
-               unsigned end = offset + len;
+               unsigned end = offset + copied;
 
                if (pglen == 0) {
                        zero_user_segments(page, 0, offset,
index 4fe3eead3868ebe418432b4593c10464188fb4ed..5a1d0ded897989c0243df2c07cd9108a38bbc594 100644 (file)
@@ -77,7 +77,6 @@ static const char *nfs_get_link(struct dentry *dentry,
  * symlinks can't do much...
  */
 const struct inode_operations nfs_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = nfs_get_link,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
index 79edde4577b29457767a3cb85c1714350184513d..7ecf16be4a444ec250678e89ad210c7f19cbbc18 100644 (file)
@@ -3605,10 +3605,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
        if (!p)
                return nfserr_resource;
        /*
-        * XXX: By default, the ->readlink() VFS op will truncate symlinks
-        * if they would overflow the buffer.  Is this kosher in NFSv4?  If
-        * not, one easy fix is: if ->readlink() precisely fills the buffer,
-        * assume that truncation occurred, and return NFS4ERR_RESOURCE.
+        * XXX: By default, vfs_readlink() will truncate symlinks if they
+        * would overflow the buffer.  Is this kosher in NFSv4?  If not, one
+        * easy fix is: if vfs_readlink() precisely fills the buffer, assume
+        * that truncation occurred, and return NFS4ERR_RESOURCE.
         */
        nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp,
                                                (char *)p, &maxcount);
index 357e844aee8440c7969dee0359cee8ff71fc223c..7a21abe7caf7623e8354dc56a1057d9469e22d39 100644 (file)
@@ -1450,7 +1450,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 __be32
 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
 {
-       struct inode    *inode;
        mm_segment_t    oldfs;
        __be32          err;
        int             host_err;
@@ -1462,10 +1461,9 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
 
        path.mnt = fhp->fh_export->ex_path.mnt;
        path.dentry = fhp->fh_dentry;
-       inode = d_inode(path.dentry);
 
        err = nfserr_inval;
-       if (!inode->i_op->readlink)
+       if (!d_is_symlink(path.dentry))
                goto out;
 
        touch_atime(&path);
@@ -1474,7 +1472,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
         */
 
        oldfs = get_fs(); set_fs(KERNEL_DS);
-       host_err = inode->i_op->readlink(path.dentry, (char __user *)buf, *lenp);
+       host_err = vfs_readlink(path.dentry, (char __user *)buf, *lenp);
        set_fs(oldfs);
 
        if (host_err < 0)
index 2b71c60fe982a1bafdca0848193acc33287b56c5..515d13c196daf81f69dc0b5501b4b9780c8d2743 100644 (file)
@@ -568,7 +568,6 @@ const struct inode_operations nilfs_special_inode_operations = {
 };
 
 const struct inode_operations nilfs_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .permission     = nilfs_permission,
 };
index 6faaf710e563ee184e20204f80c63c2157cbb186..5a4ec309e28375eb60981f9c32314e1ae28c1efd 100644 (file)
@@ -85,7 +85,7 @@ static int dnotify_handle_event(struct fsnotify_group *group,
                                struct inode *inode,
                                struct fsnotify_mark *inode_mark,
                                struct fsnotify_mark *vfsmount_mark,
-                               u32 mask, void *data, int data_type,
+                               u32 mask, const void *data, int data_type,
                                const unsigned char *file_name, u32 cookie)
 {
        struct dnotify_mark *dn_mark;
index e0e5f7c3c99fe076d11dc5d907b543d5e5376671..bbc175d4213d5776e65ee9a438cf4e90f8c0f6c2 100644 (file)
@@ -90,10 +90,10 @@ static int fanotify_get_response(struct fsnotify_group *group,
 static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
                                       struct fsnotify_mark *vfsmnt_mark,
                                       u32 event_mask,
-                                      void *data, int data_type)
+                                      const void *data, int data_type)
 {
        __u32 marks_mask, marks_ignored_mask;
-       struct path *path = data;
+       const struct path *path = data;
 
        pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p"
                 " data_type=%d\n", __func__, inode_mark, vfsmnt_mark,
@@ -140,7 +140,7 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
 }
 
 struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask,
-                                                struct path *path)
+                                                const struct path *path)
 {
        struct fanotify_event_info *event;
 
@@ -177,7 +177,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
                                 struct inode *inode,
                                 struct fsnotify_mark *inode_mark,
                                 struct fsnotify_mark *fanotify_mark,
-                                u32 mask, void *data, int data_type,
+                                u32 mask, const void *data, int data_type,
                                 const unsigned char *file_name, u32 cookie)
 {
        int ret = 0;
index 2a5fb14115dfe0415f2d39bc57acb8d902aecc60..4500a74f8d3873173ddc13a11ef7e5ab4c03cfa5 100644 (file)
@@ -47,4 +47,4 @@ static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse)
 }
 
 struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask,
-                                                struct path *path);
+                                                const struct path *path);
index db39de2dd4cbc8b0e4e962e5a874a6e5b5777bc7..b41515d3f0815246185b264532d71cc43824ef9a 100644 (file)
@@ -86,7 +86,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
 }
 
 /* Notify this dentry's parent about a child's events. */
-int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
+int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask)
 {
        struct dentry *parent;
        struct inode *p_inode;
@@ -125,7 +125,7 @@ EXPORT_SYMBOL_GPL(__fsnotify_parent);
 static int send_to_group(struct inode *to_tell,
                         struct fsnotify_mark *inode_mark,
                         struct fsnotify_mark *vfsmount_mark,
-                        __u32 mask, void *data,
+                        __u32 mask, const void *data,
                         int data_is, u32 cookie,
                         const unsigned char *file_name)
 {
@@ -187,7 +187,7 @@ static int send_to_group(struct inode *to_tell,
  * out to all of the registered fsnotify_group.  Those groups can then use the
  * notification event in whatever means they feel necessary.
  */
-int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
+int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
             const unsigned char *file_name, u32 cookie)
 {
        struct hlist_node *inode_node = NULL, *vfsmount_node = NULL;
@@ -199,7 +199,7 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
        __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
 
        if (data_is == FSNOTIFY_EVENT_PATH)
-               mnt = real_mount(((struct path *)data)->mnt);
+               mnt = real_mount(((const struct path *)data)->mnt);
        else
                mnt = NULL;
 
index 741077deef3b5544dd71ae9635facb8ac1a228a9..a3645249f7ecfa4cbdae8434bb87b47ffd02dbb1 100644 (file)
@@ -150,12 +150,10 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
  */
 void fsnotify_unmount_inodes(struct super_block *sb)
 {
-       struct inode *inode, *next_i, *need_iput = NULL;
+       struct inode *inode, *iput_inode = NULL;
 
        spin_lock(&sb->s_inode_list_lock);
-       list_for_each_entry_safe(inode, next_i, &sb->s_inodes, i_sb_list) {
-               struct inode *need_iput_tmp;
-
+       list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                /*
                 * We cannot __iget() an inode in state I_FREEING,
                 * I_WILL_FREE, or I_NEW which is fine because by that point
@@ -178,49 +176,24 @@ void fsnotify_unmount_inodes(struct super_block *sb)
                        continue;
                }
 
-               need_iput_tmp = need_iput;
-               need_iput = NULL;
-
-               /* In case fsnotify_inode_delete() drops a reference. */
-               if (inode != need_iput_tmp)
-                       __iget(inode);
-               else
-                       need_iput_tmp = NULL;
+               __iget(inode);
                spin_unlock(&inode->i_lock);
-
-               /* In case the dropping of a reference would nuke next_i. */
-               while (&next_i->i_sb_list != &sb->s_inodes) {
-                       spin_lock(&next_i->i_lock);
-                       if (!(next_i->i_state & (I_FREEING | I_WILL_FREE)) &&
-                                               atomic_read(&next_i->i_count)) {
-                               __iget(next_i);
-                               need_iput = next_i;
-                               spin_unlock(&next_i->i_lock);
-                               break;
-                       }
-                       spin_unlock(&next_i->i_lock);
-                       next_i = list_next_entry(next_i, i_sb_list);
-               }
-
-               /*
-                * We can safely drop s_inode_list_lock here because either
-                * we actually hold references on both inode and next_i or
-                * end of list.  Also no new inodes will be added since the
-                * umount has begun.
-                */
                spin_unlock(&sb->s_inode_list_lock);
 
-               if (need_iput_tmp)
-                       iput(need_iput_tmp);
+               if (iput_inode)
+                       iput(iput_inode);
 
                /* for each watch, send FS_UNMOUNT and then remove it */
                fsnotify(inode, FS_UNMOUNT, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
 
                fsnotify_inode_delete(inode);
 
-               iput(inode);
+               iput_inode = inode;
 
                spin_lock(&sb->s_inode_list_lock);
        }
        spin_unlock(&sb->s_inode_list_lock);
+
+       if (iput_inode)
+               iput(iput_inode);
 }
index ed855ef6f0775e447489e7dd43e00ff3891c850e..a6f5907a3feef4e878e6275efd0dc0a4d7fe083b 100644 (file)
@@ -26,7 +26,7 @@ extern int inotify_handle_event(struct fsnotify_group *group,
                                struct inode *inode,
                                struct fsnotify_mark *inode_mark,
                                struct fsnotify_mark *vfsmount_mark,
-                               u32 mask, void *data, int data_type,
+                               u32 mask, const void *data, int data_type,
                                const unsigned char *file_name, u32 cookie);
 
 extern const struct fsnotify_ops inotify_fsnotify_ops;
index 2cd900c2c73758c31ae941e10fee8e44494ca370..19e7ec109a75c91ff71a0fb2a3c7bdad69e883ba 100644 (file)
@@ -66,7 +66,7 @@ int inotify_handle_event(struct fsnotify_group *group,
                         struct inode *inode,
                         struct fsnotify_mark *inode_mark,
                         struct fsnotify_mark *vfsmount_mark,
-                        u32 mask, void *data, int data_type,
+                        u32 mask, const void *data, int data_type,
                         const unsigned char *file_name, u32 cookie)
 {
        struct inotify_inode_mark *i_mark;
@@ -80,7 +80,7 @@ int inotify_handle_event(struct fsnotify_group *group,
 
        if ((inode_mark->mask & FS_EXCL_UNLINK) &&
            (data_type == FSNOTIFY_EVENT_PATH)) {
-               struct path *path = data;
+               const struct path *path = data;
 
                if (d_unlinked(path->dentry))
                        return 0;
index f72712f6c28d587ab6d96c21a48940403a5ccdad..d4ec0d8961a6e9dde216bc6ef649a0e7c28f8733 100644 (file)
@@ -5194,7 +5194,7 @@ int ocfs2_change_extent_flag(handle_t *handle,
        rec = &el->l_recs[index];
        if (new_flags && (rec->e_flags & new_flags)) {
                mlog(ML_ERROR, "Owner %llu tried to set %d flags on an "
-                    "extent that already had them",
+                    "extent that already had them\n",
                     (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci),
                     new_flags);
                goto out;
@@ -5202,7 +5202,7 @@ int ocfs2_change_extent_flag(handle_t *handle,
 
        if (clear_flags && !(rec->e_flags & clear_flags)) {
                mlog(ML_ERROR, "Owner %llu tried to clear %d flags on an "
-                    "extent that didn't have them",
+                    "extent that didn't have them\n",
                     (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci),
                     clear_flags);
                goto out;
@@ -5713,8 +5713,7 @@ int ocfs2_remove_btree_range(struct inode *inode,
        struct ocfs2_refcount_tree *ref_tree = NULL;
 
        if ((flags & OCFS2_EXT_REFCOUNTED) && len) {
-               BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
-                        OCFS2_HAS_REFCOUNT_FL));
+               BUG_ON(!ocfs2_is_refcount_inode(inode));
 
                if (!refcount_tree_locked) {
                        ret = ocfs2_lock_refcount_tree(osb, refcount_loc, 1,
index 4d9c6f5ec28a62efbda693918562df97a8bfa20f..11556b7d93ecdf934ede8efb431615d4d43ec0eb 100644 (file)
@@ -464,6 +464,15 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
        trace_ocfs2_bmap((unsigned long long)OCFS2_I(inode)->ip_blkno,
                         (unsigned long long)block);
 
+       /*
+        * The swap code (ab-)uses ->bmap to get a block mapping and then
+        * bypasseÑ• the file system for actual I/O.  We really can't allow
+        * that on refcounted inodes, so we have to skip out here.  And yes,
+        * 0 is the magic code for a bmap error..
+        */
+       if (ocfs2_is_refcount_inode(inode))
+               return 0;
+
        /* We don't need to lock journal system files, since they aren't
         * accessed concurrently from multiple nodes.
         */
@@ -2253,10 +2262,10 @@ out:
        return ret;
 }
 
-static void ocfs2_dio_end_io_write(struct inode *inode,
-                                  struct ocfs2_dio_write_ctxt *dwc,
-                                  loff_t offset,
-                                  ssize_t bytes)
+static int 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;
@@ -2307,7 +2316,7 @@ static void ocfs2_dio_end_io_write(struct inode *inode,
                        mlog_errno(ret);
        }
 
-       di = (struct ocfs2_dinode *)di_bh;
+       di = (struct ocfs2_dinode *)di_bh->b_data;
 
        ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
 
@@ -2364,6 +2373,8 @@ out:
        if (locked)
                inode_unlock(inode);
        ocfs2_dio_free_write_ctx(inode, dwc);
+
+       return ret;
 }
 
 /*
@@ -2378,21 +2389,19 @@ static int ocfs2_dio_end_io(struct kiocb *iocb,
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        int level;
-
-       if (bytes <= 0)
-               return 0;
+       int ret = 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);
+       if (bytes > 0 && private)
+               ret = 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;
+       return ret;
 }
 
 static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
index 000c234d7bbd7ca221f68806ecdc710b0cd7a2e7..c4889655d32b5360228bb0c3deb7e729de855163 100644 (file)
@@ -1030,7 +1030,7 @@ int ocfs2_extend_no_holes(struct inode *inode, struct buffer_head *di_bh,
         * Only quota files call this without a bh, and they can't be
         * refcounted.
         */
-       BUG_ON(!di_bh && (oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+       BUG_ON(!di_bh && ocfs2_is_refcount_inode(inode));
        BUG_ON(!di_bh && !(oi->ip_flags & OCFS2_INODE_SYSTEM_FILE));
 
        clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size);
@@ -1667,9 +1667,9 @@ static void ocfs2_calc_trunc_pos(struct inode *inode,
        *done = ret;
 }
 
-static int ocfs2_remove_inode_range(struct inode *inode,
-                                   struct buffer_head *di_bh, u64 byte_start,
-                                   u64 byte_len)
+int ocfs2_remove_inode_range(struct inode *inode,
+                            struct buffer_head *di_bh, u64 byte_start,
+                            u64 byte_len)
 {
        int ret = 0, flags = 0, done = 0, i;
        u32 trunc_start, trunc_len, trunc_end, trunc_cpos, phys_cpos;
@@ -1719,8 +1719,7 @@ static int ocfs2_remove_inode_range(struct inode *inode,
         * within one cluster(means is not exactly aligned to clustersize).
         */
 
-       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) {
-
+       if (ocfs2_is_refcount_inode(inode)) {
                ret = ocfs2_cow_file_pos(inode, di_bh, byte_start);
                if (ret) {
                        mlog_errno(ret);
@@ -2036,7 +2035,7 @@ int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
        struct super_block *sb = inode->i_sb;
 
        if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)) ||
-           !(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) ||
+           !ocfs2_is_refcount_inode(inode) ||
            OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
                return 0;
 
@@ -2440,6 +2439,31 @@ out:
        return offset;
 }
 
+static int ocfs2_file_clone_range(struct file *file_in,
+                                 loff_t pos_in,
+                                 struct file *file_out,
+                                 loff_t pos_out,
+                                 u64 len)
+{
+       return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out,
+                                        len, false);
+}
+
+static ssize_t ocfs2_file_dedupe_range(struct file *src_file,
+                                      u64 loff,
+                                      u64 len,
+                                      struct file *dst_file,
+                                      u64 dst_loff)
+{
+       int error;
+
+       error = ocfs2_reflink_remap_range(src_file, loff, dst_file, dst_loff,
+                                         len, true);
+       if (error)
+               return error;
+       return len;
+}
+
 const struct inode_operations ocfs2_file_iops = {
        .setattr        = ocfs2_setattr,
        .getattr        = ocfs2_getattr,
@@ -2479,6 +2503,8 @@ const struct file_operations ocfs2_fops = {
        .splice_read    = generic_file_splice_read,
        .splice_write   = iter_file_splice_write,
        .fallocate      = ocfs2_fallocate,
+       .clone_file_range = ocfs2_file_clone_range,
+       .dedupe_file_range = ocfs2_file_dedupe_range,
 };
 
 const struct file_operations ocfs2_dops = {
@@ -2524,6 +2550,8 @@ const struct file_operations ocfs2_fops_no_plocks = {
        .splice_read    = generic_file_splice_read,
        .splice_write   = iter_file_splice_write,
        .fallocate      = ocfs2_fallocate,
+       .clone_file_range = ocfs2_file_clone_range,
+       .dedupe_file_range = ocfs2_file_dedupe_range,
 };
 
 const struct file_operations ocfs2_dops_no_plocks = {
index e8c62f22215c13b404dc572da2441c9f67cbfed2..897fd9a2e51dbe91f20cd4795950228c72890e91 100644 (file)
@@ -82,4 +82,7 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd,
 
 int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
                                   size_t count);
+int ocfs2_remove_inode_range(struct inode *inode,
+                            struct buffer_head *di_bh, u64 byte_start,
+                            u64 byte_len);
 #endif /* OCFS2_FILE_H */
index 5af68fcdf9d395273edc16ea173d31a495489df7..9b955f732bca1fd61d60b2ae1212f0d458bda169 100644 (file)
@@ -181,4 +181,10 @@ static inline struct ocfs2_inode_info *cache_info_to_inode(struct ocfs2_caching_
        return container_of(ci, struct ocfs2_inode_info, ip_metadata_cache);
 }
 
+/* Does this inode have the reflink flag set? */
+static inline bool ocfs2_is_refcount_inode(struct inode *inode)
+{
+       return (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL);
+}
+
 #endif /* OCFS2_INODE_H */
index 4e8f32eb0bdb2f3e9aa90806ebf748290343d8c0..e52a2852d50dba45a36209e65e327911a89f1449 100644 (file)
@@ -235,10 +235,7 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
        u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
 
        if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) {
-
-               BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
-                        OCFS2_HAS_REFCOUNT_FL));
-
+               BUG_ON(!ocfs2_is_refcount_inode(inode));
                BUG_ON(!context->refcount_loc);
 
                ret = ocfs2_lock_refcount_tree(osb, context->refcount_loc, 1,
@@ -581,10 +578,7 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
        phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
 
        if ((ext_flags & OCFS2_EXT_REFCOUNTED) && len) {
-
-               BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
-                        OCFS2_HAS_REFCOUNT_FL));
-
+               BUG_ON(!ocfs2_is_refcount_inode(inode));
                BUG_ON(!context->refcount_loc);
 
                ret = ocfs2_lock_refcount_tree(osb, context->refcount_loc, 1,
index 87e577a49b0d567550e09912c179a719a7ee692c..cec495a921e32cbbd4ff5bd5d2944bbf5c93f09b 100644 (file)
@@ -634,7 +634,15 @@ static void qsync_work_fn(struct work_struct *work)
                                                      dqi_sync_work.work);
        struct super_block *sb = oinfo->dqi_gqinode->i_sb;
 
-       dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type);
+       /*
+        * We have to be careful here not to deadlock on s_umount as umount
+        * disabling quotas may be in progress and it waits for this work to
+        * complete. If trylock fails, we'll do the sync next time...
+        */
+       if (down_read_trylock(&sb->s_umount)) {
+               dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type);
+               up_read(&sb->s_umount);
+       }
        schedule_delayed_work(&oinfo->dqi_sync_work,
                              msecs_to_jiffies(oinfo->dqi_syncms));
 }
index 8a54fd8a4fa57a76f7e0389ec8d875108c59e3a1..32c5a40c1257ecda129944a1abf4cdac83a2e8a1 100644 (file)
@@ -454,7 +454,7 @@ out:
 /* Sync changes in local quota file into global quota file and
  * reinitialize local quota file.
  * The function expects local quota file to be already locked and
- * dqonoff_mutex locked. */
+ * s_umount locked in shared mode. */
 static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                          int type,
                                          struct ocfs2_quota_recovery *rec)
@@ -597,7 +597,7 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
        printk(KERN_NOTICE "ocfs2: Finishing quota recovery on device (%s) for "
               "slot %u\n", osb->dev_str, slot_num);
 
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
+       down_read(&sb->s_umount);
        for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (list_empty(&(rec->r_list[type])))
                        continue;
@@ -674,7 +674,7 @@ out_put:
                        break;
        }
 out:
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
+       up_read(&sb->s_umount);
        kfree(rec);
        return status;
 }
@@ -840,7 +840,10 @@ static int ocfs2_local_free_info(struct super_block *sb, int type)
        }
        ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk);
 
-       /* dqonoff_mutex protects us against racing with recovery thread... */
+       /*
+        * s_umount held in exclusive mode protects us against racing with
+        * recovery thread...
+        */
        if (oinfo->dqi_rec) {
                ocfs2_free_quota_recovery(oinfo->dqi_rec);
                mark_clean = 0;
index 738b4ea8e9901c9acacafb446b2085cb3810df51..d171d2c53f7f8928762acb9731d202063328967b 100644 (file)
@@ -34,6 +34,7 @@
 #include "xattr.h"
 #include "namei.h"
 #include "ocfs2_trace.h"
+#include "file.h"
 
 #include <linux/bio.h>
 #include <linux/blkdev.h>
@@ -410,7 +411,7 @@ static int ocfs2_get_refcount_block(struct inode *inode, u64 *ref_blkno)
                goto out;
        }
 
-       BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+       BUG_ON(!ocfs2_is_refcount_inode(inode));
 
        di = (struct ocfs2_dinode *)di_bh->b_data;
        *ref_blkno = le64_to_cpu(di->i_refcount_loc);
@@ -569,7 +570,7 @@ static int ocfs2_create_refcount_tree(struct inode *inode,
        u32 num_got;
        u64 suballoc_loc, first_blkno;
 
-       BUG_ON(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL);
+       BUG_ON(ocfs2_is_refcount_inode(inode));
 
        trace_ocfs2_create_refcount_tree(
                (unsigned long long)OCFS2_I(inode)->ip_blkno);
@@ -707,7 +708,7 @@ static int ocfs2_set_refcount_tree(struct inode *inode,
        struct ocfs2_refcount_block *rb;
        struct ocfs2_refcount_tree *ref_tree;
 
-       BUG_ON(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL);
+       BUG_ON(ocfs2_is_refcount_inode(inode));
 
        ret = ocfs2_lock_refcount_tree(osb, refcount_loc, 1,
                                       &ref_tree, &ref_root_bh);
@@ -774,7 +775,7 @@ int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh)
        u64 blk = 0, bg_blkno = 0, ref_blkno = le64_to_cpu(di->i_refcount_loc);
        u16 bit = 0;
 
-       if (!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL))
+       if (!ocfs2_is_refcount_inode(inode))
                return 0;
 
        BUG_ON(!ref_blkno);
@@ -2298,11 +2299,10 @@ int ocfs2_decrease_refcount(struct inode *inode,
 {
        int ret;
        u64 ref_blkno;
-       struct ocfs2_inode_info *oi = OCFS2_I(inode);
        struct buffer_head *ref_root_bh = NULL;
        struct ocfs2_refcount_tree *tree;
 
-       BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+       BUG_ON(!ocfs2_is_refcount_inode(inode));
 
        ret = ocfs2_get_refcount_block(inode, &ref_blkno);
        if (ret) {
@@ -2532,7 +2532,6 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
                                          int *ref_blocks)
 {
        int ret;
-       struct ocfs2_inode_info *oi = OCFS2_I(inode);
        struct buffer_head *ref_root_bh = NULL;
        struct ocfs2_refcount_tree *tree;
        u64 start_cpos = ocfs2_blocks_to_clusters(inode->i_sb, phys_blkno);
@@ -2543,7 +2542,7 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
                goto out;
        }
 
-       BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+       BUG_ON(!ocfs2_is_refcount_inode(inode));
 
        ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb),
                                      refcount_loc, &tree);
@@ -3411,14 +3410,13 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
 {
        int ret;
        u32 cow_start = 0, cow_len = 0;
-       struct ocfs2_inode_info *oi = OCFS2_I(inode);
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
        struct buffer_head *ref_root_bh = NULL;
        struct ocfs2_refcount_tree *ref_tree;
        struct ocfs2_cow_context *context = NULL;
 
-       BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+       BUG_ON(!ocfs2_is_refcount_inode(inode));
 
        ret = ocfs2_refcount_cal_cow_clusters(inode, &di->id2.i_list,
                                              cpos, write_len, max_cpos,
@@ -3628,11 +3626,10 @@ int ocfs2_refcount_cow_xattr(struct inode *inode,
 {
        int ret;
        struct ocfs2_xattr_value_root *xv = vb->vb_xv;
-       struct ocfs2_inode_info *oi = OCFS2_I(inode);
        struct ocfs2_cow_context *context = NULL;
        u32 cow_start, cow_len;
 
-       BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+       BUG_ON(!ocfs2_is_refcount_inode(inode));
 
        ret = ocfs2_refcount_cal_cow_clusters(inode, &xv->xr_list,
                                              cpos, write_len, UINT_MAX,
@@ -3695,6 +3692,9 @@ int ocfs2_add_refcount_flag(struct inode *inode,
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct ocfs2_alloc_context *meta_ac = NULL;
 
+       /* We need to be able to handle at least an extent tree split. */
+       ref_blocks = ocfs2_extend_meta_needed(data_et->et_root_el);
+
        ret = ocfs2_calc_refcount_meta_credits(inode->i_sb,
                                               ref_ci, ref_root_bh,
                                               p_cluster, num_clusters,
@@ -3806,7 +3806,7 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
 
        ocfs2_init_dealloc_ctxt(&dealloc);
 
-       if (!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)) {
+       if (!ocfs2_is_refcount_inode(inode)) {
                ret = ocfs2_create_refcount_tree(inode, di_bh);
                if (ret) {
                        mlog_errno(ret);
@@ -3933,6 +3933,13 @@ static int ocfs2_add_refcounted_extent(struct inode *inode,
        ret = ocfs2_increase_refcount(handle, ref_ci, ref_root_bh,
                                      p_cluster, num_clusters,
                                      meta_ac, dealloc);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = dquot_alloc_space_nodirty(inode,
+               ocfs2_clusters_to_bytes(osb->sb, num_clusters));
        if (ret)
                mlog_errno(ret);
 
@@ -4441,3 +4448,434 @@ out:
 
        return error;
 }
+
+/* Update destination inode size, if necessary. */
+static int ocfs2_reflink_update_dest(struct inode *dest,
+                                    struct buffer_head *d_bh,
+                                    loff_t newlen)
+{
+       handle_t *handle;
+       int ret;
+
+       dest->i_blocks = ocfs2_inode_sector_count(dest);
+
+       if (newlen <= i_size_read(dest))
+               return 0;
+
+       handle = ocfs2_start_trans(OCFS2_SB(dest->i_sb),
+                                  OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               return ret;
+       }
+
+       /* Extend i_size if needed. */
+       spin_lock(&OCFS2_I(dest)->ip_lock);
+       if (newlen > i_size_read(dest))
+               i_size_write(dest, newlen);
+       spin_unlock(&OCFS2_I(dest)->ip_lock);
+       dest->i_ctime = dest->i_mtime = current_time(dest);
+
+       ret = ocfs2_mark_inode_dirty(handle, dest, d_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+out_commit:
+       ocfs2_commit_trans(OCFS2_SB(dest->i_sb), handle);
+       return ret;
+}
+
+/* Remap the range pos_in:len in s_inode to pos_out:len in t_inode. */
+static int ocfs2_reflink_remap_extent(struct inode *s_inode,
+                                     struct buffer_head *s_bh,
+                                     loff_t pos_in,
+                                     struct inode *t_inode,
+                                     struct buffer_head *t_bh,
+                                     loff_t pos_out,
+                                     loff_t len,
+                                     struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+       struct ocfs2_extent_tree s_et;
+       struct ocfs2_extent_tree t_et;
+       struct ocfs2_dinode *dis;
+       struct buffer_head *ref_root_bh = NULL;
+       struct ocfs2_refcount_tree *ref_tree;
+       struct ocfs2_super *osb;
+       loff_t pstart, plen;
+       u32 p_cluster, num_clusters, slast, spos, tpos;
+       unsigned int ext_flags;
+       int ret = 0;
+
+       osb = OCFS2_SB(s_inode->i_sb);
+       dis = (struct ocfs2_dinode *)s_bh->b_data;
+       ocfs2_init_dinode_extent_tree(&s_et, INODE_CACHE(s_inode), s_bh);
+       ocfs2_init_dinode_extent_tree(&t_et, INODE_CACHE(t_inode), t_bh);
+
+       spos = ocfs2_bytes_to_clusters(s_inode->i_sb, pos_in);
+       tpos = ocfs2_bytes_to_clusters(t_inode->i_sb, pos_out);
+       slast = ocfs2_clusters_for_bytes(s_inode->i_sb, pos_in + len);
+
+       while (spos < slast) {
+               if (fatal_signal_pending(current)) {
+                       ret = -EINTR;
+                       goto out;
+               }
+
+               /* Look up the extent. */
+               ret = ocfs2_get_clusters(s_inode, spos, &p_cluster,
+                                        &num_clusters, &ext_flags);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               num_clusters = min_t(u32, num_clusters, slast - spos);
+
+               /* Punch out the dest range. */
+               pstart = ocfs2_clusters_to_bytes(t_inode->i_sb, tpos);
+               plen = ocfs2_clusters_to_bytes(t_inode->i_sb, num_clusters);
+               ret = ocfs2_remove_inode_range(t_inode, t_bh, pstart, plen);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               if (p_cluster == 0)
+                       goto next_loop;
+
+               /* Lock the refcount btree... */
+               ret = ocfs2_lock_refcount_tree(osb,
+                                              le64_to_cpu(dis->i_refcount_loc),
+                                              1, &ref_tree, &ref_root_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               /* Mark s_inode's extent as refcounted. */
+               if (!(ext_flags & OCFS2_EXT_REFCOUNTED)) {
+                       ret = ocfs2_add_refcount_flag(s_inode, &s_et,
+                                                     &ref_tree->rf_ci,
+                                                     ref_root_bh, spos,
+                                                     p_cluster, num_clusters,
+                                                     dealloc, NULL);
+                       if (ret) {
+                               mlog_errno(ret);
+                               goto out_unlock_refcount;
+                       }
+               }
+
+               /* Map in the new extent. */
+               ext_flags |= OCFS2_EXT_REFCOUNTED;
+               ret = ocfs2_add_refcounted_extent(t_inode, &t_et,
+                                                 &ref_tree->rf_ci,
+                                                 ref_root_bh,
+                                                 tpos, p_cluster,
+                                                 num_clusters,
+                                                 ext_flags,
+                                                 dealloc);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_unlock_refcount;
+               }
+
+               ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+               brelse(ref_root_bh);
+next_loop:
+               spos += num_clusters;
+               tpos += num_clusters;
+       }
+
+out:
+       return ret;
+out_unlock_refcount:
+       ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+       brelse(ref_root_bh);
+       return ret;
+}
+
+/* Set up refcount tree and remap s_inode to t_inode. */
+static int ocfs2_reflink_remap_blocks(struct inode *s_inode,
+                                     struct buffer_head *s_bh,
+                                     loff_t pos_in,
+                                     struct inode *t_inode,
+                                     struct buffer_head *t_bh,
+                                     loff_t pos_out,
+                                     loff_t len)
+{
+       struct ocfs2_cached_dealloc_ctxt dealloc;
+       struct ocfs2_super *osb;
+       struct ocfs2_dinode *dis;
+       struct ocfs2_dinode *dit;
+       int ret;
+
+       osb = OCFS2_SB(s_inode->i_sb);
+       dis = (struct ocfs2_dinode *)s_bh->b_data;
+       dit = (struct ocfs2_dinode *)t_bh->b_data;
+       ocfs2_init_dealloc_ctxt(&dealloc);
+
+       /*
+        * If we're reflinking the entire file and the source is inline
+        * data, just copy the contents.
+        */
+       if (pos_in == pos_out && pos_in == 0 && len == i_size_read(s_inode) &&
+           i_size_read(t_inode) <= len &&
+           (OCFS2_I(s_inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)) {
+               ret = ocfs2_duplicate_inline_data(s_inode, s_bh, t_inode, t_bh);
+               if (ret)
+                       mlog_errno(ret);
+               goto out;
+       }
+
+       /*
+        * If both inodes belong to two different refcount groups then
+        * forget it because we don't know how (or want) to go merging
+        * refcount trees.
+        */
+       ret = -EOPNOTSUPP;
+       if (ocfs2_is_refcount_inode(s_inode) &&
+           ocfs2_is_refcount_inode(t_inode) &&
+           le64_to_cpu(dis->i_refcount_loc) !=
+           le64_to_cpu(dit->i_refcount_loc))
+               goto out;
+
+       /* Neither inode has a refcount tree.  Add one to s_inode. */
+       if (!ocfs2_is_refcount_inode(s_inode) &&
+           !ocfs2_is_refcount_inode(t_inode)) {
+               ret = ocfs2_create_refcount_tree(s_inode, s_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       /* Ensure that both inodes end up with the same refcount tree. */
+       if (!ocfs2_is_refcount_inode(s_inode)) {
+               ret = ocfs2_set_refcount_tree(s_inode, s_bh,
+                                             le64_to_cpu(dit->i_refcount_loc));
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+       if (!ocfs2_is_refcount_inode(t_inode)) {
+               ret = ocfs2_set_refcount_tree(t_inode, t_bh,
+                                             le64_to_cpu(dis->i_refcount_loc));
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       /* Turn off inline data in the dest file. */
+       if (OCFS2_I(t_inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               ret = ocfs2_convert_inline_data_to_extents(t_inode, t_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       /* Actually remap extents now. */
+       ret = ocfs2_reflink_remap_extent(s_inode, s_bh, pos_in, t_inode, t_bh,
+                                        pos_out, len, &dealloc);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+out:
+       if (ocfs2_dealloc_has_cluster(&dealloc)) {
+               ocfs2_schedule_truncate_log_flush(osb, 1);
+               ocfs2_run_deallocs(osb, &dealloc);
+       }
+
+       return ret;
+}
+
+/* Lock an inode and grab a bh pointing to the inode. */
+static int ocfs2_reflink_inodes_lock(struct inode *s_inode,
+                                    struct buffer_head **bh1,
+                                    struct inode *t_inode,
+                                    struct buffer_head **bh2)
+{
+       struct inode *inode1;
+       struct inode *inode2;
+       struct ocfs2_inode_info *oi1;
+       struct ocfs2_inode_info *oi2;
+       bool same_inode = (s_inode == t_inode);
+       int status;
+
+       /* First grab the VFS and rw locks. */
+       lock_two_nondirectories(s_inode, t_inode);
+       inode1 = s_inode;
+       inode2 = t_inode;
+       if (inode1->i_ino > inode2->i_ino)
+               swap(inode1, inode2);
+
+       status = ocfs2_rw_lock(inode1, 1);
+       if (status) {
+               mlog_errno(status);
+               goto out_i1;
+       }
+       if (!same_inode) {
+               status = ocfs2_rw_lock(inode2, 1);
+               if (status) {
+                       mlog_errno(status);
+                       goto out_i2;
+               }
+       }
+
+       /* Now go for the cluster locks */
+       oi1 = OCFS2_I(inode1);
+       oi2 = OCFS2_I(inode2);
+
+       trace_ocfs2_double_lock((unsigned long long)oi1->ip_blkno,
+                               (unsigned long long)oi2->ip_blkno);
+
+       if (*bh1)
+               *bh1 = NULL;
+       if (*bh2)
+               *bh2 = NULL;
+
+       /* We always want to lock the one with the lower lockid first. */
+       if (oi1->ip_blkno > oi2->ip_blkno)
+               mlog_errno(-ENOLCK);
+
+       /* lock id1 */
+       status = ocfs2_inode_lock_nested(inode1, bh1, 1, OI_LS_REFLINK_TARGET);
+       if (status < 0) {
+               if (status != -ENOENT)
+                       mlog_errno(status);
+               goto out_rw2;
+       }
+
+       /* lock id2 */
+       if (!same_inode) {
+               status = ocfs2_inode_lock_nested(inode2, bh2, 1,
+                                                OI_LS_REFLINK_TARGET);
+               if (status < 0) {
+                       if (status != -ENOENT)
+                               mlog_errno(status);
+                       goto out_cl1;
+               }
+       } else
+               *bh2 = *bh1;
+
+       trace_ocfs2_double_lock_end(
+                       (unsigned long long)OCFS2_I(inode1)->ip_blkno,
+                       (unsigned long long)OCFS2_I(inode2)->ip_blkno);
+
+       return 0;
+
+out_cl1:
+       ocfs2_inode_unlock(inode1, 1);
+       brelse(*bh1);
+       *bh1 = NULL;
+out_rw2:
+       ocfs2_rw_unlock(inode2, 1);
+out_i2:
+       ocfs2_rw_unlock(inode1, 1);
+out_i1:
+       unlock_two_nondirectories(s_inode, t_inode);
+       return status;
+}
+
+/* Unlock both inodes and release buffers. */
+static void ocfs2_reflink_inodes_unlock(struct inode *s_inode,
+                                       struct buffer_head *s_bh,
+                                       struct inode *t_inode,
+                                       struct buffer_head *t_bh)
+{
+       ocfs2_inode_unlock(s_inode, 1);
+       ocfs2_rw_unlock(s_inode, 1);
+       brelse(s_bh);
+       if (s_inode != t_inode) {
+               ocfs2_inode_unlock(t_inode, 1);
+               ocfs2_rw_unlock(t_inode, 1);
+               brelse(t_bh);
+       }
+       unlock_two_nondirectories(s_inode, t_inode);
+}
+
+/* Link a range of blocks from one file to another. */
+int ocfs2_reflink_remap_range(struct file *file_in,
+                             loff_t pos_in,
+                             struct file *file_out,
+                             loff_t pos_out,
+                             u64 len,
+                             bool is_dedupe)
+{
+       struct inode *inode_in = file_inode(file_in);
+       struct inode *inode_out = file_inode(file_out);
+       struct ocfs2_super *osb = OCFS2_SB(inode_in->i_sb);
+       struct buffer_head *in_bh = NULL, *out_bh = NULL;
+       bool same_inode = (inode_in == inode_out);
+       ssize_t ret;
+
+       if (!ocfs2_refcount_tree(osb))
+               return -EOPNOTSUPP;
+       if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
+               return -EROFS;
+
+       /* Lock both files against IO */
+       ret = ocfs2_reflink_inodes_lock(inode_in, &in_bh, inode_out, &out_bh);
+       if (ret)
+               return ret;
+
+       /* Check file eligibility and prepare for block sharing. */
+       ret = -EINVAL;
+       if ((OCFS2_I(inode_in)->ip_flags & OCFS2_INODE_SYSTEM_FILE) ||
+           (OCFS2_I(inode_out)->ip_flags & OCFS2_INODE_SYSTEM_FILE))
+               goto out_unlock;
+
+       ret = vfs_clone_file_prep_inodes(inode_in, pos_in, inode_out, pos_out,
+                       &len, is_dedupe);
+       if (ret || len == 0)
+               goto out_unlock;
+
+       /* Lock out changes to the allocation maps and remap. */
+       down_write(&OCFS2_I(inode_in)->ip_alloc_sem);
+       if (!same_inode)
+               down_write_nested(&OCFS2_I(inode_out)->ip_alloc_sem,
+                                 SINGLE_DEPTH_NESTING);
+
+       ret = ocfs2_reflink_remap_blocks(inode_in, in_bh, pos_in, inode_out,
+                                        out_bh, pos_out, len);
+
+       /* Zap any page cache for the destination file's range. */
+       if (!ret)
+               truncate_inode_pages_range(&inode_out->i_data, pos_out,
+                                          PAGE_ALIGN(pos_out + len) - 1);
+
+       up_write(&OCFS2_I(inode_in)->ip_alloc_sem);
+       if (!same_inode)
+               up_write(&OCFS2_I(inode_out)->ip_alloc_sem);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       /*
+        * Empty the extent map so that we may get the right extent
+        * record from the disk.
+        */
+       ocfs2_extent_map_trunc(inode_in, 0);
+       ocfs2_extent_map_trunc(inode_out, 0);
+
+       ret = ocfs2_reflink_update_dest(inode_out, out_bh, pos_out + len);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       ocfs2_reflink_inodes_unlock(inode_in, in_bh, inode_out, out_bh);
+       return 0;
+
+out_unlock:
+       ocfs2_reflink_inodes_unlock(inode_in, in_bh, inode_out, out_bh);
+       return ret;
+}
index 6422bbcdb52506b1631ce495ddf4524a4ae71c92..4af55bf4b35b977355fd1df6826e1ddf493f9736 100644 (file)
@@ -115,4 +115,11 @@ int ocfs2_reflink_ioctl(struct inode *inode,
                        const char __user *oldname,
                        const char __user *newname,
                        bool preserve);
+int ocfs2_reflink_remap_range(struct file *file_in,
+                             loff_t pos_in,
+                             struct file *file_out,
+                             loff_t pos_out,
+                             u64 len,
+                             bool is_dedupe);
+
 #endif /* OCFS2_REFCOUNTTREE_H */
index c894d945b084d71d7672f588d561acccf143be43..a24e42f953418b1d675481ed826d47106c1730f4 100644 (file)
@@ -985,7 +985,6 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
        for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (!sb_has_quota_loaded(sb, type))
                        continue;
-               /* Cancel periodic syncing before we grab dqonoff_mutex */
                oinfo = sb_dqinfo(sb, type)->dqi_priv;
                cancel_delayed_work_sync(&oinfo->dqi_sync_work);
                inode = igrab(sb->s_dquot.files[type]);
index 6ad8eecefe21ff26fa43ca92fbe16ee02b90c323..94cfacc9bad70ce0745c14d982a840453aaf6e44 100644 (file)
@@ -87,7 +87,6 @@ const struct address_space_operations ocfs2_fast_symlink_aops = {
 };
 
 const struct inode_operations ocfs2_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .getattr        = ocfs2_getattr,
        .setattr        = ocfs2_setattr,
index cb157a34a65679dff7f298ddacbd4a5c217c35b2..3c5384d9b3a549f319b114a782c7daab966a2c28 100644 (file)
@@ -2577,7 +2577,7 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
        if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
                return 0;
 
-       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) {
+       if (ocfs2_is_refcount_inode(inode)) {
                ret = ocfs2_lock_refcount_tree(OCFS2_SB(inode->i_sb),
                                               le64_to_cpu(di->i_refcount_loc),
                                               1, &ref_tree, &ref_root_bh);
@@ -3608,7 +3608,7 @@ int ocfs2_xattr_set(struct inode *inode,
        }
 
        /* Check whether the value is refcounted and do some preparation. */
-       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL &&
+       if (ocfs2_is_refcount_inode(inode) &&
            (!xis.not_found || !xbs.not_found)) {
                ret = ocfs2_prepare_refcount_xattr(inode, di, &xi,
                                                   &xis, &xbs, &ref_tree,
index 10b0b06e075ef0295a39f9833360a936a3a221bf..02b1bbdbcc42feef7e88af3b6cf5bdb4ff2dba66 100644 (file)
@@ -9,7 +9,6 @@
 #include "orangefs-bufmap.h"
 
 const struct inode_operations orangefs_symlink_inode_operations = {
-       .readlink = generic_readlink,
        .get_link = simple_get_link,
        .setattr = orangefs_setattr,
        .getattr = orangefs_getattr,
index 1ab8b0dbc23788f10c61e0e734e10f42cd717545..08643ac44a0278ed04be96d6df267e3b13821692 100644 (file)
@@ -296,7 +296,6 @@ static const struct inode_operations ovl_file_inode_operations = {
 static const struct inode_operations ovl_symlink_inode_operations = {
        .setattr        = ovl_setattr,
        .get_link       = ovl_get_link,
-       .readlink       = generic_readlink,
        .getattr        = ovl_getattr,
        .listxattr      = ovl_listxattr,
        .update_time    = ovl_update_time,
index 783bc19644d18d2b5b64de10f10169a6e957cc28..873300164dc6b1413da81a6e4d6d56d2a4e2843d 100644 (file)
@@ -425,7 +425,6 @@ static const char *proc_get_link(struct dentry *dentry,
 }
 
 const struct inode_operations proc_link_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = proc_get_link,
 };
 
index 40245954c4501e838b15a00b68b7105ab9ab759a..39857f6db5cfd85c5ae4dff31b85f2739d783648 100644 (file)
@@ -6,18 +6,6 @@
 /*
  * /proc/self:
  */
-static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
-                             int buflen)
-{
-       struct pid_namespace *ns = dentry->d_sb->s_fs_info;
-       pid_t tgid = task_tgid_nr_ns(current, ns);
-       char tmp[PROC_NUMBUF];
-       if (!tgid)
-               return -ENOENT;
-       sprintf(tmp, "%d", tgid);
-       return readlink_copy(buffer, buflen, tmp);
-}
-
 static const char *proc_self_get_link(struct dentry *dentry,
                                      struct inode *inode,
                                      struct delayed_call *done)
@@ -38,7 +26,6 @@ static const char *proc_self_get_link(struct dentry *dentry,
 }
 
 static const struct inode_operations proc_self_inode_operations = {
-       .readlink       = proc_self_readlink,
        .get_link       = proc_self_get_link,
 };
 
index 595b90a9766c98c93014418486397f0e508873f1..20614b62a9b793cd357b76f1eba97ab9218f89e7 100644 (file)
@@ -6,19 +6,6 @@
 /*
  * /proc/thread_self:
  */
-static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
-                             int buflen)
-{
-       struct pid_namespace *ns = dentry->d_sb->s_fs_info;
-       pid_t tgid = task_tgid_nr_ns(current, ns);
-       pid_t pid = task_pid_nr_ns(current, ns);
-       char tmp[PROC_NUMBUF + 6 + PROC_NUMBUF];
-       if (!pid)
-               return -ENOENT;
-       sprintf(tmp, "%d/task/%d", tgid, pid);
-       return readlink_copy(buffer, buflen, tmp);
-}
-
 static const char *proc_thread_self_get_link(struct dentry *dentry,
                                             struct inode *inode,
                                             struct delayed_call *done)
@@ -40,7 +27,6 @@ static const char *proc_thread_self_get_link(struct dentry *dentry,
 }
 
 static const struct inode_operations proc_thread_self_inode_operations = {
-       .readlink       = proc_thread_self_readlink,
        .get_link       = proc_thread_self_get_link,
 };
 
index 1bfac28b7e7df1febe08012abf2ad51d3189cc54..406fed92362a3da805b7f1834268acd2e996d46f 100644 (file)
  * spinlock to internal buffers before writing.
  *
  * Lock ordering (including related VFS locks) is the following:
- *   dqonoff_mutex > i_mutex > journal_lock > dquot->dq_lock > dqio_mutex
- * dqonoff_mutex > i_mutex comes from dquot_quota_sync, dquot_enable, etc.
+ *   s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_mutex
  */
 
 static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock);
@@ -572,7 +571,8 @@ int dquot_scan_active(struct super_block *sb,
        struct dquot *dquot, *old_dquot = NULL;
        int ret = 0;
 
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
+       WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount));
+
        spin_lock(&dq_list_lock);
        list_for_each_entry(dquot, &inuse_list, dq_inuse) {
                if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
@@ -603,7 +603,6 @@ int dquot_scan_active(struct super_block *sb,
        spin_unlock(&dq_list_lock);
 out:
        dqput(old_dquot);
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return ret;
 }
 EXPORT_SYMBOL(dquot_scan_active);
@@ -617,7 +616,8 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
        int cnt;
        int err, ret = 0;
 
-       mutex_lock(&dqopt->dqonoff_mutex);
+       WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount));
+
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
@@ -653,7 +653,6 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
                    && info_dirty(&dqopt->info[cnt]))
                        sb->dq_op->write_info(sb, cnt);
        dqstats_inc(DQST_SYNCS);
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
        return ret;
 }
@@ -683,7 +682,6 @@ int dquot_quota_sync(struct super_block *sb, int type)
         * Now when everything is written we can discard the pagecache so
         * that userspace sees the changes.
         */
-       mutex_lock(&dqopt->dqonoff_mutex);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
@@ -693,7 +691,6 @@ int dquot_quota_sync(struct super_block *sb, int type)
                truncate_inode_pages(&dqopt->files[cnt]->i_data, 0);
                inode_unlock(dqopt->files[cnt]);
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
        return 0;
 }
@@ -935,7 +932,7 @@ static int dqinit_needed(struct inode *inode, int type)
        return 0;
 }
 
-/* This routine is guarded by dqonoff_mutex mutex */
+/* This routine is guarded by s_umount semaphore */
 static void add_dquot_ref(struct super_block *sb, int type)
 {
        struct inode *inode, *old_inode = NULL;
@@ -2050,21 +2047,13 @@ int dquot_get_next_id(struct super_block *sb, struct kqid *qid)
        struct quota_info *dqopt = sb_dqopt(sb);
        int err;
 
-       mutex_lock(&dqopt->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, qid->type)) {
-               err = -ESRCH;
-               goto out;
-       }
-       if (!dqopt->ops[qid->type]->get_next_id) {
-               err = -ENOSYS;
-               goto out;
-       }
+       if (!sb_has_quota_active(sb, qid->type))
+               return -ESRCH;
+       if (!dqopt->ops[qid->type]->get_next_id)
+               return -ENOSYS;
        mutex_lock(&dqopt->dqio_mutex);
        err = dqopt->ops[qid->type]->get_next_id(sb, qid);
        mutex_unlock(&dqopt->dqio_mutex);
-out:
-       mutex_unlock(&dqopt->dqonoff_mutex);
-
        return err;
 }
 EXPORT_SYMBOL(dquot_get_next_id);
@@ -2107,6 +2096,10 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
        struct quota_info *dqopt = sb_dqopt(sb);
        struct inode *toputinode[MAXQUOTAS];
 
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
+
        /* Cannot turn off usage accounting without turning off limits, or
         * suspend quotas and simultaneously turn quotas off. */
        if ((flags & DQUOT_USAGE_ENABLED && !(flags & DQUOT_LIMITS_ENABLED))
@@ -2114,18 +2107,14 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
            DQUOT_USAGE_ENABLED)))
                return -EINVAL;
 
-       /* We need to serialize quota_off() for device */
-       mutex_lock(&dqopt->dqonoff_mutex);
-
        /*
         * Skip everything if there's nothing to do. We have to do this because
         * sometimes we are called when fill_super() failed and calling
         * sync_fs() in such cases does no good.
         */
-       if (!sb_any_quota_loaded(sb)) {
-               mutex_unlock(&dqopt->dqonoff_mutex);
+       if (!sb_any_quota_loaded(sb))
                return 0;
-       }
+
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                toputinode[cnt] = NULL;
                if (type != -1 && cnt != type)
@@ -2179,7 +2168,6 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
                dqopt->info[cnt].dqi_bgrace = 0;
                dqopt->ops[cnt] = NULL;
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
        /* Skip syncing and setting flags if quota files are hidden */
        if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)
@@ -2196,20 +2184,14 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
         * must also discard the blockdev buffers so that we see the
         * changes done by userspace on the next quotaon() */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               if (toputinode[cnt]) {
-                       mutex_lock(&dqopt->dqonoff_mutex);
-                       /* If quota was reenabled in the meantime, we have
-                        * nothing to do */
-                       if (!sb_has_quota_loaded(sb, cnt)) {
-                               inode_lock(toputinode[cnt]);
-                               toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |
+               /* This can happen when suspending quotas on remount-ro... */
+               if (toputinode[cnt] && !sb_has_quota_loaded(sb, cnt)) {
+                       inode_lock(toputinode[cnt]);
+                       toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |
                                  S_NOATIME | S_NOQUOTA);
-                               truncate_inode_pages(&toputinode[cnt]->i_data,
-                                                    0);
-                               inode_unlock(toputinode[cnt]);
-                               mark_inode_dirty_sync(toputinode[cnt]);
-                       }
-                       mutex_unlock(&dqopt->dqonoff_mutex);
+                       truncate_inode_pages(&toputinode[cnt]->i_data, 0);
+                       inode_unlock(toputinode[cnt]);
+                       mark_inode_dirty_sync(toputinode[cnt]);
                }
        if (sb->s_bdev)
                invalidate_bdev(sb->s_bdev);
@@ -2281,6 +2263,10 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                error = -EINVAL;
                goto out_fmt;
        }
+       if (sb_has_quota_loaded(sb, type)) {
+               error = -EBUSY;
+               goto out_fmt;
+       }
 
        if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
                /* As we bypass the pagecache we must now flush all the
@@ -2292,11 +2278,6 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                sync_filesystem(sb);
                invalidate_bdev(sb->s_bdev);
        }
-       mutex_lock(&dqopt->dqonoff_mutex);
-       if (sb_has_quota_loaded(sb, type)) {
-               error = -EBUSY;
-               goto out_lock;
-       }
 
        if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
                /* We don't want quota and atime on quota files (deadlocks
@@ -2317,7 +2298,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
        error = -EIO;
        dqopt->files[type] = igrab(inode);
        if (!dqopt->files[type])
-               goto out_lock;
+               goto out_file_flags;
        error = -EINVAL;
        if (!fmt->qf_ops->check_quota_file(sb, type))
                goto out_file_init;
@@ -2340,14 +2321,13 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
        spin_unlock(&dq_state_lock);
 
        add_dquot_ref(sb, type);
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
        return 0;
 
 out_file_init:
        dqopt->files[type] = NULL;
        iput(inode);
-out_lock:
+out_file_flags:
        if (oldflags != -1) {
                inode_lock(inode);
                /* Set the flags back (in the case of accidental quotaon()
@@ -2356,7 +2336,6 @@ out_lock:
                inode->i_flags |= oldflags;
                inode_unlock(inode);
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
 out_fmt:
        put_quota_format(fmt);
 
@@ -2371,15 +2350,16 @@ int dquot_resume(struct super_block *sb, int type)
        int ret = 0, cnt;
        unsigned int flags;
 
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
+
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
-
-               mutex_lock(&dqopt->dqonoff_mutex);
-               if (!sb_has_quota_suspended(sb, cnt)) {
-                       mutex_unlock(&dqopt->dqonoff_mutex);
+               if (!sb_has_quota_suspended(sb, cnt))
                        continue;
-               }
+
                inode = dqopt->files[cnt];
                dqopt->files[cnt] = NULL;
                spin_lock(&dq_state_lock);
@@ -2388,7 +2368,6 @@ int dquot_resume(struct super_block *sb, int type)
                                                        cnt);
                dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, cnt);
                spin_unlock(&dq_state_lock);
-               mutex_unlock(&dqopt->dqonoff_mutex);
 
                flags = dquot_generic_flag(flags, cnt);
                ret = vfs_load_quota_inode(inode, cnt,
@@ -2401,7 +2380,7 @@ int dquot_resume(struct super_block *sb, int type)
 EXPORT_SYMBOL(dquot_resume);
 
 int dquot_quota_on(struct super_block *sb, int type, int format_id,
-                  struct path *path)
+                  const struct path *path)
 {
        int error = security_quota_on(path->dentry);
        if (error)
@@ -2424,42 +2403,30 @@ EXPORT_SYMBOL(dquot_quota_on);
 int dquot_enable(struct inode *inode, int type, int format_id,
                 unsigned int flags)
 {
-       int ret = 0;
        struct super_block *sb = inode->i_sb;
-       struct quota_info *dqopt = sb_dqopt(sb);
 
        /* Just unsuspend quotas? */
        BUG_ON(flags & DQUOT_SUSPENDED);
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
 
        if (!flags)
                return 0;
        /* Just updating flags needed? */
        if (sb_has_quota_loaded(sb, type)) {
-               mutex_lock(&dqopt->dqonoff_mutex);
-               /* Now do a reliable test... */
-               if (!sb_has_quota_loaded(sb, type)) {
-                       mutex_unlock(&dqopt->dqonoff_mutex);
-                       goto load_quota;
-               }
                if (flags & DQUOT_USAGE_ENABLED &&
-                   sb_has_quota_usage_enabled(sb, type)) {
-                       ret = -EBUSY;
-                       goto out_lock;
-               }
+                   sb_has_quota_usage_enabled(sb, type))
+                       return -EBUSY;
                if (flags & DQUOT_LIMITS_ENABLED &&
-                   sb_has_quota_limits_enabled(sb, type)) {
-                       ret = -EBUSY;
-                       goto out_lock;
-               }
+                   sb_has_quota_limits_enabled(sb, type))
+                       return -EBUSY;
                spin_lock(&dq_state_lock);
                sb_dqopt(sb)->flags |= dquot_state_flag(flags, type);
                spin_unlock(&dq_state_lock);
-out_lock:
-               mutex_unlock(&dqopt->dqonoff_mutex);
-               return ret;
+               return 0;
        }
 
-load_quota:
        return vfs_load_quota_inode(inode, type, format_id, flags);
 }
 EXPORT_SYMBOL(dquot_enable);
@@ -2751,7 +2718,6 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state)
        struct quota_info *dqopt = sb_dqopt(sb);
        int type;
   
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        memset(state, 0, sizeof(*state));
        for (type = 0; type < MAXQUOTAS; type++) {
                if (!sb_has_quota_active(sb, type))
@@ -2773,7 +2739,6 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state)
                tstate->nextents = 1;   /* We don't know... */
                spin_unlock(&dq_data_lock);
        }
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
 EXPORT_SYMBOL(dquot_get_state);
@@ -2787,18 +2752,13 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii)
        if ((ii->i_fieldmask & QC_WARNS_MASK) ||
            (ii->i_fieldmask & QC_RT_SPC_TIMER))
                return -EINVAL;
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, type)) {
-               err = -ESRCH;
-               goto out;
-       }
+       if (!sb_has_quota_active(sb, type))
+               return -ESRCH;
        mi = sb_dqopt(sb)->info + type;
        if (ii->i_fieldmask & QC_FLAGS) {
                if ((ii->i_flags & QCI_ROOT_SQUASH &&
-                    mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                    mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD))
+                       return -EINVAL;
        }
        spin_lock(&dq_data_lock);
        if (ii->i_fieldmask & QC_SPC_TIMER)
@@ -2815,8 +2775,6 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii)
        mark_info_dirty(sb, type);
        /* Force write to disk */
        sb->dq_op->write_info(sb, type);
-out:
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return err;
 }
 EXPORT_SYMBOL(dquot_set_dqinfo);
index 2d445425aad713312ad9153bf9e2fc7832ec0ea8..07e08c7d05cae23d92ab891cb384e5dda90509df 100644 (file)
@@ -80,7 +80,7 @@ unsigned int qtype_enforce_flag(int type)
 }
 
 static int quota_quotaon(struct super_block *sb, int type, qid_t id,
-                        struct path *path)
+                        const struct path *path)
 {
        if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_enable)
                return -ENOSYS;
@@ -104,13 +104,9 @@ static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
 {
        __u32 fmt;
 
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, type)) {
-               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
+       if (!sb_has_quota_active(sb, type))
                return -ESRCH;
-       }
        fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        if (copy_to_user(addr, &fmt, sizeof(fmt)))
                return -EFAULT;
        return 0;
@@ -700,7 +696,7 @@ static int quota_rmxquota(struct super_block *sb, void __user *addr)
 
 /* Copy parameters and call proper function */
 static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
-                      void __user *addr, struct path *path)
+                      void __user *addr, const struct path *path)
 {
        int ret;
 
@@ -789,9 +785,14 @@ static int quotactl_cmd_write(int cmd)
        }
        return 1;
 }
-
 #endif /* CONFIG_BLOCK */
 
+/* Return true if quotactl command is manipulating quota on/off state */
+static bool quotactl_cmd_onoff(int cmd)
+{
+       return (cmd == Q_QUOTAON) || (cmd == Q_QUOTAOFF);
+}
+
 /*
  * look up a superblock on which quota ops will be performed
  * - use the name of a block device to find the superblock thereon
@@ -809,7 +810,9 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
        putname(tmp);
        if (IS_ERR(bdev))
                return ERR_CAST(bdev);
-       if (quotactl_cmd_write(cmd))
+       if (quotactl_cmd_onoff(cmd))
+               sb = get_super_exclusive_thawed(bdev);
+       else if (quotactl_cmd_write(cmd))
                sb = get_super_thawed(bdev);
        else
                sb = get_super(bdev);
@@ -872,7 +875,10 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
 
        ret = do_quotactl(sb, type, cmds, id, addr, pathp);
 
-       drop_super(sb);
+       if (!quotactl_cmd_onoff(cmds))
+               drop_super(sb);
+       else
+               drop_super_exclusive(sb);
 out:
        if (pathp && !IS_ERR(pathp))
                path_put(pathp);
index 53bccd1c786e783b9e4083658a864a880c65c11f..da6de12b5c46d4a56e15e892f527153682ff6e30 100644 (file)
@@ -1540,20 +1540,37 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
 
        sb_start_write(inode_out->i_sb);
 
-       ret = -EOPNOTSUPP;
-       if (file_out->f_op->copy_file_range)
+       /*
+        * Try cloning first, this is supported by more file systems, and
+        * more efficient if both clone and copy are supported (e.g. NFS).
+        */
+       if (file_in->f_op->clone_file_range) {
+               ret = file_in->f_op->clone_file_range(file_in, pos_in,
+                               file_out, pos_out, len);
+               if (ret == 0) {
+                       ret = len;
+                       goto done;
+               }
+       }
+
+       if (file_out->f_op->copy_file_range) {
                ret = file_out->f_op->copy_file_range(file_in, pos_in, file_out,
                                                      pos_out, len, flags);
-       if (ret == -EOPNOTSUPP)
-               ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out,
-                               len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
+               if (ret != -EOPNOTSUPP)
+                       goto done;
+       }
+
+       ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out,
+                       len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
 
+done:
        if (ret > 0) {
                fsnotify_access(file_in);
                add_rchar(current, ret);
                fsnotify_modify(file_out);
                add_wchar(current, ret);
        }
+
        inc_syscr(current);
        inc_syscw(current);
 
@@ -1648,6 +1665,114 @@ static int clone_verify_area(struct file *file, loff_t pos, u64 len, bool write)
        return security_file_permission(file, write ? MAY_WRITE : MAY_READ);
 }
 
+/*
+ * Check that the two inodes are eligible for cloning, the ranges make
+ * sense, and then flush all dirty data.  Caller must ensure that the
+ * inodes have been locked against any other modifications.
+ */
+int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,
+                              struct inode *inode_out, loff_t pos_out,
+                              u64 *len, bool is_dedupe)
+{
+       loff_t bs = inode_out->i_sb->s_blocksize;
+       loff_t blen;
+       loff_t isize;
+       bool same_inode = (inode_in == inode_out);
+       int ret;
+
+       /* Don't touch certain kinds of inodes */
+       if (IS_IMMUTABLE(inode_out))
+               return -EPERM;
+
+       if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
+               return -ETXTBSY;
+
+       /* Don't reflink dirs, pipes, sockets... */
+       if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
+               return -EISDIR;
+       if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
+               return -EINVAL;
+
+       /* Are we going all the way to the end? */
+       isize = i_size_read(inode_in);
+       if (isize == 0) {
+               *len = 0;
+               return 0;
+       }
+
+       /* Zero length dedupe exits immediately; reflink goes to EOF. */
+       if (*len == 0) {
+               if (is_dedupe) {
+                       *len = 0;
+                       return 0;
+               }
+               *len = isize - pos_in;
+       }
+
+       /* Ensure offsets don't wrap and the input is inside i_size */
+       if (pos_in + *len < pos_in || pos_out + *len < pos_out ||
+           pos_in + *len > isize)
+               return -EINVAL;
+
+       /* Don't allow dedupe past EOF in the dest file */
+       if (is_dedupe) {
+               loff_t  disize;
+
+               disize = i_size_read(inode_out);
+               if (pos_out >= disize || pos_out + *len > disize)
+                       return -EINVAL;
+       }
+
+       /* If we're linking to EOF, continue to the block boundary. */
+       if (pos_in + *len == isize)
+               blen = ALIGN(isize, bs) - pos_in;
+       else
+               blen = *len;
+
+       /* Only reflink if we're aligned to block boundaries */
+       if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) ||
+           !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs))
+               return -EINVAL;
+
+       /* Don't allow overlapped reflink within the same file */
+       if (same_inode) {
+               if (pos_out + blen > pos_in && pos_out < pos_in + blen)
+                       return -EINVAL;
+       }
+
+       /* Wait for the completion of any pending IOs on both files */
+       inode_dio_wait(inode_in);
+       if (!same_inode)
+               inode_dio_wait(inode_out);
+
+       ret = filemap_write_and_wait_range(inode_in->i_mapping,
+                       pos_in, pos_in + *len - 1);
+       if (ret)
+               return ret;
+
+       ret = filemap_write_and_wait_range(inode_out->i_mapping,
+                       pos_out, pos_out + *len - 1);
+       if (ret)
+               return ret;
+
+       /*
+        * Check that the extents are the same.
+        */
+       if (is_dedupe) {
+               bool            is_same = false;
+
+               ret = vfs_dedupe_file_range_compare(inode_in, pos_in,
+                               inode_out, pos_out, *len, &is_same);
+               if (ret)
+                       return ret;
+               if (!is_same)
+                       return -EBADE;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(vfs_clone_file_prep_inodes);
+
 int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
                struct file *file_out, loff_t pos_out, u64 len)
 {
@@ -1698,6 +1823,102 @@ int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
 }
 EXPORT_SYMBOL(vfs_clone_file_range);
 
+/*
+ * Read a page's worth of file data into the page cache.  Return the page
+ * locked.
+ */
+static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset)
+{
+       struct address_space *mapping;
+       struct page *page;
+       pgoff_t n;
+
+       n = offset >> PAGE_SHIFT;
+       mapping = inode->i_mapping;
+       page = read_mapping_page(mapping, n, NULL);
+       if (IS_ERR(page))
+               return page;
+       if (!PageUptodate(page)) {
+               put_page(page);
+               return ERR_PTR(-EIO);
+       }
+       lock_page(page);
+       return page;
+}
+
+/*
+ * Compare extents of two files to see if they are the same.
+ * Caller must have locked both inodes to prevent write races.
+ */
+int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
+                                 struct inode *dest, loff_t destoff,
+                                 loff_t len, bool *is_same)
+{
+       loff_t src_poff;
+       loff_t dest_poff;
+       void *src_addr;
+       void *dest_addr;
+       struct page *src_page;
+       struct page *dest_page;
+       loff_t cmp_len;
+       bool same;
+       int error;
+
+       error = -EINVAL;
+       same = true;
+       while (len) {
+               src_poff = srcoff & (PAGE_SIZE - 1);
+               dest_poff = destoff & (PAGE_SIZE - 1);
+               cmp_len = min(PAGE_SIZE - src_poff,
+                             PAGE_SIZE - dest_poff);
+               cmp_len = min(cmp_len, len);
+               if (cmp_len <= 0)
+                       goto out_error;
+
+               src_page = vfs_dedupe_get_page(src, srcoff);
+               if (IS_ERR(src_page)) {
+                       error = PTR_ERR(src_page);
+                       goto out_error;
+               }
+               dest_page = vfs_dedupe_get_page(dest, destoff);
+               if (IS_ERR(dest_page)) {
+                       error = PTR_ERR(dest_page);
+                       unlock_page(src_page);
+                       put_page(src_page);
+                       goto out_error;
+               }
+               src_addr = kmap_atomic(src_page);
+               dest_addr = kmap_atomic(dest_page);
+
+               flush_dcache_page(src_page);
+               flush_dcache_page(dest_page);
+
+               if (memcmp(src_addr + src_poff, dest_addr + dest_poff, cmp_len))
+                       same = false;
+
+               kunmap_atomic(dest_addr);
+               kunmap_atomic(src_addr);
+               unlock_page(dest_page);
+               unlock_page(src_page);
+               put_page(dest_page);
+               put_page(src_page);
+
+               if (!same)
+                       break;
+
+               srcoff += cmp_len;
+               destoff += cmp_len;
+               len -= cmp_len;
+       }
+
+       *is_same = same;
+       return 0;
+
+out_error:
+       return error;
+}
+EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
+
 int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
 {
        struct file_dedupe_range_info *info;
index e6a2b406af367071920a332bf6dc62a5d72e8fcf..bd39a998843da62db4b634800813c3de29d969c7 100644 (file)
@@ -1665,7 +1665,6 @@ const struct inode_operations reiserfs_dir_inode_operations = {
  * stuff added
  */
 const struct inode_operations reiserfs_symlink_inode_operations = {
-       .readlink = generic_readlink,
        .get_link       = page_get_link,
        .setattr = reiserfs_setattr,
        .listxattr = reiserfs_listxattr,
index 0a6ad4e71e88dd0c2a7a3b3c4eaaa1671ba6dcad..e314cb30a181e1017f7df769f7faf1bef89bdef1 100644 (file)
@@ -802,7 +802,7 @@ static int reiserfs_acquire_dquot(struct dquot *);
 static int reiserfs_release_dquot(struct dquot *);
 static int reiserfs_mark_dquot_dirty(struct dquot *);
 static int reiserfs_write_info(struct super_block *, int);
-static int reiserfs_quota_on(struct super_block *, int, int, struct path *);
+static int reiserfs_quota_on(struct super_block *, int, int, const struct path *);
 
 static const struct dquot_operations reiserfs_quota_operations = {
        .write_dquot = reiserfs_write_dquot,
@@ -2348,7 +2348,7 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type)
  * Standard function to be called on quota_on
  */
 static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
-                            struct path *path)
+                            const struct path *path)
 {
        int err;
        struct inode *inode;
index 79b9c31a0c8ffdd223b83f9c243918e64ef3ed59..befeba0fa70af27b9b239c38d6e9592604cad071 100644 (file)
@@ -118,7 +118,6 @@ const struct address_space_operations squashfs_symlink_aops = {
 };
 
 const struct inode_operations squashfs_symlink_inode_ops = {
-       .readlink = generic_readlink,
        .get_link = page_get_link,
        .listxattr = squashfs_listxattr
 };
index bc045c7994e1bf6fe98af3a475afaeb4ecd8f16a..0b210c3ead5c3d60b9fe9035a56d3c79519da563 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -329,12 +329,14 @@ retry:
                struct inode *inode = d_backing_inode(path.dentry);
 
                error = empty ? -ENOENT : -EINVAL;
-               if (inode->i_op->readlink) {
+               /*
+                * AFS mountpoints allow readlink(2) but are not symlinks
+                */
+               if (d_is_symlink(path.dentry) || inode->i_op->readlink) {
                        error = security_inode_readlink(path.dentry);
                        if (!error) {
                                touch_atime(&path);
-                               error = inode->i_op->readlink(path.dentry,
-                                                             buf, bufsiz);
+                               error = vfs_readlink(path.dentry, buf, bufsiz);
                        }
                }
                path_put(&path);
index 083dc0ac91408870254cac60ed4b06580deba610..13ae259d48795a782e566b7deaceadc73f86d8c7 100644 (file)
@@ -63,7 +63,7 @@ static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
        return retval;
 }
 
-int vfs_statfs(struct path *path, struct kstatfs *buf)
+int vfs_statfs(const struct path *path, struct kstatfs *buf)
 {
        int error;
 
index c183835566c19c56fd30d6a1c22d380d10668411..1709ed029a2cae70c3d4a6cccccca760a0ad003f 100644 (file)
@@ -244,7 +244,6 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
        mutex_init(&s->s_vfs_rename_mutex);
        lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key);
        mutex_init(&s->s_dquot.dqio_mutex);
-       mutex_init(&s->s_dquot.dqonoff_mutex);
        s->s_maxbytes = MAX_NON_LFS;
        s->s_op = &default_op;
        s->s_time_gran = 1000000000;
@@ -558,6 +557,13 @@ void drop_super(struct super_block *sb)
 
 EXPORT_SYMBOL(drop_super);
 
+void drop_super_exclusive(struct super_block *sb)
+{
+       up_write(&sb->s_umount);
+       put_super(sb);
+}
+EXPORT_SYMBOL(drop_super_exclusive);
+
 /**
  *     iterate_supers - call function for all active superblocks
  *     @f: function to call
@@ -628,15 +634,7 @@ void iterate_supers_type(struct file_system_type *type,
 
 EXPORT_SYMBOL(iterate_supers_type);
 
-/**
- *     get_super - get the superblock of a device
- *     @bdev: device to get the superblock for
- *     
- *     Scans the superblock list and finds the superblock of the file system
- *     mounted on the device given. %NULL is returned if no match is found.
- */
-
-struct super_block *get_super(struct block_device *bdev)
+static struct super_block *__get_super(struct block_device *bdev, bool excl)
 {
        struct super_block *sb;
 
@@ -651,11 +649,17 @@ rescan:
                if (sb->s_bdev == bdev) {
                        sb->s_count++;
                        spin_unlock(&sb_lock);
-                       down_read(&sb->s_umount);
+                       if (!excl)
+                               down_read(&sb->s_umount);
+                       else
+                               down_write(&sb->s_umount);
                        /* still alive? */
                        if (sb->s_root && (sb->s_flags & MS_BORN))
                                return sb;
-                       up_read(&sb->s_umount);
+                       if (!excl)
+                               up_read(&sb->s_umount);
+                       else
+                               up_write(&sb->s_umount);
                        /* nope, got unmounted */
                        spin_lock(&sb_lock);
                        __put_super(sb);
@@ -666,31 +670,66 @@ rescan:
        return NULL;
 }
 
-EXPORT_SYMBOL(get_super);
-
 /**
- *     get_super_thawed - get thawed superblock of a device
+ *     get_super - get the superblock of a device
  *     @bdev: device to get the superblock for
  *
  *     Scans the superblock list and finds the superblock of the file system
- *     mounted on the device. The superblock is returned once it is thawed
- *     (or immediately if it was not frozen). %NULL is returned if no match
- *     is found.
+ *     mounted on the device given. %NULL is returned if no match is found.
  */
-struct super_block *get_super_thawed(struct block_device *bdev)
+struct super_block *get_super(struct block_device *bdev)
+{
+       return __get_super(bdev, false);
+}
+EXPORT_SYMBOL(get_super);
+
+static struct super_block *__get_super_thawed(struct block_device *bdev,
+                                             bool excl)
 {
        while (1) {
-               struct super_block *s = get_super(bdev);
+               struct super_block *s = __get_super(bdev, excl);
                if (!s || s->s_writers.frozen == SB_UNFROZEN)
                        return s;
-               up_read(&s->s_umount);
+               if (!excl)
+                       up_read(&s->s_umount);
+               else
+                       up_write(&s->s_umount);
                wait_event(s->s_writers.wait_unfrozen,
                           s->s_writers.frozen == SB_UNFROZEN);
                put_super(s);
        }
 }
+
+/**
+ *     get_super_thawed - get thawed superblock of a device
+ *     @bdev: device to get the superblock for
+ *
+ *     Scans the superblock list and finds the superblock of the file system
+ *     mounted on the device. The superblock is returned once it is thawed
+ *     (or immediately if it was not frozen). %NULL is returned if no match
+ *     is found.
+ */
+struct super_block *get_super_thawed(struct block_device *bdev)
+{
+       return __get_super_thawed(bdev, false);
+}
 EXPORT_SYMBOL(get_super_thawed);
 
+/**
+ *     get_super_exclusive_thawed - get thawed superblock of a device
+ *     @bdev: device to get the superblock for
+ *
+ *     Scans the superblock list and finds the superblock of the file system
+ *     mounted on the device. The superblock is returned once it is thawed
+ *     (or immediately if it was not frozen) and s_umount semaphore is held
+ *     in exclusive mode. %NULL is returned if no match is found.
+ */
+struct super_block *get_super_exclusive_thawed(struct block_device *bdev)
+{
+       return __get_super_thawed(bdev, true);
+}
+EXPORT_SYMBOL(get_super_exclusive_thawed);
+
 /**
  * get_active_super - get an active reference to the superblock of a device
  * @bdev: device to get the superblock for
index d62c423a5a2d8723807d2bb5f65b227042dcf724..858fb72f9e0fa76a7b2214bb518537733bc1dea4 100644 (file)
@@ -145,7 +145,6 @@ static inline void write3byte(struct sysv_sb_info *sbi,
 }
 
 static const struct inode_operations sysv_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = page_get_link,
        .getattr        = sysv_getattr,
 };
index aa0625f4f6427677f38f8c5d6e177f58572ad05d..b0d783774c963c97f32df7649feeb8fb7e4e3e4f 100644 (file)
@@ -1733,7 +1733,6 @@ const struct inode_operations ubifs_file_inode_operations = {
 };
 
 const struct inode_operations ubifs_symlink_inode_operations = {
-       .readlink    = generic_readlink,
        .get_link    = ubifs_get_link,
        .setattr     = ubifs_setattr,
        .getattr     = ubifs_getattr,
index 22307cdf7014ba84887a036356deb54fe235d13d..5fdb505e307c5bf754a09a0ba06274169e45a31b 100644 (file)
@@ -48,7 +48,7 @@ static bool nsec_valid(long nsec)
        return nsec >= 0 && nsec <= 999999999;
 }
 
-static int utimes_common(struct path *path, struct timespec *times)
+static int utimes_common(const struct path *path, struct timespec *times)
 {
        int error;
        struct iattr newattrs;
index 65d27a5029093e265557824f103de3441790c31e..bbb9eb6811b2e07f05652be729a9142fbcc169d0 100644 (file)
@@ -848,24 +848,6 @@ out_unlock:
        return error;
 }
 
-STATIC ssize_t
-xfs_file_copy_range(
-       struct file     *file_in,
-       loff_t          pos_in,
-       struct file     *file_out,
-       loff_t          pos_out,
-       size_t          len,
-       unsigned int    flags)
-{
-       int             error;
-
-       error = xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
-                                    len, false);
-       if (error)
-               return error;
-       return len;
-}
-
 STATIC int
 xfs_file_clone_range(
        struct file     *file_in,
@@ -1549,7 +1531,6 @@ const struct file_operations xfs_file_operations = {
        .fsync          = xfs_file_fsync,
        .get_unmapped_area = thp_get_unmapped_area,
        .fallocate      = xfs_file_fallocate,
-       .copy_file_range = xfs_file_copy_range,
        .clone_file_range = xfs_file_clone_range,
        .dedupe_file_range = xfs_file_dedupe_range,
 };
index fc563b82aea65a666aecd67f349046c06d68147b..c67cfb451fd3a74dad2d365e372b4e5fa296eecd 100644 (file)
@@ -287,7 +287,7 @@ xfs_readlink_by_handle(
                return PTR_ERR(dentry);
 
        /* Restrict this handle operation to symlinks only. */
-       if (!d_inode(dentry)->i_op->readlink) {
+       if (!d_is_symlink(dentry)) {
                error = -EINVAL;
                goto out_dput;
        }
@@ -297,7 +297,7 @@ xfs_readlink_by_handle(
                goto out_dput;
        }
 
-       error = d_inode(dentry)->i_op->readlink(dentry, hreq->ohandle, olen);
+       error = vfs_readlink(dentry, hreq->ohandle, olen);
 
  out_dput:
        dput(dentry);
index b930be0b1596592de8fc71aecbb25c033c513f17..308bebb6dfd266f85ae225ef0c235128bb7b36ba 100644 (file)
@@ -1120,7 +1120,6 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
 };
 
 static const struct inode_operations xfs_symlink_inode_operations = {
-       .readlink               = generic_readlink,
        .get_link               = xfs_vn_get_link,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
@@ -1129,7 +1128,6 @@ static const struct inode_operations xfs_symlink_inode_operations = {
 };
 
 static const struct inode_operations xfs_inline_symlink_inode_operations = {
-       .readlink               = generic_readlink,
        .get_link               = xfs_vn_get_link_inline,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
index 88fd03c66e990a02aa444ccae9bf0227ed70fc50..aca2d4bd4303b07b41a86d0bbe1e43bb4fe88308 100644 (file)
@@ -1113,111 +1113,6 @@ err:
        return error;
 }
 
-/*
- * Read a page's worth of file data into the page cache.  Return the page
- * locked.
- */
-static struct page *
-xfs_get_page(
-       struct inode    *inode,
-       xfs_off_t       offset)
-{
-       struct address_space    *mapping;
-       struct page             *page;
-       pgoff_t                 n;
-
-       n = offset >> PAGE_SHIFT;
-       mapping = inode->i_mapping;
-       page = read_mapping_page(mapping, n, NULL);
-       if (IS_ERR(page))
-               return page;
-       if (!PageUptodate(page)) {
-               put_page(page);
-               return ERR_PTR(-EIO);
-       }
-       lock_page(page);
-       return page;
-}
-
-/*
- * Compare extents of two files to see if they are the same.
- */
-static int
-xfs_compare_extents(
-       struct inode    *src,
-       xfs_off_t       srcoff,
-       struct inode    *dest,
-       xfs_off_t       destoff,
-       xfs_off_t       len,
-       bool            *is_same)
-{
-       xfs_off_t       src_poff;
-       xfs_off_t       dest_poff;
-       void            *src_addr;
-       void            *dest_addr;
-       struct page     *src_page;
-       struct page     *dest_page;
-       xfs_off_t       cmp_len;
-       bool            same;
-       int             error;
-
-       error = -EINVAL;
-       same = true;
-       while (len) {
-               src_poff = srcoff & (PAGE_SIZE - 1);
-               dest_poff = destoff & (PAGE_SIZE - 1);
-               cmp_len = min(PAGE_SIZE - src_poff,
-                             PAGE_SIZE - dest_poff);
-               cmp_len = min(cmp_len, len);
-               ASSERT(cmp_len > 0);
-
-               trace_xfs_reflink_compare_extents(XFS_I(src), srcoff, cmp_len,
-                               XFS_I(dest), destoff);
-
-               src_page = xfs_get_page(src, srcoff);
-               if (IS_ERR(src_page)) {
-                       error = PTR_ERR(src_page);
-                       goto out_error;
-               }
-               dest_page = xfs_get_page(dest, destoff);
-               if (IS_ERR(dest_page)) {
-                       error = PTR_ERR(dest_page);
-                       unlock_page(src_page);
-                       put_page(src_page);
-                       goto out_error;
-               }
-               src_addr = kmap_atomic(src_page);
-               dest_addr = kmap_atomic(dest_page);
-
-               flush_dcache_page(src_page);
-               flush_dcache_page(dest_page);
-
-               if (memcmp(src_addr + src_poff, dest_addr + dest_poff, cmp_len))
-                       same = false;
-
-               kunmap_atomic(dest_addr);
-               kunmap_atomic(src_addr);
-               unlock_page(dest_page);
-               unlock_page(src_page);
-               put_page(dest_page);
-               put_page(src_page);
-
-               if (!same)
-                       break;
-
-               srcoff += cmp_len;
-               destoff += cmp_len;
-               len -= cmp_len;
-       }
-
-       *is_same = same;
-       return 0;
-
-out_error:
-       trace_xfs_reflink_compare_extents_error(XFS_I(dest), error, _RET_IP_);
-       return error;
-}
-
 /*
  * Link a range of blocks from one file to another.
  */
@@ -1235,14 +1130,11 @@ xfs_reflink_remap_range(
        struct inode            *inode_out = file_inode(file_out);
        struct xfs_inode        *dest = XFS_I(inode_out);
        struct xfs_mount        *mp = src->i_mount;
-       loff_t                  bs = inode_out->i_sb->s_blocksize;
        bool                    same_inode = (inode_in == inode_out);
        xfs_fileoff_t           sfsbno, dfsbno;
        xfs_filblks_t           fsblen;
        xfs_extlen_t            cowextsize;
-       loff_t                  isize;
        ssize_t                 ret;
-       loff_t                  blen;
 
        if (!xfs_sb_version_hasreflink(&mp->m_sb))
                return -EOPNOTSUPP;
@@ -1257,26 +1149,8 @@ xfs_reflink_remap_range(
        else
                xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL);
 
-       /* Don't touch certain kinds of inodes */
-       ret = -EPERM;
-       if (IS_IMMUTABLE(inode_out))
-               goto out_unlock;
-
-       ret = -ETXTBSY;
-       if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
-               goto out_unlock;
-
-
-       /* Don't reflink dirs, pipes, sockets... */
-       ret = -EISDIR;
-       if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
-               goto out_unlock;
+       /* Check file eligibility and prepare for block sharing. */
        ret = -EINVAL;
-       if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode))
-               goto out_unlock;
-       if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
-               goto out_unlock;
-
        /* Don't reflink realtime inodes */
        if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest))
                goto out_unlock;
@@ -1285,97 +1159,18 @@ xfs_reflink_remap_range(
        if (IS_DAX(inode_in) || IS_DAX(inode_out))
                goto out_unlock;
 
-       /* Are we going all the way to the end? */
-       isize = i_size_read(inode_in);
-       if (isize == 0) {
-               ret = 0;
-               goto out_unlock;
-       }
-
-       /* Zero length dedupe exits immediately; reflink goes to EOF. */
-       if (len == 0) {
-               if (is_dedupe) {
-                       ret = 0;
-                       goto out_unlock;
-               }
-               len = isize - pos_in;
-       }
-
-       /* Ensure offsets don't wrap and the input is inside i_size */
-       if (pos_in + len < pos_in || pos_out + len < pos_out ||
-           pos_in + len > isize)
-               goto out_unlock;
-
-       /* Don't allow dedupe past EOF in the dest file */
-       if (is_dedupe) {
-               loff_t  disize;
-
-               disize = i_size_read(inode_out);
-               if (pos_out >= disize || pos_out + len > disize)
-                       goto out_unlock;
-       }
-
-       /* If we're linking to EOF, continue to the block boundary. */
-       if (pos_in + len == isize)
-               blen = ALIGN(isize, bs) - pos_in;
-       else
-               blen = len;
-
-       /* Only reflink if we're aligned to block boundaries */
-       if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) ||
-           !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs))
-               goto out_unlock;
-
-       /* Don't allow overlapped reflink within the same file */
-       if (same_inode) {
-               if (pos_out + blen > pos_in && pos_out < pos_in + blen)
-                       goto out_unlock;
-       }
-
-       /* Wait for the completion of any pending IOs on both files */
-       inode_dio_wait(inode_in);
-       if (!same_inode)
-               inode_dio_wait(inode_out);
-
-       ret = filemap_write_and_wait_range(inode_in->i_mapping,
-                       pos_in, pos_in + len - 1);
-       if (ret)
-               goto out_unlock;
-
-       ret = filemap_write_and_wait_range(inode_out->i_mapping,
-                       pos_out, pos_out + len - 1);
-       if (ret)
+       ret = vfs_clone_file_prep_inodes(inode_in, pos_in, inode_out, pos_out,
+                       &len, is_dedupe);
+       if (ret || len == 0)
                goto out_unlock;
 
        trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out);
 
-       /*
-        * Check that the extents are the same.
-        */
-       if (is_dedupe) {
-               bool            is_same = false;
-
-               ret = xfs_compare_extents(inode_in, pos_in, inode_out, pos_out,
-                               len, &is_same);
-               if (ret)
-                       goto out_unlock;
-               if (!is_same) {
-                       ret = -EBADE;
-                       goto out_unlock;
-               }
-       }
-
+       /* Set flags and remap blocks. */
        ret = xfs_reflink_set_inode_flag(src, dest);
        if (ret)
                goto out_unlock;
 
-       /*
-        * Invalidate the page cache so that we can clear any CoW mappings
-        * in the destination file.
-        */
-       truncate_inode_pages_range(&inode_out->i_data, pos_out,
-                                  PAGE_ALIGN(pos_out + len) - 1);
-
        dfsbno = XFS_B_TO_FSBT(mp, pos_out);
        sfsbno = XFS_B_TO_FSBT(mp, pos_in);
        fsblen = XFS_B_TO_FSB(mp, len);
@@ -1384,6 +1179,10 @@ xfs_reflink_remap_range(
        if (ret)
                goto out_unlock;
 
+       /* Zap any page cache for the destination file's range. */
+       truncate_inode_pages_range(&inode_out->i_data, pos_out,
+                                  PAGE_ALIGN(pos_out + len) - 1);
+
        /*
         * Carry the cowextsize hint from src to dest if we're sharing the
         * entire source file to the entire destination file, the source file
diff --git a/include/asm-generic/asm-prototypes.h b/include/asm-generic/asm-prototypes.h
new file mode 100644 (file)
index 0000000..df13637
--- /dev/null
@@ -0,0 +1,7 @@
+#include <linux/bitops.h>
+extern void *__memset(void *, int, __kernel_size_t);
+extern void *__memcpy(void *, const void *, __kernel_size_t);
+extern void *__memmove(void *, const void *, __kernel_size_t);
+extern void *memset(void *, int, __kernel_size_t);
+extern void *memcpy(void *, const void *, __kernel_size_t);
+extern void *memmove(void *, const void *, __kernel_size_t);
index 9e3aa34341f48fa06070504a605a6e9b8edff11a..0968d13b388591ae02b37f9dda0fe7a498cc7475 100644 (file)
 #ifdef CONFIG_KPROBES
 #define KPROBE_BLACKLIST()     . = ALIGN(8);                                 \
                                VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \
-                               *(_kprobe_blacklist)                          \
+                               KEEP(*(_kprobe_blacklist))                    \
                                VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .;
 #else
 #define KPROBE_BLACKLIST()
 #ifdef CONFIG_EVENT_TRACING
 #define FTRACE_EVENTS()        . = ALIGN(8);                                   \
                        VMLINUX_SYMBOL(__start_ftrace_events) = .;      \
-                       *(_ftrace_events)                               \
+                       KEEP(*(_ftrace_events))                         \
                        VMLINUX_SYMBOL(__stop_ftrace_events) = .;       \
                        VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .;   \
-                       *(_ftrace_enum_map)                             \
+                       KEEP(*(_ftrace_enum_map))                       \
                        VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .;
 #else
 #define FTRACE_EVENTS()
 
 #ifdef CONFIG_TRACING
 #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .;      \
-                        *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
+                        KEEP(*(__trace_printk_fmt)) /* Trace_printk fmt' pointer */ \
                         VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
 #define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .; \
-                        *(__tracepoint_str) /* Trace_printk fmt' pointer */ \
+                        KEEP(*(__tracepoint_str)) /* Trace_printk fmt' pointer */ \
                         VMLINUX_SYMBOL(__stop___tracepoint_str) = .;
 #else
 #define TRACE_PRINTKS()
 #ifdef CONFIG_FTRACE_SYSCALLS
 #define TRACE_SYSCALLS() . = ALIGN(8);                                 \
                         VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \
-                        *(__syscalls_metadata)                         \
+                        KEEP(*(__syscalls_metadata))                   \
                         VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
 #else
 #define TRACE_SYSCALLS()
 #ifdef CONFIG_SERIAL_EARLYCON
 #define EARLYCON_TABLE() STRUCT_ALIGN();                       \
                         VMLINUX_SYMBOL(__earlycon_table) = .;  \
-                        *(__earlycon_table)                    \
+                        KEEP(*(__earlycon_table))              \
                         VMLINUX_SYMBOL(__earlycon_table_end) = .;
 #else
 #define EARLYCON_TABLE()
 #define _OF_TABLE_1(name)                                              \
        . = ALIGN(8);                                                   \
        VMLINUX_SYMBOL(__##name##_of_table) = .;                        \
-       *(__##name##_of_table)                                          \
-       *(__##name##_of_table_end)
+       KEEP(*(__##name##_of_table))                                    \
+       KEEP(*(__##name##_of_table_end))
 
 #define CLKSRC_OF_TABLES()     OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
 #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
 #define ACPI_PROBE_TABLE(name)                                         \
        . = ALIGN(8);                                                   \
        VMLINUX_SYMBOL(__##name##_acpi_probe_table) = .;                \
-       *(__##name##_acpi_probe_table)                                  \
+       KEEP(*(__##name##_acpi_probe_table))                            \
        VMLINUX_SYMBOL(__##name##_acpi_probe_table_end) = .;
 #else
 #define ACPI_PROBE_TABLE(name)
 #define KERNEL_DTB()                                                   \
        STRUCT_ALIGN();                                                 \
        VMLINUX_SYMBOL(__dtb_start) = .;                                \
-       *(.dtb.init.rodata)                                             \
+       KEEP(*(.dtb.init.rodata))                                       \
        VMLINUX_SYMBOL(__dtb_end) = .;
 
 /*
        /* implement dynamic printk debug */                            \
        . = ALIGN(8);                                                   \
        VMLINUX_SYMBOL(__start___jump_table) = .;                       \
-       *(__jump_table)                                                 \
+       KEEP(*(__jump_table))                                           \
        VMLINUX_SYMBOL(__stop___jump_table) = .;                        \
        . = ALIGN(8);                                                   \
        VMLINUX_SYMBOL(__start___verbose) = .;                          \
-       *(__verbose)                                                    \
+       KEEP(*(__verbose))                                              \
        VMLINUX_SYMBOL(__stop___verbose) = .;                           \
        LIKELY_PROFILE()                                                \
        BRANCH_PROFILE()                                                \
                VMLINUX_SYMBOL(__start_rodata) = .;                     \
                *(.rodata) *(.rodata.*)                                 \
                RO_AFTER_INIT_DATA      /* Read only after init */      \
-               *(__vermagic)           /* Kernel version magic */      \
+               KEEP(*(__vermagic))     /* Kernel version magic */      \
                . = ALIGN(8);                                           \
                VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .;         \
-               *(__tracepoints_ptrs)   /* Tracepoints: pointer array */\
+               KEEP(*(__tracepoints_ptrs)) /* Tracepoints: pointer array */ \
                VMLINUX_SYMBOL(__stop___tracepoints_ptrs) = .;          \
                *(__tracepoints_strings)/* Tracepoints: strings */      \
        }                                                               \
        /* PCI quirks */                                                \
        .pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {        \
                VMLINUX_SYMBOL(__start_pci_fixups_early) = .;           \
-               *(.pci_fixup_early)                                     \
+               KEEP(*(.pci_fixup_early))                               \
                VMLINUX_SYMBOL(__end_pci_fixups_early) = .;             \
                VMLINUX_SYMBOL(__start_pci_fixups_header) = .;          \
-               *(.pci_fixup_header)                                    \
+               KEEP(*(.pci_fixup_header))                              \
                VMLINUX_SYMBOL(__end_pci_fixups_header) = .;            \
                VMLINUX_SYMBOL(__start_pci_fixups_final) = .;           \
-               *(.pci_fixup_final)                                     \
+               KEEP(*(.pci_fixup_final))                               \
                VMLINUX_SYMBOL(__end_pci_fixups_final) = .;             \
                VMLINUX_SYMBOL(__start_pci_fixups_enable) = .;          \
-               *(.pci_fixup_enable)                                    \
+               KEEP(*(.pci_fixup_enable))                              \
                VMLINUX_SYMBOL(__end_pci_fixups_enable) = .;            \
                VMLINUX_SYMBOL(__start_pci_fixups_resume) = .;          \
-               *(.pci_fixup_resume)                                    \
+               KEEP(*(.pci_fixup_resume))                              \
                VMLINUX_SYMBOL(__end_pci_fixups_resume) = .;            \
                VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .;    \
-               *(.pci_fixup_resume_early)                              \
+               KEEP(*(.pci_fixup_resume_early))                        \
                VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .;      \
                VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .;         \
-               *(.pci_fixup_suspend)                                   \
+               KEEP(*(.pci_fixup_suspend))                             \
                VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .;           \
                VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .;    \
-               *(.pci_fixup_suspend_late)                              \
+               KEEP(*(.pci_fixup_suspend_late))                        \
                VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .;      \
        }                                                               \
                                                                        \
        /* Built-in firmware blobs */                                   \
        .builtin_fw        : AT(ADDR(.builtin_fw) - LOAD_OFFSET) {      \
                VMLINUX_SYMBOL(__start_builtin_fw) = .;                 \
-               *(.builtin_fw)                                          \
+               KEEP(*(.builtin_fw))                                    \
                VMLINUX_SYMBOL(__end_builtin_fw) = .;                   \
        }                                                               \
                                                                        \
                                                                        \
        /* Kernel symbol table: strings */                              \
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {        \
-               KEEP(*(__ksymtab_strings))                              \
+               *(__ksymtab_strings)                                    \
        }                                                               \
                                                                        \
        /* __*init sections */                                          \
        /* Built-in module parameters. */                               \
        __param : AT(ADDR(__param) - LOAD_OFFSET) {                     \
                VMLINUX_SYMBOL(__start___param) = .;                    \
-               *(__param)                                              \
+               KEEP(*(__param))                                        \
                VMLINUX_SYMBOL(__stop___param) = .;                     \
        }                                                               \
                                                                        \
        /* Built-in module versions. */                                 \
        __modver : AT(ADDR(__modver) - LOAD_OFFSET) {                   \
                VMLINUX_SYMBOL(__start___modver) = .;                   \
-               *(__modver)                                             \
+               KEEP(*(__modver))                                       \
                VMLINUX_SYMBOL(__stop___modver) = .;                    \
                . = ALIGN((align));                                     \
                VMLINUX_SYMBOL(__end_rodata) = .;                       \
        . = ALIGN(align);                                               \
        __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {               \
                VMLINUX_SYMBOL(__start___ex_table) = .;                 \
-               *(__ex_table)                                           \
+               KEEP(*(__ex_table))                                     \
                VMLINUX_SYMBOL(__stop___ex_table) = .;                  \
        }
 
 #ifdef CONFIG_CONSTRUCTORS
 #define KERNEL_CTORS() . = ALIGN(8);                      \
                        VMLINUX_SYMBOL(__ctors_start) = .; \
-                       *(.ctors)                          \
-                       *(SORT(.init_array.*))             \
-                       *(.init_array)                     \
+                       KEEP(*(.ctors))                    \
+                       KEEP(*(SORT(.init_array.*)))       \
+                       KEEP(*(.init_array))               \
                        VMLINUX_SYMBOL(__ctors_end) = .;
 #else
 #define KERNEL_CTORS()
        . = ALIGN(8);                                                   \
        __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) {             \
                VMLINUX_SYMBOL(__start___bug_table) = .;                \
-               *(__bug_table)                                          \
+               KEEP(*(__bug_table))                                    \
                VMLINUX_SYMBOL(__stop___bug_table) = .;                 \
        }
 #else
        . = ALIGN(4);                                                   \
        .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {               \
                VMLINUX_SYMBOL(__tracedata_start) = .;                  \
-               *(.tracedata)                                           \
+               KEEP(*(.tracedata))                                     \
                VMLINUX_SYMBOL(__tracedata_end) = .;                    \
        }
 #else
 #define INIT_SETUP(initsetup_align)                                    \
                . = ALIGN(initsetup_align);                             \
                VMLINUX_SYMBOL(__setup_start) = .;                      \
-               *(.init.setup)                                          \
+               KEEP(*(.init.setup))                                    \
                VMLINUX_SYMBOL(__setup_end) = .;
 
 #define INIT_CALLS_LEVEL(level)                                                \
index 12f84327ca366f35c393ba7ee519a3c38ef224a9..03b97629442c183d923b0b7c3a68337702030fcd 100644 (file)
  * The scatter list pointing to the input data must contain:
  *
  * * for RFC4106 ciphers, the concatenation of
- * associated authentication data || IV || plaintext or ciphertext. Note, the
- * same IV (buffer) is also set with the aead_request_set_crypt call. Note,
- * the API call of aead_request_set_ad must provide the length of the AAD and
- * the IV. The API call of aead_request_set_crypt only points to the size of
- * the input plaintext or ciphertext.
+ *   associated authentication data || IV || plaintext or ciphertext. Note, the
+ *   same IV (buffer) is also set with the aead_request_set_crypt call. Note,
+ *   the API call of aead_request_set_ad must provide the length of the AAD and
+ *   the IV. The API call of aead_request_set_crypt only points to the size of
+ *   the input plaintext or ciphertext.
  *
  * * for "normal" AEAD ciphers, the concatenation of
- * associated authentication data || plaintext or ciphertext.
+ *   associated authentication data || plaintext or ciphertext.
  *
  * It is important to note that if multiple scatter gather list entries form
  * the input data mentioned above, the first entry must not point to a NULL
@@ -452,7 +452,7 @@ static inline void aead_request_free(struct aead_request *req)
  * completes
  *
  * The callback function is registered with the aead_request handle and
- * must comply with the following template
+ * must comply with the following template::
  *
  *     void callback_function(struct crypto_async_request *req, int error)
  */
@@ -483,30 +483,18 @@ static inline void aead_request_set_callback(struct aead_request *req,
  * destination is the ciphertext. For a decryption operation, the use is
  * reversed - the source is the ciphertext and the destination is the plaintext.
  *
- * For both src/dst the layout is associated data, plain/cipher text,
- * authentication tag.
- *
- * The content of the AD in the destination buffer after processing
- * will either be untouched, or it will contain a copy of the AD
- * from the source buffer.  In order to ensure that it always has
- * a copy of the AD, the user must copy the AD over either before
- * or after processing.  Of course this is not relevant if the user
- * is doing in-place processing where src == dst.
- *
- * IMPORTANT NOTE AEAD requires an authentication tag (MAC). For decryption,
- *               the caller must concatenate the ciphertext followed by the
- *               authentication tag and provide the entire data stream to the
- *               decryption operation (i.e. the data length used for the
- *               initialization of the scatterlist and the data length for the
- *               decryption operation is identical). For encryption, however,
- *               the authentication tag is created while encrypting the data.
- *               The destination buffer must hold sufficient space for the
- *               ciphertext and the authentication tag while the encryption
- *               invocation must only point to the plaintext data size. The
- *               following code snippet illustrates the memory usage
- *               buffer = kmalloc(ptbuflen + (enc ? authsize : 0));
- *               sg_init_one(&sg, buffer, ptbuflen + (enc ? authsize : 0));
- *               aead_request_set_crypt(req, &sg, &sg, ptbuflen, iv);
+ * The memory structure for cipher operation has the following structure:
+ *
+ * - AEAD encryption input:  assoc data || plaintext
+ * - AEAD encryption output: assoc data || cipherntext || auth tag
+ * - AEAD decryption input:  assoc data || ciphertext || auth tag
+ * - AEAD decryption output: assoc data || plaintext
+ *
+ * Albeit the kernel requires the presence of the AAD buffer, however,
+ * the kernel does not fill the AAD buffer in the output case. If the
+ * caller wants to have that data buffer filled, the caller must either
+ * use an in-place cipher operation (i.e. same memory location for
+ * input/output memory location).
  */
 static inline void aead_request_set_crypt(struct aead_request *req,
                                          struct scatterlist *src,
index 5102a8f282e606932fa5e447216da4efab06c31e..6b424ad3482e3c5662d05108ea8cb06298cca808 100644 (file)
 #ifndef _CRYPTO_DH_
 #define _CRYPTO_DH_
 
+/**
+ * DOC: DH Helper Functions
+ *
+ * To use DH with the KPP cipher API, the following data structure and
+ * functions should be used.
+ *
+ * To use DH with KPP, the following functions should be used to operate on
+ * a DH private key. The packet private key that can be set with
+ * the KPP API function call of crypto_kpp_set_secret.
+ */
+
+/**
+ * struct dh - define a DH private key
+ *
+ * @key:       Private DH key
+ * @p:         Diffie-Hellman parameter P
+ * @g:         Diffie-Hellman generator G
+ * @key_size:  Size of the private DH key
+ * @p_size:    Size of DH parameter P
+ * @g_size:    Size of DH generator G
+ */
 struct dh {
        void *key;
        void *p;
@@ -22,8 +43,45 @@ struct dh {
        unsigned int g_size;
 };
 
+/**
+ * crypto_dh_key_len() - Obtain the size of the private DH key
+ * @params:    private DH key
+ *
+ * This function returns the packet DH key size. A caller can use that
+ * with the provided DH private key reference to obtain the required
+ * memory size to hold a packet key.
+ *
+ * Return: size of the key in bytes
+ */
 int crypto_dh_key_len(const struct dh *params);
+
+/**
+ * crypto_dh_encode_key() - encode the private key
+ * @buf:       Buffer allocated by the caller to hold the packet DH
+ *             private key. The buffer should be at least crypto_dh_key_len
+ *             bytes in size.
+ * @len:       Length of the packet private key buffer
+ * @params:    Buffer with the caller-specified private key
+ *
+ * The DH implementations operate on a packet representation of the private
+ * key.
+ *
+ * Return:     -EINVAL if buffer has insufficient size, 0 on success
+ */
 int crypto_dh_encode_key(char *buf, unsigned int len, const struct dh *params);
+
+/**
+ * crypto_dh_decode_key() - decode a private key
+ * @buf:       Buffer holding a packet key that should be decoded
+ * @len:       Lenth of the packet private key buffer
+ * @params:    Buffer allocated by the caller that is filled with the
+ *             unpacket DH private key.
+ *
+ * The unpacking obtains the private key by pointing @p to the correct location
+ * in @buf. Thus, both pointers refer to the same memory.
+ *
+ * Return:     -EINVAL if buffer has insufficient size, 0 on success
+ */
 int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params);
 
 #endif
index 84bad548d1944aebaf9c58efc1f17704bb4688c6..03a64f62ba7a9fb46c89a9034d8530f28a94123c 100644 (file)
 #ifndef _CRYPTO_ECDH_
 #define _CRYPTO_ECDH_
 
+/**
+ * DOC: ECDH Helper Functions
+ *
+ * To use ECDH with the KPP cipher API, the following data structure and
+ * functions should be used.
+ *
+ * The ECC curves known to the ECDH implementation are specified in this
+ * header file.
+ *
+ * To use ECDH with KPP, the following functions should be used to operate on
+ * an ECDH private key. The packet private key that can be set with
+ * the KPP API function call of crypto_kpp_set_secret.
+ */
+
 /* Curves IDs */
 #define ECC_CURVE_NIST_P192    0x0001
 #define ECC_CURVE_NIST_P256    0x0002
 
+/**
+ * struct ecdh - define an ECDH private key
+ *
+ * @curve_id:  ECC curve the key is based on.
+ * @key:       Private ECDH key
+ * @key_size:  Size of the private ECDH key
+ */
 struct ecdh {
        unsigned short curve_id;
        char *key;
        unsigned short key_size;
 };
 
+/**
+ * crypto_ecdh_key_len() - Obtain the size of the private ECDH key
+ * @params:    private ECDH key
+ *
+ * This function returns the packet ECDH key size. A caller can use that
+ * with the provided ECDH private key reference to obtain the required
+ * memory size to hold a packet key.
+ *
+ * Return: size of the key in bytes
+ */
 int crypto_ecdh_key_len(const struct ecdh *params);
+
+/**
+ * crypto_ecdh_encode_key() - encode the private key
+ * @buf:       Buffer allocated by the caller to hold the packet ECDH
+ *             private key. The buffer should be at least crypto_ecdh_key_len
+ *             bytes in size.
+ * @len:       Length of the packet private key buffer
+ * @p:         Buffer with the caller-specified private key
+ *
+ * The ECDH implementations operate on a packet representation of the private
+ * key.
+ *
+ * Return:     -EINVAL if buffer has insufficient size, 0 on success
+ */
 int crypto_ecdh_encode_key(char *buf, unsigned int len, const struct ecdh *p);
+
+/**
+ * crypto_ecdh_decode_key() - decode a private key
+ * @buf:       Buffer holding a packet key that should be decoded
+ * @len:       Lenth of the packet private key buffer
+ * @p:         Buffer allocated by the caller that is filled with the
+ *             unpacket ECDH private key.
+ *
+ * The unpacking obtains the private key by pointing @p to the correct location
+ * in @buf. Thus, both pointers refer to the same memory.
+ *
+ * Return:     -EINVAL if buffer has insufficient size, 0 on success
+ */
 int crypto_ecdh_decode_key(const char *buf, unsigned int len, struct ecdh *p);
 
 #endif
index 26605888a199ed0446d27268844ea5bff09b8aaa..216a2b876147ea73a5f44fd043714926e5a0da1a 100644 (file)
@@ -605,7 +605,7 @@ static inline struct ahash_request *ahash_request_cast(
  * the cipher operation completes.
  *
  * The callback function is registered with the &ahash_request handle and
- * must comply with the following template
+ * must comply with the following template::
  *
  *     void callback_function(struct crypto_async_request *req, int error)
  */
index 30791f75c180dc6c9bc6ef7b639d28e02096cd4e..4307a2f2365f49433ecf46a03007a7316ab4df58 100644 (file)
@@ -71,7 +71,7 @@ struct crypto_kpp {
  *
  * @reqsize:           Request context size required by algorithm
  *                     implementation
- * @base               Common crypto API algorithm data structure
+ * @base:              Common crypto API algorithm data structure
  */
 struct kpp_alg {
        int (*set_secret)(struct crypto_kpp *tfm, void *buffer,
@@ -89,7 +89,7 @@ struct kpp_alg {
 };
 
 /**
- * DOC: Generic Key-agreement Protocol Primitevs API
+ * DOC: Generic Key-agreement Protocol Primitives API
  *
  * The KPP API is used with the algorithm type
  * CRYPTO_ALG_TYPE_KPP (listed as type "kpp" in /proc/crypto)
@@ -264,6 +264,12 @@ struct kpp_secret {
  * Function invokes the specific kpp operation for a given alg.
  *
  * @tfm:       tfm handle
+ * @buffer:    Buffer holding the packet representation of the private
+ *             key. The structure of the packet key depends on the particular
+ *             KPP implementation. Packing and unpacking helpers are provided
+ *             for ECDH and DH (see the respective header files for those
+ *             implementations).
+ * @len:       Length of the packet private key buffer.
  *
  * Return: zero on success; error code in case of error
  */
@@ -279,7 +285,10 @@ static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, void *buffer,
  * crypto_kpp_generate_public_key() - Invoke kpp operation
  *
  * Function invokes the specific kpp operation for generating the public part
- * for a given kpp algorithm
+ * for a given kpp algorithm.
+ *
+ * To generate a private key, the caller should use a random number generator.
+ * The output of the requested length serves as the private key.
  *
  * @req:       kpp key request
  *
index cc4d98a7892e253ad1b925ca401ce41947b9a590..750b14f1ada4b3ca98809f1e0624f347f2a1355d 100644 (file)
@@ -516,7 +516,7 @@ static inline void skcipher_request_zero(struct skcipher_request *req)
  * skcipher_request_set_callback() - set asynchronous callback function
  * @req: request handle
  * @flags: specify zero or an ORing of the flags
- *         CRYPTO_TFM_REQ_MAY_BACKLOG the request queue may back log and
+ *        CRYPTO_TFM_REQ_MAY_BACKLOG the request queue may back log and
  *        increase the wait queue beyond the initial maximum size;
  *        CRYPTO_TFM_REQ_MAY_SLEEP the request processing may sleep
  * @compl: callback function pointer to be registered with the request handle
@@ -533,7 +533,7 @@ static inline void skcipher_request_zero(struct skcipher_request *req)
  * cipher operation completes.
  *
  * The callback function is registered with the skcipher_request handle and
- * must comply with the following template
+ * must comply with the following template::
  *
  *     void callback_function(struct crypto_async_request *req, int error)
  */
index 9d4443f93db6b1568baa5bd1066b66cf6885484d..f51fca8d0b6f86f4229a3ff487c39c18ad1a92c4 100644 (file)
@@ -147,7 +147,7 @@ extern void             audit_log_d_path(struct audit_buffer *ab,
 extern void                audit_log_key(struct audit_buffer *ab,
                                          char *key);
 extern void                audit_log_link_denied(const char *operation,
-                                                 struct path *link);
+                                                 const struct path *link);
 extern void                audit_log_lost(const char *message);
 #ifdef CONFIG_SECURITY
 extern void                audit_log_secctx(struct audit_buffer *ab, u32 secid);
index 7b6e5d168c956063c37f614e2fe2f243435700db..92bc89ae7e20733c28f6130cf00314a42aa0c580 100644 (file)
@@ -20,7 +20,7 @@ struct cgroup_bpf {
         * when this cgroup is accessed.
         */
        struct bpf_prog *prog[MAX_BPF_ATTACH_TYPE];
-       struct bpf_prog *effective[MAX_BPF_ATTACH_TYPE];
+       struct bpf_prog __rcu *effective[MAX_BPF_ATTACH_TYPE];
 };
 
 void cgroup_bpf_put(struct cgroup *cgrp);
index 8796ff03f4729f953d4a888163bf5b559225aa35..f74ae68086dc69b3c02ced58a13f6daed0b4cd77 100644 (file)
@@ -216,7 +216,7 @@ u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5);
 u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
 
 bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp);
-void bpf_prog_calc_digest(struct bpf_prog *fp);
+int bpf_prog_calc_digest(struct bpf_prog *fp);
 
 const struct bpf_func_proto *bpf_get_trace_printk_proto(void);
 
@@ -238,6 +238,8 @@ struct bpf_prog * __must_check bpf_prog_add(struct bpf_prog *prog, int i);
 void bpf_prog_sub(struct bpf_prog *prog, int i);
 struct bpf_prog * __must_check bpf_prog_inc(struct bpf_prog *prog);
 void bpf_prog_put(struct bpf_prog *prog);
+int __bpf_prog_charge(struct user_struct *user, u32 pages);
+void __bpf_prog_uncharge(struct user_struct *user, u32 pages);
 
 struct bpf_map *bpf_map_get_with_uref(u32 ufd);
 struct bpf_map *__bpf_map_get(struct fd f);
@@ -318,6 +320,15 @@ static inline struct bpf_prog * __must_check bpf_prog_inc(struct bpf_prog *prog)
 {
        return ERR_PTR(-EOPNOTSUPP);
 }
+
+static inline int __bpf_prog_charge(struct user_struct *user, u32 pages)
+{
+       return 0;
+}
+
+static inline void __bpf_prog_uncharge(struct user_struct *user, u32 pages)
+{
+}
 #endif /* CONFIG_BPF_SYSCALL */
 
 /* verifier prototypes for helper functions called from eBPF programs */
index 22acee76cf4cd49493116621a3b30ed53f2034af..2ab7bf53d529acf95fbdf7ddbc338b0dae6b5755 100644 (file)
@@ -101,7 +101,6 @@ enum cpuhp_state {
        CPUHP_AP_ARM_L2X0_STARTING,
        CPUHP_AP_ARM_ARCH_TIMER_STARTING,
        CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
-       CPUHP_AP_DUMMY_TIMER_STARTING,
        CPUHP_AP_JCORE_TIMER_STARTING,
        CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
        CPUHP_AP_ARM_TWD_STARTING,
@@ -115,6 +114,8 @@ enum cpuhp_state {
        CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
        CPUHP_AP_KVM_ARM_VGIC_STARTING,
        CPUHP_AP_KVM_ARM_TIMER_STARTING,
+       /* Must be the last timer callback */
+       CPUHP_AP_DUMMY_TIMER_STARTING,
        CPUHP_AP_ARM_XEN_STARTING,
        CPUHP_AP_ARM_CORESIGHT_STARTING,
        CPUHP_AP_ARM_CORESIGHT4_STARTING,
index da7fbf1cdd5613cb709c1a50fa44d2e2e7159d91..c717f5ea88cb7e7f04471f34ac14bcf9bc75a4d1 100644 (file)
@@ -722,6 +722,11 @@ void init_cpu_present(const struct cpumask *src);
 void init_cpu_possible(const struct cpumask *src);
 void init_cpu_online(const struct cpumask *src);
 
+static inline void reset_cpu_possible_mask(void)
+{
+       bitmap_zero(cpumask_bits(&__cpu_possible_mask), NR_CPUS);
+}
+
 static inline void
 set_cpu_possible(unsigned int cpu, bool possible)
 {
index 167aea29d41e7ce2ba69aacd3bc931cfcc0c7a67..c0b0cf3d2d2fac2ec58ac9f0b39f7fd30b552ffc 100644 (file)
@@ -963,7 +963,7 @@ static inline void ablkcipher_request_free(struct ablkcipher_request *req)
  * ablkcipher_request_set_callback() - set asynchronous callback function
  * @req: request handle
  * @flags: specify zero or an ORing of the flags
- *         CRYPTO_TFM_REQ_MAY_BACKLOG the request queue may back log and
+ *        CRYPTO_TFM_REQ_MAY_BACKLOG the request queue may back log and
  *        increase the wait queue beyond the initial maximum size;
  *        CRYPTO_TFM_REQ_MAY_SLEEP the request processing may sleep
  * @compl: callback function pointer to be registered with the request handle
@@ -980,7 +980,7 @@ static inline void ablkcipher_request_free(struct ablkcipher_request *req)
  * cipher operation completes.
  *
  * The callback function is registered with the ablkcipher_request handle and
- * must comply with the following template
+ * must comply with the following template::
  *
  *     void callback_function(struct crypto_async_request *req, int error)
  */
index 5beed7b30561119cf66e5f8aa0779d54cd602d3c..c965e44694997ea0ea18ca17fd1a7eb1596b3a53 100644 (file)
@@ -139,7 +139,7 @@ struct dentry_operations {
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)(struct dentry *, char *, int);
        struct vfsmount *(*d_automount)(struct path *);
-       int (*d_manage)(struct dentry *, bool);
+       int (*d_manage)(const struct path *, bool);
        struct dentry *(*d_real)(struct dentry *, const struct inode *,
                                 unsigned int);
 } ____cacheline_aligned;
@@ -254,7 +254,7 @@ extern struct dentry *d_find_alias(struct inode *);
 extern void d_prune_aliases(struct inode *);
 
 /* test whether we have any submounts in a subdir tree */
-extern int have_submounts(struct dentry *);
+extern int path_has_submounts(const struct path *);
 
 /*
  * This adds the entry to the hash queues.
index 5ac3bdd5cee677ab7ff752c8ea87a959b35e134a..699b6c499c4f5a3c600380b8aa8971ab3bba61b4 100644 (file)
@@ -44,7 +44,7 @@ void dcookie_unregister(struct dcookie_user * user);
  *
  * Returns 0 on success, with *cookie filled in
  */
-int get_dcookie(struct path *path, unsigned long *cookie);
+int get_dcookie(const struct path *path, unsigned long *cookie);
 
 #else
 
@@ -58,7 +58,7 @@ static inline void dcookie_unregister(struct dcookie_user * user)
        return;
 }
 
-static inline int get_dcookie(struct path *path, unsigned long *cookie)
+static inline int get_dcookie(const struct path *path, unsigned long *cookie)
 {
        return -ENOSYS;
 }
index 7444f5feda12559b5bf5fd5dd564226da1157eeb..61eb82cbafbad4c61258cd8ab1754f60e3ca5910 100644 (file)
@@ -17,7 +17,7 @@ struct file_operations;
 struct vfsmount;
 struct dentry;
 struct path;
-extern struct file *alloc_file(struct path *, fmode_t mode,
+extern struct file *alloc_file(const struct path *, fmode_t mode,
        const struct file_operations *fop);
 
 static inline void fput_light(struct file *file, int fput_needed)
index 6a1658308612622b3d5e3eff2bfcd8cf5c1ff386..70231425379751021b57326eec85e70d881d3f42 100644 (file)
@@ -57,9 +57,6 @@ struct bpf_prog_aux;
 /* BPF program can access up to 512 bytes of stack space. */
 #define MAX_BPF_STACK  512
 
-/* Maximum BPF program size in bytes. */
-#define MAX_BPF_SIZE   (BPF_MAXINSNS * sizeof(struct bpf_insn))
-
 /* Helper macros for filter block array initializers. */
 
 /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
@@ -517,6 +514,17 @@ static __always_inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog,
        return BPF_PROG_RUN(prog, xdp);
 }
 
+static inline u32 bpf_prog_insn_size(const struct bpf_prog *prog)
+{
+       return prog->len * sizeof(struct bpf_insn);
+}
+
+static inline u32 bpf_prog_digest_scratch_size(const struct bpf_prog *prog)
+{
+       return round_up(bpf_prog_insn_size(prog) +
+                       sizeof(__be64) + 1, SHA_MESSAGE_BYTES);
+}
+
 static inline unsigned int bpf_prog_size(unsigned int proglen)
 {
        return max(sizeof(struct bpf_prog),
@@ -602,6 +610,7 @@ bool bpf_helper_changes_pkt_data(void *func);
 struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
                                       const struct bpf_insn *patch, u32 len);
 void bpf_warn_invalid_xdp_action(u32 act);
+void bpf_warn_invalid_xdp_buffer(void);
 
 #ifdef CONFIG_BPF_JIT
 extern int bpf_jit_enable;
index 83de8b6601baf5da358e2acb87f1b90bf41e95e0..2ba074328894cea30d6273a574417d789fae271d 100644 (file)
@@ -543,6 +543,7 @@ is_uncached_acl(struct posix_acl *acl)
 #define IOP_LOOKUP     0x0002
 #define IOP_NOFOLLOW   0x0004
 #define IOP_XATTR      0x0008
+#define IOP_DEFAULT_READLINK   0x0010
 
 /*
  * Keep mostly read-only and often accessed (especially for
@@ -1726,8 +1727,14 @@ extern ssize_t vfs_writev(struct file *, const struct iovec __user *,
                unsigned long, loff_t *, int);
 extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *,
                                   loff_t, size_t, unsigned int);
+extern int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,
+                                     struct inode *inode_out, loff_t pos_out,
+                                     u64 *len, bool is_dedupe);
 extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
                struct file *file_out, loff_t pos_out, u64 len);
+extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
+                                        struct inode *dest, loff_t destoff,
+                                        loff_t len, bool *is_same);
 extern int vfs_dedupe_file_range(struct file *file,
                                 struct file_dedupe_range *same);
 
@@ -2084,11 +2091,11 @@ extern int may_umount_tree(struct vfsmount *);
 extern int may_umount(struct vfsmount *);
 extern long do_mount(const char *, const char __user *,
                     const char *, unsigned long, void *);
-extern struct vfsmount *collect_mounts(struct path *);
+extern struct vfsmount *collect_mounts(const struct path *);
 extern void drop_collected_mounts(struct vfsmount *);
 extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
                          struct vfsmount *);
-extern int vfs_statfs(struct path *, struct kstatfs *);
+extern int vfs_statfs(const struct path *, struct kstatfs *);
 extern int user_statfs(const char __user *, struct kstatfs *);
 extern int fd_statfs(int, struct kstatfs *);
 extern int vfs_ustat(dev_t, struct kstatfs *);
@@ -2657,7 +2664,7 @@ extern struct file * open_exec(const char *);
  
 /* fs/dcache.c -- generic fs support functions */
 extern bool is_subdir(struct dentry *, struct dentry *);
-extern bool path_is_under(struct path *, struct path *);
+extern bool path_is_under(const struct path *, const struct path *);
 
 extern char *file_path(struct file *, char *, int);
 
@@ -2861,7 +2868,6 @@ extern int __page_symlink(struct inode *inode, const char *symname, int len,
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern const struct inode_operations page_symlink_inode_operations;
 extern void kfree_link(void *);
-extern int generic_readlink(struct dentry *, char __user *, int);
 extern void generic_fillattr(struct inode *, struct kstat *);
 int vfs_getattr_nosec(struct path *path, struct kstat *stat);
 extern int vfs_getattr(struct path *, struct kstat *);
@@ -2882,6 +2888,7 @@ extern int vfs_lstat(const char __user *, struct kstat *);
 extern int vfs_fstat(unsigned int, struct kstat *);
 extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
 extern const char *vfs_get_link(struct dentry *, struct delayed_call *);
+extern int vfs_readlink(struct dentry *, char __user *, int);
 
 extern int __generic_block_fiemap(struct inode *inode,
                                  struct fiemap_extent_info *fieinfo,
@@ -2896,8 +2903,10 @@ extern void put_filesystem(struct file_system_type *fs);
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(struct block_device *);
 extern struct super_block *get_super_thawed(struct block_device *);
+extern struct super_block *get_super_exclusive_thawed(struct block_device *bdev);
 extern struct super_block *get_active_super(struct block_device *bdev);
 extern void drop_super(struct super_block *sb);
+extern void drop_super_exclusive(struct super_block *sb);
 extern void iterate_supers(void (*)(struct super_block *, void *), void *);
 extern void iterate_supers_type(struct file_system_type *,
                                void (*)(struct super_block *, void *), void *);
index b8bcc058e03147e39624609ae0a7331e978b0d58..b43d3f5bd9ead666e4e53894e8f98bdf25fb7ad8 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/bug.h>
 
 /* Notify this dentry's parent about a child's events. */
-static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
+static inline int fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask)
 {
        if (!dentry)
                dentry = path->dentry;
@@ -28,7 +28,7 @@ static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u3
 /* simple call site for access decisions */
 static inline int fsnotify_perm(struct file *file, int mask)
 {
-       struct path *path = &file->f_path;
+       const struct path *path = &file->f_path;
        /*
         * Do not use file_inode() here or anywhere in this file to get the
         * inode.  That would break *notity on overlayfs.
@@ -176,7 +176,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
  */
 static inline void fsnotify_access(struct file *file)
 {
-       struct path *path = &file->f_path;
+       const struct path *path = &file->f_path;
        struct inode *inode = path->dentry->d_inode;
        __u32 mask = FS_ACCESS;
 
@@ -194,7 +194,7 @@ static inline void fsnotify_access(struct file *file)
  */
 static inline void fsnotify_modify(struct file *file)
 {
-       struct path *path = &file->f_path;
+       const struct path *path = &file->f_path;
        struct inode *inode = path->dentry->d_inode;
        __u32 mask = FS_MODIFY;
 
@@ -212,7 +212,7 @@ static inline void fsnotify_modify(struct file *file)
  */
 static inline void fsnotify_open(struct file *file)
 {
-       struct path *path = &file->f_path;
+       const struct path *path = &file->f_path;
        struct inode *inode = path->dentry->d_inode;
        __u32 mask = FS_OPEN;
 
@@ -228,7 +228,7 @@ static inline void fsnotify_open(struct file *file)
  */
 static inline void fsnotify_close(struct file *file)
 {
-       struct path *path = &file->f_path;
+       const struct path *path = &file->f_path;
        struct inode *inode = path->dentry->d_inode;
        fmode_t mode = file->f_mode;
        __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
index 79467b239fcfff1804e94fb111153fe615a1de67..0cf34d6cc253853c459e60908aa06128b4a8cf45 100644 (file)
@@ -96,7 +96,7 @@ struct fsnotify_ops {
                            struct inode *inode,
                            struct fsnotify_mark *inode_mark,
                            struct fsnotify_mark *vfsmount_mark,
-                           u32 mask, void *data, int data_type,
+                           u32 mask, const void *data, int data_type,
                            const unsigned char *file_name, u32 cookie);
        void (*free_group_priv)(struct fsnotify_group *group);
        void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
@@ -245,9 +245,9 @@ struct fsnotify_mark {
 /* called from the vfs helpers */
 
 /* main fsnotify call to send events */
-extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
+extern int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
                    const unsigned char *name, u32 cookie);
-extern int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask);
+extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask);
 extern void __fsnotify_inode_delete(struct inode *inode);
 extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
 extern u32 fsnotify_get_cookie(void);
@@ -357,13 +357,13 @@ extern void fsnotify_init_event(struct fsnotify_event *event,
 
 #else
 
-static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
+static inline int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
                           const unsigned char *name, u32 cookie)
 {
        return 0;
 }
 
-static inline int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
+static inline int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask)
 {
        return 0;
 }
index ee2d8c6f91300db725b3681c830d4568de71cb19..0b71024c082c37f817b4b0303a826abaa796fc95 100644 (file)
@@ -2,7 +2,6 @@
 #define _GPIO_KEYS_H
 
 struct device;
-struct gpio_desc;
 
 /**
  * struct gpio_keys_button - configuration parameters
@@ -18,7 +17,6 @@ struct gpio_desc;
  *                     disable button via sysfs
  * @value:             axis value for %EV_ABS
  * @irq:               Irq number in case of interrupt keys
- * @gpiod:             GPIO descriptor
  */
 struct gpio_keys_button {
        unsigned int code;
@@ -31,7 +29,6 @@ struct gpio_keys_button {
        bool can_disable;
        int value;
        unsigned int irq;
-       struct gpio_desc *gpiod;
 };
 
 /**
@@ -46,7 +43,7 @@ struct gpio_keys_button {
  * @name:              input device name
  */
 struct gpio_keys_platform_data {
-       struct gpio_keys_button *buttons;
+       const struct gpio_keys_button *buttons;
        int nbuttons;
        unsigned int poll_interval;
        unsigned int rep:1;
index fec597fb34cbb10e8b7b8a873c6c0e9395c60595..a4860bc9b73d4ffe927d087c24b70970084ff330 100644 (file)
@@ -115,6 +115,8 @@ enum {
 #define AXP806_CLDO2_V_CTRL            0x25
 #define AXP806_CLDO3_V_CTRL            0x26
 #define AXP806_VREF_TEMP_WARN_L                0xf3
+#define AXP806_BUS_ADDR_EXT            0xfe
+#define AXP806_REG_ADDR_EXT            0xff
 
 /* Interrupt */
 #define AXP152_IRQ1_EN                 0x40
@@ -226,6 +228,10 @@ enum {
 #define AXP20X_OCV_MAX                 0xf
 
 /* AXP22X specific registers */
+#define AXP22X_PMIC_ADC_H              0x56
+#define AXP22X_PMIC_ADC_L              0x57
+#define AXP22X_TS_ADC_H                        0x58
+#define AXP22X_TS_ADC_L                        0x59
 #define AXP22X_BATLOW_THRES1           0xe6
 
 /* AXP288 specific registers */
index 8e1cdbef3dad05e3d2665f2b12c9e9128ed75583..2c0127cb06c590f0ed3a13cdf5d890c477ebb6f5 100644 (file)
@@ -28,8 +28,6 @@
 #include <linux/mfd/core.h>
 #include <linux/platform_data/edma.h>
 
-#include <mach/hardware.h>
-
 struct regmap;
 
 /*
@@ -99,8 +97,6 @@ struct davinci_vcif {
        dma_addr_t dma_rx_addr;
 };
 
-struct davinci_vc;
-
 struct davinci_vc {
        /* Device data */
        struct device *dev;
index cf619dbeace285ee0ad2b9fc3b5e479604e42174..956caa0628f5e4e6f2daf1fbf1b4c4c491b59c11 100644 (file)
@@ -26,6 +26,7 @@ struct intel_soc_pmic {
        struct regmap *regmap;
        struct regmap_irq_chip_data *irq_chip_data;
        struct regmap_irq_chip_data *irq_chip_data_level2;
+       struct regmap_irq_chip_data *irq_chip_data_tmu;
        struct device *dev;
 };
 
index 6d435a3c06bcc6f7804181966c5e7e4f9a119caf..83701ef7d3c7bfbb1dc59f6e92a6f0664a7c48c5 100644 (file)
@@ -290,6 +290,7 @@ enum rk818_reg {
 #define SWITCH2_EN     BIT(6)
 #define SWITCH1_EN     BIT(5)
 #define DEV_OFF_RST    BIT(3)
+#define DEV_OFF                BIT(0)
 
 #define VB_LO_ACT              BIT(4)
 #define VB_LO_SEL_3500MV       (7 << 0)
index cadc6543909d96ef553bcde9935bfecaaca42a26..e5a6cdeb77dbcc5e8603199bb6021bdc17f8516c 100644 (file)
 #define RN5T618_DC3CTL2                        0x31
 #define RN5T618_DC4CTL                 0x32
 #define RN5T618_DC4CTL2                        0x33
+#define RN5T618_DC5CTL                 0x34
+#define RN5T618_DC5CTL2                        0x35
 #define RN5T618_DC1DAC                 0x36
 #define RN5T618_DC2DAC                 0x37
 #define RN5T618_DC3DAC                 0x38
 #define RN5T618_DC4DAC                 0x39
+#define RN5T618_DC5DAC                 0x3a
 #define RN5T618_DC1DAC_SLP             0x3b
 #define RN5T618_DC2DAC_SLP             0x3c
 #define RN5T618_DC3DAC_SLP             0x3d
 #define RN5T618_LDO3DAC                        0x4e
 #define RN5T618_LDO4DAC                        0x4f
 #define RN5T618_LDO5DAC                        0x50
+#define RN5T618_LDO6DAC                        0x51
+#define RN5T618_LDO7DAC                        0x52
+#define RN5T618_LDO8DAC                        0x53
+#define RN5T618_LDO9DAC                        0x54
+#define RN5T618_LDO10DAC               0x55
 #define RN5T618_LDORTCDAC              0x56
 #define RN5T618_LDORTC2DAC             0x57
 #define RN5T618_LDO1DAC_SLP            0x58
@@ -231,6 +239,7 @@ enum {
 enum {
        RN5T567 = 0,
        RN5T618,
+       RC5T619,
 };
 
 struct rn5t618 {
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
new file mode 100644 (file)
index 0000000..d7a29f2
--- /dev/null
@@ -0,0 +1,94 @@
+/* Header of ADC MFD core driver for sunxi platforms
+ *
+ * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef __SUN4I_GPADC__H__
+#define __SUN4I_GPADC__H__
+
+#define SUN4I_GPADC_CTRL0                              0x00
+
+#define SUN4I_GPADC_CTRL0_ADC_FIRST_DLY(x)             ((GENMASK(7, 0) & (x)) << 24)
+#define SUN4I_GPADC_CTRL0_ADC_FIRST_DLY_MODE           BIT(23)
+#define SUN4I_GPADC_CTRL0_ADC_CLK_SELECT               BIT(22)
+#define SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(x)           ((GENMASK(1, 0) & (x)) << 20)
+#define SUN4I_GPADC_CTRL0_FS_DIV(x)                    ((GENMASK(3, 0) & (x)) << 16)
+#define SUN4I_GPADC_CTRL0_T_ACQ(x)                     (GENMASK(15, 0) & (x))
+
+#define SUN4I_GPADC_CTRL1                              0x04
+
+#define SUN4I_GPADC_CTRL1_STYLUS_UP_DEBOUNCE(x)                ((GENMASK(7, 0) & (x)) << 12)
+#define SUN4I_GPADC_CTRL1_STYLUS_UP_DEBOUNCE_EN                BIT(9)
+#define SUN4I_GPADC_CTRL1_TOUCH_PAN_CALI_EN            BIT(6)
+#define SUN4I_GPADC_CTRL1_TP_DUAL_EN                   BIT(5)
+#define SUN4I_GPADC_CTRL1_TP_MODE_EN                   BIT(4)
+#define SUN4I_GPADC_CTRL1_TP_ADC_SELECT                        BIT(3)
+#define SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(x)           (GENMASK(2, 0) & (x))
+
+/* TP_CTRL1 bits for sun6i SOCs */
+#define SUN6I_GPADC_CTRL1_TOUCH_PAN_CALI_EN            BIT(7)
+#define SUN6I_GPADC_CTRL1_TP_DUAL_EN                   BIT(6)
+#define SUN6I_GPADC_CTRL1_TP_MODE_EN                   BIT(5)
+#define SUN6I_GPADC_CTRL1_TP_ADC_SELECT                        BIT(4)
+#define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x)           (GENMASK(3, 0) & BIT(x))
+
+#define SUN4I_GPADC_CTRL2                              0x08
+
+#define SUN4I_GPADC_CTRL2_TP_SENSITIVE_ADJUST(x)       ((GENMASK(3, 0) & (x)) << 28)
+#define SUN4I_GPADC_CTRL2_TP_MODE_SELECT(x)            ((GENMASK(1, 0) & (x)) << 26)
+#define SUN4I_GPADC_CTRL2_PRE_MEA_EN                   BIT(24)
+#define SUN4I_GPADC_CTRL2_PRE_MEA_THRE_CNT(x)          (GENMASK(23, 0) & (x))
+
+#define SUN4I_GPADC_CTRL3                              0x0c
+
+#define SUN4I_GPADC_CTRL3_FILTER_EN                    BIT(2)
+#define SUN4I_GPADC_CTRL3_FILTER_TYPE(x)               (GENMASK(1, 0) & (x))
+
+#define SUN4I_GPADC_TPR                                        0x18
+
+#define SUN4I_GPADC_TPR_TEMP_ENABLE                    BIT(16)
+#define SUN4I_GPADC_TPR_TEMP_PERIOD(x)                 (GENMASK(15, 0) & (x))
+
+#define SUN4I_GPADC_INT_FIFOC                          0x10
+
+#define SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN              BIT(18)
+#define SUN4I_GPADC_INT_FIFOC_TP_OVERRUN_IRQ_EN                BIT(17)
+#define SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN           BIT(16)
+#define SUN4I_GPADC_INT_FIFOC_TP_DATA_XY_CHANGE                BIT(13)
+#define SUN4I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(x)    ((GENMASK(4, 0) & (x)) << 8)
+#define SUN4I_GPADC_INT_FIFOC_TP_DATA_DRQ_EN           BIT(7)
+#define SUN4I_GPADC_INT_FIFOC_TP_FIFO_FLUSH            BIT(4)
+#define SUN4I_GPADC_INT_FIFOC_TP_UP_IRQ_EN             BIT(1)
+#define SUN4I_GPADC_INT_FIFOC_TP_DOWN_IRQ_EN           BIT(0)
+
+#define SUN4I_GPADC_INT_FIFOS                          0x14
+
+#define SUN4I_GPADC_INT_FIFOS_TEMP_DATA_PENDING                BIT(18)
+#define SUN4I_GPADC_INT_FIFOS_FIFO_OVERRUN_PENDING     BIT(17)
+#define SUN4I_GPADC_INT_FIFOS_FIFO_DATA_PENDING                BIT(16)
+#define SUN4I_GPADC_INT_FIFOS_TP_IDLE_FLG              BIT(2)
+#define SUN4I_GPADC_INT_FIFOS_TP_UP_PENDING            BIT(1)
+#define SUN4I_GPADC_INT_FIFOS_TP_DOWN_PENDING          BIT(0)
+
+#define SUN4I_GPADC_CDAT                               0x1c
+#define SUN4I_GPADC_TEMP_DATA                          0x20
+#define SUN4I_GPADC_DATA                               0x24
+
+#define SUN4I_GPADC_IRQ_FIFO_DATA                      0
+#define SUN4I_GPADC_IRQ_TEMP_DATA                      1
+
+/* 10s delay before suspending the IP */
+#define SUN4I_GPADC_AUTOSUSPEND_DELAY                  10000
+
+struct sun4i_gpadc_dev {
+       struct device                   *dev;
+       struct regmap                   *regmap;
+       struct regmap_irq_chip_data     *regmap_irqc;
+       void __iomem                    *base;
+};
+
+#endif
index 3cbec4b2496a6a5cdbef0816aa92e157e8fcfd4a..eac285756b37a918c1bfb11845b2a160f559618f 100644 (file)
 #define TPS65217_PPATH_AC_CURRENT_MASK 0x0C
 #define TPS65217_PPATH_USB_CURRENT_MASK        0x03
 
-#define TPS65217_INT_RESERVEDM         BIT(7)
 #define TPS65217_INT_PBM               BIT(6)
 #define TPS65217_INT_ACM               BIT(5)
 #define TPS65217_INT_USBM              BIT(4)
 #define TPS65217_INT_PBI               BIT(2)
 #define TPS65217_INT_ACI               BIT(1)
 #define TPS65217_INT_USBI              BIT(0)
+#define TPS65217_INT_SHIFT             4
+#define TPS65217_INT_MASK              (TPS65217_INT_PBM | TPS65217_INT_ACM | \
+                                       TPS65217_INT_USBM)
 
 #define TPS65217_CHGCONFIG0_TREG       BIT(7)
 #define TPS65217_CHGCONFIG0_DPPM       BIT(6)
index d1db9527fab5897e320dffc6925017b8bc29207d..bccd2d68b1e306c741ef295f9fe73d2d9e830086 100644 (file)
@@ -282,10 +282,9 @@ struct tps65218 {
        struct regulator_desc desc[TPS65218_NUM_REGULATOR];
        struct tps_info *info[TPS65218_NUM_REGULATOR];
        struct regmap *regmap;
+       u8 *strobes;
 };
 
-int tps65218_reg_read(struct tps65218 *tps, unsigned int reg,
-                                       unsigned int *val);
 int tps65218_reg_write(struct tps65218 *tps, unsigned int reg,
                        unsigned int val, unsigned int level);
 int tps65218_set_bits(struct tps65218 *tps, unsigned int reg,
index 1a603701550e33e51dd2f4c78a5d4311abc0112a..b25d0297ba887a901da8dd5349ac777e908da533 100644 (file)
@@ -319,21 +319,7 @@ struct tps65912 {
        struct regmap_irq_chip_data *irq_data;
 };
 
-static const struct regmap_range tps65912_yes_ranges[] = {
-       regmap_reg_range(TPS65912_INT_STS, TPS65912_GPIO5),
-};
-
-static const struct regmap_access_table tps65912_volatile_table = {
-       .yes_ranges = tps65912_yes_ranges,
-       .n_yes_ranges = ARRAY_SIZE(tps65912_yes_ranges),
-};
-
-static const struct regmap_config tps65912_regmap_config = {
-       .reg_bits = 8,
-       .val_bits = 8,
-       .cache_type = REGCACHE_RBTREE,
-       .volatile_table = &tps65912_volatile_table,
-};
+extern const struct regmap_config tps65912_regmap_config;
 
 int tps65912_device_init(struct tps65912 *tps);
 int tps65912_device_exit(struct tps65912 *tps);
index a426cb55dc43b9ff6c02b00293d3b24b9881c4ea..ed30d5d713e3400944e6247a7079ee4840a1ae94 100644 (file)
@@ -32,6 +32,7 @@
 #define STORE_QUEUE_MINOR      155     /* unused */
 #define I2O_MINOR              166
 #define MICROCODE_MINOR                184
+#define IRNET_MINOR            187
 #define VFIO_MINOR             196
 #define TUN_MINOR              200
 #define CUSE_MINOR             203
index 08d947fc4c59dac845652dee2ad1c98aac2f2626..808751d7b737e28cd0b933d19b6544cae85bab79 100644 (file)
@@ -509,10 +509,6 @@ struct mm_struct {
        bool tlb_flush_pending;
 #endif
        struct uprobes_state uprobes_state;
-#ifdef CONFIG_X86_INTEL_MPX
-       /* address of the bounds directory */
-       void __user *bd_addr;
-#endif
 #ifdef CONFIG_HUGETLB_PAGE
        atomic_long_t hugetlb_usage;
 #endif
index 1172cce949a4c36226fea3b1c64c66d6b01c313e..c6f55158d5e5aa086d284a454008f65b790fcfe6 100644 (file)
@@ -79,12 +79,12 @@ extern void mnt_drop_write(struct vfsmount *mnt);
 extern void mnt_drop_write_file(struct file *file);
 extern void mntput(struct vfsmount *mnt);
 extern struct vfsmount *mntget(struct vfsmount *mnt);
-extern struct vfsmount *mnt_clone_internal(struct path *path);
+extern struct vfsmount *mnt_clone_internal(const struct path *path);
 extern int __mnt_is_readonly(struct vfsmount *mnt);
 extern bool mnt_may_suid(struct vfsmount *mnt);
 
 struct path;
-extern struct vfsmount *clone_private_mount(struct path *path);
+extern struct vfsmount *clone_private_mount(const struct path *path);
 
 struct file_system_type;
 extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
@@ -98,4 +98,6 @@ extern dev_t name_to_dev_t(const char *name);
 
 extern unsigned int sysctl_mount_max;
 
+extern bool path_is_mountpoint(const struct path *path);
+
 #endif /* _LINUX_MOUNT_H */
index d8905a229f34833a4336b0a69431a4a0a94bc76e..c5f3a012ae62fec6766cf55a85c7f61ddecee3f7 100644 (file)
@@ -142,6 +142,12 @@ enum nand_ecc_algo {
  */
 #define NAND_ECC_GENERIC_ERASED_CHECK  BIT(0)
 #define NAND_ECC_MAXIMIZE              BIT(1)
+/*
+ * If your controller already sends the required NAND commands when
+ * reading or writing a page, then the framework is not supposed to
+ * send READ0 and SEQIN/PAGEPROG respectively.
+ */
+#define NAND_ECC_CUSTOM_PAGE_ACCESS    BIT(2)
 
 /* Bit mask for flags passed to do_nand_read_ecc */
 #define NAND_GET_DEVICE                0x80
@@ -186,6 +192,7 @@ enum nand_ecc_algo {
 /* Macros to identify the above */
 #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
 #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
+#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE)
 
 /* Non chip related options */
 /* This option skips the bbt scan during initialization. */
@@ -210,6 +217,16 @@ enum nand_ecc_algo {
  */
 #define NAND_USE_BOUNCE_BUFFER 0x00100000
 
+/*
+ * In case your controller is implementing ->cmd_ctrl() and is relying on the
+ * default ->cmdfunc() implementation, you may want to let the core handle the
+ * tCCS delay which is required when a column change (RNDIN or RNDOUT) is
+ * requested.
+ * If your controller already takes care of this delay, you don't need to set
+ * this flag.
+ */
+#define NAND_WAIT_TCCS         0x00200000
+
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
 #define NAND_CONTROLLER_ALLOC  0x80000000
@@ -558,6 +575,11 @@ struct nand_ecc_ctrl {
                        int page);
 };
 
+static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc)
+{
+       return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS);
+}
+
 /**
  * struct nand_buffers - buffer structure for read/write
  * @ecccalc:   buffer pointer for calculated ECC, size is oobsize.
@@ -584,6 +606,10 @@ struct nand_buffers {
  *
  * All these timings are expressed in picoseconds.
  *
+ * @tBERS_max: Block erase time
+ * @tCCS_min: Change column setup time
+ * @tPROG_max: Page program time
+ * @tR_max: Page read time
  * @tALH_min: ALE hold time
  * @tADL_min: ALE to data loading time
  * @tALS_min: ALE setup time
@@ -621,6 +647,10 @@ struct nand_buffers {
  * @tWW_min: WP# transition to WE# low
  */
 struct nand_sdr_timings {
+       u32 tBERS_max;
+       u32 tCCS_min;
+       u32 tPROG_max;
+       u32 tR_max;
        u32 tALH_min;
        u32 tADL_min;
        u32 tALS_min;
diff --git a/include/linux/platform_data/drv260x-pdata.h b/include/linux/platform_data/drv260x-pdata.h
deleted file mode 100644 (file)
index 0a03b09..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Platform data for DRV260X haptics driver family
- *
- * Author: Dan Murphy <dmurphy@ti.com>
- *
- * Copyright:   (C) 2014 Texas Instruments, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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_DRV260X_PDATA_H
-#define _LINUX_DRV260X_PDATA_H
-
-struct drv260x_platform_data {
-       u32 library_selection;
-       u32 mode;
-       u32 vib_rated_voltage;
-       u32 vib_overdrive_voltage;
-};
-
-#endif
index 21b15f6fee2546e520a355b5a1d8cd4835fdc518..7815d50c26ff4bf021484cf801ee53be0ce09aaf 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __MACB_PDATA_H__
 #define __MACB_PDATA_H__
 
+#include <linux/clk.h>
+
 /**
  * struct macb_platform_data - platform data for MACB Ethernet
  * @phy_mask:          phy mask passed when register the MDIO bus
  * @phy_irq_pin:       PHY IRQ
  * @is_rmii:           using RMII interface?
  * @rev_eth_addr:      reverse Ethernet address byte order
+ * @pclk:              platform clock
+ * @hclk:              AHB clock
  */
 struct macb_platform_data {
        u32             phy_mask;
        int             phy_irq_pin;
        u8              is_rmii;
        u8              rev_eth_addr;
+       struct clk      *pclk;
+       struct clk      *hclk;
 };
 
 #endif /* __MACB_PDATA_H__ */
index c55e42ee57fa0c9ba3083d6bf03b04fae275d13c..f01659026b2681e7c141899097cedc582a58c447 100644 (file)
 #ifndef __MTD_NAND_S3C2410_H
 #define __MTD_NAND_S3C2410_H
 
+#include <linux/mtd/nand.h>
+
 /**
  * struct s3c2410_nand_set - define a set of one or more nand chips
- * @disable_ecc:       Entirely disable ECC - Dangerous
  * @flash_bbt:                 Openmoko u-boot can create a Bad Block Table
  *                     Setting this flag will allow the kernel to
  *                     look for it at boot time and also skip the NAND
@@ -31,7 +32,6 @@
  * a warning at boot time.
  */
 struct s3c2410_nand_set {
-       unsigned int            disable_ecc:1;
        unsigned int            flash_bbt:1;
 
        unsigned int            options;
@@ -40,6 +40,7 @@ struct s3c2410_nand_set {
        char                    *name;
        int                     *nr_map;
        struct mtd_partition    *partitions;
+       struct device_node      *of_node;
 };
 
 struct s3c2410_platform_nand {
@@ -51,6 +52,8 @@ struct s3c2410_platform_nand {
 
        unsigned int    ignore_unset_ecc:1;
 
+       nand_ecc_modes_t        ecc_mode;
+
        int                     nr_sets;
        struct s3c2410_nand_set *sets;
 
index 55107a8ff8877f270b02fc67a689eac992f2ea74..3434eef2a5aad963d579670ed081b68db382239d 100644 (file)
@@ -431,7 +431,7 @@ struct qc_info {
 
 /* Operations handling requests from userspace */
 struct quotactl_ops {
-       int (*quota_on)(struct super_block *, int, int, struct path *);
+       int (*quota_on)(struct super_block *, int, int, const struct path *);
        int (*quota_off)(struct super_block *, int);
        int (*quota_enable)(struct super_block *, unsigned int);
        int (*quota_disable)(struct super_block *, unsigned int);
@@ -520,7 +520,6 @@ static inline void quota_send_warning(struct kqid qid, dev_t dev,
 struct quota_info {
        unsigned int flags;                     /* Flags for diskquotas on this device */
        struct mutex dqio_mutex;                /* lock device while I/O in progress */
-       struct mutex dqonoff_mutex;             /* Serialize quotaon & quotaoff */
        struct inode *files[MAXQUOTAS];         /* inodes of quotafiles */
        struct mem_dqinfo info[MAXQUOTAS];      /* Information for each quota type */
        const struct quota_format_ops *ops[MAXQUOTAS];  /* Operations for each type */
index f00fa86ac9660ad79e243f9c9e590bf854dcb48d..799a63d0e1a823e38c0c54f52e5e297cde9bb60c 100644 (file)
@@ -90,7 +90,7 @@ int dquot_file_open(struct inode *inode, struct file *file);
 int dquot_enable(struct inode *inode, int type, int format_id,
        unsigned int flags);
 int dquot_quota_on(struct super_block *sb, int type, int format_id,
-       struct path *path);
+       const struct path *path);
 int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
        int format_id, int type);
 int dquot_quota_off(struct super_block *sb, int type);
index e0aca147600169a6fa67dcb3c7d5f7725a52a9d6..64125443f8a638e787adfbaebab4755f5d63852a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
+#include <linux/kfifo.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -99,6 +100,8 @@ struct rmi_2d_sensor_platform_data {
        bool topbuttonpad;
        bool kernel_tracking;
        int dmax;
+       int dribble;
+       int palm_detect;
 };
 
 /**
@@ -106,7 +109,7 @@ struct rmi_2d_sensor_platform_data {
  * @buttonpad - the touchpad is a buttonpad, so enable only the first actual
  * button that is found.
  * @trackstick_buttons - Set when the function 30 is handling the physical
- * buttons of the trackstick (as a PD/2 passthrough device.
+ * buttons of the trackstick (as a PS/2 passthrough device).
  * @disable - the touchpad incorrectly reports F30 and it should be ignored.
  * This is a special case which is due to misconfigured firmware.
  */
@@ -116,14 +119,17 @@ struct rmi_f30_data {
        bool disable;
 };
 
-/**
- * struct rmi_f01_power - override default power management settings.
- *
+
+/*
+ * Set the state of a register
+ *     DEFAULT - use the default value set by the firmware config
+ *     OFF - explicitly disable the register
+ *     ON - explicitly enable the register
  */
-enum rmi_f01_nosleep {
-       RMI_F01_NOSLEEP_DEFAULT = 0,
-       RMI_F01_NOSLEEP_OFF = 1,
-       RMI_F01_NOSLEEP_ON = 2
+enum rmi_reg_state {
+       RMI_REG_STATE_DEFAULT = 0,
+       RMI_REG_STATE_OFF = 1,
+       RMI_REG_STATE_ON = 2
 };
 
 /**
@@ -143,7 +149,7 @@ enum rmi_f01_nosleep {
  * when the touch sensor is in doze mode, in units of 10ms.
  */
 struct rmi_f01_power_management {
-       enum rmi_f01_nosleep nosleep;
+       enum rmi_reg_state nosleep;
        u8 wakeup_threshold;
        u8 doze_holdoff;
        u8 doze_interval;
@@ -204,16 +210,18 @@ struct rmi_device_platform_data_spi {
  * @reset_delay_ms - after issuing a reset command to the touch sensor, the
  * driver waits a few milliseconds to give the firmware a chance to
  * to re-initialize.  You can override the default wait period here.
+ * @irq: irq associated with the attn gpio line, or negative
  */
 struct rmi_device_platform_data {
        int reset_delay_ms;
+       int irq;
 
        struct rmi_device_platform_data_spi spi_data;
 
        /* function handler pdata */
-       struct rmi_2d_sensor_platform_data *sensor_pdata;
+       struct rmi_2d_sensor_platform_data sensor_pdata;
        struct rmi_f01_power_management power_management;
-       struct rmi_f30_data *f30_data;
+       struct rmi_f30_data f30_data;
 };
 
 /**
@@ -264,9 +272,6 @@ struct rmi_transport_dev {
        struct rmi_device_platform_data pdata;
 
        struct input_dev *input;
-
-       void *attn_data;
-       int attn_size;
 };
 
 /**
@@ -324,17 +329,24 @@ struct rmi_device {
 
 };
 
+struct rmi4_attn_data {
+       unsigned long irq_status;
+       size_t size;
+       void *data;
+};
+
 struct rmi_driver_data {
        struct list_head function_list;
 
        struct rmi_device *rmi_dev;
 
        struct rmi_function *f01_container;
-       bool f01_bootloader_mode;
+       struct rmi_function *f34_container;
+       bool bootloader_mode;
 
-       u32 attn_count;
        int num_of_irq_regs;
        int irq_count;
+       void *irq_memory;
        unsigned long *irq_status;
        unsigned long *fn_irq_bits;
        unsigned long *current_irq_mask;
@@ -343,17 +355,23 @@ struct rmi_driver_data {
        struct input_dev *input;
 
        u8 pdt_props;
-       u8 bsr;
+
+       u8 num_rx_electrodes;
+       u8 num_tx_electrodes;
 
        bool enabled;
+       struct mutex enabled_mutex;
 
-       void *data;
+       struct rmi4_attn_data attn_data;
+       DECLARE_KFIFO(attn_fifo, struct rmi4_attn_data, 16);
 };
 
 int rmi_register_transport_device(struct rmi_transport_dev *xport);
 void rmi_unregister_transport_device(struct rmi_transport_dev *xport);
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev);
 
-int rmi_driver_suspend(struct rmi_device *rmi_dev);
-int rmi_driver_resume(struct rmi_device *rmi_dev);
+void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
+                      void *data, size_t size);
+
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake);
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake);
 #endif
index 954ad6bfb56a2c0dd90abb1c559c2990ce8596e5..3212b39b5bfcb543fff0f1cd174f2124e3b9cc45 100644 (file)
@@ -22,7 +22,8 @@ struct sock;
 struct sockaddr;
 
 int inet6_csk_bind_conflict(const struct sock *sk,
-                           const struct inet_bind_bucket *tb, bool relax);
+                           const struct inet_bind_bucket *tb, bool relax,
+                           bool soreuseport_ok);
 
 struct dst_entry *inet6_csk_route_req(const struct sock *sk, struct flowi6 *fl6,
                                      const struct request_sock *req, u8 proto);
index 146054ceea8e0566f79739b1ed115dea53423258..85ee3879499ebc4ebd63a59b2c425918858154c6 100644 (file)
@@ -63,7 +63,8 @@ struct inet_connection_sock_af_ops {
 #endif
        void        (*addr2sockaddr)(struct sock *sk, struct sockaddr *);
        int         (*bind_conflict)(const struct sock *sk,
-                                    const struct inet_bind_bucket *tb, bool relax);
+                                    const struct inet_bind_bucket *tb,
+                                    bool relax, bool soreuseport_ok);
        void        (*mtu_reduced)(struct sock *sk);
 };
 
@@ -261,7 +262,8 @@ inet_csk_rto_backoff(const struct inet_connection_sock *icsk,
 struct sock *inet_csk_accept(struct sock *sk, int flags, int *err);
 
 int inet_csk_bind_conflict(const struct sock *sk,
-                          const struct inet_bind_bucket *tb, bool relax);
+                          const struct inet_bind_bucket *tb, bool relax,
+                          bool soreuseport_ok);
 int inet_csk_get_port(struct sock *sk, unsigned short snum);
 
 struct dst_entry *inet_csk_route_req(const struct sock *sk, struct flowi4 *fl4,
index dd657a33f8c304455c99d83121fc743a86d13973..d3938f11ae52ee234ea0b4c4e3f7b2e37615601d 100644 (file)
@@ -698,7 +698,8 @@ static inline int nla_len(const struct nlattr *nla)
  */
 static inline int nla_ok(const struct nlattr *nla, int remaining)
 {
-       return nla->nla_len >= sizeof(*nla) &&
+       return remaining >= (int) sizeof(*nla) &&
+              nla->nla_len >= sizeof(*nla) &&
               nla->nla_len <= remaining;
 }
 
index aafafeb0c1178a224629bbfd09c8bcaa3fdda166..223b734abccdc3b7f3baae457261dd66862fcd1d 100644 (file)
@@ -1156,7 +1156,8 @@ config CGROUP_PERF
 
 config CGROUP_BPF
        bool "Support for eBPF programs attached to cgroups"
-       depends on BPF_SYSCALL && SOCK_CGROUP_DATA
+       depends on BPF_SYSCALL
+       select SOCK_CGROUP_DATA
        help
          Allow attaching eBPF programs to a cgroup using the bpf(2)
          syscall command BPF_PROG_ATTACH.
index 91bff3c0b368c4ac6584c8cbad6b5b40e9a338ed..6e399bb69d7c6ab54ddf22d2d908c630c0d17fc0 100644 (file)
@@ -1893,7 +1893,7 @@ void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
  * @call_panic: optional pointer to int that will be updated if secid fails
  */
 void audit_log_name(struct audit_context *context, struct audit_names *n,
-                   struct path *path, int record_num, int *call_panic)
+                   const struct path *path, int record_num, int *call_panic)
 {
        struct audit_buffer *ab;
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
@@ -2081,7 +2081,7 @@ EXPORT_SYMBOL(audit_log_task_info);
  * @operation: specific link operation
  * @link: the path that triggered the restriction
  */
-void audit_log_link_denied(const char *operation, struct path *link)
+void audit_log_link_denied(const char *operation, const struct path *link)
 {
        struct audit_buffer *ab;
        struct audit_names *name;
index 431444c3708bf4634568b9a8d83318de7c0fa22f..960d49c9db5e3c79b70171c6c9ca1f4d8acf58f2 100644 (file)
@@ -212,7 +212,7 @@ extern void audit_copy_inode(struct audit_names *name,
 extern void audit_log_cap(struct audit_buffer *ab, char *prefix,
                          kernel_cap_t *cap);
 extern void audit_log_name(struct audit_context *context,
-                          struct audit_names *n, struct path *path,
+                          struct audit_names *n, const struct path *path,
                           int record_num, int *call_panic);
 
 extern int audit_pid;
index f75154889aa9b5df52bdf5967a275ac1235cf819..7ea57e516029d6b82a9e72adfea70d45f538cb2b 100644 (file)
@@ -74,7 +74,7 @@ int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_
 }
 
 static void audit_update_mark(struct audit_fsnotify_mark *audit_mark,
-                            struct inode *inode)
+                            const struct inode *inode)
 {
        audit_mark->dev = inode ? inode->i_sb->s_dev : AUDIT_DEV_UNSET;
        audit_mark->ino = inode ? inode->i_ino : AUDIT_INO_UNSET;
@@ -167,11 +167,11 @@ static int audit_mark_handle_event(struct fsnotify_group *group,
                                    struct inode *to_tell,
                                    struct fsnotify_mark *inode_mark,
                                    struct fsnotify_mark *vfsmount_mark,
-                                   u32 mask, void *data, int data_type,
+                                   u32 mask, const void *data, int data_type,
                                    const unsigned char *dname, u32 cookie)
 {
        struct audit_fsnotify_mark *audit_mark;
-       struct inode *inode = NULL;
+       const struct inode *inode = NULL;
 
        audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark);
 
@@ -179,10 +179,10 @@ static int audit_mark_handle_event(struct fsnotify_group *group,
 
        switch (data_type) {
        case (FSNOTIFY_EVENT_PATH):
-               inode = ((struct path *)data)->dentry->d_inode;
+               inode = ((const struct path *)data)->dentry->d_inode;
                break;
        case (FSNOTIFY_EVENT_INODE):
-               inode = (struct inode *)data;
+               inode = (const struct inode *)data;
                break;
        default:
                BUG();
index 055f11b0a50f1ac2a4684b51f300c054b71bd8ad..8b1dde96a0faa1bda645f0e03388f0a47f565bdc 100644 (file)
@@ -947,7 +947,7 @@ static int audit_tree_handle_event(struct fsnotify_group *group,
                                   struct inode *to_tell,
                                   struct fsnotify_mark *inode_mark,
                                   struct fsnotify_mark *vfsmount_mark,
-                                  u32 mask, void *data, int data_type,
+                                  u32 mask, const void *data, int data_type,
                                   const unsigned char *file_name, u32 cookie)
 {
        return 0;
index 2d7bdcb996b66f1a88fe0aa560e5cd313147bf18..f79e4658433d45e9d32a299ebf3f427b508ada2c 100644 (file)
@@ -471,10 +471,10 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
                                    struct inode *to_tell,
                                    struct fsnotify_mark *inode_mark,
                                    struct fsnotify_mark *vfsmount_mark,
-                                   u32 mask, void *data, int data_type,
+                                   u32 mask, const void *data, int data_type,
                                    const unsigned char *dname, u32 cookie)
 {
-       struct inode *inode;
+       const struct inode *inode;
        struct audit_parent *parent;
 
        parent = container_of(inode_mark, struct audit_parent, mark);
@@ -483,10 +483,10 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
 
        switch (data_type) {
        case (FSNOTIFY_EVENT_PATH):
-               inode = d_backing_inode(((struct path *)data)->dentry);
+               inode = d_backing_inode(((const struct path *)data)->dentry);
                break;
        case (FSNOTIFY_EVENT_INODE):
-               inode = (struct inode *)data;
+               inode = (const struct inode *)data;
                break;
        default:
                BUG();
index 83e0d153b0b46d64fe4916ea50ccced539c6ea9a..1eb4f1303756164f2893d964198eecd40b0bcd62 100644 (file)
@@ -105,19 +105,29 @@ struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
        gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO |
                          gfp_extra_flags;
        struct bpf_prog *fp;
+       u32 pages, delta;
+       int ret;
 
        BUG_ON(fp_old == NULL);
 
        size = round_up(size, PAGE_SIZE);
-       if (size <= fp_old->pages * PAGE_SIZE)
+       pages = size / PAGE_SIZE;
+       if (pages <= fp_old->pages)
                return fp_old;
 
+       delta = pages - fp_old->pages;
+       ret = __bpf_prog_charge(fp_old->aux->user, delta);
+       if (ret)
+               return NULL;
+
        fp = __vmalloc(size, gfp_flags, PAGE_KERNEL);
-       if (fp != NULL) {
+       if (fp == NULL) {
+               __bpf_prog_uncharge(fp_old->aux->user, delta);
+       } else {
                kmemcheck_annotate_bitfield(fp, meta);
 
                memcpy(fp, fp_old, fp_old->pages * PAGE_SIZE);
-               fp->pages = size / PAGE_SIZE;
+               fp->pages = pages;
                fp->aux->prog = fp;
 
                /* We keep fp->aux from fp_old around in the new
@@ -136,28 +146,29 @@ void __bpf_prog_free(struct bpf_prog *fp)
        vfree(fp);
 }
 
-#define SHA_BPF_RAW_SIZE                                               \
-       round_up(MAX_BPF_SIZE + sizeof(__be64) + 1, SHA_MESSAGE_BYTES)
-
-/* Called under verifier mutex. */
-void bpf_prog_calc_digest(struct bpf_prog *fp)
+int bpf_prog_calc_digest(struct bpf_prog *fp)
 {
        const u32 bits_offset = SHA_MESSAGE_BYTES - sizeof(__be64);
-       static u32 ws[SHA_WORKSPACE_WORDS];
-       static u8 raw[SHA_BPF_RAW_SIZE];
-       struct bpf_insn *dst = (void *)raw;
+       u32 raw_size = bpf_prog_digest_scratch_size(fp);
+       u32 ws[SHA_WORKSPACE_WORDS];
        u32 i, bsize, psize, blocks;
+       struct bpf_insn *dst;
        bool was_ld_map;
-       u8 *todo = raw;
+       u8 *raw, *todo;
        __be32 *result;
        __be64 *bits;
 
+       raw = vmalloc(raw_size);
+       if (!raw)
+               return -ENOMEM;
+
        sha_init(fp->digest);
        memset(ws, 0, sizeof(ws));
 
        /* We need to take out the map fd for the digest calculation
         * since they are unstable from user space side.
         */
+       dst = (void *)raw;
        for (i = 0, was_ld_map = false; i < fp->len; i++) {
                dst[i] = fp->insnsi[i];
                if (!was_ld_map &&
@@ -177,12 +188,13 @@ void bpf_prog_calc_digest(struct bpf_prog *fp)
                }
        }
 
-       psize = fp->len * sizeof(struct bpf_insn);
-       memset(&raw[psize], 0, sizeof(raw) - psize);
+       psize = bpf_prog_insn_size(fp);
+       memset(&raw[psize], 0, raw_size - psize);
        raw[psize++] = 0x80;
 
        bsize  = round_up(psize, SHA_MESSAGE_BYTES);
        blocks = bsize / SHA_MESSAGE_BYTES;
+       todo   = raw;
        if (bsize - psize >= sizeof(__be64)) {
                bits = (__be64 *)(todo + bsize - sizeof(__be64));
        } else {
@@ -199,6 +211,9 @@ void bpf_prog_calc_digest(struct bpf_prog *fp)
        result = (__force __be32 *)fp->digest;
        for (i = 0; i < SHA_DIGEST_WORDS; i++)
                result[i] = cpu_to_be32(fp->digest[i]);
+
+       vfree(raw);
+       return 0;
 }
 
 static bool bpf_is_jmp_and_has_target(const struct bpf_insn *insn)
index 4819ec9d95f6bdb82f4ae475d85b48c55f6e400c..e89acea22ecfc9a625de1924b2e4f997d88d158b 100644 (file)
@@ -615,19 +615,39 @@ static void free_used_maps(struct bpf_prog_aux *aux)
        kfree(aux->used_maps);
 }
 
+int __bpf_prog_charge(struct user_struct *user, u32 pages)
+{
+       unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+       unsigned long user_bufs;
+
+       if (user) {
+               user_bufs = atomic_long_add_return(pages, &user->locked_vm);
+               if (user_bufs > memlock_limit) {
+                       atomic_long_sub(pages, &user->locked_vm);
+                       return -EPERM;
+               }
+       }
+
+       return 0;
+}
+
+void __bpf_prog_uncharge(struct user_struct *user, u32 pages)
+{
+       if (user)
+               atomic_long_sub(pages, &user->locked_vm);
+}
+
 static int bpf_prog_charge_memlock(struct bpf_prog *prog)
 {
        struct user_struct *user = get_current_user();
-       unsigned long memlock_limit;
-
-       memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+       int ret;
 
-       atomic_long_add(prog->pages, &user->locked_vm);
-       if (atomic_long_read(&user->locked_vm) > memlock_limit) {
-               atomic_long_sub(prog->pages, &user->locked_vm);
+       ret = __bpf_prog_charge(user, prog->pages);
+       if (ret) {
                free_uid(user);
-               return -EPERM;
+               return ret;
        }
+
        prog->aux->user = user;
        return 0;
 }
@@ -636,7 +656,7 @@ static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
 {
        struct user_struct *user = prog->aux->user;
 
-       atomic_long_sub(prog->pages, &user->locked_vm);
+       __bpf_prog_uncharge(user, prog->pages);
        free_uid(user);
 }
 
@@ -811,7 +831,7 @@ static int bpf_prog_load(union bpf_attr *attr)
 
        err = -EFAULT;
        if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns),
-                          prog->len * sizeof(struct bpf_insn)) != 0)
+                          bpf_prog_insn_size(prog)) != 0)
                goto free_prog;
 
        prog->orig_prog = NULL;
index d28f9a3380a91d4b6f600a2027b99c868a1bb768..83ed2f8f6f228b1ae90f66d89e436b71a5c6a27c 100644 (file)
@@ -462,14 +462,19 @@ static void init_reg_state(struct bpf_reg_state *regs)
        regs[BPF_REG_1].type = PTR_TO_CTX;
 }
 
-static void mark_reg_unknown_value(struct bpf_reg_state *regs, u32 regno)
+static void __mark_reg_unknown_value(struct bpf_reg_state *regs, u32 regno)
 {
-       BUG_ON(regno >= MAX_BPF_REG);
        regs[regno].type = UNKNOWN_VALUE;
        regs[regno].id = 0;
        regs[regno].imm = 0;
 }
 
+static void mark_reg_unknown_value(struct bpf_reg_state *regs, u32 regno)
+{
+       BUG_ON(regno >= MAX_BPF_REG);
+       __mark_reg_unknown_value(regs, regno);
+}
+
 static void reset_reg_range_values(struct bpf_reg_state *regs, u32 regno)
 {
        regs[regno].min_value = BPF_REGISTER_MIN_RANGE;
@@ -1970,8 +1975,13 @@ static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id,
 
        if (reg->type == PTR_TO_MAP_VALUE_OR_NULL && reg->id == id) {
                reg->type = type;
+               /* We don't need id from this point onwards anymore, thus we
+                * should better reset it, so that state pruning has chances
+                * to take effect.
+                */
+               reg->id = 0;
                if (type == UNKNOWN_VALUE)
-                       mark_reg_unknown_value(regs, regno);
+                       __mark_reg_unknown_value(regs, regno);
        }
 }
 
@@ -1982,16 +1992,16 @@ static void mark_map_regs(struct bpf_verifier_state *state, u32 regno,
                          enum bpf_reg_type type)
 {
        struct bpf_reg_state *regs = state->regs;
+       u32 id = regs[regno].id;
        int i;
 
        for (i = 0; i < MAX_BPF_REG; i++)
-               mark_map_reg(regs, i, regs[regno].id, type);
+               mark_map_reg(regs, i, id, type);
 
        for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) {
                if (state->stack_slot_type[i] != STACK_SPILL)
                        continue;
-               mark_map_reg(state->spilled_regs, i / BPF_REG_SIZE,
-                            regs[regno].id, type);
+               mark_map_reg(state->spilled_regs, i / BPF_REG_SIZE, id, type);
        }
 }
 
@@ -2926,6 +2936,10 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env)
        int insn_cnt = env->prog->len;
        int i, j, err;
 
+       err = bpf_prog_calc_digest(env->prog);
+       if (err)
+               return err;
+
        for (i = 0; i < insn_cnt; i++, insn++) {
                if (BPF_CLASS(insn->code) == BPF_LDX &&
                    (BPF_MODE(insn->code) != BPF_MEM || insn->imm != 0)) {
@@ -3173,8 +3187,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
                log_level = 0;
        }
 
-       bpf_prog_calc_digest(env->prog);
-
        ret = replace_map_fd_with_map_ptr(env);
        if (ret < 0)
                goto skip_full_check;
index 217fd2e7f4354140146c910f8de0607458462557..5339aca811d2289690198119206eaa42d959452f 100644 (file)
@@ -1586,7 +1586,11 @@ EXPORT_SYMBOL_GPL(__cpuhp_state_add_instance);
  * @startup:   startup callback function
  * @teardown:  teardown callback function
  *
- * Returns 0 if successful, otherwise a proper error code
+ * Returns:
+ *   On success:
+ *      Positive state number if @state is CPUHP_AP_ONLINE_DYN
+ *      0 for all other states
+ *   On failure: proper (negative) error code
  */
 int __cpuhp_setup_state(enum cpuhp_state state,
                        const char *name, bool invoke,
index 9be9bda7c1f94cf633bb11b4be141ceecf0244b4..4544b115f5eb85d4b01ec966f933f191cd2cae1e 100644 (file)
@@ -37,10 +37,10 @@ static void irq_spread_init_one(struct cpumask *irqmsk, struct cpumask *nmsk,
 
 static int get_nodes_in_cpumask(const struct cpumask *mask, nodemask_t *nodemsk)
 {
-       int n, nodes;
+       int n, nodes = 0;
 
        /* Calculate the number of nodes in the supplied affinity mask */
-       for (n = 0, nodes = 0; n < num_online_nodes(); n++) {
+       for_each_online_node(n) {
                if (cpumask_intersects(mask, cpumask_of_node(n))) {
                        node_set(n, *nodemsk);
                        nodes++;
@@ -82,7 +82,7 @@ irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
        nodes = get_nodes_in_cpumask(cpu_online_mask, &nodemsk);
 
        /*
-        * If the number of nodes in the mask is less than or equal the
+        * If the number of nodes in the mask is greater than or equal the
         * number of vectors we just spread the vectors across the nodes.
         */
        if (affv <= nodes) {
index f6aae7977824ab7595950e378c2dd0f0bbe0256d..d2a20e83ebaed372ddb68d00bd8f44a50989b804 100644 (file)
@@ -871,6 +871,9 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
        int cpu = smp_processor_id();
 
+       if (!bc)
+               return;
+
        /* Set it up only once ! */
        if (bc->event_handler != tick_handle_oneshot_broadcast) {
                int was_periodic = clockevent_state_periodic(bc);
index 54287d443806243fba2efa67e6b5ec71f3a4f56d..b1b20dc63265029e0f5e77221d8a2d851032992f 100644 (file)
@@ -3212,7 +3212,6 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
 #endif /* CONFIG_TMPFS_XATTR */
 
 static const struct inode_operations shmem_short_symlink_operations = {
-       .readlink       = generic_readlink,
        .get_link       = simple_get_link,
 #ifdef CONFIG_TMPFS_XATTR
        .listxattr      = shmem_listxattr,
@@ -3220,7 +3219,6 @@ static const struct inode_operations shmem_short_symlink_operations = {
 };
 
 static const struct inode_operations shmem_symlink_inode_operations = {
-       .readlink       = generic_readlink,
        .get_link       = shmem_get_link,
 #ifdef CONFIG_TMPFS_XATTR
        .listxattr      = shmem_listxattr,
index 779b3fa6052d68648c3f8b7a8d3f85292be453e1..019557d0a11d2434ff7186da5504917717bf7d2b 100644 (file)
@@ -111,9 +111,9 @@ static inline void lec_arp_put(struct lec_arp_table *entry)
 }
 
 static struct lane2_ops lane2_ops = {
-       lane2_resolve,          /* resolve,             spec 3.1.3 */
-       lane2_associate_req,    /* associate_req,       spec 3.1.4 */
-       NULL                    /* associate indicator, spec 3.1.5 */
+       .resolve = lane2_resolve,               /* spec 3.1.3 */
+       .associate_req = lane2_associate_req,   /* spec 3.1.4 */
+       .associate_indicator = NULL             /* spec 3.1.5 */
 };
 
 static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
index 9e60e74c807d961bf9eab2d439eb6ffa95599007..a89fdebeffdae49a0b2b1bb363b5dfa11bfb6c9a 100644 (file)
@@ -535,33 +535,32 @@ static void eg_destroy_cache(struct mpoa_client *mpc)
 
 
 static const struct in_cache_ops ingress_ops = {
-       in_cache_add_entry,               /* add_entry       */
-       in_cache_get,                     /* get             */
-       in_cache_get_with_mask,           /* get_with_mask   */
-       in_cache_get_by_vcc,              /* get_by_vcc      */
-       in_cache_put,                     /* put             */
-       in_cache_remove_entry,            /* remove_entry    */
-       cache_hit,                        /* cache_hit       */
-       clear_count_and_expired,          /* clear_count     */
-       check_resolving_entries,          /* check_resolving */
-       refresh_entries,                  /* refresh         */
-       in_destroy_cache                  /* destroy_cache   */
+       .add_entry = in_cache_add_entry,
+       .get = in_cache_get,
+       .get_with_mask = in_cache_get_with_mask,
+       .get_by_vcc = in_cache_get_by_vcc,
+       .put = in_cache_put,
+       .remove_entry = in_cache_remove_entry,
+       .cache_hit = cache_hit,
+       .clear_count = clear_count_and_expired,
+       .check_resolving = check_resolving_entries,
+       .refresh = refresh_entries,
+       .destroy_cache = in_destroy_cache
 };
 
 static const struct eg_cache_ops egress_ops = {
-       eg_cache_add_entry,               /* add_entry        */
-       eg_cache_get_by_cache_id,         /* get_by_cache_id  */
-       eg_cache_get_by_tag,              /* get_by_tag       */
-       eg_cache_get_by_vcc,              /* get_by_vcc       */
-       eg_cache_get_by_src_ip,           /* get_by_src_ip    */
-       eg_cache_put,                     /* put              */
-       eg_cache_remove_entry,            /* remove_entry     */
-       update_eg_cache_entry,            /* update           */
-       clear_expired,                    /* clear_expired    */
-       eg_destroy_cache                  /* destroy_cache    */
+       .add_entry = eg_cache_add_entry,
+       .get_by_cache_id = eg_cache_get_by_cache_id,
+       .get_by_tag = eg_cache_get_by_tag,
+       .get_by_vcc = eg_cache_get_by_vcc,
+       .get_by_src_ip = eg_cache_get_by_src_ip,
+       .put = eg_cache_put,
+       .remove_entry = eg_cache_remove_entry,
+       .update = update_eg_cache_entry,
+       .clear_expired = clear_expired,
+       .destroy_cache = eg_destroy_cache
 };
 
-
 void atm_mpoa_init_cache(struct mpoa_client *mpc)
 {
        mpc->in_ops = &ingress_ops;
index b1461708a9774b03376d78a8761677feb031bfe6..7190bd648154e61d19f652dba5fbd861a72f6c36 100644 (file)
@@ -2972,6 +2972,12 @@ void bpf_warn_invalid_xdp_action(u32 act)
 }
 EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action);
 
+void bpf_warn_invalid_xdp_buffer(void)
+{
+       WARN_ONCE(1, "Illegal XDP buffer encountered, expect throughput degradation\n");
+}
+EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_buffer);
+
 static u32 sk_filter_convert_ctx_access(enum bpf_access_type type, int dst_reg,
                                        int src_reg, int ctx_off,
                                        struct bpf_insn *insn_buf,
index b2c26b081134a0c5b3697bfbad0148a029a5b95e..41f803e35da3bafd93a5d0853ee2e034995ad9c5 100644 (file)
@@ -201,7 +201,7 @@ static struct dn_dev_sysctl_table {
                .extra1 = &min_t3,
                .extra2 = &max_t3
        },
-       {0}
+       { }
        },
 };
 
index d5d3ead0a6c31e42e8843d30f8c643324a91b8e9..19ea045c50ed7d9bfc885e13a67f6bca6075674c 100644 (file)
@@ -45,11 +45,12 @@ void inet_get_local_port_range(struct net *net, int *low, int *high)
 EXPORT_SYMBOL(inet_get_local_port_range);
 
 int inet_csk_bind_conflict(const struct sock *sk,
-                          const struct inet_bind_bucket *tb, bool relax)
+                          const struct inet_bind_bucket *tb, bool relax,
+                          bool reuseport_ok)
 {
        struct sock *sk2;
-       int reuse = sk->sk_reuse;
-       int reuseport = sk->sk_reuseport;
+       bool reuse = sk->sk_reuse;
+       bool reuseport = !!sk->sk_reuseport && reuseport_ok;
        kuid_t uid = sock_i_uid((struct sock *)sk);
 
        /*
@@ -105,6 +106,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
        struct inet_bind_bucket *tb;
        kuid_t uid = sock_i_uid(sk);
        u32 remaining, offset;
+       bool reuseport_ok = !!snum;
 
        if (port) {
 have_port:
@@ -165,7 +167,8 @@ other_parity_scan:
                                        smallest_size = tb->num_owners;
                                        smallest_port = port;
                                }
-                               if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false))
+                               if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false,
+                                                                             reuseport_ok))
                                        goto tb_found;
                                goto next_port;
                        }
@@ -206,13 +209,14 @@ tb_found:
                      sk->sk_reuseport && uid_eq(tb->fastuid, uid))) &&
                    smallest_size == -1)
                        goto success;
-               if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, true)) {
+               if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, true,
+                                                            reuseport_ok)) {
                        if ((reuse ||
                             (tb->fastreuseport > 0 &&
                              sk->sk_reuseport &&
                              !rcu_access_pointer(sk->sk_reuseport_cb) &&
                              uid_eq(tb->fastuid, uid))) &&
-                           smallest_size != -1 && --attempts >= 0) {
+                           !snum && smallest_size != -1 && --attempts >= 0) {
                                spin_unlock_bh(&head->lock);
                                goto again;
                        }
index 1c86c478f578b49373e61a4c397f23f3dc7f3fc6..7396e75e161b83ee2b8a426bce0eb770884960dd 100644 (file)
 #include <net/sock_reuseport.h>
 
 int inet6_csk_bind_conflict(const struct sock *sk,
-                           const struct inet_bind_bucket *tb, bool relax)
+                           const struct inet_bind_bucket *tb, bool relax,
+                           bool reuseport_ok)
 {
        const struct sock *sk2;
-       int reuse = sk->sk_reuse;
-       int reuseport = sk->sk_reuseport;
+       bool reuse = !!sk->sk_reuse;
+       bool reuseport = !!sk->sk_reuseport && reuseport_ok;
        kuid_t uid = sock_i_uid((struct sock *)sk);
 
        /* We must walk the whole port owner list in this case. -DaveM */
index 2413a0637d992d81081db67e2c08528eb6a42f17..890acace01d0a642517b1536598e4482b20a4456 100644 (file)
@@ -2174,6 +2174,8 @@ static int ip6_route_del(struct fib6_config *cfg)
                                continue;
                        if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
                                continue;
+                       if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
+                               continue;
                        dst_hold(&rt->dst);
                        read_unlock_bh(&table->tb6_lock);
 
index 8d65bb9477fce626c7e781c0d38d78b488b5271c..c69f0f38f5669de49c7db9ac038a7b8dbe8ff664 100644 (file)
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
 #include <linux/netdevice.h>
-#include <linux/miscdevice.h>
 #include <linux/poll.h>
 #include <linux/capability.h>
 #include <linux/ctype.h>       /* isspace() */
index 940225866da09a6133af23d0c776928a37daf7dd..32061442cc8e935bb18785b66db75411874dd5f2 100644 (file)
 /***************************** INCLUDES *****************************/
 
 #include "irnet.h"             /* Module global include */
+#include <linux/miscdevice.h>
 
 /************************ CONSTANTS & MACROS ************************/
 
-/* /dev/irnet file constants */
-#define IRNET_MAJOR    10      /* Misc range */
-#define IRNET_MINOR    187     /* Official allocation */
-
 /* IrNET control channel stuff */
 #define IRNET_MAX_COMMAND      256     /* Max length of a command line */
 
@@ -111,9 +108,9 @@ static const struct file_operations irnet_device_fops =
 /* Structure so that the misc major (drivers/char/misc.c) take care of us... */
 static struct miscdevice irnet_misc_device =
 {
-       IRNET_MINOR,
-       "irnet",
-       &irnet_device_fops
+       .minor = IRNET_MINOR,
+       .name = "irnet",
+       .fops = &irnet_device_fops
 };
 
 #endif /* IRNET_PPP_H */
index b9ac598e2116345a7b05365c74adf95bbe5abd35..77cfdde9d82ff67585c436e28d2f9cbb538621e7 100644 (file)
@@ -23,7 +23,6 @@
  *
  ********************************************************************/
 
-#include <linux/miscdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/module.h>
index edd6f2945f694f1fc6103caad0b04856a9cd5875..a98fc2b5e0dc94664a19ba319099385276212c44 100644 (file)
@@ -265,7 +265,8 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
        if (uni) {
                rcu_assign_pointer(sdata->default_unicast_key, key);
                ieee80211_check_fast_xmit_iface(sdata);
-               drv_set_default_unicast_key(sdata->local, sdata, idx);
+               if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+                       drv_set_default_unicast_key(sdata->local, sdata, idx);
        }
 
        if (multi)
index eeab7250f4b978bd2af2b320ae8f430ab00cc81d..3e289a64ed4317a8a495cb7cac8197fb9ce10c3e 100644 (file)
@@ -2472,7 +2472,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        if (!ifmsh->mshcfg.dot11MeshForwarding)
                goto out;
 
-       fwd_skb = skb_copy(skb, GFP_ATOMIC);
+       fwd_skb = skb_copy_expand(skb, local->tx_headroom, 0, GFP_ATOMIC);
        if (!fwd_skb) {
                net_info_ratelimited("%s: failed to clone mesh frame\n",
                                    sdata->name);
index 1711bae4abf2f16f49f80747ae2c9f75a2fea38b..b6cfcf038c11fa529e00da2eed70f6ff48426a37 100644 (file)
@@ -1972,6 +1972,7 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
                u16 brate;
                unsigned int shift;
 
+               rinfo->flags = 0;
                sband = local->hw.wiphy->bands[(rate >> 4) & 0xf];
                brate = sband->bitrates[rate & 0xf].bitrate;
                if (rinfo->bw == RATE_INFO_BW_5)
@@ -1987,14 +1988,15 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
                rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
 }
 
-static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
+static int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
 {
        u16 rate = ACCESS_ONCE(sta_get_last_rx_stats(sta)->last_rate);
 
        if (rate == STA_STATS_RATE_INVALID)
-               rinfo->flags = 0;
-       else
-               sta_stats_decode_rate(sta->local, rate, rinfo);
+               return -EINVAL;
+
+       sta_stats_decode_rate(sta->local, rate, rinfo);
+       return 0;
 }
 
 static void sta_set_tidstats(struct sta_info *sta,
@@ -2199,8 +2201,8 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        }
 
        if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE))) {
-               sta_set_rate_info_rx(sta, &sinfo->rxrate);
-               sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
+               if (sta_set_rate_info_rx(sta, &sinfo->rxrate) == 0)
+                       sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
        }
 
        sinfo->filled |= BIT(NL80211_STA_INFO_TID_STATS);
index e040c5140f61f88257137651b0e547543253d8d8..35ac28d0720cb89310cea548bed003957bb10a46 100644 (file)
@@ -252,7 +252,7 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
        offload.cookie = (unsigned long)f;
        offload.dissector = dissector;
        offload.mask = mask;
-       offload.key = &f->key;
+       offload.key = &f->mkey;
        offload.exts = &f->exts;
 
        tc->type = TC_SETUP_CLSFLOWER;
@@ -509,6 +509,7 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
 
        if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
                key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+               mask->control.addr_type = ~0;
                fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
                               &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
                               sizeof(key->ipv4.src));
@@ -517,6 +518,7 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
                               sizeof(key->ipv4.dst));
        } else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
                key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+               mask->control.addr_type = ~0;
                fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
                               &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
                               sizeof(key->ipv6.src));
@@ -571,6 +573,7 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
        if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
            tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
                key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+               mask->enc_control.addr_type = ~0;
                fl_set_key_val(tb, &key->enc_ipv4.src,
                               TCA_FLOWER_KEY_ENC_IPV4_SRC,
                               &mask->enc_ipv4.src,
@@ -586,6 +589,7 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
        if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
            tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
                key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+               mask->enc_control.addr_type = ~0;
                fl_set_key_val(tb, &key->enc_ipv6.src,
                               TCA_FLOWER_KEY_ENC_IPV6_SRC,
                               &mask->enc_ipv6.src,
index 1f03065686fee7ff433855bf9216736c6157fa60..410ddc1e344389cae97cb86327309516b0487c96 100644 (file)
@@ -331,7 +331,9 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
         * on this endpoint.
         */
        if (!ep->base.bind_addr.port)
-               goto out;
+               return NULL;
+
+       rcu_read_lock();
        t = sctp_epaddr_lookup_transport(ep, paddr);
        if (!t)
                goto out;
@@ -339,6 +341,7 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
        *transport = t;
        asoc = t->asoc;
 out:
+       rcu_read_unlock();
        return asoc;
 }
 
index d5f4b4a8369bc64d8501be37d153e99dead88af5..318c6786d6539a301ac7b76d82a49a1af3818d10 100644 (file)
@@ -4472,18 +4472,17 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
                                  const union sctp_addr *paddr, void *p)
 {
        struct sctp_transport *transport;
-       int err = -ENOENT;
+       int err;
 
        rcu_read_lock();
        transport = sctp_addrs_lookup_transport(net, laddr, paddr);
+       rcu_read_unlock();
        if (!transport)
-               goto out;
+               return -ENOENT;
 
-       rcu_read_unlock();
        err = cb(transport, p);
        sctp_transport_put(transport);
 
-out:
        return err;
 }
 EXPORT_SYMBOL_GPL(sctp_transport_lookup_process);
index fd8cf0214d514f777736fade0a707a509e8829ec..1406db4d97d14fe2d204f9b93ecfbdb53ec3e34f 100644 (file)
@@ -662,19 +662,19 @@ static void vmci_transport_notify_pkt_process_negotiate(struct sock *sk)
 
 /* Socket control packet based operations. */
 const struct vmci_transport_notify_ops vmci_transport_notify_pkt_ops = {
-       vmci_transport_notify_pkt_socket_init,
-       vmci_transport_notify_pkt_socket_destruct,
-       vmci_transport_notify_pkt_poll_in,
-       vmci_transport_notify_pkt_poll_out,
-       vmci_transport_notify_pkt_handle_pkt,
-       vmci_transport_notify_pkt_recv_init,
-       vmci_transport_notify_pkt_recv_pre_block,
-       vmci_transport_notify_pkt_recv_pre_dequeue,
-       vmci_transport_notify_pkt_recv_post_dequeue,
-       vmci_transport_notify_pkt_send_init,
-       vmci_transport_notify_pkt_send_pre_block,
-       vmci_transport_notify_pkt_send_pre_enqueue,
-       vmci_transport_notify_pkt_send_post_enqueue,
-       vmci_transport_notify_pkt_process_request,
-       vmci_transport_notify_pkt_process_negotiate,
+       .socket_init = vmci_transport_notify_pkt_socket_init,
+       .socket_destruct = vmci_transport_notify_pkt_socket_destruct,
+       .poll_in = vmci_transport_notify_pkt_poll_in,
+       .poll_out = vmci_transport_notify_pkt_poll_out,
+       .handle_notify_pkt = vmci_transport_notify_pkt_handle_pkt,
+       .recv_init = vmci_transport_notify_pkt_recv_init,
+       .recv_pre_block = vmci_transport_notify_pkt_recv_pre_block,
+       .recv_pre_dequeue = vmci_transport_notify_pkt_recv_pre_dequeue,
+       .recv_post_dequeue = vmci_transport_notify_pkt_recv_post_dequeue,
+       .send_init = vmci_transport_notify_pkt_send_init,
+       .send_pre_block = vmci_transport_notify_pkt_send_pre_block,
+       .send_pre_enqueue = vmci_transport_notify_pkt_send_pre_enqueue,
+       .send_post_enqueue = vmci_transport_notify_pkt_send_post_enqueue,
+       .process_request = vmci_transport_notify_pkt_process_request,
+       .process_negotiate = vmci_transport_notify_pkt_process_negotiate,
 };
index 21e591dafb031c728e3f3c8bc624750b54e94f94..f3a0afc46208137a84227cc60d1d8fe9da8d7ec0 100644 (file)
@@ -420,19 +420,19 @@ vmci_transport_notify_pkt_send_pre_enqueue(
 
 /* Socket always on control packet based operations. */
 const struct vmci_transport_notify_ops vmci_transport_notify_pkt_q_state_ops = {
-       vmci_transport_notify_pkt_socket_init,
-       vmci_transport_notify_pkt_socket_destruct,
-       vmci_transport_notify_pkt_poll_in,
-       vmci_transport_notify_pkt_poll_out,
-       vmci_transport_notify_pkt_handle_pkt,
-       vmci_transport_notify_pkt_recv_init,
-       vmci_transport_notify_pkt_recv_pre_block,
-       vmci_transport_notify_pkt_recv_pre_dequeue,
-       vmci_transport_notify_pkt_recv_post_dequeue,
-       vmci_transport_notify_pkt_send_init,
-       vmci_transport_notify_pkt_send_pre_block,
-       vmci_transport_notify_pkt_send_pre_enqueue,
-       vmci_transport_notify_pkt_send_post_enqueue,
-       vmci_transport_notify_pkt_process_request,
-       vmci_transport_notify_pkt_process_negotiate,
+       .socket_init = vmci_transport_notify_pkt_socket_init,
+       .socket_destruct = vmci_transport_notify_pkt_socket_destruct,
+       .poll_in = vmci_transport_notify_pkt_poll_in,
+       .poll_out = vmci_transport_notify_pkt_poll_out,
+       .handle_notify_pkt = vmci_transport_notify_pkt_handle_pkt,
+       .recv_init = vmci_transport_notify_pkt_recv_init,
+       .recv_pre_block = vmci_transport_notify_pkt_recv_pre_block,
+       .recv_pre_dequeue = vmci_transport_notify_pkt_recv_pre_dequeue,
+       .recv_post_dequeue = vmci_transport_notify_pkt_recv_post_dequeue,
+       .send_init = vmci_transport_notify_pkt_send_init,
+       .send_pre_block = vmci_transport_notify_pkt_send_pre_block,
+       .send_pre_enqueue = vmci_transport_notify_pkt_send_pre_enqueue,
+       .send_post_enqueue = vmci_transport_notify_pkt_send_post_enqueue,
+       .process_request = vmci_transport_notify_pkt_process_request,
+       .process_negotiate = vmci_transport_notify_pkt_process_negotiate,
 };
index 43239527a2058007242bd32ae4bf1891f6622252..a06dfe143c675039b57cdc5a83164228730d3e5e 100644 (file)
@@ -70,7 +70,7 @@ static struct ctl_table x25_table[] = {
                .mode =         0644,
                .proc_handler = proc_dointvec,
        },
-       { 0, },
+       { },
 };
 
 void __init x25_register_sysctl(void)
index f2219c1489e5aa0f77b40929796dca8ff2794fe5..13315ff1193c1c9a7ea4ce675f9c19c8ea08cef0 100644 (file)
@@ -141,10 +141,10 @@ CLANG ?= clang
 
 # Trick to allow make to be run from this directory
 all:
-       $(MAKE) -C ../../ $$PWD/
+       $(MAKE) -C ../../ $(CURDIR)/
 
 clean:
-       $(MAKE) -C ../../ M=$$PWD clean
+       $(MAKE) -C ../../ M=$(CURDIR) clean
        @rm -f *~
 
 # Verify LLVM compiler tools are available and bpf target is supported by llc
index 04b9622b6f515082a15f021a41e71b9223e14bae..91762d946a53eb08d301be0448f80fcdadafe999 100644 (file)
@@ -13,4 +13,4 @@ HOSTCFLAGS_ucon.o += -I$(objtree)/usr/include
 all: modules
 
 modules clean:
-       $(MAKE) -C ../.. SUBDIRS=$(PWD) $@
+       $(MAKE) -C ../.. SUBDIRS=$(CURDIR) $@
index 7675d11ee65e6d41e353debcd2fc51abff9a5dfa..eadcd4d359d91fc7823a75263c44c520e05f900b 100644 (file)
@@ -488,9 +488,9 @@ endif
 
 quiet_cmd_export_list = EXPORTS $@
 cmd_export_list = $(OBJDUMP) -h $< | \
-       sed -ne '/___ksymtab/{s/.*+/$(ref_prefix)/;s/ .*/)/;p}' >$(ksyms-lds);\
+       sed -ne '/___ksymtab/s/.*+\([^ ]*\).*/$(ref_prefix)\1)/p' >$(ksyms-lds);\
        rm -f $(dummy-object);\
-       $(AR) rcs$(KBUILD_ARFLAGS) $(dummy-object);\
+       echo | $(CC) $(a_flags) -c -o $(dummy-object) -x assembler -;\
        $(LD) $(ld_flags) -r -o $@ -T $(ksyms-lds) $(dummy-object);\
        rm $(dummy-object) $(ksyms-lds)
 
@@ -517,11 +517,18 @@ $($(subst $(obj)/,,$(@:.o=-objs)))    \
 $($(subst $(obj)/,,$(@:.o=-y)))       \
 $($(subst $(obj)/,,$(@:.o=-m)))), $^)
 
-quiet_cmd_link_multi-y = LD      $@
-cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
+cmd_link_multi-link = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
+
+ifdef CONFIG_THIN_ARCHIVES
+  quiet_cmd_link_multi-y = AR      $@
+  cmd_link_multi-y = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) $@ $(link_multi_deps)
+else
+  quiet_cmd_link_multi-y = LD      $@
+  cmd_link_multi-y = $(cmd_link_multi-link)
+endif
 
 quiet_cmd_link_multi-m = LD [M]  $@
-cmd_link_multi-m = $(cmd_link_multi-y)
+cmd_link_multi-m = $(cmd_link_multi-link)
 
 $(multi-used-y): FORCE
        $(call if_changed,link_multi-y)
index 8dc1918b6783dd337590f97b5aa33be5125980ea..513da1a4a2daaf7ed329b816c49d787916e72e3b 100755 (executable)
@@ -59,6 +59,7 @@ cat > "$new_ksyms_file" << EOT
  */
 
 EOT
+[ "$(ls -A "$MODVERDIR")" ] &&
 sed -ns -e '3{s/ /\n/g;/^$/!p;}' "$MODVERDIR"/*.mod | sort -u |
 while read sym; do
        if [ -n "$CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX" ]; then
diff --git a/scripts/coccinelle/misc/boolconv.cocci b/scripts/coccinelle/misc/boolconv.cocci
new file mode 100644 (file)
index 0000000..33c464d
--- /dev/null
@@ -0,0 +1,90 @@
+/// Remove unneeded conversion to bool
+///
+//# Relational and logical operators evaluate to bool,
+//# explicit conversion is overly verbose and unneeded.
+//
+// Copyright: (C) 2016 Andrew F. Davis <afd@ti.com> GPLv2.
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+//----------------------------------------------------------
+//  For patch mode
+//----------------------------------------------------------
+
+@depends on patch@
+expression A, B;
+symbol true, false;
+@@
+
+(
+  A == B
+|
+  A != B
+|
+  A > B
+|
+  A < B
+|
+  A >= B
+|
+  A <= B
+|
+  A && B
+|
+  A || B
+)
+- ? true : false
+
+//----------------------------------------------------------
+//  For context mode
+//----------------------------------------------------------
+
+@r depends on !patch@
+expression A, B;
+symbol true, false;
+position p;
+@@
+
+(
+  A == B
+|
+  A != B
+|
+  A > B
+|
+  A < B
+|
+  A >= B
+|
+  A <= B
+|
+  A && B
+|
+  A || B
+)
+* ? true : false@p
+
+//----------------------------------------------------------
+//  For org mode
+//----------------------------------------------------------
+
+@script:python depends on r&&org@
+p << r.p;
+@@
+
+msg = "WARNING: conversion to bool not needed here"
+coccilib.org.print_todo(p[0], msg)
+
+//----------------------------------------------------------
+//  For report mode
+//----------------------------------------------------------
+
+@script:python depends on r&&report@
+p << r.p;
+@@
+
+msg = "WARNING: conversion to bool not needed here"
+coccilib.report.print_report(p[0], msg)
index b421150a2effcd925e83758bbf609d038e67ac1b..f698d6d0f5d7b06c765eda7a9d8e0ae4d594a678 100644 (file)
@@ -5,7 +5,7 @@
 /// So pass the IRQF_ONESHOT flag in this case.
 ///
 //
-// Confidence: Good
+// Confidence: Moderate
 // Comments:
 // Options: --no-includes
 
@@ -15,16 +15,13 @@ virtual org
 virtual report
 
 @r1@
-expression dev;
-expression irq;
-expression thread_fn;
-expression flags;
+expression dev, irq, thread_fn;
 position p;
 @@
 (
 request_threaded_irq@p(irq, NULL, thread_fn,
 (
-flags | IRQF_ONESHOT
+IRQF_ONESHOT | ...
 |
 IRQF_ONESHOT
 )
@@ -32,21 +29,34 @@ IRQF_ONESHOT
 |
 devm_request_threaded_irq@p(dev, irq, NULL, thread_fn,
 (
-flags | IRQF_ONESHOT
+IRQF_ONESHOT | ...
 |
 IRQF_ONESHOT
 )
 , ...)
 )
 
-@depends on patch@
-expression dev;
-expression irq;
-expression thread_fn;
-expression flags;
+@r2@
+expression dev, irq, thread_fn, flags, e;
 position p != r1.p;
 @@
 (
+flags = IRQF_ONESHOT | ...
+|
+flags |= IRQF_ONESHOT | ...
+)
+... when != flags = e
+(
+request_threaded_irq@p(irq, NULL, thread_fn, flags, ...);
+|
+devm_request_threaded_irq@p(dev, irq, NULL, thread_fn, flags, ...);
+)
+
+@depends on patch@
+expression dev, irq, thread_fn, flags;
+position p != {r1.p,r2.p};
+@@
+(
 request_threaded_irq@p(irq, NULL, thread_fn,
 (
 -0
@@ -69,15 +79,25 @@ devm_request_threaded_irq@p(dev, irq, NULL, thread_fn,
 )
 
 @depends on context@
-position p != r1.p;
+expression dev, irq;
+position p != {r1.p,r2.p};
 @@
-*request_threaded_irq@p(...)
+(
+*request_threaded_irq@p(irq, NULL, ...)
+|
+*devm_request_threaded_irq@p(dev, irq, NULL, ...)
+)
+
 
 @match depends on report || org@
-expression irq;
-position p != r1.p;
+expression dev, irq;
+position p != {r1.p,r2.p};
 @@
+(
 request_threaded_irq@p(irq, NULL, ...)
+|
+devm_request_threaded_irq@p(dev, irq, NULL, ...)
+)
 
 @script:python depends on org@
 p << match.p;
index a9096d9931721e9e6999e9a31a17b05e32749d4c..bd4c4b235588a61b27623cc2d7f00a693effd6e2 100644 (file)
@@ -27,6 +27,7 @@ __typeof, TYPEOF_KEYW
 __typeof__, TYPEOF_KEYW
 __volatile, VOLATILE_KEYW
 __volatile__, VOLATILE_KEYW
+__builtin_va_list, VA_LIST_KEYW
 # According to rth, c99 defines _Bool, __restrict, __restrict__, restrict.  KAO
 _Bool, BOOL_KEYW
 _restrict, RESTRICT_KEYW
index e9452482e198c786074e4572b24cb68e85c7975f..738018ba73757d1b8f9f8b5fdd56a453bc8864ef 100644 (file)
@@ -57,7 +57,7 @@ is_reserved_hash (register const char *str, register unsigned int len)
       101, 101, 101, 101, 101, 101, 101, 101, 101,   0,
       101, 101, 101, 101, 101, 101,  15, 101, 101, 101,
         0, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101,   0, 101,   0, 101,   5,
+      101, 101, 101, 101, 101,   0, 101,   0,   0,   5,
        25,  20,  55,  30, 101,  15, 101, 101,  10,   0,
        10,  40,  10, 101,  10,   5,   0,  10,  15, 101,
       101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
@@ -89,7 +89,7 @@ is_reserved_word (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 46,
+      TOTAL_KEYWORDS = 47,
       MIN_WORD_LENGTH = 3,
       MAX_WORD_LENGTH = 24,
       MIN_HASH_VALUE = 3,
@@ -99,7 +99,7 @@ is_reserved_word (register const char *str, register unsigned int len)
   static const struct resword wordlist[] =
     {
       {""}, {""}, {""},
-#line 35 "scripts/genksyms/keywords.gperf"
+#line 36 "scripts/genksyms/keywords.gperf"
       {"asm", ASM_KEYW},
       {""},
 #line 15 "scripts/genksyms/keywords.gperf"
@@ -119,20 +119,21 @@ is_reserved_word (register const char *str, register unsigned int len)
       {"__const__", CONST_KEYW},
 #line 25 "scripts/genksyms/keywords.gperf"
       {"__signed__", SIGNED_KEYW},
-#line 53 "scripts/genksyms/keywords.gperf"
+#line 54 "scripts/genksyms/keywords.gperf"
       {"static", STATIC_KEYW},
-      {""},
-#line 48 "scripts/genksyms/keywords.gperf"
+#line 30 "scripts/genksyms/keywords.gperf"
+      {"__builtin_va_list", VA_LIST_KEYW},
+#line 49 "scripts/genksyms/keywords.gperf"
       {"int", INT_KEYW},
-#line 41 "scripts/genksyms/keywords.gperf"
-      {"char", CHAR_KEYW},
 #line 42 "scripts/genksyms/keywords.gperf"
+      {"char", CHAR_KEYW},
+#line 43 "scripts/genksyms/keywords.gperf"
       {"const", CONST_KEYW},
-#line 54 "scripts/genksyms/keywords.gperf"
+#line 55 "scripts/genksyms/keywords.gperf"
       {"struct", STRUCT_KEYW},
-#line 33 "scripts/genksyms/keywords.gperf"
-      {"__restrict__", RESTRICT_KEYW},
 #line 34 "scripts/genksyms/keywords.gperf"
+      {"__restrict__", RESTRICT_KEYW},
+#line 35 "scripts/genksyms/keywords.gperf"
       {"restrict", RESTRICT_KEYW},
 #line 12 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
@@ -143,7 +144,7 @@ is_reserved_word (register const char *str, register unsigned int len)
       {"__volatile__", VOLATILE_KEYW},
 #line 10 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
-#line 32 "scripts/genksyms/keywords.gperf"
+#line 33 "scripts/genksyms/keywords.gperf"
       {"_restrict", RESTRICT_KEYW},
       {""},
 #line 17 "scripts/genksyms/keywords.gperf"
@@ -152,64 +153,64 @@ is_reserved_word (register const char *str, register unsigned int len)
       {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
 #line 21 "scripts/genksyms/keywords.gperf"
       {"__extension__", EXTENSION_KEYW},
-#line 44 "scripts/genksyms/keywords.gperf"
+#line 45 "scripts/genksyms/keywords.gperf"
       {"enum", ENUM_KEYW},
 #line 13 "scripts/genksyms/keywords.gperf"
       {"EXPORT_UNUSED_SYMBOL", EXPORT_SYMBOL_KEYW},
-#line 45 "scripts/genksyms/keywords.gperf"
+#line 46 "scripts/genksyms/keywords.gperf"
       {"extern", EXTERN_KEYW},
       {""},
 #line 24 "scripts/genksyms/keywords.gperf"
       {"__signed", SIGNED_KEYW},
 #line 14 "scripts/genksyms/keywords.gperf"
       {"EXPORT_UNUSED_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
-#line 57 "scripts/genksyms/keywords.gperf"
+#line 58 "scripts/genksyms/keywords.gperf"
       {"union", UNION_KEYW},
       {""}, {""},
 #line 22 "scripts/genksyms/keywords.gperf"
       {"__inline", INLINE_KEYW},
-#line 40 "scripts/genksyms/keywords.gperf"
+#line 41 "scripts/genksyms/keywords.gperf"
       {"auto", AUTO_KEYW},
 #line 28 "scripts/genksyms/keywords.gperf"
       {"__volatile", VOLATILE_KEYW},
       {""}, {""},
-#line 58 "scripts/genksyms/keywords.gperf"
+#line 59 "scripts/genksyms/keywords.gperf"
       {"unsigned", UNSIGNED_KEYW},
       {""},
-#line 51 "scripts/genksyms/keywords.gperf"
+#line 52 "scripts/genksyms/keywords.gperf"
       {"short", SHORT_KEYW},
-#line 47 "scripts/genksyms/keywords.gperf"
+#line 48 "scripts/genksyms/keywords.gperf"
       {"inline", INLINE_KEYW},
       {""},
-#line 60 "scripts/genksyms/keywords.gperf"
+#line 61 "scripts/genksyms/keywords.gperf"
       {"volatile", VOLATILE_KEYW},
-#line 49 "scripts/genksyms/keywords.gperf"
+#line 50 "scripts/genksyms/keywords.gperf"
       {"long", LONG_KEYW},
-#line 31 "scripts/genksyms/keywords.gperf"
+#line 32 "scripts/genksyms/keywords.gperf"
       {"_Bool", BOOL_KEYW},
       {""}, {""},
-#line 50 "scripts/genksyms/keywords.gperf"
+#line 51 "scripts/genksyms/keywords.gperf"
       {"register", REGISTER_KEYW},
-#line 59 "scripts/genksyms/keywords.gperf"
+#line 60 "scripts/genksyms/keywords.gperf"
       {"void", VOID_KEYW},
       {""},
-#line 43 "scripts/genksyms/keywords.gperf"
+#line 44 "scripts/genksyms/keywords.gperf"
       {"double", DOUBLE_KEYW},
       {""},
 #line 26 "scripts/genksyms/keywords.gperf"
       {"__typeof", TYPEOF_KEYW},
       {""}, {""},
-#line 52 "scripts/genksyms/keywords.gperf"
+#line 53 "scripts/genksyms/keywords.gperf"
       {"signed", SIGNED_KEYW},
       {""}, {""}, {""}, {""},
-#line 56 "scripts/genksyms/keywords.gperf"
+#line 57 "scripts/genksyms/keywords.gperf"
       {"typeof", TYPEOF_KEYW},
-#line 55 "scripts/genksyms/keywords.gperf"
+#line 56 "scripts/genksyms/keywords.gperf"
       {"typedef", TYPEDEF_KEYW},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 46 "scripts/genksyms/keywords.gperf"
+#line 47 "scripts/genksyms/keywords.gperf"
       {"float", FLOAT_KEYW}
     };
 
index 99950b5afb0dd68e80ae00136a37545282be48e0..69148d30ca3f8737142409ed16608220ccc46e44 100644 (file)
@@ -172,22 +172,23 @@ extern int yydebug;
      VOID_KEYW = 281,
      VOLATILE_KEYW = 282,
      TYPEOF_KEYW = 283,
-     EXPORT_SYMBOL_KEYW = 284,
-     ASM_PHRASE = 285,
-     ATTRIBUTE_PHRASE = 286,
-     TYPEOF_PHRASE = 287,
-     BRACE_PHRASE = 288,
-     BRACKET_PHRASE = 289,
-     EXPRESSION_PHRASE = 290,
-     CHAR = 291,
-     DOTS = 292,
-     IDENT = 293,
-     INT = 294,
-     REAL = 295,
-     STRING = 296,
-     TYPE = 297,
-     OTHER = 298,
-     FILENAME = 299
+     VA_LIST_KEYW = 284,
+     EXPORT_SYMBOL_KEYW = 285,
+     ASM_PHRASE = 286,
+     ATTRIBUTE_PHRASE = 287,
+     TYPEOF_PHRASE = 288,
+     BRACE_PHRASE = 289,
+     BRACKET_PHRASE = 290,
+     EXPRESSION_PHRASE = 291,
+     CHAR = 292,
+     DOTS = 293,
+     IDENT = 294,
+     INT = 295,
+     REAL = 296,
+     STRING = 297,
+     TYPE = 298,
+     OTHER = 299,
+     FILENAME = 300
    };
 #endif
 
@@ -439,20 +440,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  4
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   515
+#define YYLAST   524
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  54
+#define YYNTOKENS  55
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  49
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  133
+#define YYNRULES  134
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  188
+#define YYNSTATES  189
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   299
+#define YYMAXUTOK   300
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -464,15 +465,15 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      48,    49,    50,     2,    47,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    53,    45,
-       2,    51,     2,     2,     2,     2,     2,     2,     2,     2,
+      49,    50,    51,     2,    48,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    54,    46,
+       2,    52,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    52,     2,    46,     2,     2,     2,     2,
+       2,     2,     2,    53,     2,    47,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -489,7 +490,8 @@ static const yytype_uint8 yytranslate[] =
        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
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45
 };
 
 #if YYDEBUG
@@ -502,76 +504,76 @@ static const yytype_uint16 yyprhs[] =
       46,    50,    55,    56,    58,    60,    63,    65,    67,    69,
       71,    73,    75,    77,    79,    81,    86,    88,    91,    94,
       97,   101,   105,   109,   112,   115,   118,   120,   122,   124,
-     126,   128,   130,   132,   134,   136,   138,   140,   143,   144,
-     146,   148,   151,   153,   155,   157,   159,   162,   164,   166,
-     168,   173,   178,   181,   185,   189,   192,   194,   196,   198,
-     203,   208,   211,   215,   219,   222,   224,   228,   229,   231,
-     233,   237,   240,   243,   245,   246,   248,   250,   255,   260,
-     263,   267,   271,   275,   276,   278,   281,   285,   289,   290,
-     292,   294,   297,   301,   304,   305,   307,   309,   313,   316,
-     319,   321,   324,   325,   328,   332,   337,   339,   343,   345,
-     349,   352,   353,   355
+     126,   128,   130,   132,   134,   136,   138,   140,   142,   145,
+     146,   148,   150,   153,   155,   157,   159,   161,   164,   166,
+     168,   170,   175,   180,   183,   187,   191,   194,   196,   198,
+     200,   205,   210,   213,   217,   221,   224,   226,   230,   231,
+     233,   235,   239,   242,   245,   247,   248,   250,   252,   257,
+     262,   265,   269,   273,   277,   278,   280,   283,   287,   291,
+     292,   294,   296,   299,   303,   306,   307,   309,   311,   315,
+     318,   321,   323,   326,   327,   330,   334,   339,   341,   345,
+     347,   351,   354,   355,   357
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      55,     0,    -1,    56,    -1,    55,    56,    -1,    -1,    57,
-      58,    -1,    -1,    12,    23,    59,    61,    -1,    -1,    23,
-      60,    61,    -1,    61,    -1,    85,    -1,   100,    -1,   102,
-      -1,     1,    45,    -1,     1,    46,    -1,    65,    62,    45,
-      -1,    -1,    63,    -1,    64,    -1,    63,    47,    64,    -1,
-      75,   101,    96,    86,    -1,    -1,    66,    -1,    67,    -1,
-      66,    67,    -1,    68,    -1,    69,    -1,     5,    -1,    17,
-      -1,    21,    -1,    11,    -1,    14,    -1,    70,    -1,    74,
-      -1,    28,    48,    82,    49,    -1,    32,    -1,    22,    38,
-      -1,    24,    38,    -1,    10,    38,    -1,    22,    38,    88,
-      -1,    24,    38,    88,    -1,    10,    38,    97,    -1,    10,
-      97,    -1,    22,    88,    -1,    24,    88,    -1,     7,    -1,
+      56,     0,    -1,    57,    -1,    56,    57,    -1,    -1,    58,
+      59,    -1,    -1,    12,    23,    60,    62,    -1,    -1,    23,
+      61,    62,    -1,    62,    -1,    86,    -1,   101,    -1,   103,
+      -1,     1,    46,    -1,     1,    47,    -1,    66,    63,    46,
+      -1,    -1,    64,    -1,    65,    -1,    64,    48,    65,    -1,
+      76,   102,    97,    87,    -1,    -1,    67,    -1,    68,    -1,
+      67,    68,    -1,    69,    -1,    70,    -1,     5,    -1,    17,
+      -1,    21,    -1,    11,    -1,    14,    -1,    71,    -1,    75,
+      -1,    28,    49,    83,    50,    -1,    33,    -1,    22,    39,
+      -1,    24,    39,    -1,    10,    39,    -1,    22,    39,    89,
+      -1,    24,    39,    89,    -1,    10,    39,    98,    -1,    10,
+      98,    -1,    22,    89,    -1,    24,    89,    -1,     7,    -1,
       19,    -1,    15,    -1,    16,    -1,    20,    -1,    25,    -1,
-      13,    -1,     9,    -1,    26,    -1,     6,    -1,    42,    -1,
-      50,    72,    -1,    -1,    73,    -1,    74,    -1,    73,    74,
-      -1,     8,    -1,    27,    -1,    31,    -1,    18,    -1,    71,
-      75,    -1,    76,    -1,    38,    -1,    42,    -1,    76,    48,
-      79,    49,    -1,    76,    48,     1,    49,    -1,    76,    34,
-      -1,    48,    75,    49,    -1,    48,     1,    49,    -1,    71,
-      77,    -1,    78,    -1,    38,    -1,    42,    -1,    78,    48,
-      79,    49,    -1,    78,    48,     1,    49,    -1,    78,    34,
-      -1,    48,    77,    49,    -1,    48,     1,    49,    -1,    80,
-      37,    -1,    80,    -1,    81,    47,    37,    -1,    -1,    81,
-      -1,    82,    -1,    81,    47,    82,    -1,    66,    83,    -1,
-      71,    83,    -1,    84,    -1,    -1,    38,    -1,    42,    -1,
-      84,    48,    79,    49,    -1,    84,    48,     1,    49,    -1,
-      84,    34,    -1,    48,    83,    49,    -1,    48,     1,    49,
-      -1,    65,    75,    33,    -1,    -1,    87,    -1,    51,    35,
-      -1,    52,    89,    46,    -1,    52,     1,    46,    -1,    -1,
-      90,    -1,    91,    -1,    90,    91,    -1,    65,    92,    45,
-      -1,     1,    45,    -1,    -1,    93,    -1,    94,    -1,    93,
-      47,    94,    -1,    77,    96,    -1,    38,    95,    -1,    95,
-      -1,    53,    35,    -1,    -1,    96,    31,    -1,    52,    98,
-      46,    -1,    52,    98,    47,    46,    -1,    99,    -1,    98,
-      47,    99,    -1,    38,    -1,    38,    51,    35,    -1,    30,
-      45,    -1,    -1,    30,    -1,    29,    48,    38,    49,    45,
-      -1
+      13,    -1,     9,    -1,    26,    -1,     6,    -1,    29,    -1,
+      43,    -1,    51,    73,    -1,    -1,    74,    -1,    75,    -1,
+      74,    75,    -1,     8,    -1,    27,    -1,    32,    -1,    18,
+      -1,    72,    76,    -1,    77,    -1,    39,    -1,    43,    -1,
+      77,    49,    80,    50,    -1,    77,    49,     1,    50,    -1,
+      77,    35,    -1,    49,    76,    50,    -1,    49,     1,    50,
+      -1,    72,    78,    -1,    79,    -1,    39,    -1,    43,    -1,
+      79,    49,    80,    50,    -1,    79,    49,     1,    50,    -1,
+      79,    35,    -1,    49,    78,    50,    -1,    49,     1,    50,
+      -1,    81,    38,    -1,    81,    -1,    82,    48,    38,    -1,
+      -1,    82,    -1,    83,    -1,    82,    48,    83,    -1,    67,
+      84,    -1,    72,    84,    -1,    85,    -1,    -1,    39,    -1,
+      43,    -1,    85,    49,    80,    50,    -1,    85,    49,     1,
+      50,    -1,    85,    35,    -1,    49,    84,    50,    -1,    49,
+       1,    50,    -1,    66,    76,    34,    -1,    -1,    88,    -1,
+      52,    36,    -1,    53,    90,    47,    -1,    53,     1,    47,
+      -1,    -1,    91,    -1,    92,    -1,    91,    92,    -1,    66,
+      93,    46,    -1,     1,    46,    -1,    -1,    94,    -1,    95,
+      -1,    94,    48,    95,    -1,    78,    97,    -1,    39,    96,
+      -1,    96,    -1,    54,    36,    -1,    -1,    97,    32,    -1,
+      53,    99,    47,    -1,    53,    99,    48,    47,    -1,   100,
+      -1,    99,    48,   100,    -1,    39,    -1,    39,    52,    36,
+      -1,    31,    46,    -1,    -1,    31,    -1,    30,    49,    39,
+      50,    46,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   124,   124,   125,   129,   129,   135,   135,   137,   137,
-     139,   140,   141,   142,   143,   144,   148,   162,   163,   167,
-     175,   188,   194,   195,   199,   200,   204,   210,   214,   215,
-     216,   217,   218,   222,   223,   224,   225,   229,   231,   233,
-     237,   239,   241,   246,   249,   250,   254,   255,   256,   257,
-     258,   259,   260,   261,   262,   263,   264,   268,   273,   274,
-     278,   279,   283,   283,   283,   284,   292,   293,   297,   306,
-     315,   317,   319,   321,   323,   330,   331,   335,   336,   337,
-     339,   341,   343,   345,   350,   351,   352,   356,   357,   361,
-     362,   367,   372,   374,   378,   379,   387,   391,   393,   395,
-     397,   399,   404,   413,   414,   419,   424,   425,   429,   430,
-     434,   435,   439,   441,   446,   447,   451,   452,   456,   457,
-     458,   462,   466,   467,   471,   472,   476,   477,   480,   485,
-     493,   497,   498,   502
+       0,   125,   125,   126,   130,   130,   136,   136,   138,   138,
+     140,   141,   142,   143,   144,   145,   149,   163,   164,   168,
+     176,   189,   195,   196,   200,   201,   205,   211,   215,   216,
+     217,   218,   219,   223,   224,   225,   226,   230,   232,   234,
+     238,   240,   242,   247,   250,   251,   255,   256,   257,   258,
+     259,   260,   261,   262,   263,   264,   265,   266,   270,   275,
+     276,   280,   281,   285,   285,   285,   286,   294,   295,   299,
+     308,   317,   319,   321,   323,   325,   332,   333,   337,   338,
+     339,   341,   343,   345,   347,   352,   353,   354,   358,   359,
+     363,   364,   369,   374,   376,   380,   381,   389,   393,   395,
+     397,   399,   401,   406,   415,   416,   421,   426,   427,   431,
+     432,   436,   437,   441,   443,   448,   449,   453,   454,   458,
+     459,   460,   464,   468,   469,   473,   474,   478,   479,   482,
+     487,   495,   499,   500,   504
 };
 #endif
 
@@ -586,12 +588,12 @@ static const char *const yytname[] =
   "INLINE_KEYW", "INT_KEYW", "LONG_KEYW", "REGISTER_KEYW", "RESTRICT_KEYW",
   "SHORT_KEYW", "SIGNED_KEYW", "STATIC_KEYW", "STRUCT_KEYW",
   "TYPEDEF_KEYW", "UNION_KEYW", "UNSIGNED_KEYW", "VOID_KEYW",
-  "VOLATILE_KEYW", "TYPEOF_KEYW", "EXPORT_SYMBOL_KEYW", "ASM_PHRASE",
-  "ATTRIBUTE_PHRASE", "TYPEOF_PHRASE", "BRACE_PHRASE", "BRACKET_PHRASE",
-  "EXPRESSION_PHRASE", "CHAR", "DOTS", "IDENT", "INT", "REAL", "STRING",
-  "TYPE", "OTHER", "FILENAME", "';'", "'}'", "','", "'('", "')'", "'*'",
-  "'='", "'{'", "':'", "$accept", "declaration_seq", "declaration", "$@1",
-  "declaration1", "$@2", "$@3", "simple_declaration",
+  "VOLATILE_KEYW", "TYPEOF_KEYW", "VA_LIST_KEYW", "EXPORT_SYMBOL_KEYW",
+  "ASM_PHRASE", "ATTRIBUTE_PHRASE", "TYPEOF_PHRASE", "BRACE_PHRASE",
+  "BRACKET_PHRASE", "EXPRESSION_PHRASE", "CHAR", "DOTS", "IDENT", "INT",
+  "REAL", "STRING", "TYPE", "OTHER", "FILENAME", "';'", "'}'", "','",
+  "'('", "')'", "'*'", "'='", "'{'", "':'", "$accept", "declaration_seq",
+  "declaration", "$@1", "declaration1", "$@2", "$@3", "simple_declaration",
   "init_declarator_list_opt", "init_declarator_list", "init_declarator",
   "decl_specifier_seq_opt", "decl_specifier_seq", "decl_specifier",
   "storage_class_specifier", "type_specifier", "simple_type_specifier",
@@ -619,28 +621,28 @@ static const yytype_uint16 yytoknum[] =
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
      285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
-     295,   296,   297,   298,   299,    59,   125,    44,    40,    41,
-      42,    61,   123,    58
+     295,   296,   297,   298,   299,   300,    59,   125,    44,    40,
+      41,    42,    61,   123,    58
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    54,    55,    55,    57,    56,    59,    58,    60,    58,
-      58,    58,    58,    58,    58,    58,    61,    62,    62,    63,
-      63,    64,    65,    65,    66,    66,    67,    67,    68,    68,
-      68,    68,    68,    69,    69,    69,    69,    69,    69,    69,
-      69,    69,    69,    69,    69,    69,    70,    70,    70,    70,
-      70,    70,    70,    70,    70,    70,    70,    71,    72,    72,
-      73,    73,    74,    74,    74,    74,    75,    75,    76,    76,
-      76,    76,    76,    76,    76,    77,    77,    78,    78,    78,
-      78,    78,    78,    78,    79,    79,    79,    80,    80,    81,
-      81,    82,    83,    83,    84,    84,    84,    84,    84,    84,
-      84,    84,    85,    86,    86,    87,    88,    88,    89,    89,
-      90,    90,    91,    91,    92,    92,    93,    93,    94,    94,
-      94,    95,    96,    96,    97,    97,    98,    98,    99,    99,
-     100,   101,   101,   102
+       0,    55,    56,    56,    58,    57,    60,    59,    61,    59,
+      59,    59,    59,    59,    59,    59,    62,    63,    63,    64,
+      64,    65,    66,    66,    67,    67,    68,    68,    69,    69,
+      69,    69,    69,    70,    70,    70,    70,    70,    70,    70,
+      70,    70,    70,    70,    70,    70,    71,    71,    71,    71,
+      71,    71,    71,    71,    71,    71,    71,    71,    72,    73,
+      73,    74,    74,    75,    75,    75,    75,    76,    76,    77,
+      77,    77,    77,    77,    77,    77,    78,    78,    79,    79,
+      79,    79,    79,    79,    79,    80,    80,    80,    81,    81,
+      82,    82,    83,    84,    84,    85,    85,    85,    85,    85,
+      85,    85,    85,    86,    87,    87,    88,    89,    89,    90,
+      90,    91,    91,    92,    92,    93,    93,    94,    94,    95,
+      95,    95,    96,    97,    97,    98,    98,    99,    99,   100,
+     100,   101,   102,   102,   103
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -651,15 +653,15 @@ static const yytype_uint8 yyr2[] =
        3,     4,     0,     1,     1,     2,     1,     1,     1,     1,
        1,     1,     1,     1,     1,     4,     1,     2,     2,     2,
        3,     3,     3,     2,     2,     2,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     1,     1,     2,     0,     1,
-       1,     2,     1,     1,     1,     1,     2,     1,     1,     1,
-       4,     4,     2,     3,     3,     2,     1,     1,     1,     4,
-       4,     2,     3,     3,     2,     1,     3,     0,     1,     1,
-       3,     2,     2,     1,     0,     1,     1,     4,     4,     2,
-       3,     3,     3,     0,     1,     2,     3,     3,     0,     1,
-       1,     2,     3,     2,     0,     1,     1,     3,     2,     2,
-       1,     2,     0,     2,     3,     4,     1,     3,     1,     3,
-       2,     0,     1,     5
+       1,     1,     1,     1,     1,     1,     1,     1,     2,     0,
+       1,     1,     2,     1,     1,     1,     1,     2,     1,     1,
+       1,     4,     4,     2,     3,     3,     2,     1,     1,     1,
+       4,     4,     2,     3,     3,     2,     1,     3,     0,     1,
+       1,     3,     2,     2,     1,     0,     1,     1,     4,     4,
+       2,     3,     3,     3,     0,     1,     2,     3,     3,     0,
+       1,     1,     2,     3,     2,     0,     1,     1,     3,     2,
+       2,     1,     2,     0,     2,     3,     4,     1,     3,     1,
+       3,     2,     0,     1,     5
 };
 
 /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
@@ -668,217 +670,219 @@ static const yytype_uint8 yyr2[] =
 static const yytype_uint8 yydefact[] =
 {
        4,     4,     2,     0,     1,     3,     0,    28,    55,    46,
-      62,    53,     0,    31,     0,    52,    32,    48,    49,    29,
-      65,    47,    50,    30,     0,     8,     0,    51,    54,    63,
-       0,     0,     0,    64,    36,    56,     5,    10,    17,    23,
-      24,    26,    27,    33,    34,    11,    12,    13,    14,    15,
-      39,     0,    43,     6,    37,     0,    44,    22,    38,    45,
-       0,     0,   130,    68,    69,     0,    58,     0,    18,    19,
-       0,   131,    67,    25,    42,   128,     0,   126,    22,    40,
-       0,   114,     0,     0,   110,     9,    17,    41,    94,     0,
-       0,     0,     0,    57,    59,    60,    16,     0,    66,   132,
-     102,   122,    72,     0,     0,   124,     0,     7,   113,   107,
-      77,    78,     0,     0,     0,   122,    76,     0,   115,   116,
-     120,   106,     0,   111,   131,    95,    56,     0,    94,    91,
-      93,    35,     0,    74,    73,    61,    20,   103,     0,     0,
-      85,    88,    89,   129,   125,   127,   119,     0,    77,     0,
-     121,    75,   118,    81,     0,   112,     0,     0,    96,     0,
-      92,    99,     0,   133,   123,     0,    21,   104,    71,    70,
-      84,     0,    83,    82,     0,     0,   117,   101,   100,     0,
-       0,   105,    86,    90,    80,    79,    98,    97
+      63,    53,     0,    31,     0,    52,    32,    48,    49,    29,
+      66,    47,    50,    30,     0,     8,     0,    51,    54,    64,
+       0,    56,     0,     0,    65,    36,    57,     5,    10,    17,
+      23,    24,    26,    27,    33,    34,    11,    12,    13,    14,
+      15,    39,     0,    43,     6,    37,     0,    44,    22,    38,
+      45,     0,     0,   131,    69,    70,     0,    59,     0,    18,
+      19,     0,   132,    68,    25,    42,   129,     0,   127,    22,
+      40,     0,   115,     0,     0,   111,     9,    17,    41,    95,
+       0,     0,     0,     0,    58,    60,    61,    16,     0,    67,
+     133,   103,   123,    73,     0,     0,   125,     0,     7,   114,
+     108,    78,    79,     0,     0,     0,   123,    77,     0,   116,
+     117,   121,   107,     0,   112,   132,    96,    57,     0,    95,
+      92,    94,    35,     0,    75,    74,    62,    20,   104,     0,
+       0,    86,    89,    90,   130,   126,   128,   120,     0,    78,
+       0,   122,    76,   119,    82,     0,   113,     0,     0,    97,
+       0,    93,   100,     0,   134,   124,     0,    21,   105,    72,
+      71,    85,     0,    84,    83,     0,     0,   118,   102,   101,
+       0,     0,   106,    87,    91,    81,    80,    99,    98
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,     2,     3,    36,    78,    57,    37,    67,    68,
-      69,    81,    39,    40,    41,    42,    43,    70,    93,    94,
-      44,   124,    72,   115,   116,   139,   140,   141,   142,   129,
-     130,    45,   166,   167,    56,    82,    83,    84,   117,   118,
-     119,   120,   137,    52,    76,    77,    46,   101,    47
+      -1,     1,     2,     3,    37,    79,    58,    38,    68,    69,
+      70,    82,    40,    41,    42,    43,    44,    71,    94,    95,
+      45,   125,    73,   116,   117,   140,   141,   142,   143,   130,
+     131,    46,   167,   168,    57,    83,    84,    85,   118,   119,
+     120,   121,   138,    53,    77,    78,    47,   102,    48
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -92
+#define YYPACT_NINF -111
 static const yytype_int16 yypact[] =
 {
-     -92,    19,   -92,   208,   -92,   -92,    39,   -92,   -92,   -92,
-     -92,   -92,   -27,   -92,    23,   -92,   -92,   -92,   -92,   -92,
-     -92,   -92,   -92,   -92,   -22,   -92,     9,   -92,   -92,   -92,
-      -6,    16,    25,   -92,   -92,   -92,   -92,   -92,    31,   473,
-     -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,
-      49,    37,   -92,   -92,    51,   108,   -92,   473,    51,   -92,
-     473,    59,   -92,   -92,   -92,    12,    -3,    60,    57,   -92,
-      31,    -7,    24,   -92,   -92,    55,    42,   -92,   473,   -92,
-      46,   -21,    61,   158,   -92,   -92,    31,   -92,   389,    71,
-      82,    88,    89,   -92,    -3,   -92,   -92,    31,   -92,   -92,
-     -92,   -92,   -92,   254,    73,   -92,   -24,   -92,   -92,   -92,
-      90,   -92,    17,    75,    45,   -92,    32,    96,    95,   -92,
-     -92,   -92,    99,   -92,   115,   -92,   -92,     3,    48,   -92,
-      34,   -92,   102,   -92,   -92,   -92,   -92,   -11,   100,   103,
-     111,   104,   -92,   -92,   -92,   -92,   -92,   106,   -92,   113,
-     -92,   -92,   126,   -92,   299,   -92,   -21,   121,   -92,   132,
-     -92,   -92,   344,   -92,   -92,   125,   -92,   -92,   -92,   -92,
-     -92,   435,   -92,   -92,   138,   139,   -92,   -92,   -92,   142,
-     143,   -92,   -92,   -92,   -92,   -92,   -92,   -92
+    -111,    13,  -111,   210,  -111,  -111,    28,  -111,  -111,  -111,
+    -111,  -111,   -27,  -111,    44,  -111,  -111,  -111,  -111,  -111,
+    -111,  -111,  -111,  -111,   -24,  -111,   -20,  -111,  -111,  -111,
+      31,  -111,    32,    42,  -111,  -111,  -111,  -111,  -111,    34,
+     481,  -111,  -111,  -111,  -111,  -111,  -111,  -111,  -111,  -111,
+    -111,    51,    56,  -111,  -111,    52,   108,  -111,   481,    52,
+    -111,   481,    58,  -111,  -111,  -111,    19,     0,    54,    55,
+    -111,    34,    30,   -18,  -111,  -111,    68,   -25,  -111,   481,
+    -111,    45,    33,    59,   159,  -111,  -111,    34,  -111,   395,
+      57,    60,    81,    88,  -111,     0,  -111,  -111,    34,  -111,
+    -111,  -111,  -111,  -111,   257,    72,  -111,   -23,  -111,  -111,
+    -111,    85,  -111,    20,   106,    47,  -111,   -10,    97,    96,
+    -111,  -111,  -111,    99,  -111,   115,  -111,  -111,     5,    50,
+    -111,    11,  -111,   102,  -111,  -111,  -111,  -111,   -22,   100,
+     103,   111,   104,  -111,  -111,  -111,  -111,  -111,   113,  -111,
+     121,  -111,  -111,   124,  -111,   303,  -111,    33,   132,  -111,
+     139,  -111,  -111,   349,  -111,  -111,   122,  -111,  -111,  -111,
+    -111,  -111,   442,  -111,  -111,   140,   143,  -111,  -111,  -111,
+     144,   145,  -111,  -111,  -111,  -111,  -111,  -111,  -111
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-     -92,   -92,   192,   -92,   -92,   -92,   -92,   -47,   -92,   -92,
-      97,     0,   -60,   -32,   -92,   -92,   -92,   -79,   -92,   -92,
-     -58,   -26,   -92,   -38,   -92,   -91,   -92,   -92,   -59,   -28,
-     -92,   -92,   -92,   -92,   -20,   -92,   -92,   112,   -92,   -92,
-      41,    91,    83,   149,   -92,   101,   -92,   -92,   -92
+    -111,  -111,   160,  -111,  -111,  -111,  -111,   -51,  -111,  -111,
+      98,    -1,   -61,   -37,  -111,  -111,  -111,   -78,  -111,  -111,
+     -53,   -30,  -111,   -66,  -111,  -110,  -111,  -111,   -60,   -63,
+    -111,  -111,  -111,  -111,   -21,  -111,  -111,   116,  -111,  -111,
+      40,    90,    83,   152,  -111,   105,  -111,  -111,  -111
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -110
+#define YYTABLE_NINF -111
 static const yytype_int16 yytable[] =
 {
-      88,    89,   114,    38,   157,    10,    59,    73,    95,   128,
-      85,    50,    71,    91,    75,    20,    54,   110,   147,     4,
-     164,   111,   144,    99,    29,    51,   100,   112,    33,    66,
-      55,   107,   113,   114,    79,   114,   135,   -94,    87,    92,
-     165,   125,    60,    88,    98,   158,    53,    58,   128,   128,
-      63,   127,   -94,    66,    64,   148,    73,    86,   102,   111,
-      65,    55,    66,   175,    61,   112,   153,    66,   161,    63,
-      62,   180,   103,    64,   149,    75,   151,   114,    86,    65,
-     154,    66,   162,   148,    48,    49,   125,   111,   105,   106,
-     158,   108,   109,   112,    88,    66,   127,    90,    66,   159,
-     160,    51,    88,    55,    97,    96,   104,   121,   143,    80,
-     150,    88,   183,     7,     8,     9,    10,    11,    12,    13,
-     131,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-      24,   132,    26,    27,    28,    29,    30,   133,   134,    33,
-      34,   155,   156,   113,   108,    99,   -22,   163,   170,   168,
-      35,   171,   169,   -22,  -108,   172,   -22,   164,   -22,   122,
-     181,   -22,   173,     7,     8,     9,    10,    11,    12,    13,
-     177,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-      24,   178,    26,    27,    28,    29,    30,   184,   185,    33,
-      34,   186,   187,     5,   136,   123,   -22,   176,   152,    74,
-      35,   146,     0,   -22,  -109,     0,   -22,   145,   -22,     6,
-       0,   -22,     0,     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,     0,     0,     0,     0,     0,   -22,     0,     0,     0,
-      35,     0,     0,   -22,     0,   138,   -22,     0,   -22,     7,
-       8,     9,    10,    11,    12,    13,     0,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,     0,    26,    27,
-      28,    29,    30,     0,     0,    33,    34,     0,     0,     0,
-       0,   -87,     0,     0,     0,     0,    35,     0,     0,     0,
-     174,     0,     0,   -87,     7,     8,     9,    10,    11,    12,
-      13,     0,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,     0,    26,    27,    28,    29,    30,     0,     0,
-      33,    34,     0,     0,     0,     0,   -87,     0,     0,     0,
-       0,    35,     0,     0,     0,   179,     0,     0,   -87,     7,
-       8,     9,    10,    11,    12,    13,     0,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,     0,    26,    27,
-      28,    29,    30,     0,     0,    33,    34,     0,     0,     0,
-       0,   -87,     0,     0,     0,     0,    35,     0,     0,     0,
-       0,     0,     0,   -87,     7,     8,     9,    10,    11,    12,
+      89,    90,    39,    74,   115,    60,   158,    86,    10,    72,
+     165,   129,    51,     4,    96,    55,    76,   103,    20,    59,
+      92,   148,   106,   107,   145,   154,    52,    29,   108,    56,
+     166,   104,    34,    56,    80,   115,    93,   115,    88,   155,
+     -95,    99,   136,    89,   126,   176,   162,   150,   159,   152,
+     129,   129,    74,   181,   128,   -95,    67,    87,    64,   149,
+     163,   100,    65,   112,   101,   160,   161,    54,    66,   113,
+      67,    67,   111,    64,    49,    50,   112,    65,    87,   115,
+      61,    62,   113,    66,    67,    67,   149,   114,    63,   126,
+     112,   109,   110,   159,    89,    76,   113,    91,    67,   128,
+      97,    67,    89,    98,    52,    56,   122,   132,   144,    81,
+     133,    89,   184,     7,     8,     9,    10,    11,    12,    13,
+     105,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,   134,    26,    27,    28,    29,    30,    31,   135,   114,
+      34,    35,   151,   156,   157,   109,   100,   -22,   164,   171,
+     169,    36,   172,   170,   -22,  -109,   165,   -22,   182,   -22,
+     123,     5,   -22,   173,     7,     8,     9,    10,    11,    12,
+      13,   174,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    24,   178,    26,    27,    28,    29,    30,    31,   179,
+     185,    34,    35,   186,   187,   188,   137,   177,   -22,   153,
+     124,   147,    36,    75,     0,   -22,  -110,     0,   -22,     0,
+     -22,     6,   146,   -22,     0,     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,     0,     0,     0,     0,     0,   -22,
+       0,     0,     0,    36,     0,     0,   -22,     0,   139,   -22,
+       0,   -22,     7,     8,     9,    10,    11,    12,    13,     0,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+       0,    26,    27,    28,    29,    30,    31,     0,     0,    34,
+      35,     0,     0,     0,     0,   -88,     0,     0,     0,     0,
+      36,     0,     0,     0,   175,     0,     0,   -88,     7,     8,
+       9,    10,    11,    12,    13,     0,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,     0,    26,    27,    28,
+      29,    30,    31,     0,     0,    34,    35,     0,     0,     0,
+       0,   -88,     0,     0,     0,     0,    36,     0,     0,     0,
+     180,     0,     0,   -88,     7,     8,     9,    10,    11,    12,
       13,     0,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,     0,    26,    27,    28,    29,    30,     0,     0,
-      33,    34,     0,     0,     0,     0,     0,   125,     0,     0,
-       0,   126,     0,     0,     0,     0,     0,   127,     0,    66,
+      23,    24,     0,    26,    27,    28,    29,    30,    31,     0,
+       0,    34,    35,     0,     0,     0,     0,   -88,     0,     0,
+       0,     0,    36,     0,     0,     0,     0,     0,     0,   -88,
        7,     8,     9,    10,    11,    12,    13,     0,    15,    16,
       17,    18,    19,    20,    21,    22,    23,    24,     0,    26,
-      27,    28,    29,    30,     0,     0,    33,    34,     0,     0,
-       0,     0,   182,     0,     0,     0,     0,    35,     7,     8,
-       9,    10,    11,    12,    13,     0,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,     0,    26,    27,    28,
-      29,    30,     0,     0,    33,    34,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    35
+      27,    28,    29,    30,    31,     0,     0,    34,    35,     0,
+       0,     0,     0,     0,   126,     0,     0,     0,   127,     0,
+       0,     0,     0,     0,   128,     0,    67,     7,     8,     9,
+      10,    11,    12,    13,     0,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,     0,    26,    27,    28,    29,
+      30,    31,     0,     0,    34,    35,     0,     0,     0,     0,
+     183,     0,     0,     0,     0,    36,     7,     8,     9,    10,
+      11,    12,    13,     0,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,     0,    26,    27,    28,    29,    30,
+      31,     0,     0,    34,    35,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,    36
 };
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-92)))
+  (!!((Yystate) == (-111)))
 
 #define yytable_value_is_error(Yytable_value) \
   YYID (0)
 
 static const yytype_int16 yycheck[] =
 {
-      60,    60,    81,     3,     1,     8,    26,    39,    66,    88,
-      57,    38,    38,     1,    38,    18,    38,    38,     1,     0,
-      31,    42,    46,    30,    27,    52,    33,    48,    31,    50,
-      52,    78,    53,   112,    54,   114,    94,    34,    58,    65,
-      51,    38,    48,   103,    70,    42,    23,    38,   127,   128,
-      38,    48,    49,    50,    42,    38,    88,    57,    34,    42,
-      48,    52,    50,   154,    48,    48,    34,    50,    34,    38,
-      45,   162,    48,    42,   112,    38,   114,   156,    78,    48,
-      48,    50,    48,    38,    45,    46,    38,    42,    46,    47,
-      42,    45,    46,    48,   154,    50,    48,    38,    50,   127,
-     128,    52,   162,    52,    47,    45,    51,    46,    35,     1,
-      35,   171,   171,     5,     6,     7,     8,     9,    10,    11,
-      49,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-      22,    49,    24,    25,    26,    27,    28,    49,    49,    31,
-      32,    45,    47,    53,    45,    30,    38,    45,    37,    49,
-      42,    47,    49,    45,    46,    49,    48,    31,    50,     1,
-      35,    53,    49,     5,     6,     7,     8,     9,    10,    11,
-      49,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-      22,    49,    24,    25,    26,    27,    28,    49,    49,    31,
-      32,    49,    49,     1,    97,    83,    38,   156,   115,    50,
-      42,   110,    -1,    45,    46,    -1,    48,   106,    50,     1,
-      -1,    53,    -1,     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,    -1,    -1,    -1,    -1,    -1,    38,    -1,    -1,    -1,
-      42,    -1,    -1,    45,    -1,     1,    48,    -1,    50,     5,
-       6,     7,     8,     9,    10,    11,    -1,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    -1,    24,    25,
-      26,    27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,
-      -1,    37,    -1,    -1,    -1,    -1,    42,    -1,    -1,    -1,
-       1,    -1,    -1,    49,     5,     6,     7,     8,     9,    10,
-      11,    -1,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    -1,    24,    25,    26,    27,    28,    -1,    -1,
-      31,    32,    -1,    -1,    -1,    -1,    37,    -1,    -1,    -1,
-      -1,    42,    -1,    -1,    -1,     1,    -1,    -1,    49,     5,
-       6,     7,     8,     9,    10,    11,    -1,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    -1,    24,    25,
-      26,    27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,
-      -1,    37,    -1,    -1,    -1,    -1,    42,    -1,    -1,    -1,
-      -1,    -1,    -1,    49,     5,     6,     7,     8,     9,    10,
+      61,    61,     3,    40,    82,    26,     1,    58,     8,    39,
+      32,    89,    39,     0,    67,    39,    39,    35,    18,    39,
+       1,     1,    47,    48,    47,    35,    53,    27,    79,    53,
+      52,    49,    32,    53,    55,   113,    66,   115,    59,    49,
+      35,    71,    95,   104,    39,   155,    35,   113,    43,   115,
+     128,   129,    89,   163,    49,    50,    51,    58,    39,    39,
+      49,    31,    43,    43,    34,   128,   129,    23,    49,    49,
+      51,    51,    39,    39,    46,    47,    43,    43,    79,   157,
+      49,    49,    49,    49,    51,    51,    39,    54,    46,    39,
+      43,    46,    47,    43,   155,    39,    49,    39,    51,    49,
+      46,    51,   163,    48,    53,    53,    47,    50,    36,     1,
+      50,   172,   172,     5,     6,     7,     8,     9,    10,    11,
+      52,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    50,    24,    25,    26,    27,    28,    29,    50,    54,
+      32,    33,    36,    46,    48,    46,    31,    39,    46,    38,
+      50,    43,    48,    50,    46,    47,    32,    49,    36,    51,
+       1,     1,    54,    50,     5,     6,     7,     8,     9,    10,
+      11,    50,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    50,    24,    25,    26,    27,    28,    29,    50,
+      50,    32,    33,    50,    50,    50,    98,   157,    39,   116,
+      84,   111,    43,    51,    -1,    46,    47,    -1,    49,    -1,
+      51,     1,   107,    54,    -1,     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,    -1,    -1,    -1,    -1,    -1,    39,
+      -1,    -1,    -1,    43,    -1,    -1,    46,    -1,     1,    49,
+      -1,    51,     5,     6,     7,     8,     9,    10,    11,    -1,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      -1,    24,    25,    26,    27,    28,    29,    -1,    -1,    32,
+      33,    -1,    -1,    -1,    -1,    38,    -1,    -1,    -1,    -1,
+      43,    -1,    -1,    -1,     1,    -1,    -1,    50,     5,     6,
+       7,     8,     9,    10,    11,    -1,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    -1,    24,    25,    26,
+      27,    28,    29,    -1,    -1,    32,    33,    -1,    -1,    -1,
+      -1,    38,    -1,    -1,    -1,    -1,    43,    -1,    -1,    -1,
+       1,    -1,    -1,    50,     5,     6,     7,     8,     9,    10,
       11,    -1,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    -1,    24,    25,    26,    27,    28,    -1,    -1,
-      31,    32,    -1,    -1,    -1,    -1,    -1,    38,    -1,    -1,
-      -1,    42,    -1,    -1,    -1,    -1,    -1,    48,    -1,    50,
+      21,    22,    -1,    24,    25,    26,    27,    28,    29,    -1,
+      -1,    32,    33,    -1,    -1,    -1,    -1,    38,    -1,    -1,
+      -1,    -1,    43,    -1,    -1,    -1,    -1,    -1,    -1,    50,
        5,     6,     7,     8,     9,    10,    11,    -1,    13,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    -1,    24,
-      25,    26,    27,    28,    -1,    -1,    31,    32,    -1,    -1,
-      -1,    -1,    37,    -1,    -1,    -1,    -1,    42,     5,     6,
-       7,     8,     9,    10,    11,    -1,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    -1,    24,    25,    26,
-      27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    42
+      25,    26,    27,    28,    29,    -1,    -1,    32,    33,    -1,
+      -1,    -1,    -1,    -1,    39,    -1,    -1,    -1,    43,    -1,
+      -1,    -1,    -1,    -1,    49,    -1,    51,     5,     6,     7,
+       8,     9,    10,    11,    -1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    -1,    24,    25,    26,    27,
+      28,    29,    -1,    -1,    32,    33,    -1,    -1,    -1,    -1,
+      38,    -1,    -1,    -1,    -1,    43,     5,     6,     7,     8,
+       9,    10,    11,    -1,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    -1,    24,    25,    26,    27,    28,
+      29,    -1,    -1,    32,    33,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    43
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    55,    56,    57,     0,    56,     1,     5,     6,     7,
+       0,    56,    57,    58,     0,    57,     1,     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,    42,    58,    61,    65,    66,
-      67,    68,    69,    70,    74,    85,   100,   102,    45,    46,
-      38,    52,    97,    23,    38,    52,    88,    60,    38,    88,
-      48,    48,    45,    38,    42,    48,    50,    62,    63,    64,
-      71,    75,    76,    67,    97,    38,    98,    99,    59,    88,
-       1,    65,    89,    90,    91,    61,    65,    88,    66,    82,
-      38,     1,    75,    72,    73,    74,    45,    47,    75,    30,
-      33,   101,    34,    48,    51,    46,    47,    61,    45,    46,
-      38,    42,    48,    53,    71,    77,    78,    92,    93,    94,
-      95,    46,     1,    91,    75,    38,    42,    48,    71,    83,
-      84,    49,    49,    49,    49,    74,    64,    96,     1,    79,
-      80,    81,    82,    35,    46,    99,    95,     1,    38,    77,
-      35,    77,    96,    34,    48,    45,    47,     1,    42,    83,
-      83,    34,    48,    45,    31,    51,    86,    87,    49,    49,
-      37,    47,    49,    49,     1,    79,    94,    49,    49,     1,
-      79,    35,    37,    82,    49,    49,    49,    49
+      28,    29,    30,    31,    32,    33,    43,    59,    62,    66,
+      67,    68,    69,    70,    71,    75,    86,   101,   103,    46,
+      47,    39,    53,    98,    23,    39,    53,    89,    61,    39,
+      89,    49,    49,    46,    39,    43,    49,    51,    63,    64,
+      65,    72,    76,    77,    68,    98,    39,    99,   100,    60,
+      89,     1,    66,    90,    91,    92,    62,    66,    89,    67,
+      83,    39,     1,    76,    73,    74,    75,    46,    48,    76,
+      31,    34,   102,    35,    49,    52,    47,    48,    62,    46,
+      47,    39,    43,    49,    54,    72,    78,    79,    93,    94,
+      95,    96,    47,     1,    92,    76,    39,    43,    49,    72,
+      84,    85,    50,    50,    50,    50,    75,    65,    97,     1,
+      80,    81,    82,    83,    36,    47,   100,    96,     1,    39,
+      78,    36,    78,    97,    35,    49,    46,    48,     1,    43,
+      84,    84,    35,    49,    46,    32,    52,    87,    88,    50,
+      50,    38,    48,    50,    50,     1,    80,    95,    50,    50,
+       1,    80,    36,    38,    83,    50,    50,    50,    50
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1845,27 +1849,27 @@ yyreduce:
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 56:
+  case 57:
 
     { (*(yyvsp[(1) - (1)]))->tag = SYM_TYPEDEF; (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 57:
+  case 58:
 
     { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); }
     break;
 
-  case 58:
+  case 59:
 
     { (yyval) = NULL; }
     break;
 
-  case 61:
+  case 62:
 
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 65:
+  case 66:
 
     { /* restrict has no effect in prototypes so ignore it */
                  remove_node((yyvsp[(1) - (1)]));
@@ -1873,12 +1877,12 @@ yyreduce:
                }
     break;
 
-  case 66:
+  case 67:
 
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 68:
+  case 69:
 
     { if (current_name != NULL) {
                    error_with_pos("unexpected second declaration name");
@@ -1890,7 +1894,7 @@ yyreduce:
                }
     break;
 
-  case 69:
+  case 70:
 
     { if (current_name != NULL) {
                    error_with_pos("unexpected second declaration name");
@@ -1902,11 +1906,6 @@ yyreduce:
                }
     break;
 
-  case 70:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
-    break;
-
   case 71:
 
     { (yyval) = (yyvsp[(4) - (4)]); }
@@ -1914,12 +1913,12 @@ yyreduce:
 
   case 72:
 
-    { (yyval) = (yyvsp[(2) - (2)]); }
+    { (yyval) = (yyvsp[(4) - (4)]); }
     break;
 
   case 73:
 
-    { (yyval) = (yyvsp[(3) - (3)]); }
+    { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
   case 74:
@@ -1929,12 +1928,12 @@ yyreduce:
 
   case 75:
 
-    { (yyval) = (yyvsp[(2) - (2)]); }
+    { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 79:
+  case 76:
 
-    { (yyval) = (yyvsp[(4) - (4)]); }
+    { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
   case 80:
@@ -1944,12 +1943,12 @@ yyreduce:
 
   case 81:
 
-    { (yyval) = (yyvsp[(2) - (2)]); }
+    { (yyval) = (yyvsp[(4) - (4)]); }
     break;
 
   case 82:
 
-    { (yyval) = (yyvsp[(3) - (3)]); }
+    { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
   case 83:
@@ -1959,40 +1958,45 @@ yyreduce:
 
   case 84:
 
+    { (yyval) = (yyvsp[(3) - (3)]); }
+    break;
+
+  case 85:
+
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 86:
+  case 87:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 87:
+  case 88:
 
     { (yyval) = NULL; }
     break;
 
-  case 90:
+  case 91:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 91:
+  case 92:
 
     { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); }
     break;
 
-  case 92:
+  case 93:
 
     { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); }
     break;
 
-  case 94:
+  case 95:
 
     { (yyval) = NULL; }
     break;
 
-  case 95:
+  case 96:
 
     { /* For version 2 checksums, we don't want to remember
                     private parameter names.  */
@@ -2001,39 +2005,39 @@ yyreduce:
                }
     break;
 
-  case 96:
+  case 97:
 
     { remove_node((yyvsp[(1) - (1)]));
                  (yyval) = (yyvsp[(1) - (1)]);
                }
     break;
 
-  case 97:
+  case 98:
 
     { (yyval) = (yyvsp[(4) - (4)]); }
     break;
 
-  case 98:
+  case 99:
 
     { (yyval) = (yyvsp[(4) - (4)]); }
     break;
 
-  case 99:
+  case 100:
 
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 100:
+  case 101:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 101:
+  case 102:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 102:
+  case 103:
 
     { struct string_list *decl = *(yyvsp[(2) - (3)]);
                  *(yyvsp[(2) - (3)]) = NULL;
@@ -2042,87 +2046,87 @@ yyreduce:
                }
     break;
 
-  case 103:
+  case 104:
 
     { (yyval) = NULL; }
     break;
 
-  case 105:
+  case 106:
 
     { remove_list((yyvsp[(2) - (2)]), &(*(yyvsp[(1) - (2)]))->next); (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 106:
+  case 107:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 107:
+  case 108:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 108:
+  case 109:
 
     { (yyval) = NULL; }
     break;
 
-  case 111:
+  case 112:
 
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 112:
+  case 113:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 113:
+  case 114:
 
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 114:
+  case 115:
 
     { (yyval) = NULL; }
     break;
 
-  case 117:
+  case 118:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 118:
+  case 119:
 
     { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); }
     break;
 
-  case 119:
+  case 120:
 
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 121:
+  case 122:
 
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 122:
+  case 123:
 
     { (yyval) = NULL; }
     break;
 
-  case 124:
+  case 125:
 
     { (yyval) = (yyvsp[(3) - (3)]); }
     break;
 
-  case 125:
+  case 126:
 
     { (yyval) = (yyvsp[(4) - (4)]); }
     break;
 
-  case 128:
+  case 129:
 
     {
                        const char *name = strdup((*(yyvsp[(1) - (1)]))->string);
@@ -2130,7 +2134,7 @@ yyreduce:
                }
     break;
 
-  case 129:
+  case 130:
 
     {
                        const char *name = strdup((*(yyvsp[(1) - (3)]))->string);
@@ -2139,17 +2143,17 @@ yyreduce:
                }
     break;
 
-  case 130:
+  case 131:
 
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
-  case 131:
+  case 132:
 
     { (yyval) = NULL; }
     break;
 
-  case 133:
+  case 134:
 
     { export_symbol((*(yyvsp[(3) - (5)]))->string); (yyval) = (yyvsp[(5) - (5)]); }
     break;
index 4c00cef6d71dddd64999b6bef21f0c6e58f19756..46a5e124eda1c9df1fbb18fa531216874269921c 100644 (file)
@@ -72,22 +72,23 @@ extern int yydebug;
      VOID_KEYW = 281,
      VOLATILE_KEYW = 282,
      TYPEOF_KEYW = 283,
-     EXPORT_SYMBOL_KEYW = 284,
-     ASM_PHRASE = 285,
-     ATTRIBUTE_PHRASE = 286,
-     TYPEOF_PHRASE = 287,
-     BRACE_PHRASE = 288,
-     BRACKET_PHRASE = 289,
-     EXPRESSION_PHRASE = 290,
-     CHAR = 291,
-     DOTS = 292,
-     IDENT = 293,
-     INT = 294,
-     REAL = 295,
-     STRING = 296,
-     TYPE = 297,
-     OTHER = 298,
-     FILENAME = 299
+     VA_LIST_KEYW = 284,
+     EXPORT_SYMBOL_KEYW = 285,
+     ASM_PHRASE = 286,
+     ATTRIBUTE_PHRASE = 287,
+     TYPEOF_PHRASE = 288,
+     BRACE_PHRASE = 289,
+     BRACKET_PHRASE = 290,
+     EXPRESSION_PHRASE = 291,
+     CHAR = 292,
+     DOTS = 293,
+     IDENT = 294,
+     INT = 295,
+     REAL = 296,
+     STRING = 297,
+     TYPE = 298,
+     OTHER = 299,
+     FILENAME = 300
    };
 #endif
 
index 723ab30fe9d46951b6106c38bc81b1460c5df342..4fba255e54ae49ed0fcf196b4e72695624eab58b 100644 (file)
@@ -98,6 +98,7 @@ static void record_compound(struct string_list **keyw,
 %token VOID_KEYW
 %token VOLATILE_KEYW
 %token TYPEOF_KEYW
+%token VA_LIST_KEYW
 
 %token EXPORT_SYMBOL_KEYW
 
@@ -261,6 +262,7 @@ simple_type_specifier:
        | DOUBLE_KEYW
        | VOID_KEYW
        | BOOL_KEYW
+       | VA_LIST_KEYW
        | TYPE                  { (*$1)->tag = SYM_TYPEDEF; $$ = $1; }
        ;
 
index 1f22a186c18cb56a2c19a4b38bf90f41f1b171d8..299b92ca1ae092d82e9a0e3bffaec45988ebcc37 100644 (file)
@@ -76,7 +76,6 @@ static void usage(void)
 {
        fprintf(stderr, "Usage: kallsyms [--all-symbols] "
                        "[--symbol-prefix=<prefix char>] "
-                       "[--page-offset=<CONFIG_PAGE_OFFSET>] "
                        "[--base-relative] < in.map > out.S\n");
        exit(1);
 }
index d42d534a66cd7006a38e113b4b5b8e30359e7a76..a9bc5334a478d6774d1409a837665b4f143d8597 100644 (file)
@@ -5,7 +5,9 @@
  * Derived from menuconfig.
  *
  */
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 #include <string.h>
 #include <stdlib.h>
 
index 8275f0e55106bc0055d0a1adfe2a169ad1b54193..4b2f44c20caf8941d150f261074b40d589a10376 100644 (file)
@@ -364,12 +364,14 @@ int dialog_inputbox(WINDOW *main_window,
        WINDOW *prompt_win;
        WINDOW *form_win;
        PANEL *panel;
-       int i, x, y;
+       int i, x, y, lines, columns, win_lines, win_cols;
        int res = -1;
        int cursor_position = strlen(init);
        int cursor_form_win;
        char *result = *resultp;
 
+       getmaxyx(stdscr, lines, columns);
+
        if (strlen(init)+1 > *result_len) {
                *result_len = strlen(init)+1;
                *resultp = result = realloc(result, *result_len);
@@ -386,14 +388,19 @@ int dialog_inputbox(WINDOW *main_window,
        if (title)
                prompt_width = max(prompt_width, strlen(title));
 
+       win_lines = min(prompt_lines+6, lines-2);
+       win_cols = min(prompt_width+7, columns-2);
+       prompt_lines = max(win_lines-6, 0);
+       prompt_width = max(win_cols-7, 0);
+
        /* place dialog in middle of screen */
-       y = (getmaxy(stdscr)-(prompt_lines+4))/2;
-       x = (getmaxx(stdscr)-(prompt_width+4))/2;
+       y = (lines-win_lines)/2;
+       x = (columns-win_cols)/2;
 
        strncpy(result, init, *result_len);
 
        /* create the windows */
-       win = newwin(prompt_lines+6, prompt_width+7, y, x);
+       win = newwin(win_lines, win_cols, y, x);
        prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
        form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
        keypad(form_win, TRUE);
index fc5555992220956d31ce82b765b8ab6f35898379..ae6c725464110c67bf1e72325c4f7fa8879b6c94 100644 (file)
@@ -65,11 +65,19 @@ ConfigSettings::ConfigSettings()
 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
 {
        QList<int> result;
-       QStringList entryList = value(key).toStringList();
-       QStringList::Iterator it;
 
-       for (it = entryList.begin(); it != entryList.end(); ++it)
-               result.push_back((*it).toInt());
+       if (contains(key))
+       {
+               QStringList entryList = value(key).toStringList();
+               QStringList::Iterator it;
+
+               for (it = entryList.begin(); it != entryList.end(); ++it)
+                       result.push_back((*it).toInt());
+
+               *ok = true;
+       }
+       else
+               *ok = false;
 
        return result;
 }
@@ -1014,7 +1022,7 @@ ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
 
        if (!objectName().isEmpty()) {
                configSettings->beginGroup(objectName());
-               _showDebug = configSettings->value("/showDebug", false).toBool();
+               setShowDebug(configSettings->value("/showDebug", false).toBool());
                configSettings->endGroup();
                connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
        }
@@ -1474,6 +1482,7 @@ ConfigMainWindow::ConfigMainWindow(void)
        optionMenu->addSeparator();
        optionMenu->addActions(optGroup->actions());
        optionMenu->addSeparator();
+       optionMenu->addAction(showDebugAction);
 
        // create help menu
        menu->addSeparator();
index f742c65108b9d41f0c4d0bbed22924fc35383b37..c80291319cb2e20e15df93b685b8065ffdd9742e 100755 (executable)
@@ -209,15 +209,6 @@ case "${KCONFIG_CONFIG}" in
        . "./${KCONFIG_CONFIG}"
 esac
 
-archive_builtin
-
-#link vmlinux.o
-info LD vmlinux.o
-modpost_link vmlinux.o
-
-# modpost vmlinux.o to check for section mismatches
-${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o
-
 # Update version
 info GEN .version
 if [ ! -r .version ]; then
@@ -231,6 +222,15 @@ fi;
 # final build of init/
 ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}"
 
+archive_builtin
+
+#link vmlinux.o
+info LD vmlinux.o
+modpost_link vmlinux.o
+
+# modpost vmlinux.o to check for section mismatches
+${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o
+
 kallsymso=""
 kallsyms_vmlinux=""
 if [ -n "${CONFIG_KALLSYMS}" ]; then
@@ -246,10 +246,14 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then
        #     the right size, but due to the added section, some
        #     addresses have shifted.
        #     From here, we generate a correct .tmp_kallsyms2.o
-       # 2a) We may use an extra pass as this has been necessary to
-       #     woraround some alignment related bugs.
-       #     KALLSYMS_EXTRA_PASS=1 is used to trigger this.
-       # 3)  The correct ${kallsymso} is linked into the final vmlinux.
+       # 3)  That link may have expanded the kernel image enough that
+       #     more linker branch stubs / trampolines had to be added, which
+       #     introduces new names, which further expands kallsyms. Do another
+       #     pass if that is the case. In theory it's possible this results
+       #     in even more stubs, but unlikely.
+       #     KALLSYMS_EXTRA_PASS=1 may also used to debug or work around
+       #     other bugs.
+       # 4)  The correct ${kallsymso} is linked into the final vmlinux.
        #
        # a)  Verify that the System.map from vmlinux matches the map from
        #     ${kallsymso}.
@@ -265,8 +269,11 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then
        vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2
        kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o
 
-       # step 2a
-       if [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
+       # step 3
+       size1=$(stat -c "%s" .tmp_kallsyms1.o)
+       size2=$(stat -c "%s" .tmp_kallsyms2.o)
+
+       if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
                kallsymso=.tmp_kallsyms3.o
                kallsyms_vmlinux=.tmp_vmlinux3
 
index 5a6b39a29b7a781eb9bf9e10d24b336c46c38bea..29c89a6bad3d3ac34e539189e83769f1c63ddab3 100644 (file)
@@ -609,6 +609,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
 {
        unsigned int crc;
        enum export export;
+       bool is_crc = false;
 
        if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
            strncmp(symname, "__ksymtab", 9) == 0)
@@ -618,6 +619,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
 
        /* CRC'd symbol */
        if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
+               is_crc = true;
                crc = (unsigned int) sym->st_value;
                sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
                                export);
@@ -663,6 +665,10 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
                else
                        symname++;
 #endif
+               if (is_crc) {
+                       const char *e = is_vmlinux(mod->name) ?"":".ko";
+                       warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", symname + strlen(CRC_PFX), mod->name, e);
+               }
                mod->unres = alloc_symbol(symname,
                                          ELF_ST_BIND(sym->st_info) == STB_WEAK,
                                          mod->unres);
index 8ea9fd2b65736c42b055791ee88b9151a573a02d..3c575cd07888807d14693ad8475b6b5a953a1ca4 100755 (executable)
@@ -51,7 +51,7 @@ set_debarch() {
                debarch=hppa ;;
        mips*)
                debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el || true) ;;
-       arm64)
+       aarch64|arm64)
                debarch=arm64 ;;
        arm*)
                if grep -q CONFIG_AEABI=y $KCONFIG_CONFIG; then
index 57673bae5597ab9a5078fe9527825aa4456086c9..bb43f153fd8e70fd48c32a2f92fa6699242501f7 100755 (executable)
@@ -116,7 +116,8 @@ echo 'mv vmlinux.bz2 $RPM_BUILD_ROOT'"/boot/vmlinux-$KERNELRELEASE.bz2"
 echo "%endif"
 
 if ! $PREBUILT; then
-echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/{build,source}"
+echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/build"
+echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/source"
 echo "mkdir -p "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE"
 echo "EXCLUDES=\"$RCS_TAR_IGNORE --exclude .tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude=firmware --exclude .config.old --exclude .missing-syscalls.d\""
 echo "tar "'$EXCLUDES'" -cf- . | (cd "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE;tar xvf -)"
index 8332959fbca4fb5b9a6c4f89b5ef479133ca9b43..aaf7ed329a453a87b91a38f73b6cc25c27764c82 100644 (file)
@@ -1,5 +1,5 @@
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 endif
 
index 250a891e6ef0ecd082da136102b3c5a7a6f33a7a..b4401536cfa90f370bbe7c131aa4cba847ad4e2a 100644 (file)
@@ -3,7 +3,7 @@ include ../scripts/Makefile.include
 bindir ?= /usr/bin
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 endif
 
index 0a6fda9837f7dd3a60a89fbe3083bf8a3835b6f3..adba83b325d556d4b9280114905cdd3fb4b7313a 100644 (file)
@@ -2,7 +2,7 @@ include ../../scripts/Makefile.include
 include ../../scripts/utilities.mak            # QUIET_CLEAN
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
index 62d89d50fcbd0484e7c38883b9d3d512e627eaef..e2efddf1023177c202d626257c8466f3cb8c40c3 100644 (file)
@@ -7,7 +7,7 @@ BPF_EXTRAVERSION = 1
 MAKEFLAGS += --no-print-directory
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
index 1d57af56814b8671c10d9619202f042ad5c031d4..3bc0ef9f8923060c6bf6f9aebda2bdc4866e74f7 100644 (file)
@@ -50,7 +50,7 @@ ifndef VERBOSE
 endif
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
index ce4b7e5275661774d6db64e1eeaa5086c7de732a..3f8cc44a0dbdad3665ad7b1f03a58a6ce3f92707 100644 (file)
@@ -2,7 +2,7 @@ include ../../scripts/Makefile.include
 include ../../scripts/utilities.mak            # QUIET_CLEAN
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
index c76012ebdb9ccaa144fae77f6f56c1ea3acd1884..2616c66e10c1ea0bf4016138bd2a6cdbc3650020 100644 (file)
@@ -86,7 +86,7 @@ ifndef VERBOSE
 endif
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
index 041b493ad3ab5133f8503e549f6c1cfc717d4b89..27e019c09bd2c41d8014e30bd79342a91fc28e09 100644 (file)
@@ -11,12 +11,12 @@ LD = ld
 AR = ar
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 endif
 
 SUBCMD_SRCDIR          = $(srctree)/tools/lib/subcmd/
-LIBSUBCMD_OUTPUT       = $(if $(OUTPUT),$(OUTPUT),$(PWD)/)
+LIBSUBCMD_OUTPUT       = $(if $(OUTPUT),$(OUTPUT),$(CURDIR)/)
 LIBSUBCMD              = $(LIBSUBCMD_OUTPUT)libsubcmd.a
 
 OBJTOOL    := $(OUTPUT)objtool
index 8f1c258b151a2ccc4d98ac1c66ced1f4ff204afb..e5af38eede17f5ec09aaaabf9ad963b6524e7cb1 100644 (file)
@@ -100,7 +100,7 @@ LC_NUMERIC=C
 export LC_COLLATE LC_NUMERIC
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
 endif
index 0784748f1670904240508879d6a1363f858e99ef..e46723568516f98d4371d41b5c4591935827fb0c 100644 (file)
@@ -42,7 +42,7 @@ LC_NUMERIC=C
 export LC_COLLATE LC_NUMERIC
 
 ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
 endif
index 8358863259c53463d86d0578b9837b10201dc266..d6e1c02ddcfead4532cdc73f2d81207f62a8db5f 100644 (file)
@@ -108,9 +108,6 @@ MKDIR = mkdir
 # Now we set up the build system
 #
 
-# set up PWD so that older versions of make will work with our build.
-PWD = $(shell pwd)
-
 GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; done;}
 
 export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS
index 96b146fe6f8d02db3d94dccefe401919a693450f..a8a6f8eec5c2d5d125d0e43ee1a4316d4b91b2d6 100644 (file)
@@ -1,7 +1,6 @@
 obj-m  :=
 
 KDIR   := /lib/modules/$(shell uname -r)/build
-PWD            := $(shell pwd)
 KMISC   := /lib/modules/$(shell uname -r)/cpufrequtils/
 
 ifeq ("$(CONFIG_X86_TSC)", "y")
@@ -9,7 +8,7 @@ ifeq ("$(CONFIG_X86_TSC)", "y")
 endif
 
 default:
-       $(MAKE) -C $(KDIR) M=$(PWD)
+       $(MAKE) -C $(KDIR) M=$(CURDIR)
 
 clean:
        - rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c
index 71620fa959530211c6c73c25ab71aaaba7cfa50a..45be8b55a663453748a8c3156b865610fcfc37a8 100644 (file)
@@ -125,12 +125,13 @@ struct nfit_test_dcr {
        (((node & 0xfff) << 16) | ((socket & 0xf) << 12) \
         | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf))
 
-static u32 handle[NUM_DCR] = {
+static u32 handle[] = {
        [0] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 0),
        [1] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1),
        [2] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0),
        [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1),
        [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),
+       [5] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0),
 };
 
 static unsigned long dimm_fail_cmd_flags[NUM_DCR];
@@ -142,6 +143,7 @@ struct nfit_test {
        void *nfit_buf;
        dma_addr_t nfit_dma;
        size_t nfit_size;
+       int dcr_idx;
        int num_dcr;
        int num_pm;
        void **dimm;
@@ -426,11 +428,11 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
                        break;
                case ND_CMD_GET_CONFIG_DATA:
                        rc = nfit_test_cmd_get_config_data(buf, buf_len,
-                               t->label[i]);
+                               t->label[i - t->dcr_idx]);
                        break;
                case ND_CMD_SET_CONFIG_DATA:
                        rc = nfit_test_cmd_set_config_data(buf, buf_len,
-                               t->label[i]);
+                               t->label[i - t->dcr_idx]);
                        break;
                case ND_CMD_SMART:
                        rc = nfit_test_cmd_smart(buf, buf_len);
@@ -682,7 +684,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
        if (!t->spa_set[2])
                return -ENOMEM;
 
-       for (i = 0; i < NUM_DCR; i++) {
+       for (i = 0; i < t->num_dcr; i++) {
                t->dimm[i] = test_alloc(t, DIMM_SIZE, &t->dimm_dma[i]);
                if (!t->dimm[i])
                        return -ENOMEM;
@@ -699,7 +701,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
                        return -ENOMEM;
        }
 
-       for (i = 0; i < NUM_DCR; i++) {
+       for (i = 0; i < t->num_dcr; i++) {
                t->dcr[i] = test_alloc(t, LABEL_SIZE, &t->dcr_dma[i]);
                if (!t->dcr[i])
                        return -ENOMEM;
@@ -728,6 +730,7 @@ static int nfit_test1_alloc(struct nfit_test *t)
        size_t nfit_size = sizeof(struct acpi_nfit_system_address) * 2
                + sizeof(struct acpi_nfit_memory_map)
                + offsetof(struct acpi_nfit_control_region, window_size);
+       int i;
 
        t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma);
        if (!t->nfit_buf)
@@ -738,6 +741,13 @@ static int nfit_test1_alloc(struct nfit_test *t)
        if (!t->spa_set[0])
                return -ENOMEM;
 
+       for (i = 0; i < t->num_dcr; i++) {
+               t->label[i] = test_alloc(t, LABEL_SIZE, &t->label_dma[i]);
+               if (!t->label[i])
+                       return -ENOMEM;
+               sprintf(t->label[i], "label%d", i);
+       }
+
        t->spa_set[1] = test_alloc(t, SPA_VCD_SIZE, &t->spa_set_dma[1]);
        if (!t->spa_set[1])
                return -ENOMEM;
@@ -1450,7 +1460,7 @@ static void nfit_test1_setup(struct nfit_test *t)
        memdev = nfit_buf + offset;
        memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
        memdev->header.length = sizeof(*memdev);
-       memdev->device_handle = 0;
+       memdev->device_handle = handle[5];
        memdev->physical_id = 0;
        memdev->region_id = 0;
        memdev->range_index = 0+1;
@@ -1472,7 +1482,7 @@ static void nfit_test1_setup(struct nfit_test *t)
                        window_size);
        dcr->region_index = 0+1;
        dcr_common_init(dcr);
-       dcr->serial_number = ~0;
+       dcr->serial_number = ~handle[5];
        dcr->code = NFIT_FIC_BYTE;
        dcr->windows = 0;
 
@@ -1483,6 +1493,9 @@ static void nfit_test1_setup(struct nfit_test *t)
        set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en);
        set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en);
        set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en);
+       set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en);
+       set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en);
+       set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en);
 }
 
 static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa,
@@ -1886,12 +1899,15 @@ static __init int nfit_test_init(void)
                switch (i) {
                case 0:
                        nfit_test->num_pm = NUM_PM;
+                       nfit_test->dcr_idx = 0;
                        nfit_test->num_dcr = NUM_DCR;
                        nfit_test->alloc = nfit_test0_alloc;
                        nfit_test->setup = nfit_test0_setup;
                        break;
                case 1:
                        nfit_test->num_pm = 1;
+                       nfit_test->dcr_idx = NUM_DCR;
+                       nfit_test->num_dcr = 1;
                        nfit_test->alloc = nfit_test1_alloc;
                        nfit_test->setup = nfit_test1_setup;
                        break;
index 0103bf2e0c0d046ea6ff6a2f76af333e5e2d6ae4..853d7e43434acaeb2eddab46c48a64e98701864e 100644 (file)
@@ -1059,7 +1059,7 @@ static struct bpf_test tests[] = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "unknown func 6",
+               .errstr_unpriv = "unknown func bpf_trace_printk#6",
                .result_unpriv = REJECT,
                .result = ACCEPT,
        },
@@ -2660,6 +2660,34 @@ static struct bpf_test tests[] = {
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS
        },
+       {
+               "multiple registers share map_lookup_elem bad reg type",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_1, 10),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
+                       BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_0),
+                       BPF_MOV64_REG(BPF_REG_5, BPF_REG_0),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+                       BPF_MOV64_IMM(BPF_REG_1, 1),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+                       BPF_MOV64_IMM(BPF_REG_1, 2),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_3, 0, 1),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_1, 3),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 4 },
+               .result = REJECT,
+               .errstr = "R3 invalid mem access 'inv'",
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS
+       },
        {
                "invalid map access from else condition",
                .insns = {