Merge branch 'for-linus' of git://git.kernel.dk/linux-block
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Dec 2016 18:23:39 +0000 (10:23 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Dec 2016 18:23:39 +0000 (10:23 -0800)
Pull block layer fixes from Jens Axboe:
 "Just a set of small fixes that have either been queued up after the
  original pull for this merge window, or just missed the original pull
  request.

   - a few bcache fixes/changes from Eric and Kent

   - add WRITE_SAME to the command filter whitelist frm Mauricio

   - kill an unused struct member from Ritesh

   - partition IO alignment fix from Stefan

   - nvme sysfs printf fix from Stephen"

* 'for-linus' of git://git.kernel.dk/linux-block:
  block: check partition alignment
  nvme : Use correct scnprintf in cmb show
  block: allow WRITE_SAME commands with the SG_IO ioctl
  block: Remove unused member (busy) from struct blk_queue_tag
  bcache: partition support: add 16 minors per bcacheN device
  bcache: Make gc wakeup sane, remove set_task_state()

727 files changed:
CREDITS
Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/DocBook/Makefile
Documentation/DocBook/crypto-API.tmpl [deleted file]
Documentation/admin-guide/kernel-parameters.txt
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/mmc/sdhci-cadence.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/net/hisilicon-hix5hd2-gmac.txt
Documentation/devicetree/bindings/net/phy.txt
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
Documentation/x86/intel_rdt_ui.txt [new file with mode: 0644]
MAINTAINERS
arch/Kconfig
arch/arm/boot/dts/hisi-x5hd2.dtsi
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/acpi.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/numa.h
arch/arm64/kernel/acpi.c
arch/arm64/kernel/setup.c
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/parisc/Kconfig
arch/parisc/include/asm/elf.h
arch/parisc/include/asm/pdcpat.h
arch/parisc/include/asm/processor.h
arch/parisc/kernel/entry.S
arch/parisc/kernel/firmware.c
arch/parisc/kernel/inventory.c
arch/parisc/kernel/perf.c
arch/parisc/kernel/process.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/sys_parisc.c
arch/parisc/kernel/time.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/ima.h [new file with mode: 0644]
arch/powerpc/include/asm/kexec.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/ima_kexec.c [new file with mode: 0644]
arch/powerpc/kernel/kexec_elf_64.c
arch/powerpc/kernel/machine_kexec_file_64.c
arch/powerpc/oprofile/cell/spu_task_sync.c
arch/powerpc/platforms/85xx/corenet_generic.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/events/intel/cqm.c
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/intel_rdt.h [new file with mode: 0644]
arch/x86/include/asm/intel_rdt_common.h [new file with mode: 0644]
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/Makefile
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/intel_rdt.c [new file with mode: 0644]
arch/x86/kernel/cpu/intel_rdt_rdtgroup.c [new file with mode: 0644]
arch/x86/kernel/cpu/intel_rdt_schemata.c [new file with mode: 0644]
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/head_64.S
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.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/acpica/actables.h
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbutils.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/bus.c
drivers/acpi/nfit/core.c
drivers/acpi/numa.c
drivers/acpi/osl.c
drivers/acpi/processor_core.c
drivers/acpi/scan.c
drivers/acpi/spcr.c
drivers/acpi/tables.c
drivers/base/cacheinfo.c
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/s3c64xx-cpufreq.c
drivers/dax/dax.c
drivers/dax/pmem.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-tps65218.c
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.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/gpu/drm/radeon/radeon_bios.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-octeon-core.c
drivers/i2c/busses/i2c-octeon-core.h
drivers/i2c/busses/i2c-xgene-slimpro.c
drivers/i2c/muxes/i2c-mux-mlxcpld.c
drivers/i2c/muxes/i2c-mux-pca954x.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/iommu/amd_iommu_init.c
drivers/iommu/dmar.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/mailbox/bcm-pdc-mailbox.c
drivers/mailbox/mailbox-sti.c
drivers/mailbox/mailbox-test.c
drivers/mailbox/pcc.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/mmc/core/core.c
drivers/mmc/core/sd.c
drivers/mmc/host/sdhci-cadence.c
drivers/mmc/host/sdhci.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/Kconfig
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/cavium/octeon/octeon_mgmt.c
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/freescale/fman/Kconfig
drivers/net/ethernet/freescale/fman/fman.c
drivers/net/ethernet/freescale/fman/mac.c
drivers/net/ethernet/hisilicon/hip04_eth.c
drivers/net/ethernet/hisilicon/hisi_femac.c
drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/mellanox/mlx5/core/fs_counters.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/Kconfig
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/mcdi_port.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/netcp_ethss.c
drivers/net/gtp.c
drivers/net/irda/w83977af_ir.c
drivers/net/phy/phy_device.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/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/staging/lustre/lustre/llite/symlink.c
drivers/target/iscsi/cxgbit/cxgbit_target.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target.h
drivers/target/iscsi/iscsi_target_auth.c
drivers/target/iscsi/iscsi_target_auth.h
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_datain_values.c
drivers/target/iscsi/iscsi_target_datain_values.h
drivers/target/iscsi/iscsi_target_device.h
drivers/target/iscsi/iscsi_target_erl0.h
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_erl1.h
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/iscsi/iscsi_target_erl2.h
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_login.h
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_nego.h
drivers/target/iscsi/iscsi_target_nodeattrib.h
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_parameters.h
drivers/target/iscsi/iscsi_target_seq_pdu_list.h
drivers/target/iscsi/iscsi_target_tmr.h
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/iscsi/iscsi_target_tpg.h
drivers/target/iscsi/iscsi_target_transport.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
drivers/target/loopback/tcm_loop.h
drivers/target/sbp/sbp_target.c
drivers/target/target_core_alua.c
drivers/target/target_core_alua.h
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_file.c
drivers/target/target_core_file.h
drivers/target/target_core_iblock.h
drivers/target/target_core_internal.h
drivers/target/target_core_pr.c
drivers/target/target_core_pr.h
drivers/target/target_core_pscsi.h
drivers/target/target_core_rd.c
drivers/target/target_core_rd.h
drivers/target/target_core_sbc.c
drivers/target/target_core_ua.h
drivers/target/target_core_user.c
drivers/target/target_core_xcopy.c
drivers/target/target_core_xcopy.h
drivers/target/tcm_fc/tcm_fc.h
drivers/usb/gadget/function/f_tcm.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/dir.c
fs/nfs/file.c
fs/nfs/filelayout/filelayoutdev.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/flexfilelayout/flexfilelayoutdev.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/pnfs.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/splice.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/acpi/acpi_io.h
include/acpi/acpixf.h
include/acpi/actbl.h
include/acpi/platform/aclinuxex.h
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/dt-bindings/net/mdio.h [deleted file]
include/linux/audit.h
include/linux/bpf-cgroup.h
include/linux/bpf.h
include/linux/cacheinfo.h
include/linux/configfs.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/ima.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/nfs_fs.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/ratelimit.h
include/linux/rmi.h
include/linux/sched.h
include/net/inet6_connection_sock.h
include/net/inet_connection_sock.h
include/net/netlink.h
include/target/iscsi/iscsi_target_core.h
include/target/iscsi/iscsi_target_stat.h
include/target/iscsi/iscsi_transport.h
include/target/target_core_backend.h
include/target/target_core_base.h
include/target/target_core_fabric.h
include/uapi/linux/magic.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/kcov.c
kernel/kexec_file.c
kernel/time/tick-broadcast.c
lib/Kconfig.debug
mm/fadvise.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/ipv4/ip_output.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/openvswitch/flow_netlink.c
net/rds/rdma.c
net/sched/cls_flower.c
net/sched/sch_fq.c
net/sched/sch_netem.c
net/sctp/bind_addr.c
net/sctp/endpointola.c
net/sctp/protocol.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
scripts/selinux/genheaders/Makefile
scripts/selinux/genheaders/genheaders.c
scripts/selinux/mdp/Makefile
scripts/selinux/mdp/mdp.c
security/integrity/ima/Kconfig
security/integrity/ima/Makefile
security/integrity/ima/ima.h
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_kexec.c [new file with mode: 0644]
security/integrity/ima/ima_main.c
security/integrity/ima/ima_queue.c
security/integrity/ima/ima_template.c
security/integrity/ima/ima_template_lib.c
security/selinux/include/classmap.h
sound/usb/endpoint.c
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

diff --git a/CREDITS b/CREDITS
index 10a9eee807b6315540ed15062c811b8b6a7315c5..c58560701d13158f535046c09fd4b825922ced94 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -3949,8 +3949,6 @@ E: gwingerde@gmail.com
 D: Ralink rt2x00 WLAN driver
 D: Minix V2 file-system
 D: Misc fixes
-S: Geessinkweg 177
-S: 7544 TX Enschede
 S: The Netherlands
 
 N: Lars Wirzenius
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 49874173705507f72fac2f5f55da46fc34c3cc52..2a4a423d08e0d3ed8bce7cc0c9bcd36bb30bb19d 100644 (file)
@@ -272,6 +272,22 @@ Description:       Parameters for the CPU cache attributes
                                     the modified cache line is written to main
                                     memory only when it is replaced
 
+
+What:          /sys/devices/system/cpu/cpu*/cache/index*/id
+Date:          September 2016
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+Description:   Cache id
+
+               The id provides a unique number for a specific instance of
+               a cache of a particular type. E.g. there may be a level
+               3 unified cache on each socket in a server and we may
+               assign them ids 0, 1, 2, ...
+
+               Note that id value can be non-contiguous. E.g. level 1
+               caches typically exist per core, but there may not be a
+               power of two cores on a socket, so these caches may be
+               numbered 0, 1, 2, 3, 4, 5, 8, 9, 10, ...
+
 What:          /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats
                /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/turbo_stat
                /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/sub_turbo_stat
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>
index be2d6d0a03a486c340c85ed7ba73c59b22a6d41f..21e2d88637050b7a33f141e558fff43d3f23d0c9 100644 (file)
                        The builtin appraise policy appraises all files
                        owned by uid=0.
 
+       ima_canonical_fmt [IMA]
+                       Use the canonical format for the binary runtime
+                       measurements, instead of host native format.
+
        ima_hash=       [IMA]
                        Format: { md5 | sha1 | rmd160 | sha256 | sha384
                                   | sha512 | ... }
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
 
index 750374fc9d945d39f4426e22eed96532e3ba3e9f..c0f37cb41a9b47516f29cafa573d7886d103a2a7 100644 (file)
@@ -1,7 +1,9 @@
 * Cadence SD/SDIO/eMMC Host Controller
 
 Required properties:
-- compatible: should be "cdns,sd4hc".
+- compatible: should be one of the following:
+    "cdns,sd4hc"               - default of the IP
+    "socionext,uniphier-sd4hc" - for Socionext UniPhier SoCs
 - reg: offset and length of the register set for the device.
 - interrupts: a single interrupt specifier.
 - clocks: phandle to the input clock.
@@ -19,7 +21,7 @@ if supported.  See mmc.txt for details.
 
 Example:
        emmc: sdhci@5a000000 {
-               compatible = "cdns,sd4hc";
+               compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc";
                reg = <0x5a000000 0x400>;
                interrupts = <0 78 4>;
                clocks = <&clk 4>;
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 063c02da018a6d5ca24e5a58329b1dee0c1b5c0a..eea73adc678f963888c3171006516272abd37f62 100644 (file)
@@ -2,11 +2,14 @@ Hisilicon hix5hd2 gmac controller
 
 Required properties:
 - compatible: should contain one of the following SoC strings:
-       * "hisilicon,hix5hd2-gemac"
-       * "hisilicon,hi3798cv200-gemac"
+       * "hisilicon,hix5hd2-gmac"
+       * "hisilicon,hi3798cv200-gmac"
+       * "hisilicon,hi3516a-gmac"
        and one of the following version string:
-       * "hisilicon,hisi-gemac-v1"
-       * "hisilicon,hisi-gemac-v2"
+       * "hisilicon,hisi-gmac-v1"
+       * "hisilicon,hisi-gmac-v2"
+  The version v1 includes SoCs hix5hd2.
+  The version v2 includes SoCs hi3798cv200, hi3516a.
 - reg: specifies base physical address(s) and size of the device registers.
   The first region is the MAC register base and size.
   The second region is external interface control register.
@@ -35,7 +38,7 @@ Required properties:
 
 Example:
        gmac0: ethernet@f9840000 {
-               compatible = "hisilicon,hi3798cv200-gemac", "hisilicon,hisi-gemac-v2";
+               compatible = "hisilicon,hi3798cv200-gmac", "hisilicon,hisi-gmac-v2";
                reg = <0xf9840000 0x1000>,<0xf984300c 0x4>;
                interrupts = <0 71 4>;
                #address-cells = <1>;
index 54749b60a4666adb70514674761fd1031320376b..ff1bc4b1bb3b5e1d91a1747fcc73c24d587cd1a8 100644 (file)
@@ -38,8 +38,14 @@ Optional Properties:
 - enet-phy-lane-swap: If set, indicates the PHY will swap the TX/RX lanes to
   compensate for the board being designed with the lanes swapped.
 
-- eee-broken-modes: Bits to clear in the MDIO_AN_EEE_ADV register to
-  disable EEE broken modes.
+- eee-broken-100tx:
+- eee-broken-1000t:
+- eee-broken-10gt:
+- eee-broken-1000kx:
+- eee-broken-10gkx4:
+- eee-broken-10gkr:
+  Mark the corresponding energy efficient ethernet mode as broken and
+  request the ethernet to stop advertising it.
 
 Example:
 
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
 ------------
diff --git a/Documentation/x86/intel_rdt_ui.txt b/Documentation/x86/intel_rdt_ui.txt
new file mode 100644 (file)
index 0000000..d918d26
--- /dev/null
@@ -0,0 +1,214 @@
+User Interface for Resource Allocation in Intel Resource Director Technology
+
+Copyright (C) 2016 Intel Corporation
+
+Fenghua Yu <fenghua.yu@intel.com>
+Tony Luck <tony.luck@intel.com>
+
+This feature is enabled by the CONFIG_INTEL_RDT_A Kconfig and the
+X86 /proc/cpuinfo flag bits "rdt", "cat_l3" and "cdp_l3".
+
+To use the feature mount the file system:
+
+ # mount -t resctrl resctrl [-o cdp] /sys/fs/resctrl
+
+mount options are:
+
+"cdp": Enable code/data prioritization in L3 cache allocations.
+
+
+Info directory
+--------------
+
+The 'info' directory contains information about the enabled
+resources. Each resource has its own subdirectory. The subdirectory
+names reflect the resource names. Each subdirectory contains the
+following files:
+
+"num_closids":  The number of CLOSIDs which are valid for this
+               resource. The kernel uses the smallest number of
+               CLOSIDs of all enabled resources as limit.
+
+"cbm_mask":     The bitmask which is valid for this resource. This
+               mask is equivalent to 100%.
+
+"min_cbm_bits": The minimum number of consecutive bits which must be
+               set when writing a mask.
+
+
+Resource groups
+---------------
+Resource groups are represented as directories in the resctrl file
+system. The default group is the root directory. Other groups may be
+created as desired by the system administrator using the "mkdir(1)"
+command, and removed using "rmdir(1)".
+
+There are three files associated with each group:
+
+"tasks": A list of tasks that belongs to this group. Tasks can be
+       added to a group by writing the task ID to the "tasks" file
+       (which will automatically remove them from the previous
+       group to which they belonged). New tasks created by fork(2)
+       and clone(2) are added to the same group as their parent.
+       If a pid is not in any sub partition, it is in root partition
+       (i.e. default partition).
+
+"cpus": A bitmask of logical CPUs assigned to this group. Writing
+       a new mask can add/remove CPUs from this group. Added CPUs
+       are removed from their previous group. Removed ones are
+       given to the default (root) group. You cannot remove CPUs
+       from the default group.
+
+"schemata": A list of all the resources available to this group.
+       Each resource has its own line and format - see below for
+       details.
+
+When a task is running the following rules define which resources
+are available to it:
+
+1) If the task is a member of a non-default group, then the schemata
+for that group is used.
+
+2) Else if the task belongs to the default group, but is running on a
+CPU that is assigned to some specific group, then the schemata for
+the CPU's group is used.
+
+3) Otherwise the schemata for the default group is used.
+
+
+Schemata files - general concepts
+---------------------------------
+Each line in the file describes one resource. The line starts with
+the name of the resource, followed by specific values to be applied
+in each of the instances of that resource on the system.
+
+Cache IDs
+---------
+On current generation systems there is one L3 cache per socket and L2
+caches are generally just shared by the hyperthreads on a core, but this
+isn't an architectural requirement. We could have multiple separate L3
+caches on a socket, multiple cores could share an L2 cache. So instead
+of using "socket" or "core" to define the set of logical cpus sharing
+a resource we use a "Cache ID". At a given cache level this will be a
+unique number across the whole system (but it isn't guaranteed to be a
+contiguous sequence, there may be gaps).  To find the ID for each logical
+CPU look in /sys/devices/system/cpu/cpu*/cache/index*/id
+
+Cache Bit Masks (CBM)
+---------------------
+For cache resources we describe the portion of the cache that is available
+for allocation using a bitmask. The maximum value of the mask is defined
+by each cpu model (and may be different for different cache levels). It
+is found using CPUID, but is also provided in the "info" directory of
+the resctrl file system in "info/{resource}/cbm_mask". X86 hardware
+requires that these masks have all the '1' bits in a contiguous block. So
+0x3, 0x6 and 0xC are legal 4-bit masks with two bits set, but 0x5, 0x9
+and 0xA are not.  On a system with a 20-bit mask each bit represents 5%
+of the capacity of the cache. You could partition the cache into four
+equal parts with masks: 0x1f, 0x3e0, 0x7c00, 0xf8000.
+
+
+L3 details (code and data prioritization disabled)
+--------------------------------------------------
+With CDP disabled the L3 schemata format is:
+
+       L3:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+L3 details (CDP enabled via mount option to resctrl)
+----------------------------------------------------
+When CDP is enabled L3 control is split into two separate resources
+so you can specify independent masks for code and data like this:
+
+       L3data:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+       L3code:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+L2 details
+----------
+L2 cache does not support code and data prioritization, so the
+schemata format is always:
+
+       L2:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+Example 1
+---------
+On a two socket machine (one L3 cache per socket) with just four bits
+for cache bit masks
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+# mkdir p0 p1
+# echo "L3:0=3;1=c" > /sys/fs/resctrl/p0/schemata
+# echo "L3:0=3;1=3" > /sys/fs/resctrl/p1/schemata
+
+The default resource group is unmodified, so we have access to all parts
+of all caches (its schemata file reads "L3:0=f;1=f").
+
+Tasks that are under the control of group "p0" may only allocate from the
+"lower" 50% on cache ID 0, and the "upper" 50% of cache ID 1.
+Tasks in group "p1" use the "lower" 50% of cache on both sockets.
+
+Example 2
+---------
+Again two sockets, but this time with a more realistic 20-bit mask.
+
+Two real time tasks pid=1234 running on processor 0 and pid=5678 running on
+processor 1 on socket 0 on a 2-socket and dual core machine. To avoid noisy
+neighbors, each of the two real-time tasks exclusively occupies one quarter
+of L3 cache on socket 0.
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+
+First we reset the schemata for the default group so that the "upper"
+50% of the L3 cache on socket 0 cannot be used by ordinary tasks:
+
+# echo "L3:0=3ff;1=fffff" > schemata
+
+Next we make a resource group for our first real time task and give
+it access to the "top" 25% of the cache on socket 0.
+
+# mkdir p0
+# echo "L3:0=f8000;1=fffff" > p0/schemata
+
+Finally we move our first real time task into this resource group. We
+also use taskset(1) to ensure the task always runs on a dedicated CPU
+on socket 0. Most uses of resource groups will also constrain which
+processors tasks run on.
+
+# echo 1234 > p0/tasks
+# taskset -cp 1 1234
+
+Ditto for the second real time task (with the remaining 25% of cache):
+
+# mkdir p1
+# echo "L3:0=7c00;1=fffff" > p1/schemata
+# echo 5678 > p1/tasks
+# taskset -cp 2 5678
+
+Example 3
+---------
+
+A single socket system which has real-time tasks running on core 4-7 and
+non real-time workload assigned to core 0-3. The real-time tasks share text
+and data, so a per task association is not required and due to interaction
+with the kernel it's desired that the kernel on these cores shares L3 with
+the tasks.
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+
+First we reset the schemata for the default group so that the "upper"
+50% of the L3 cache on socket 0 cannot be used by ordinary tasks:
+
+# echo "L3:0=3ff" > schemata
+
+Next we make a resource group for our real time cores and give
+it access to the "top" 50% of the cache on socket 0.
+
+# mkdir p0
+# echo "L3:0=ffc00;" > p0/schemata
+
+Finally we move core 4-7 over to the new group and make sure that the
+kernel and the tasks running there get 50% of the cache.
+
+# echo C0 > p0/cpus
index bf8690d0a1e190f64fbd5e6beffbdc1ad91fad3c..7c21c7638bb5c2570735b7d9b331f937ab298d4c 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>
@@ -10321,6 +10327,14 @@ L:     linux-rdma@vger.kernel.org
 S:     Supported
 F:     drivers/infiniband/sw/rdmavt
 
+RDT - RESOURCE ALLOCATION
+M:     Fenghua Yu <fenghua.yu@intel.com>
+L:     linux-kernel@vger.kernel.org
+S:     Supported
+F:     arch/x86/kernel/cpu/intel_rdt*
+F:     arch/x86/include/asm/intel_rdt*
+F:     Documentation/x86/intel_rdt*
+
 READ-COPY UPDATE (RCU)
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 M:     Josh Triplett <josh@joshtriplett.org>
index 19483aea4bbc9e15b51f0bc7f200880902794a74..99839c23d453fa8ded2061968aead8a6ee4b2317 100644 (file)
@@ -5,6 +5,9 @@
 config KEXEC_CORE
        bool
 
+config HAVE_IMA_KEXEC
+       bool
+
 config OPROFILE
        tristate "OProfile system profiling"
        depends on PROFILING
index c02e092fad8b17bf8c8e80c29b218db7ba86ea46..6c712a97e1fef042b00c8fe55d406e78285b973e 100644 (file)
                };
 
                gmac0: ethernet@1840000 {
-                       compatible = "hisilicon,hix5hd2-gemac", "hisilicon,hisi-gemac-v1";
+                       compatible = "hisilicon,hix5hd2-gmac", "hisilicon,hisi-gmac-v1";
                        reg = <0x1840000 0x1000>,<0x184300c 0x4>;
                        interrupts = <0 71 4>;
                        clocks = <&clock HIX5HD2_MAC0_CLK>;
                };
 
                gmac1: ethernet@1841000 {
-                       compatible = "hisilicon,hix5hd2-gemac", "hisilicon,hisi-gemac-v1";
+                       compatible = "hisilicon,hix5hd2-gmac", "hisilicon,hisi-gmac-v1";
                        reg = <0x1841000 0x1000>,<0x1843010 0x4>;
                        interrupts = <0 72 4>;
                        clocks = <&clock HIX5HD2_MAC1_CLK>;
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 d0de0e032bc2c689f849ee679754f7b18d9451c3..c1976c0adca73025ec4526fc40be077101f8ef62 100644 (file)
@@ -29,7 +29,7 @@
 
 /* Basic configuration for ACPI */
 #ifdef CONFIG_ACPI
-/* ACPI table mapping after acpi_gbl_permanent_mmap is set */
+/* ACPI table mapping after acpi_permanent_mmap is set */
 static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
                                            acpi_size size)
 {
index b71086d251954f7b72837899346525322dc5d724..bfe632808d7724c0a51562efb60501e67f6bf157 100644 (file)
@@ -165,6 +165,11 @@ extern u64                 kimage_vaddr;
 /* the offset between the kernel virtual and physical mappings */
 extern u64                     kimage_voffset;
 
+static inline unsigned long kaslr_offset(void)
+{
+       return kimage_vaddr - KIMAGE_VADDR;
+}
+
 /*
  * Allow all memory at the discovery stage. We will clip it later.
  */
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 252a6d9c1da5d7868fffd23ec6ed93a95944c91d..64d9cbd61678233dc24648f11bb5b242df3ee244 100644 (file)
@@ -132,14 +132,13 @@ static int __init acpi_fadt_sanity_check(void)
        struct acpi_table_header *table;
        struct acpi_table_fadt *fadt;
        acpi_status status;
-       acpi_size tbl_size;
        int ret = 0;
 
        /*
         * FADT is required on arm64; retrieve it to check its presence
         * and carry out revision and ACPI HW reduced compliancy tests
         */
-       status = acpi_get_table_with_size(ACPI_SIG_FADT, 0, &table, &tbl_size);
+       status = acpi_get_table(ACPI_SIG_FADT, 0, &table);
        if (ACPI_FAILURE(status)) {
                const char *msg = acpi_format_exception(status);
 
@@ -170,10 +169,10 @@ static int __init acpi_fadt_sanity_check(void)
 
 out:
        /*
-        * acpi_get_table_with_size() creates FADT table mapping that
+        * acpi_get_table() creates FADT table mapping that
         * should be released after parsing and before resuming boot
         */
-       early_acpi_os_unmap_memory(table, tbl_size);
+       acpi_put_table(table);
        return ret;
 }
 
index a53f52ac81c62ad4e6e70056949d143f7de4bfd4..b051367e21491cada86f115f4386fda8aace299a 100644 (file)
@@ -338,11 +338,11 @@ subsys_initcall(topology_init);
 static int dump_kernel_offset(struct notifier_block *self, unsigned long v,
                              void *p)
 {
-       u64 const kaslr_offset = kimage_vaddr - KIMAGE_VADDR;
+       const unsigned long offset = kaslr_offset();
 
-       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset > 0) {
-               pr_emerg("Kernel Offset: 0x%llx from 0x%lx\n",
-                        kaslr_offset, KIMAGE_VADDR);
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && offset > 0) {
+               pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n",
+                        offset, KIMAGE_VADDR);
        } else {
                pr_emerg("Kernel Offset: disabled\n");
        }
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 a14b865870131a052c995fed98cc9e3ed7a3cd2d..3a71f38cdc0553eeb8c026b2b12d3b412e2f2657 100644 (file)
@@ -7,6 +7,7 @@ config PARISC
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_SYSCALL_TRACEPOINTS
        select ARCH_WANT_FRAME_POINTERS
+       select ARCH_HAS_ELF_RANDOMIZE
        select RTC_CLASS
        select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
index 78c9fd32c5546b6ec91d591e853d89a761383c92..a6b2a421571edfb5f981e1558d75525a23a59404 100644 (file)
@@ -348,9 +348,10 @@ struct pt_regs;    /* forward declaration... */
 
 #define ELF_HWCAP      0
 
-#define STACK_RND_MASK (is_32bit_task() ? \
-                               0x7ff >> (PAGE_SHIFT - 12) : \
-                               0x3ffff >> (PAGE_SHIFT - 12))
+/* Masks for stack and mmap randomization */
+#define BRK_RND_MASK   (is_32bit_task() ? 0x07ffUL : 0x3ffffUL)
+#define MMAP_RND_MASK  (is_32bit_task() ? 0x1fffUL : 0x3ffffUL)
+#define STACK_RND_MASK MMAP_RND_MASK
 
 struct mm_struct;
 extern unsigned long arch_randomize_brk(struct mm_struct *);
index 47539f11795835e8397bb77602d8e82d99e14a3f..e1d289092705f00431408f90ca6bd48e47c8cba4 100644 (file)
@@ -289,7 +289,7 @@ extern int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info);
 extern int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod, unsigned long view_type, void *mem_addr);
 extern int pdc_pat_cell_num_to_loc(void *, unsigned long);
 
-extern int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa);
+extern int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, unsigned long hpa);
 
 extern int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, unsigned long count, unsigned long offset);
 
index ca40741378be76c70ecf718a7240e0b96c316530..a3661ee6b060c1d258ab740e5468cfffb665f8d5 100644 (file)
@@ -93,9 +93,7 @@ struct system_cpuinfo_parisc {
 /* Per CPU data structure - ie varies per CPU.  */
 struct cpuinfo_parisc {
        unsigned long it_value;     /* Interval Timer at last timer Intr */
-       unsigned long it_delta;     /* Interval delta (tic_10ms / HZ * 100) */
        unsigned long irq_count;    /* number of IRQ's since boot */
-       unsigned long irq_max_cr16; /* longest time to handle a single IRQ */
        unsigned long cpuid;        /* aka slot_number or set to NO_PROC_ID */
        unsigned long hpa;          /* Host Physical address */
        unsigned long txn_addr;     /* MMIO addr of EIR or id_eid */
@@ -103,8 +101,6 @@ struct cpuinfo_parisc {
        unsigned long pending_ipi;  /* bitmap of type ipi_message_type */
 #endif
        unsigned long bh_count;     /* number of times bh was invoked */
-       unsigned long prof_counter; /* per CPU profiling support */
-       unsigned long prof_multiplier;  /* per CPU profiling support */
        unsigned long fp_rev;
        unsigned long fp_model;
        unsigned int state;
index 4fcff2dcc9c304decddf7b7643e90f7803968531..ad4cb1613c57a56552e32d795d5d83fdffd99672 100644 (file)
@@ -878,6 +878,9 @@ ENTRY_CFI(syscall_exit_rfi)
        STREG   %r19,PT_SR7(%r16)
 
 intr_return:
+       /* NOTE: Need to enable interrupts incase we schedule. */
+       ssm     PSW_SM_I, %r0
+
        /* check for reschedule */
        mfctl   %cr30,%r1
        LDREG   TI_FLAGS(%r1),%r19      /* sched.h: TIF_NEED_RESCHED */
@@ -904,11 +907,6 @@ intr_check_sig:
        LDREG   PT_IASQ1(%r16), %r20
        cmpib,COND(=),n 0,%r20,intr_restore /* backward */
 
-       /* NOTE: We need to enable interrupts if we have to deliver
-        * signals. We used to do this earlier but it caused kernel
-        * stack overflows. */
-       ssm     PSW_SM_I, %r0
-
        copy    %r0, %r25                       /* long in_syscall = 0 */
 #ifdef CONFIG_64BIT
        ldo     -16(%r30),%r29                  /* Reference param save area */
@@ -960,10 +958,6 @@ intr_do_resched:
        cmpib,COND(=)   0, %r20, intr_do_preempt
        nop
 
-       /* NOTE: We need to enable interrupts if we schedule.  We used
-        * to do this earlier but it caused kernel stack overflows. */
-       ssm     PSW_SM_I, %r0
-
 #ifdef CONFIG_64BIT
        ldo     -16(%r30),%r29          /* Reference param save area */
 #endif
index e5d71905cad567cc03e22ffdeb7f7295d635b12b..9d797ae4fa22248665a13e0ff29d72532e9e4bdb 100644 (file)
@@ -1258,7 +1258,7 @@ int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long
  *
  * Retrieve the cpu number for the cpu at the specified HPA.
  */
-int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa)
+int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, unsigned long hpa)
 {
        int retval;
        unsigned long flags;
index c05d1876d27c4975453194686976c6cb0147531d..c9789d9c73b40478bb5ff931fd2c3afb30a4840f 100644 (file)
@@ -216,9 +216,9 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
        register_parisc_device(dev);    /* advertise device */
 
 #ifdef DEBUG_PAT
-       pdc_pat_cell_mod_maddr_block_t io_pdc_cell;
        /* dump what we see so far... */
        switch (PAT_GET_ENTITY(dev->mod_info)) {
+               pdc_pat_cell_mod_maddr_block_t io_pdc_cell;
                unsigned long i;
 
        case PAT_ENTITY_PROC:
@@ -259,9 +259,9 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
                                pa_pdc_cell->mod[4 + i * 3]);   /* finish (ie end) */
                        printk(KERN_DEBUG 
                                "  IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
-                               i, io_pdc_cell->mod[2 + i * 3], /* type */
-                               io_pdc_cell->mod[3 + i * 3],    /* start */
-                               io_pdc_cell->mod[4 + i * 3]);   /* finish (ie end) */
+                               i, io_pdc_cell.mod[2 + i * 3],  /* type */
+                               io_pdc_cell.mod[3 + i * 3],     /* start */
+                               io_pdc_cell.mod[4 + i * 3]);    /* finish (ie end) */
                }
                printk(KERN_DEBUG "\n");
                break;
index 518f4f5f1f43ec6b2dcaceb9b2f5c9536097d59f..6eabce62463bbbcf29031143c46d7b75c841b6fa 100644 (file)
@@ -301,7 +301,6 @@ static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t
 static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, 
        loff_t *ppos)
 {
-       int err;
        size_t image_size;
        uint32_t image_type;
        uint32_t interface_type;
@@ -320,8 +319,8 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun
        if (count != sizeof(uint32_t))
                return -EIO;
 
-       if ((err = copy_from_user(&image_type, buf, sizeof(uint32_t))) != 0) 
-               return err;
+       if (copy_from_user(&image_type, buf, sizeof(uint32_t)))
+               return -EFAULT;
 
        /* Get the interface type and test type */
        interface_type = (image_type >> 16) & 0xffff;
index 40639439d8b35c7cec7c60d978ae6aa5b070b22f..ea6603ee8d24981abe93c5bc79477e626e54254a 100644 (file)
@@ -276,11 +276,7 @@ void *dereference_function_descriptor(void *ptr)
 
 static inline unsigned long brk_rnd(void)
 {
-       /* 8MB for 32bit, 1GB for 64bit */
-       if (is_32bit_task())
-               return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
-       else
-               return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT;
+       return (get_random_int() & BRK_RND_MASK) << PAGE_SHIFT;
 }
 
 unsigned long arch_randomize_brk(struct mm_struct *mm)
index 0c2a94a0f7518b8082ecda3f0307ead9534ea972..85de47f4eb594564bc9639ff76a099b5ff9aa8c7 100644 (file)
@@ -78,11 +78,6 @@ DEFINE_PER_CPU(struct cpuinfo_parisc, cpu_data);
 static void
 init_percpu_prof(unsigned long cpunum)
 {
-       struct cpuinfo_parisc *p;
-
-       p = &per_cpu(cpu_data, cpunum);
-       p->prof_counter = 1;
-       p->prof_multiplier = 1;
 }
 
 
@@ -99,6 +94,7 @@ static int processor_probe(struct parisc_device *dev)
        unsigned long txn_addr;
        unsigned long cpuid;
        struct cpuinfo_parisc *p;
+       struct pdc_pat_cpu_num cpu_info __maybe_unused;
 
 #ifdef CONFIG_SMP
        if (num_online_cpus() >= nr_cpu_ids) {
@@ -123,10 +119,6 @@ static int processor_probe(struct parisc_device *dev)
                ulong status;
                unsigned long bytecnt;
                pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;
-#undef USE_PAT_CPUID
-#ifdef USE_PAT_CPUID
-               struct pdc_pat_cpu_num cpu_info;
-#endif
 
                pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL);
                if (!pa_pdc_cell)
@@ -145,22 +137,27 @@ static int processor_probe(struct parisc_device *dev)
 
                kfree(pa_pdc_cell);
 
+               /* get the cpu number */
+               status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa.start);
+               BUG_ON(PDC_OK != status);
+
+               pr_info("Logical CPU #%lu is physical cpu #%lu at location "
+                       "0x%lx with hpa %pa\n",
+                       cpuid, cpu_info.cpu_num, cpu_info.cpu_loc,
+                       &dev->hpa.start);
+
+#undef USE_PAT_CPUID
 #ifdef USE_PAT_CPUID
 /* We need contiguous numbers for cpuid. Firmware's notion
  * of cpuid is for physical CPUs and we just don't care yet.
  * We'll care when we need to query PAT PDC about a CPU *after*
  * boot time (ie shutdown a CPU from an OS perspective).
  */
-               /* get the cpu number */
-               status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa.start);
-
-               BUG_ON(PDC_OK != status);
-
                if (cpu_info.cpu_num >= NR_CPUS) {
-                       printk(KERN_WARNING "IGNORING CPU at 0x%x,"
+                       printk(KERN_WARNING "IGNORING CPU at %pa,"
                                " cpu_slot_id > NR_CPUS"
                                " (%ld > %d)\n",
-                               dev->hpa.start, cpu_info.cpu_num, NR_CPUS);
+                               &dev->hpa.start, cpu_info.cpu_num, NR_CPUS);
                        /* Ignore CPU since it will only crash */
                        boot_cpu_data.cpu_count--;
                        return 1;
index 0a393a04e89182cba498fa64774dd32177860eb7..a81e177cac7be0c7d1d0f86f0a871d350fea5fdc 100644 (file)
@@ -225,19 +225,17 @@ static unsigned long mmap_rnd(void)
 {
        unsigned long rnd = 0;
 
-       /*
-       *  8 bits of randomness in 32bit mmaps, 20 address space bits
-       * 28 bits of randomness in 64bit mmaps, 40 address space bits
-       */
-       if (current->flags & PF_RANDOMIZE) {
-               if (is_32bit_task())
-                       rnd = get_random_int() % (1<<8);
-               else
-                       rnd = get_random_int() % (1<<28);
-       }
+       if (current->flags & PF_RANDOMIZE)
+               rnd = get_random_int() & MMAP_RND_MASK;
+
        return rnd << PAGE_SHIFT;
 }
 
+unsigned long arch_mmap_rnd(void)
+{
+       return (get_random_int() & MMAP_RND_MASK) << PAGE_SHIFT;
+}
+
 static unsigned long mmap_legacy_base(void)
 {
        return TASK_UNMAPPED_BASE + mmap_rnd();
index 325f30d82b6434368425d652402fabf66fd4f8ee..4215f5596c8b6291516a9d39190e77df1b2bf488 100644 (file)
@@ -59,10 +59,9 @@ static unsigned long clocktick __read_mostly;        /* timer cycles per tick */
  */
 irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 {
-       unsigned long now, now2;
+       unsigned long now;
        unsigned long next_tick;
-       unsigned long cycles_elapsed, ticks_elapsed = 1;
-       unsigned long cycles_remainder;
+       unsigned long ticks_elapsed = 0;
        unsigned int cpu = smp_processor_id();
        struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu);
 
@@ -71,102 +70,49 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 
        profile_tick(CPU_PROFILING);
 
-       /* Initialize next_tick to the expected tick time. */
+       /* Initialize next_tick to the old expected tick time. */
        next_tick = cpuinfo->it_value;
 
-       /* Get current cycle counter (Control Register 16). */
-       now = mfctl(16);
-
-       cycles_elapsed = now - next_tick;
-
-       if ((cycles_elapsed >> 6) < cpt) {
-               /* use "cheap" math (add/subtract) instead
-                * of the more expensive div/mul method
-                */
-               cycles_remainder = cycles_elapsed;
-               while (cycles_remainder > cpt) {
-                       cycles_remainder -= cpt;
-                       ticks_elapsed++;
-               }
-       } else {
-               /* TODO: Reduce this to one fdiv op */
-               cycles_remainder = cycles_elapsed % cpt;
-               ticks_elapsed += cycles_elapsed / cpt;
-       }
-
-       /* convert from "division remainder" to "remainder of clock tick" */
-       cycles_remainder = cpt - cycles_remainder;
-
-       /* Determine when (in CR16 cycles) next IT interrupt will fire.
-        * We want IT to fire modulo clocktick even if we miss/skip some.
-        * But those interrupts don't in fact get delivered that regularly.
-        */
-       next_tick = now + cycles_remainder;
+       /* Calculate how many ticks have elapsed. */
+       do {
+               ++ticks_elapsed;
+               next_tick += cpt;
+               now = mfctl(16);
+       } while (next_tick - now > cpt);
 
+       /* Store (in CR16 cycles) up to when we are accounting right now. */
        cpuinfo->it_value = next_tick;
 
-       /* Program the IT when to deliver the next interrupt.
-        * Only bottom 32-bits of next_tick are writable in CR16!
-        */
-       mtctl(next_tick, 16);
+       /* Go do system house keeping. */
+       if (cpu == 0)
+               xtime_update(ticks_elapsed);
+
+       update_process_times(user_mode(get_irq_regs()));
 
-       /* Skip one clocktick on purpose if we missed next_tick.
+       /* Skip clockticks on purpose if we know we would miss those.
         * The new CR16 must be "later" than current CR16 otherwise
         * itimer would not fire until CR16 wrapped - e.g 4 seconds
         * later on a 1Ghz processor. We'll account for the missed
-        * tick on the next timer interrupt.
+        * ticks on the next timer interrupt.
+        * We want IT to fire modulo clocktick even if we miss/skip some.
+        * But those interrupts don't in fact get delivered that regularly.
         *
         * "next_tick - now" will always give the difference regardless
         * if one or the other wrapped. If "now" is "bigger" we'll end up
         * with a very large unsigned number.
         */
-       now2 = mfctl(16);
-       if (next_tick - now2 > cpt)
-               mtctl(next_tick+cpt, 16);
+       while (next_tick - mfctl(16) > cpt)
+               next_tick += cpt;
 
-#if 1
-/*
- * GGG: DEBUG code for how many cycles programming CR16 used.
- */
-       if (unlikely(now2 - now > 0x3000))      /* 12K cycles */
-               printk (KERN_CRIT "timer_interrupt(CPU %d): SLOW! 0x%lx cycles!"
-                       " cyc %lX rem %lX "
-                       " next/now %lX/%lX\n",
-                       cpu, now2 - now, cycles_elapsed, cycles_remainder,
-                       next_tick, now );
-#endif
-
-       /* Can we differentiate between "early CR16" (aka Scenario 1) and
-        * "long delay" (aka Scenario 3)? I don't think so.
-        *
-        * Timer_interrupt will be delivered at least a few hundred cycles
-        * after the IT fires. But it's arbitrary how much time passes
-        * before we call it "late". I've picked one second.
-        *
-        * It's important NO printk's are between reading CR16 and
-        * setting up the next value. May introduce huge variance.
-        */
-       if (unlikely(ticks_elapsed > HZ)) {
-               /* Scenario 3: very long delay?  bad in any case */
-               printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
-                       " cycles %lX rem %lX "
-                       " next/now %lX/%lX\n",
-                       cpu,
-                       cycles_elapsed, cycles_remainder,
-                       next_tick, now );
-       }
-
-       /* Done mucking with unreliable delivery of interrupts.
-        * Go do system house keeping.
+       /* Program the IT when to deliver the next interrupt.
+        * Only bottom 32-bits of next_tick are writable in CR16!
+        * Timer interrupt will be delivered at least a few hundred cycles
+        * after the IT fires, so if we are too close (<= 500 cycles) to the
+        * next cycle, simply skip it.
         */
-
-       if (!--cpuinfo->prof_counter) {
-               cpuinfo->prof_counter = cpuinfo->prof_multiplier;
-               update_process_times(user_mode(get_irq_regs()));
-       }
-
-       if (cpu == 0)
-               xtime_update(ticks_elapsed);
+       if (next_tick - mfctl(16) <= 500)
+               next_tick += cpt;
+       mtctl(next_tick, 16);
 
        return IRQ_HANDLED;
 }
index 3da87e19887827f55f14bd47bca849bdc9a14492..a8ee573fe610bd5e2d8191b4dffb05e134a6d3c2 100644 (file)
@@ -469,6 +469,7 @@ config KEXEC
 config KEXEC_FILE
        bool "kexec file based system call"
        select KEXEC_CORE
+       select HAVE_IMA_KEXEC
        select BUILD_BIN2C
        depends on PPC64
        depends on CRYPTO=y
diff --git a/arch/powerpc/include/asm/ima.h b/arch/powerpc/include/asm/ima.h
new file mode 100644 (file)
index 0000000..2313bdf
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _ASM_POWERPC_IMA_H
+#define _ASM_POWERPC_IMA_H
+
+struct kimage;
+
+int ima_get_kexec_buffer(void **addr, size_t *size);
+int ima_free_kexec_buffer(void);
+
+#ifdef CONFIG_IMA
+void remove_ima_buffer(void *fdt, int chosen_node);
+#else
+static inline void remove_ima_buffer(void *fdt, int chosen_node) {}
+#endif
+
+#ifdef CONFIG_IMA_KEXEC
+int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
+                             size_t size);
+
+int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node);
+#else
+static inline int setup_ima_buffer(const struct kimage *image, void *fdt,
+                                  int chosen_node)
+{
+       remove_ima_buffer(fdt, chosen_node);
+       return 0;
+}
+#endif /* CONFIG_IMA_KEXEC */
+
+#endif /* _ASM_POWERPC_IMA_H */
index 6c3b71502fbcbcc6566790b6f910955668bc43aa..25668bc8cb2a4c621db3c4a8b332b8c2ef9882a4 100644 (file)
@@ -94,11 +94,22 @@ static inline bool kdump_in_progress(void)
 #ifdef CONFIG_KEXEC_FILE
 extern struct kexec_file_ops kexec_elf64_ops;
 
+#ifdef CONFIG_IMA_KEXEC
+#define ARCH_HAS_KIMAGE_ARCH
+
+struct kimage_arch {
+       phys_addr_t ima_buffer_addr;
+       size_t ima_buffer_size;
+};
+#endif
+
 int setup_purgatory(struct kimage *image, const void *slave_code,
                    const void *fdt, unsigned long kernel_load_addr,
                    unsigned long fdt_load_addr);
-int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
-                 unsigned long initrd_len, const char *cmdline);
+int setup_new_fdt(const struct kimage *image, void *fdt,
+                 unsigned long initrd_load_addr, unsigned long initrd_len,
+                 const char *cmdline);
+int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size);
 #endif /* CONFIG_KEXEC_FILE */
 
 #else /* !CONFIG_KEXEC_CORE */
index a3a6047fd39502b389d5854f203426b6e79456c1..23f8082d7bfad95f4c9fbb8201e3e58c3104928f 100644 (file)
@@ -112,6 +112,10 @@ obj-$(CONFIG_PCI_MSI)              += msi.o
 obj-$(CONFIG_KEXEC_CORE)       += machine_kexec.o crash.o \
                                   machine_kexec_$(BITS).o
 obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file_$(BITS).o kexec_elf_$(BITS).o
+ifeq ($(CONFIG_HAVE_IMA_KEXEC)$(CONFIG_IMA),yy)
+obj-y                          += ima_kexec.o
+endif
+
 obj-$(CONFIG_AUDIT)            += audit.o
 obj64-$(CONFIG_AUDIT)          += compat_audit.o
 
diff --git a/arch/powerpc/kernel/ima_kexec.c b/arch/powerpc/kernel/ima_kexec.c
new file mode 100644 (file)
index 0000000..5ea42c9
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2016 IBM Corporation
+ *
+ * Authors:
+ * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/of.h>
+#include <linux/memblock.h>
+#include <linux/libfdt.h>
+
+static int get_addr_size_cells(int *addr_cells, int *size_cells)
+{
+       struct device_node *root;
+
+       root = of_find_node_by_path("/");
+       if (!root)
+               return -EINVAL;
+
+       *addr_cells = of_n_addr_cells(root);
+       *size_cells = of_n_size_cells(root);
+
+       of_node_put(root);
+
+       return 0;
+}
+
+static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
+                              size_t *size)
+{
+       int ret, addr_cells, size_cells;
+
+       ret = get_addr_size_cells(&addr_cells, &size_cells);
+       if (ret)
+               return ret;
+
+       if (len < 4 * (addr_cells + size_cells))
+               return -ENOENT;
+
+       *addr = of_read_number(prop, addr_cells);
+       *size = of_read_number(prop + 4 * addr_cells, size_cells);
+
+       return 0;
+}
+
+/**
+ * ima_get_kexec_buffer - get IMA buffer from the previous kernel
+ * @addr:      On successful return, set to point to the buffer contents.
+ * @size:      On successful return, set to the buffer size.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int ima_get_kexec_buffer(void **addr, size_t *size)
+{
+       int ret, len;
+       unsigned long tmp_addr;
+       size_t tmp_size;
+       const void *prop;
+
+       prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
+       if (!prop)
+               return -ENOENT;
+
+       ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size);
+       if (ret)
+               return ret;
+
+       *addr = __va(tmp_addr);
+       *size = tmp_size;
+
+       return 0;
+}
+
+/**
+ * ima_free_kexec_buffer - free memory used by the IMA buffer
+ */
+int ima_free_kexec_buffer(void)
+{
+       int ret;
+       unsigned long addr;
+       size_t size;
+       struct property *prop;
+
+       prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
+       if (!prop)
+               return -ENOENT;
+
+       ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size);
+       if (ret)
+               return ret;
+
+       ret = of_remove_property(of_chosen, prop);
+       if (ret)
+               return ret;
+
+       return memblock_free(addr, size);
+
+}
+
+/**
+ * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
+ *
+ * The IMA measurement buffer is of no use to a subsequent kernel, so we always
+ * remove it from the device tree.
+ */
+void remove_ima_buffer(void *fdt, int chosen_node)
+{
+       int ret, len;
+       unsigned long addr;
+       size_t size;
+       const void *prop;
+
+       prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
+       if (!prop)
+               return;
+
+       ret = do_get_kexec_buffer(prop, len, &addr, &size);
+       fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
+       if (ret)
+               return;
+
+       ret = delete_fdt_mem_rsv(fdt, addr, size);
+       if (!ret)
+               pr_debug("Removed old IMA buffer reservation.\n");
+}
+
+#ifdef CONFIG_IMA_KEXEC
+/**
+ * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer
+ *
+ * Architectures should use this function to pass on the IMA buffer
+ * information to the next kernel.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
+                             size_t size)
+{
+       image->arch.ima_buffer_addr = load_addr;
+       image->arch.ima_buffer_size = size;
+
+       return 0;
+}
+
+static int write_number(void *p, u64 value, int cells)
+{
+       if (cells == 1) {
+               u32 tmp;
+
+               if (value > U32_MAX)
+                       return -EINVAL;
+
+               tmp = cpu_to_be32(value);
+               memcpy(p, &tmp, sizeof(tmp));
+       } else if (cells == 2) {
+               u64 tmp;
+
+               tmp = cpu_to_be64(value);
+               memcpy(p, &tmp, sizeof(tmp));
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * setup_ima_buffer - add IMA buffer information to the fdt
+ * @image:             kexec image being loaded.
+ * @fdt:               Flattened device tree for the next kernel.
+ * @chosen_node:       Offset to the chosen node.
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node)
+{
+       int ret, addr_cells, size_cells, entry_size;
+       u8 value[16];
+
+       remove_ima_buffer(fdt, chosen_node);
+       if (!image->arch.ima_buffer_size)
+               return 0;
+
+       ret = get_addr_size_cells(&addr_cells, &size_cells);
+       if (ret)
+               return ret;
+
+       entry_size = 4 * (addr_cells + size_cells);
+
+       if (entry_size > sizeof(value))
+               return -EINVAL;
+
+       ret = write_number(value, image->arch.ima_buffer_addr, addr_cells);
+       if (ret)
+               return ret;
+
+       ret = write_number(value + 4 * addr_cells, image->arch.ima_buffer_size,
+                          size_cells);
+       if (ret)
+               return ret;
+
+       ret = fdt_setprop(fdt, chosen_node, "linux,ima-kexec-buffer", value,
+                         entry_size);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = fdt_add_mem_rsv(fdt, image->arch.ima_buffer_addr,
+                             image->arch.ima_buffer_size);
+       if (ret)
+               return -EINVAL;
+
+       pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
+                image->arch.ima_buffer_addr, image->arch.ima_buffer_size);
+
+       return 0;
+}
+#endif /* CONFIG_IMA_KEXEC */
index 6acffd34a70f302fb020317c3cc56bf2564beb68..9a42309b091a67c7a6bd9d62133e48f34e8e94eb 100644 (file)
@@ -627,7 +627,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
                goto out;
        }
 
-       ret = setup_new_fdt(fdt, initrd_load_addr, initrd_len, cmdline);
+       ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline);
        if (ret)
                goto out;
 
index 7abc8a75ee48cbf8b6e3bbb7f639ef9e45da06db..992c0d258e5d564c3b57526e968b26e78bb9292d 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/libfdt.h>
+#include <asm/ima.h>
 
 #define SLAVE_CODE_SIZE                256
 
@@ -180,7 +181,7 @@ int setup_purgatory(struct kimage *image, const void *slave_code,
  *
  * Return: 0 on success, or negative errno on error.
  */
-static int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size)
+int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size)
 {
        int i, ret, num_rsvs = fdt_num_mem_rsv(fdt);
 
@@ -209,6 +210,7 @@ static int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size
 
 /*
  * setup_new_fdt - modify /chosen and memory reservation for the next kernel
+ * @image:             kexec image being loaded.
  * @fdt:               Flattened device tree for the next kernel.
  * @initrd_load_addr:  Address where the next initrd will be loaded.
  * @initrd_len:                Size of the next initrd, or 0 if there will be none.
@@ -217,8 +219,9 @@ static int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size
  *
  * Return: 0 on success, or negative errno on error.
  */
-int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
-                 unsigned long initrd_len, const char *cmdline)
+int setup_new_fdt(const struct kimage *image, void *fdt,
+                 unsigned long initrd_load_addr, unsigned long initrd_len,
+                 const char *cmdline)
 {
        int ret, chosen_node;
        const void *prop;
@@ -328,6 +331,12 @@ int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
                }
        }
 
+       ret = setup_ima_buffer(image, fdt, chosen_node);
+       if (ret) {
+               pr_err("Error setting up the new device tree.\n");
+               return ret;
+       }
+
        ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
        if (ret) {
                pr_err("Error setting up the new device tree.\n");
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 3803b0addf657edafae38ee217136db69a5db900..6c0ba75fb2561f730908050c18afc35ebd45eb5f 100644 (file)
@@ -117,9 +117,6 @@ static const struct of_device_id of_device_ids[] = {
        {
                .compatible     = "fsl,qe",
        },
-       {
-               .compatible    = "fsl,fman",
-       },
        /* The following two are for the Freescale hypervisor */
        {
                .name           = "hypervisor",
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..e487493bbd47f0f84caed99f6c952bf6b3062413 100644 (file)
@@ -412,6 +412,19 @@ config GOLDFISH
        def_bool y
        depends on X86_GOLDFISH
 
+config INTEL_RDT_A
+       bool "Intel Resource Director Technology Allocation support"
+       default n
+       depends on X86 && CPU_SUP_INTEL
+       select KERNFS
+       help
+         Select to enable resource allocation which is a sub-feature of
+         Intel Resource Director Technology(RDT). More information about
+         RDT can be found in the Intel x86 Architecture Software
+         Developer Manual.
+
+         Say N if unsure.
+
 if X86_32
 config X86_EXTENDED_PLATFORM
        bool "Support for extended (non-PC) x86 platforms"
@@ -555,18 +568,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
index 8f82b02934fa701a451ee5e7d8f76193eaefc2fa..0c45cc8e64ba77f6988cff5a0e5443dfe0449435 100644 (file)
@@ -7,9 +7,9 @@
 #include <linux/perf_event.h>
 #include <linux/slab.h>
 #include <asm/cpu_device_id.h>
+#include <asm/intel_rdt_common.h>
 #include "../perf_event.h"
 
-#define MSR_IA32_PQR_ASSOC     0x0c8f
 #define MSR_IA32_QM_CTR                0x0c8e
 #define MSR_IA32_QM_EVTSEL     0x0c8d
 
@@ -24,32 +24,13 @@ static unsigned int cqm_l3_scale; /* supposedly cacheline size */
 static bool cqm_enabled, mbm_enabled;
 unsigned int mbm_socket_max;
 
-/**
- * struct intel_pqr_state - State cache for the PQR MSR
- * @rmid:              The cached Resource Monitoring ID
- * @closid:            The cached Class Of Service ID
- * @rmid_usecnt:       The usage counter for rmid
- *
- * The upper 32 bits of MSR_IA32_PQR_ASSOC contain closid and the
- * lower 10 bits rmid. The update to MSR_IA32_PQR_ASSOC always
- * contains both parts, so we need to cache them.
- *
- * The cache also helps to avoid pointless updates if the value does
- * not change.
- */
-struct intel_pqr_state {
-       u32                     rmid;
-       u32                     closid;
-       int                     rmid_usecnt;
-};
-
 /*
  * The cached intel_pqr_state is strictly per CPU and can never be
  * updated from a remote CPU. Both functions which modify the state
  * (intel_cqm_event_start and intel_cqm_event_stop) are called with
  * interrupts disabled, which is sufficient for the protection.
  */
-static DEFINE_PER_CPU(struct intel_pqr_state, pqr_state);
+DEFINE_PER_CPU(struct intel_pqr_state, pqr_state);
 static struct hrtimer *mbm_timers;
 /**
  * struct sample - mbm event's (local or total) data
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..eafee3161d1c0fa04cd82b12dcf15003a89d04b4 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 */
 
 #define X86_FEATURE_CPB                ( 7*32+ 2) /* AMD Core Performance Boost */
 #define X86_FEATURE_EPB                ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
+#define X86_FEATURE_CAT_L3     ( 7*32+ 4) /* Cache Allocation Technology L3 */
+#define X86_FEATURE_CAT_L2     ( 7*32+ 5) /* Cache Allocation Technology L2 */
+#define X86_FEATURE_CDP_L3     ( 7*32+ 6) /* Code and Data Prioritization L3 */
 
 #define X86_FEATURE_HW_PSTATE  ( 7*32+ 8) /* AMD HW-PState */
 #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 #define X86_FEATURE_RTM                ( 9*32+11) /* Restricted Transactional Memory */
 #define X86_FEATURE_CQM                ( 9*32+12) /* Cache QoS Monitoring */
 #define X86_FEATURE_MPX                ( 9*32+14) /* Memory Protection Extension */
+#define X86_FEATURE_RDT_A      ( 9*32+15) /* Resource Director Technology Allocation */
 #define X86_FEATURE_AVX512F    ( 9*32+16) /* AVX-512 Foundation */
 #define X86_FEATURE_AVX512DQ   ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */
 #define X86_FEATURE_RDSEED     ( 9*32+18) /* The RDSEED instruction */
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
        }
 };
 
diff --git a/arch/x86/include/asm/intel_rdt.h b/arch/x86/include/asm/intel_rdt.h
new file mode 100644 (file)
index 0000000..95ce5c8
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef _ASM_X86_INTEL_RDT_H
+#define _ASM_X86_INTEL_RDT_H
+
+#ifdef CONFIG_INTEL_RDT_A
+
+#include <linux/kernfs.h>
+#include <linux/jump_label.h>
+
+#include <asm/intel_rdt_common.h>
+
+#define IA32_L3_QOS_CFG                0xc81
+#define IA32_L3_CBM_BASE       0xc90
+#define IA32_L2_CBM_BASE       0xd10
+
+#define L3_QOS_CDP_ENABLE      0x01ULL
+
+/**
+ * struct rdtgroup - store rdtgroup's data in resctrl file system.
+ * @kn:                                kernfs node
+ * @rdtgroup_list:             linked list for all rdtgroups
+ * @closid:                    closid for this rdtgroup
+ * @cpu_mask:                  CPUs assigned to this rdtgroup
+ * @flags:                     status bits
+ * @waitcount:                 how many cpus expect to find this
+ *                             group when they acquire rdtgroup_mutex
+ */
+struct rdtgroup {
+       struct kernfs_node      *kn;
+       struct list_head        rdtgroup_list;
+       int                     closid;
+       struct cpumask          cpu_mask;
+       int                     flags;
+       atomic_t                waitcount;
+};
+
+/* rdtgroup.flags */
+#define        RDT_DELETED             1
+
+/* List of all resource groups */
+extern struct list_head rdt_all_groups;
+
+int __init rdtgroup_init(void);
+
+/**
+ * struct rftype - describe each file in the resctrl file system
+ * @name: file name
+ * @mode: access mode
+ * @kf_ops: operations
+ * @seq_show: show content of the file
+ * @write: write to the file
+ */
+struct rftype {
+       char                    *name;
+       umode_t                 mode;
+       struct kernfs_ops       *kf_ops;
+
+       int (*seq_show)(struct kernfs_open_file *of,
+                       struct seq_file *sf, void *v);
+       /*
+        * write() is the generic write callback which maps directly to
+        * kernfs write operation and overrides all other operations.
+        * Maximum write size is determined by ->max_write_len.
+        */
+       ssize_t (*write)(struct kernfs_open_file *of,
+                        char *buf, size_t nbytes, loff_t off);
+};
+
+/**
+ * struct rdt_resource - attributes of an RDT resource
+ * @enabled:                   Is this feature enabled on this machine
+ * @capable:                   Is this feature available on this machine
+ * @name:                      Name to use in "schemata" file
+ * @num_closid:                        Number of CLOSIDs available
+ * @max_cbm:                   Largest Cache Bit Mask allowed
+ * @min_cbm_bits:              Minimum number of consecutive bits to be set
+ *                             in a cache bit mask
+ * @domains:                   All domains for this resource
+ * @num_domains:               Number of domains active
+ * @msr_base:                  Base MSR address for CBMs
+ * @tmp_cbms:                  Scratch space when updating schemata
+ * @num_tmp_cbms:              Number of CBMs in tmp_cbms
+ * @cache_level:               Which cache level defines scope of this domain
+ * @cbm_idx_multi:             Multiplier of CBM index
+ * @cbm_idx_offset:            Offset of CBM index. CBM index is computed by:
+ *                             closid * cbm_idx_multi + cbm_idx_offset
+ */
+struct rdt_resource {
+       bool                    enabled;
+       bool                    capable;
+       char                    *name;
+       int                     num_closid;
+       int                     cbm_len;
+       int                     min_cbm_bits;
+       u32                     max_cbm;
+       struct list_head        domains;
+       int                     num_domains;
+       int                     msr_base;
+       u32                     *tmp_cbms;
+       int                     num_tmp_cbms;
+       int                     cache_level;
+       int                     cbm_idx_multi;
+       int                     cbm_idx_offset;
+};
+
+/**
+ * struct rdt_domain - group of cpus sharing an RDT resource
+ * @list:      all instances of this resource
+ * @id:                unique id for this instance
+ * @cpu_mask:  which cpus share this resource
+ * @cbm:       array of cache bit masks (indexed by CLOSID)
+ */
+struct rdt_domain {
+       struct list_head        list;
+       int                     id;
+       struct cpumask          cpu_mask;
+       u32                     *cbm;
+};
+
+/**
+ * struct msr_param - set a range of MSRs from a domain
+ * @res:       The resource to use
+ * @low:       Beginning index from base MSR
+ * @high:      End index
+ */
+struct msr_param {
+       struct rdt_resource     *res;
+       int                     low;
+       int                     high;
+};
+
+extern struct mutex rdtgroup_mutex;
+
+extern struct rdt_resource rdt_resources_all[];
+extern struct rdtgroup rdtgroup_default;
+DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
+
+int __init rdtgroup_init(void);
+
+enum {
+       RDT_RESOURCE_L3,
+       RDT_RESOURCE_L3DATA,
+       RDT_RESOURCE_L3CODE,
+       RDT_RESOURCE_L2,
+
+       /* Must be the last */
+       RDT_NUM_RESOURCES,
+};
+
+#define for_each_capable_rdt_resource(r)                                     \
+       for (r = rdt_resources_all; r < rdt_resources_all + RDT_NUM_RESOURCES;\
+            r++)                                                             \
+               if (r->capable)
+
+#define for_each_enabled_rdt_resource(r)                                     \
+       for (r = rdt_resources_all; r < rdt_resources_all + RDT_NUM_RESOURCES;\
+            r++)                                                             \
+               if (r->enabled)
+
+/* CPUID.(EAX=10H, ECX=ResID=1).EAX */
+union cpuid_0x10_1_eax {
+       struct {
+               unsigned int cbm_len:5;
+       } split;
+       unsigned int full;
+};
+
+/* CPUID.(EAX=10H, ECX=ResID=1).EDX */
+union cpuid_0x10_1_edx {
+       struct {
+               unsigned int cos_max:16;
+       } split;
+       unsigned int full;
+};
+
+DECLARE_PER_CPU_READ_MOSTLY(int, cpu_closid);
+
+void rdt_cbm_update(void *arg);
+struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn);
+void rdtgroup_kn_unlock(struct kernfs_node *kn);
+ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
+                               char *buf, size_t nbytes, loff_t off);
+int rdtgroup_schemata_show(struct kernfs_open_file *of,
+                          struct seq_file *s, void *v);
+
+/*
+ * intel_rdt_sched_in() - Writes the task's CLOSid to IA32_PQR_MSR
+ *
+ * Following considerations are made so that this has minimal impact
+ * on scheduler hot path:
+ * - This will stay as no-op unless we are running on an Intel SKU
+ *   which supports resource control and we enable by mounting the
+ *   resctrl file system.
+ * - Caches the per cpu CLOSid values and does the MSR write only
+ *   when a task with a different CLOSid is scheduled in.
+ *
+ * Must be called with preemption disabled.
+ */
+static inline void intel_rdt_sched_in(void)
+{
+       if (static_branch_likely(&rdt_enable_key)) {
+               struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
+               int closid;
+
+               /*
+                * If this task has a closid assigned, use it.
+                * Else use the closid assigned to this cpu.
+                */
+               closid = current->closid;
+               if (closid == 0)
+                       closid = this_cpu_read(cpu_closid);
+
+               if (closid != state->closid) {
+                       state->closid = closid;
+                       wrmsr(MSR_IA32_PQR_ASSOC, state->rmid, closid);
+               }
+       }
+}
+
+#else
+
+static inline void intel_rdt_sched_in(void) {}
+
+#endif /* CONFIG_INTEL_RDT_A */
+#endif /* _ASM_X86_INTEL_RDT_H */
diff --git a/arch/x86/include/asm/intel_rdt_common.h b/arch/x86/include/asm/intel_rdt_common.h
new file mode 100644 (file)
index 0000000..b31081b
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _ASM_X86_INTEL_RDT_COMMON_H
+#define _ASM_X86_INTEL_RDT_COMMON_H
+
+#define MSR_IA32_PQR_ASSOC     0x0c8f
+
+/**
+ * struct intel_pqr_state - State cache for the PQR MSR
+ * @rmid:              The cached Resource Monitoring ID
+ * @closid:            The cached Class Of Service ID
+ * @rmid_usecnt:       The usage counter for rmid
+ *
+ * The upper 32 bits of MSR_IA32_PQR_ASSOC contain closid and the
+ * lower 10 bits rmid. The update to MSR_IA32_PQR_ASSOC always
+ * contains both parts, so we need to cache them.
+ *
+ * The cache also helps to avoid pointless updates if the value does
+ * not change.
+ */
+struct intel_pqr_state {
+       u32                     rmid;
+       u32                     closid;
+       int                     rmid_usecnt;
+};
+
+DECLARE_PER_CPU(struct intel_pqr_state, pqr_state);
+
+#endif /* _ASM_X86_INTEL_RDT_COMMON_H */
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 33b63670bf09e6d34c1f194cfe3600d9ea16dcb4..52000010c62ebaaf60939186128d44af757d2226 100644 (file)
@@ -32,6 +32,8 @@ obj-$(CONFIG_CPU_SUP_CENTAUR)         += centaur.o
 obj-$(CONFIG_CPU_SUP_TRANSMETA_32)     += transmeta.o
 obj-$(CONFIG_CPU_SUP_UMC_32)           += umc.o
 
+obj-$(CONFIG_INTEL_RDT_A)      += intel_rdt.o intel_rdt_rdtgroup.o intel_rdt_schemata.o
+
 obj-$(CONFIG_X86_MCE)                  += mcheck/
 obj-$(CONFIG_MTRR)                     += mtrr/
 obj-$(CONFIG_MICROCODE)                        += microcode/
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 be633715650212059e8a67eb7a4974b188d5e076..0282b0df004a86023d00abceb53cbed24fe118f6 100644 (file)
@@ -153,6 +153,7 @@ struct _cpuid4_info_regs {
        union _cpuid4_leaf_eax eax;
        union _cpuid4_leaf_ebx ebx;
        union _cpuid4_leaf_ecx ecx;
+       unsigned int id;
        unsigned long size;
        struct amd_northbridge *nb;
 };
@@ -894,6 +895,8 @@ static void __cache_cpumap_setup(unsigned int cpu, int index,
 static void ci_leaf_init(struct cacheinfo *this_leaf,
                         struct _cpuid4_info_regs *base)
 {
+       this_leaf->id = base->id;
+       this_leaf->attributes = CACHE_ID;
        this_leaf->level = base->eax.split.level;
        this_leaf->type = cache_type_map[base->eax.split.type];
        this_leaf->coherency_line_size =
@@ -920,6 +923,22 @@ static int __init_cache_level(unsigned int cpu)
        return 0;
 }
 
+/*
+ * The max shared threads number comes from CPUID.4:EAX[25-14] with input
+ * ECX as cache index. Then right shift apicid by the number's order to get
+ * cache id for this cache node.
+ */
+static void get_cache_id(int cpu, struct _cpuid4_info_regs *id4_regs)
+{
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+       unsigned long num_threads_sharing;
+       int index_msb;
+
+       num_threads_sharing = 1 + id4_regs->eax.split.num_threads_sharing;
+       index_msb = get_count_order(num_threads_sharing);
+       id4_regs->id = c->apicid >> index_msb;
+}
+
 static int __populate_cache_leaves(unsigned int cpu)
 {
        unsigned int idx, ret;
@@ -931,6 +950,7 @@ static int __populate_cache_leaves(unsigned int cpu)
                ret = cpuid4_cache_lookup_regs(idx, &id4_regs);
                if (ret)
                        return ret;
+               get_cache_id(cpu, &id4_regs);
                ci_leaf_init(this_leaf++, &id4_regs);
                __cache_cpumap_setup(cpu, idx, &id4_regs);
        }
diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
new file mode 100644 (file)
index 0000000..5a533fe
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Resource Director Technology(RDT)
+ * - Cache Allocation code.
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Authors:
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ *    Tony Luck <tony.luck@intel.com>
+ *    Vikas Shivappa <vikas.shivappa@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * More information about RDT be found in the Intel (R) x86 Architecture
+ * Software Developer Manual June 2016, volume 3, section 17.17.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/cacheinfo.h>
+#include <linux/cpuhotplug.h>
+
+#include <asm/intel-family.h>
+#include <asm/intel_rdt.h>
+
+/* Mutex to protect rdtgroup access. */
+DEFINE_MUTEX(rdtgroup_mutex);
+
+DEFINE_PER_CPU_READ_MOSTLY(int, cpu_closid);
+
+#define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].domains)
+
+struct rdt_resource rdt_resources_all[] = {
+       {
+               .name           = "L3",
+               .domains        = domain_init(RDT_RESOURCE_L3),
+               .msr_base       = IA32_L3_CBM_BASE,
+               .min_cbm_bits   = 1,
+               .cache_level    = 3,
+               .cbm_idx_multi  = 1,
+               .cbm_idx_offset = 0
+       },
+       {
+               .name           = "L3DATA",
+               .domains        = domain_init(RDT_RESOURCE_L3DATA),
+               .msr_base       = IA32_L3_CBM_BASE,
+               .min_cbm_bits   = 1,
+               .cache_level    = 3,
+               .cbm_idx_multi  = 2,
+               .cbm_idx_offset = 0
+       },
+       {
+               .name           = "L3CODE",
+               .domains        = domain_init(RDT_RESOURCE_L3CODE),
+               .msr_base       = IA32_L3_CBM_BASE,
+               .min_cbm_bits   = 1,
+               .cache_level    = 3,
+               .cbm_idx_multi  = 2,
+               .cbm_idx_offset = 1
+       },
+       {
+               .name           = "L2",
+               .domains        = domain_init(RDT_RESOURCE_L2),
+               .msr_base       = IA32_L2_CBM_BASE,
+               .min_cbm_bits   = 1,
+               .cache_level    = 2,
+               .cbm_idx_multi  = 1,
+               .cbm_idx_offset = 0
+       },
+};
+
+static int cbm_idx(struct rdt_resource *r, int closid)
+{
+       return closid * r->cbm_idx_multi + r->cbm_idx_offset;
+}
+
+/*
+ * cache_alloc_hsw_probe() - Have to probe for Intel haswell server CPUs
+ * as they do not have CPUID enumeration support for Cache allocation.
+ * The check for Vendor/Family/Model is not enough to guarantee that
+ * the MSRs won't #GP fault because only the following SKUs support
+ * CAT:
+ *     Intel(R) Xeon(R)  CPU E5-2658  v3  @  2.20GHz
+ *     Intel(R) Xeon(R)  CPU E5-2648L v3  @  1.80GHz
+ *     Intel(R) Xeon(R)  CPU E5-2628L v3  @  2.00GHz
+ *     Intel(R) Xeon(R)  CPU E5-2618L v3  @  2.30GHz
+ *     Intel(R) Xeon(R)  CPU E5-2608L v3  @  2.00GHz
+ *     Intel(R) Xeon(R)  CPU E5-2658A v3  @  2.20GHz
+ *
+ * Probe by trying to write the first of the L3 cach mask registers
+ * and checking that the bits stick. Max CLOSids is always 4 and max cbm length
+ * is always 20 on hsw server parts. The minimum cache bitmask length
+ * allowed for HSW server is always 2 bits. Hardcode all of them.
+ */
+static inline bool cache_alloc_hsw_probe(void)
+{
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+           boot_cpu_data.x86 == 6 &&
+           boot_cpu_data.x86_model == INTEL_FAM6_HASWELL_X) {
+               struct rdt_resource *r  = &rdt_resources_all[RDT_RESOURCE_L3];
+               u32 l, h, max_cbm = BIT_MASK(20) - 1;
+
+               if (wrmsr_safe(IA32_L3_CBM_BASE, max_cbm, 0))
+                       return false;
+               rdmsr(IA32_L3_CBM_BASE, l, h);
+
+               /* If all the bits were set in MSR, return success */
+               if (l != max_cbm)
+                       return false;
+
+               r->num_closid = 4;
+               r->cbm_len = 20;
+               r->max_cbm = max_cbm;
+               r->min_cbm_bits = 2;
+               r->capable = true;
+               r->enabled = true;
+
+               return true;
+       }
+
+       return false;
+}
+
+static void rdt_get_config(int idx, struct rdt_resource *r)
+{
+       union cpuid_0x10_1_eax eax;
+       union cpuid_0x10_1_edx edx;
+       u32 ebx, ecx;
+
+       cpuid_count(0x00000010, idx, &eax.full, &ebx, &ecx, &edx.full);
+       r->num_closid = edx.split.cos_max + 1;
+       r->cbm_len = eax.split.cbm_len + 1;
+       r->max_cbm = BIT_MASK(eax.split.cbm_len + 1) - 1;
+       r->capable = true;
+       r->enabled = true;
+}
+
+static void rdt_get_cdp_l3_config(int type)
+{
+       struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3];
+       struct rdt_resource *r = &rdt_resources_all[type];
+
+       r->num_closid = r_l3->num_closid / 2;
+       r->cbm_len = r_l3->cbm_len;
+       r->max_cbm = r_l3->max_cbm;
+       r->capable = true;
+       /*
+        * By default, CDP is disabled. CDP can be enabled by mount parameter
+        * "cdp" during resctrl file system mount time.
+        */
+       r->enabled = false;
+}
+
+static inline bool get_rdt_resources(void)
+{
+       bool ret = false;
+
+       if (cache_alloc_hsw_probe())
+               return true;
+
+       if (!boot_cpu_has(X86_FEATURE_RDT_A))
+               return false;
+
+       if (boot_cpu_has(X86_FEATURE_CAT_L3)) {
+               rdt_get_config(1, &rdt_resources_all[RDT_RESOURCE_L3]);
+               if (boot_cpu_has(X86_FEATURE_CDP_L3)) {
+                       rdt_get_cdp_l3_config(RDT_RESOURCE_L3DATA);
+                       rdt_get_cdp_l3_config(RDT_RESOURCE_L3CODE);
+               }
+               ret = true;
+       }
+       if (boot_cpu_has(X86_FEATURE_CAT_L2)) {
+               /* CPUID 0x10.2 fields are same format at 0x10.1 */
+               rdt_get_config(2, &rdt_resources_all[RDT_RESOURCE_L2]);
+               ret = true;
+       }
+
+       return ret;
+}
+
+static int get_cache_id(int cpu, int level)
+{
+       struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu);
+       int i;
+
+       for (i = 0; i < ci->num_leaves; i++) {
+               if (ci->info_list[i].level == level)
+                       return ci->info_list[i].id;
+       }
+
+       return -1;
+}
+
+void rdt_cbm_update(void *arg)
+{
+       struct msr_param *m = (struct msr_param *)arg;
+       struct rdt_resource *r = m->res;
+       int i, cpu = smp_processor_id();
+       struct rdt_domain *d;
+
+       list_for_each_entry(d, &r->domains, list) {
+               /* Find the domain that contains this CPU */
+               if (cpumask_test_cpu(cpu, &d->cpu_mask))
+                       goto found;
+       }
+       pr_info_once("cpu %d not found in any domain for resource %s\n",
+                    cpu, r->name);
+
+       return;
+
+found:
+       for (i = m->low; i < m->high; i++) {
+               int idx = cbm_idx(r, i);
+
+               wrmsrl(r->msr_base + idx, d->cbm[i]);
+       }
+}
+
+/*
+ * rdt_find_domain - Find a domain in a resource that matches input resource id
+ *
+ * Search resource r's domain list to find the resource id. If the resource
+ * id is found in a domain, return the domain. Otherwise, if requested by
+ * caller, return the first domain whose id is bigger than the input id.
+ * The domain list is sorted by id in ascending order.
+ */
+static struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id,
+                                         struct list_head **pos)
+{
+       struct rdt_domain *d;
+       struct list_head *l;
+
+       if (id < 0)
+               return ERR_PTR(id);
+
+       list_for_each(l, &r->domains) {
+               d = list_entry(l, struct rdt_domain, list);
+               /* When id is found, return its domain. */
+               if (id == d->id)
+                       return d;
+               /* Stop searching when finding id's position in sorted list. */
+               if (id < d->id)
+                       break;
+       }
+
+       if (pos)
+               *pos = l;
+
+       return NULL;
+}
+
+/*
+ * domain_add_cpu - Add a cpu to a resource's domain list.
+ *
+ * If an existing domain in the resource r's domain list matches the cpu's
+ * resource id, add the cpu in the domain.
+ *
+ * Otherwise, a new domain is allocated and inserted into the right position
+ * in the domain list sorted by id in ascending order.
+ *
+ * The order in the domain list is visible to users when we print entries
+ * in the schemata file and schemata input is validated to have the same order
+ * as this list.
+ */
+static void domain_add_cpu(int cpu, struct rdt_resource *r)
+{
+       int i, id = get_cache_id(cpu, r->cache_level);
+       struct list_head *add_pos = NULL;
+       struct rdt_domain *d;
+
+       d = rdt_find_domain(r, id, &add_pos);
+       if (IS_ERR(d)) {
+               pr_warn("Could't find cache id for cpu %d\n", cpu);
+               return;
+       }
+
+       if (d) {
+               cpumask_set_cpu(cpu, &d->cpu_mask);
+               return;
+       }
+
+       d = kzalloc_node(sizeof(*d), GFP_KERNEL, cpu_to_node(cpu));
+       if (!d)
+               return;
+
+       d->id = id;
+
+       d->cbm = kmalloc_array(r->num_closid, sizeof(*d->cbm), GFP_KERNEL);
+       if (!d->cbm) {
+               kfree(d);
+               return;
+       }
+
+       for (i = 0; i < r->num_closid; i++) {
+               int idx = cbm_idx(r, i);
+
+               d->cbm[i] = r->max_cbm;
+               wrmsrl(r->msr_base + idx, d->cbm[i]);
+       }
+
+       cpumask_set_cpu(cpu, &d->cpu_mask);
+       list_add_tail(&d->list, add_pos);
+       r->num_domains++;
+}
+
+static void domain_remove_cpu(int cpu, struct rdt_resource *r)
+{
+       int id = get_cache_id(cpu, r->cache_level);
+       struct rdt_domain *d;
+
+       d = rdt_find_domain(r, id, NULL);
+       if (IS_ERR_OR_NULL(d)) {
+               pr_warn("Could't find cache id for cpu %d\n", cpu);
+               return;
+       }
+
+       cpumask_clear_cpu(cpu, &d->cpu_mask);
+       if (cpumask_empty(&d->cpu_mask)) {
+               r->num_domains--;
+               kfree(d->cbm);
+               list_del(&d->list);
+               kfree(d);
+       }
+}
+
+static void clear_closid(int cpu)
+{
+       struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
+
+       per_cpu(cpu_closid, cpu) = 0;
+       state->closid = 0;
+       wrmsr(MSR_IA32_PQR_ASSOC, state->rmid, 0);
+}
+
+static int intel_rdt_online_cpu(unsigned int cpu)
+{
+       struct rdt_resource *r;
+
+       mutex_lock(&rdtgroup_mutex);
+       for_each_capable_rdt_resource(r)
+               domain_add_cpu(cpu, r);
+       /* The cpu is set in default rdtgroup after online. */
+       cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
+       clear_closid(cpu);
+       mutex_unlock(&rdtgroup_mutex);
+
+       return 0;
+}
+
+static int intel_rdt_offline_cpu(unsigned int cpu)
+{
+       struct rdtgroup *rdtgrp;
+       struct rdt_resource *r;
+
+       mutex_lock(&rdtgroup_mutex);
+       for_each_capable_rdt_resource(r)
+               domain_remove_cpu(cpu, r);
+       list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
+               if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask))
+                       break;
+       }
+       clear_closid(cpu);
+       mutex_unlock(&rdtgroup_mutex);
+
+       return 0;
+}
+
+static int __init intel_rdt_late_init(void)
+{
+       struct rdt_resource *r;
+       int state, ret;
+
+       if (!get_rdt_resources())
+               return -ENODEV;
+
+       state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+                                 "x86/rdt/cat:online:",
+                                 intel_rdt_online_cpu, intel_rdt_offline_cpu);
+       if (state < 0)
+               return state;
+
+       ret = rdtgroup_init();
+       if (ret) {
+               cpuhp_remove_state(state);
+               return ret;
+       }
+
+       for_each_capable_rdt_resource(r)
+               pr_info("Intel RDT %s allocation detected\n", r->name);
+
+       return 0;
+}
+
+late_initcall(intel_rdt_late_init);
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
new file mode 100644 (file)
index 0000000..8af04af
--- /dev/null
@@ -0,0 +1,1115 @@
+/*
+ * User interface for Resource Alloction in Resource Director Technology(RDT)
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Fenghua Yu <fenghua.yu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * More information about RDT be found in the Intel (R) x86 Architecture
+ * Software Developer Manual.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/cpu.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/kernfs.h>
+#include <linux/seq_file.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/task_work.h>
+
+#include <uapi/linux/magic.h>
+
+#include <asm/intel_rdt.h>
+#include <asm/intel_rdt_common.h>
+
+DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
+struct kernfs_root *rdt_root;
+struct rdtgroup rdtgroup_default;
+LIST_HEAD(rdt_all_groups);
+
+/* Kernel fs node for "info" directory under root */
+static struct kernfs_node *kn_info;
+
+/*
+ * Trivial allocator for CLOSIDs. Since h/w only supports a small number,
+ * we can keep a bitmap of free CLOSIDs in a single integer.
+ *
+ * Using a global CLOSID across all resources has some advantages and
+ * some drawbacks:
+ * + We can simply set "current->closid" to assign a task to a resource
+ *   group.
+ * + Context switch code can avoid extra memory references deciding which
+ *   CLOSID to load into the PQR_ASSOC MSR
+ * - We give up some options in configuring resource groups across multi-socket
+ *   systems.
+ * - Our choices on how to configure each resource become progressively more
+ *   limited as the number of resources grows.
+ */
+static int closid_free_map;
+
+static void closid_init(void)
+{
+       struct rdt_resource *r;
+       int rdt_min_closid = 32;
+
+       /* Compute rdt_min_closid across all resources */
+       for_each_enabled_rdt_resource(r)
+               rdt_min_closid = min(rdt_min_closid, r->num_closid);
+
+       closid_free_map = BIT_MASK(rdt_min_closid) - 1;
+
+       /* CLOSID 0 is always reserved for the default group */
+       closid_free_map &= ~1;
+}
+
+int closid_alloc(void)
+{
+       int closid = ffs(closid_free_map);
+
+       if (closid == 0)
+               return -ENOSPC;
+       closid--;
+       closid_free_map &= ~(1 << closid);
+
+       return closid;
+}
+
+static void closid_free(int closid)
+{
+       closid_free_map |= 1 << closid;
+}
+
+/* set uid and gid of rdtgroup dirs and files to that of the creator */
+static int rdtgroup_kn_set_ugid(struct kernfs_node *kn)
+{
+       struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
+                               .ia_uid = current_fsuid(),
+                               .ia_gid = current_fsgid(), };
+
+       if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
+           gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
+               return 0;
+
+       return kernfs_setattr(kn, &iattr);
+}
+
+static int rdtgroup_add_file(struct kernfs_node *parent_kn, struct rftype *rft)
+{
+       struct kernfs_node *kn;
+       int ret;
+
+       kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
+                                 0, rft->kf_ops, rft, NULL, NULL);
+       if (IS_ERR(kn))
+               return PTR_ERR(kn);
+
+       ret = rdtgroup_kn_set_ugid(kn);
+       if (ret) {
+               kernfs_remove(kn);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rdtgroup_add_files(struct kernfs_node *kn, struct rftype *rfts,
+                             int len)
+{
+       struct rftype *rft;
+       int ret;
+
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       for (rft = rfts; rft < rfts + len; rft++) {
+               ret = rdtgroup_add_file(kn, rft);
+               if (ret)
+                       goto error;
+       }
+
+       return 0;
+error:
+       pr_warn("Failed to add %s, err=%d\n", rft->name, ret);
+       while (--rft >= rfts)
+               kernfs_remove_by_name(kn, rft->name);
+       return ret;
+}
+
+static int rdtgroup_seqfile_show(struct seq_file *m, void *arg)
+{
+       struct kernfs_open_file *of = m->private;
+       struct rftype *rft = of->kn->priv;
+
+       if (rft->seq_show)
+               return rft->seq_show(of, m, arg);
+       return 0;
+}
+
+static ssize_t rdtgroup_file_write(struct kernfs_open_file *of, char *buf,
+                                  size_t nbytes, loff_t off)
+{
+       struct rftype *rft = of->kn->priv;
+
+       if (rft->write)
+               return rft->write(of, buf, nbytes, off);
+
+       return -EINVAL;
+}
+
+static struct kernfs_ops rdtgroup_kf_single_ops = {
+       .atomic_write_len       = PAGE_SIZE,
+       .write                  = rdtgroup_file_write,
+       .seq_show               = rdtgroup_seqfile_show,
+};
+
+static int rdtgroup_cpus_show(struct kernfs_open_file *of,
+                             struct seq_file *s, void *v)
+{
+       struct rdtgroup *rdtgrp;
+       int ret = 0;
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+
+       if (rdtgrp)
+               seq_printf(s, "%*pb\n", cpumask_pr_args(&rdtgrp->cpu_mask));
+       else
+               ret = -ENOENT;
+       rdtgroup_kn_unlock(of->kn);
+
+       return ret;
+}
+
+/*
+ * This is safe against intel_rdt_sched_in() called from __switch_to()
+ * because __switch_to() is executed with interrupts disabled. A local call
+ * from rdt_update_closid() is proteced against __switch_to() because
+ * preemption is disabled.
+ */
+static void rdt_update_cpu_closid(void *closid)
+{
+       if (closid)
+               this_cpu_write(cpu_closid, *(int *)closid);
+       /*
+        * We cannot unconditionally write the MSR because the current
+        * executing task might have its own closid selected. Just reuse
+        * the context switch code.
+        */
+       intel_rdt_sched_in();
+}
+
+/*
+ * Update the PGR_ASSOC MSR on all cpus in @cpu_mask,
+ *
+ * Per task closids must have been set up before calling this function.
+ *
+ * The per cpu closids are updated with the smp function call, when @closid
+ * is not NULL. If @closid is NULL then all affected percpu closids must
+ * have been set up before calling this function.
+ */
+static void
+rdt_update_closid(const struct cpumask *cpu_mask, int *closid)
+{
+       int cpu = get_cpu();
+
+       if (cpumask_test_cpu(cpu, cpu_mask))
+               rdt_update_cpu_closid(closid);
+       smp_call_function_many(cpu_mask, rdt_update_cpu_closid, closid, 1);
+       put_cpu();
+}
+
+static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
+                                  char *buf, size_t nbytes, loff_t off)
+{
+       cpumask_var_t tmpmask, newmask;
+       struct rdtgroup *rdtgrp, *r;
+       int ret;
+
+       if (!buf)
+               return -EINVAL;
+
+       if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
+               return -ENOMEM;
+       if (!zalloc_cpumask_var(&newmask, GFP_KERNEL)) {
+               free_cpumask_var(tmpmask);
+               return -ENOMEM;
+       }
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       if (!rdtgrp) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+
+       ret = cpumask_parse(buf, newmask);
+       if (ret)
+               goto unlock;
+
+       /* check that user didn't specify any offline cpus */
+       cpumask_andnot(tmpmask, newmask, cpu_online_mask);
+       if (cpumask_weight(tmpmask)) {
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       /* Check whether cpus are dropped from this group */
+       cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
+       if (cpumask_weight(tmpmask)) {
+               /* Can't drop from default group */
+               if (rdtgrp == &rdtgroup_default) {
+                       ret = -EINVAL;
+                       goto unlock;
+               }
+               /* Give any dropped cpus to rdtgroup_default */
+               cpumask_or(&rdtgroup_default.cpu_mask,
+                          &rdtgroup_default.cpu_mask, tmpmask);
+               rdt_update_closid(tmpmask, &rdtgroup_default.closid);
+       }
+
+       /*
+        * If we added cpus, remove them from previous group that owned them
+        * and update per-cpu closid
+        */
+       cpumask_andnot(tmpmask, newmask, &rdtgrp->cpu_mask);
+       if (cpumask_weight(tmpmask)) {
+               list_for_each_entry(r, &rdt_all_groups, rdtgroup_list) {
+                       if (r == rdtgrp)
+                               continue;
+                       cpumask_andnot(&r->cpu_mask, &r->cpu_mask, tmpmask);
+               }
+               rdt_update_closid(tmpmask, &rdtgrp->closid);
+       }
+
+       /* Done pushing/pulling - update this group with new mask */
+       cpumask_copy(&rdtgrp->cpu_mask, newmask);
+
+unlock:
+       rdtgroup_kn_unlock(of->kn);
+       free_cpumask_var(tmpmask);
+       free_cpumask_var(newmask);
+
+       return ret ?: nbytes;
+}
+
+struct task_move_callback {
+       struct callback_head    work;
+       struct rdtgroup         *rdtgrp;
+};
+
+static void move_myself(struct callback_head *head)
+{
+       struct task_move_callback *callback;
+       struct rdtgroup *rdtgrp;
+
+       callback = container_of(head, struct task_move_callback, work);
+       rdtgrp = callback->rdtgrp;
+
+       /*
+        * If resource group was deleted before this task work callback
+        * was invoked, then assign the task to root group and free the
+        * resource group.
+        */
+       if (atomic_dec_and_test(&rdtgrp->waitcount) &&
+           (rdtgrp->flags & RDT_DELETED)) {
+               current->closid = 0;
+               kfree(rdtgrp);
+       }
+
+       preempt_disable();
+       /* update PQR_ASSOC MSR to make resource group go into effect */
+       intel_rdt_sched_in();
+       preempt_enable();
+
+       kfree(callback);
+}
+
+static int __rdtgroup_move_task(struct task_struct *tsk,
+                               struct rdtgroup *rdtgrp)
+{
+       struct task_move_callback *callback;
+       int ret;
+
+       callback = kzalloc(sizeof(*callback), GFP_KERNEL);
+       if (!callback)
+               return -ENOMEM;
+       callback->work.func = move_myself;
+       callback->rdtgrp = rdtgrp;
+
+       /*
+        * Take a refcount, so rdtgrp cannot be freed before the
+        * callback has been invoked.
+        */
+       atomic_inc(&rdtgrp->waitcount);
+       ret = task_work_add(tsk, &callback->work, true);
+       if (ret) {
+               /*
+                * Task is exiting. Drop the refcount and free the callback.
+                * No need to check the refcount as the group cannot be
+                * deleted before the write function unlocks rdtgroup_mutex.
+                */
+               atomic_dec(&rdtgrp->waitcount);
+               kfree(callback);
+       } else {
+               tsk->closid = rdtgrp->closid;
+       }
+       return ret;
+}
+
+static int rdtgroup_task_write_permission(struct task_struct *task,
+                                         struct kernfs_open_file *of)
+{
+       const struct cred *tcred = get_task_cred(task);
+       const struct cred *cred = current_cred();
+       int ret = 0;
+
+       /*
+        * Even if we're attaching all tasks in the thread group, we only
+        * need to check permissions on one of them.
+        */
+       if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
+           !uid_eq(cred->euid, tcred->uid) &&
+           !uid_eq(cred->euid, tcred->suid))
+               ret = -EPERM;
+
+       put_cred(tcred);
+       return ret;
+}
+
+static int rdtgroup_move_task(pid_t pid, struct rdtgroup *rdtgrp,
+                             struct kernfs_open_file *of)
+{
+       struct task_struct *tsk;
+       int ret;
+
+       rcu_read_lock();
+       if (pid) {
+               tsk = find_task_by_vpid(pid);
+               if (!tsk) {
+                       rcu_read_unlock();
+                       return -ESRCH;
+               }
+       } else {
+               tsk = current;
+       }
+
+       get_task_struct(tsk);
+       rcu_read_unlock();
+
+       ret = rdtgroup_task_write_permission(tsk, of);
+       if (!ret)
+               ret = __rdtgroup_move_task(tsk, rdtgrp);
+
+       put_task_struct(tsk);
+       return ret;
+}
+
+static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
+                                   char *buf, size_t nbytes, loff_t off)
+{
+       struct rdtgroup *rdtgrp;
+       int ret = 0;
+       pid_t pid;
+
+       if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)
+               return -EINVAL;
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+
+       if (rdtgrp)
+               ret = rdtgroup_move_task(pid, rdtgrp, of);
+       else
+               ret = -ENOENT;
+
+       rdtgroup_kn_unlock(of->kn);
+
+       return ret ?: nbytes;
+}
+
+static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
+{
+       struct task_struct *p, *t;
+
+       rcu_read_lock();
+       for_each_process_thread(p, t) {
+               if (t->closid == r->closid)
+                       seq_printf(s, "%d\n", t->pid);
+       }
+       rcu_read_unlock();
+}
+
+static int rdtgroup_tasks_show(struct kernfs_open_file *of,
+                              struct seq_file *s, void *v)
+{
+       struct rdtgroup *rdtgrp;
+       int ret = 0;
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       if (rdtgrp)
+               show_rdt_tasks(rdtgrp, s);
+       else
+               ret = -ENOENT;
+       rdtgroup_kn_unlock(of->kn);
+
+       return ret;
+}
+
+/* Files in each rdtgroup */
+static struct rftype rdtgroup_base_files[] = {
+       {
+               .name           = "cpus",
+               .mode           = 0644,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .write          = rdtgroup_cpus_write,
+               .seq_show       = rdtgroup_cpus_show,
+       },
+       {
+               .name           = "tasks",
+               .mode           = 0644,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .write          = rdtgroup_tasks_write,
+               .seq_show       = rdtgroup_tasks_show,
+       },
+       {
+               .name           = "schemata",
+               .mode           = 0644,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .write          = rdtgroup_schemata_write,
+               .seq_show       = rdtgroup_schemata_show,
+       },
+};
+
+static int rdt_num_closids_show(struct kernfs_open_file *of,
+                               struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       seq_printf(seq, "%d\n", r->num_closid);
+
+       return 0;
+}
+
+static int rdt_cbm_mask_show(struct kernfs_open_file *of,
+                            struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       seq_printf(seq, "%x\n", r->max_cbm);
+
+       return 0;
+}
+
+static int rdt_min_cbm_bits_show(struct kernfs_open_file *of,
+                            struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       seq_printf(seq, "%d\n", r->min_cbm_bits);
+
+       return 0;
+}
+
+/* rdtgroup information files for one cache resource. */
+static struct rftype res_info_files[] = {
+       {
+               .name           = "num_closids",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_num_closids_show,
+       },
+       {
+               .name           = "cbm_mask",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_cbm_mask_show,
+       },
+       {
+               .name           = "min_cbm_bits",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_min_cbm_bits_show,
+       },
+};
+
+static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn)
+{
+       struct kernfs_node *kn_subdir;
+       struct rdt_resource *r;
+       int ret;
+
+       /* create the directory */
+       kn_info = kernfs_create_dir(parent_kn, "info", parent_kn->mode, NULL);
+       if (IS_ERR(kn_info))
+               return PTR_ERR(kn_info);
+       kernfs_get(kn_info);
+
+       for_each_enabled_rdt_resource(r) {
+               kn_subdir = kernfs_create_dir(kn_info, r->name,
+                                             kn_info->mode, r);
+               if (IS_ERR(kn_subdir)) {
+                       ret = PTR_ERR(kn_subdir);
+                       goto out_destroy;
+               }
+               kernfs_get(kn_subdir);
+               ret = rdtgroup_kn_set_ugid(kn_subdir);
+               if (ret)
+                       goto out_destroy;
+               ret = rdtgroup_add_files(kn_subdir, res_info_files,
+                                        ARRAY_SIZE(res_info_files));
+               if (ret)
+                       goto out_destroy;
+               kernfs_activate(kn_subdir);
+       }
+
+       /*
+        * This extra ref will be put in kernfs_remove() and guarantees
+        * that @rdtgrp->kn is always accessible.
+        */
+       kernfs_get(kn_info);
+
+       ret = rdtgroup_kn_set_ugid(kn_info);
+       if (ret)
+               goto out_destroy;
+
+       kernfs_activate(kn_info);
+
+       return 0;
+
+out_destroy:
+       kernfs_remove(kn_info);
+       return ret;
+}
+
+static void l3_qos_cfg_update(void *arg)
+{
+       bool *enable = arg;
+
+       wrmsrl(IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL);
+}
+
+static int set_l3_qos_cfg(struct rdt_resource *r, bool enable)
+{
+       cpumask_var_t cpu_mask;
+       struct rdt_domain *d;
+       int cpu;
+
+       if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       list_for_each_entry(d, &r->domains, list) {
+               /* Pick one CPU from each domain instance to update MSR */
+               cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
+       }
+       cpu = get_cpu();
+       /* Update QOS_CFG MSR on this cpu if it's in cpu_mask. */
+       if (cpumask_test_cpu(cpu, cpu_mask))
+               l3_qos_cfg_update(&enable);
+       /* Update QOS_CFG MSR on all other cpus in cpu_mask. */
+       smp_call_function_many(cpu_mask, l3_qos_cfg_update, &enable, 1);
+       put_cpu();
+
+       free_cpumask_var(cpu_mask);
+
+       return 0;
+}
+
+static int cdp_enable(void)
+{
+       struct rdt_resource *r_l3data = &rdt_resources_all[RDT_RESOURCE_L3DATA];
+       struct rdt_resource *r_l3code = &rdt_resources_all[RDT_RESOURCE_L3CODE];
+       struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3];
+       int ret;
+
+       if (!r_l3->capable || !r_l3data->capable || !r_l3code->capable)
+               return -EINVAL;
+
+       ret = set_l3_qos_cfg(r_l3, true);
+       if (!ret) {
+               r_l3->enabled = false;
+               r_l3data->enabled = true;
+               r_l3code->enabled = true;
+       }
+       return ret;
+}
+
+static void cdp_disable(void)
+{
+       struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3];
+
+       r->enabled = r->capable;
+
+       if (rdt_resources_all[RDT_RESOURCE_L3DATA].enabled) {
+               rdt_resources_all[RDT_RESOURCE_L3DATA].enabled = false;
+               rdt_resources_all[RDT_RESOURCE_L3CODE].enabled = false;
+               set_l3_qos_cfg(r, false);
+       }
+}
+
+static int parse_rdtgroupfs_options(char *data)
+{
+       char *token, *o = data;
+       int ret = 0;
+
+       while ((token = strsep(&o, ",")) != NULL) {
+               if (!*token)
+                       return -EINVAL;
+
+               if (!strcmp(token, "cdp"))
+                       ret = cdp_enable();
+       }
+
+       return ret;
+}
+
+/*
+ * We don't allow rdtgroup directories to be created anywhere
+ * except the root directory. Thus when looking for the rdtgroup
+ * structure for a kernfs node we are either looking at a directory,
+ * in which case the rdtgroup structure is pointed at by the "priv"
+ * field, otherwise we have a file, and need only look to the parent
+ * to find the rdtgroup.
+ */
+static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn)
+{
+       if (kernfs_type(kn) == KERNFS_DIR) {
+               /*
+                * All the resource directories use "kn->priv"
+                * to point to the "struct rdtgroup" for the
+                * resource. "info" and its subdirectories don't
+                * have rdtgroup structures, so return NULL here.
+                */
+               if (kn == kn_info || kn->parent == kn_info)
+                       return NULL;
+               else
+                       return kn->priv;
+       } else {
+               return kn->parent->priv;
+       }
+}
+
+struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn)
+{
+       struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
+
+       if (!rdtgrp)
+               return NULL;
+
+       atomic_inc(&rdtgrp->waitcount);
+       kernfs_break_active_protection(kn);
+
+       mutex_lock(&rdtgroup_mutex);
+
+       /* Was this group deleted while we waited? */
+       if (rdtgrp->flags & RDT_DELETED)
+               return NULL;
+
+       return rdtgrp;
+}
+
+void rdtgroup_kn_unlock(struct kernfs_node *kn)
+{
+       struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
+
+       if (!rdtgrp)
+               return;
+
+       mutex_unlock(&rdtgroup_mutex);
+
+       if (atomic_dec_and_test(&rdtgrp->waitcount) &&
+           (rdtgrp->flags & RDT_DELETED)) {
+               kernfs_unbreak_active_protection(kn);
+               kernfs_put(kn);
+               kfree(rdtgrp);
+       } else {
+               kernfs_unbreak_active_protection(kn);
+       }
+}
+
+static struct dentry *rdt_mount(struct file_system_type *fs_type,
+                               int flags, const char *unused_dev_name,
+                               void *data)
+{
+       struct dentry *dentry;
+       int ret;
+
+       mutex_lock(&rdtgroup_mutex);
+       /*
+        * resctrl file system can only be mounted once.
+        */
+       if (static_branch_unlikely(&rdt_enable_key)) {
+               dentry = ERR_PTR(-EBUSY);
+               goto out;
+       }
+
+       ret = parse_rdtgroupfs_options(data);
+       if (ret) {
+               dentry = ERR_PTR(ret);
+               goto out_cdp;
+       }
+
+       closid_init();
+
+       ret = rdtgroup_create_info_dir(rdtgroup_default.kn);
+       if (ret) {
+               dentry = ERR_PTR(ret);
+               goto out_cdp;
+       }
+
+       dentry = kernfs_mount(fs_type, flags, rdt_root,
+                             RDTGROUP_SUPER_MAGIC, NULL);
+       if (IS_ERR(dentry))
+               goto out_cdp;
+
+       static_branch_enable(&rdt_enable_key);
+       goto out;
+
+out_cdp:
+       cdp_disable();
+out:
+       mutex_unlock(&rdtgroup_mutex);
+
+       return dentry;
+}
+
+static int reset_all_cbms(struct rdt_resource *r)
+{
+       struct msr_param msr_param;
+       cpumask_var_t cpu_mask;
+       struct rdt_domain *d;
+       int i, cpu;
+
+       if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       msr_param.res = r;
+       msr_param.low = 0;
+       msr_param.high = r->num_closid;
+
+       /*
+        * Disable resource control for this resource by setting all
+        * CBMs in all domains to the maximum mask value. Pick one CPU
+        * from each domain to update the MSRs below.
+        */
+       list_for_each_entry(d, &r->domains, list) {
+               cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
+
+               for (i = 0; i < r->num_closid; i++)
+                       d->cbm[i] = r->max_cbm;
+       }
+       cpu = get_cpu();
+       /* Update CBM on this cpu if it's in cpu_mask. */
+       if (cpumask_test_cpu(cpu, cpu_mask))
+               rdt_cbm_update(&msr_param);
+       /* Update CBM on all other cpus in cpu_mask. */
+       smp_call_function_many(cpu_mask, rdt_cbm_update, &msr_param, 1);
+       put_cpu();
+
+       free_cpumask_var(cpu_mask);
+
+       return 0;
+}
+
+/*
+ * Move tasks from one to the other group. If @from is NULL, then all tasks
+ * in the systems are moved unconditionally (used for teardown).
+ *
+ * If @mask is not NULL the cpus on which moved tasks are running are set
+ * in that mask so the update smp function call is restricted to affected
+ * cpus.
+ */
+static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
+                                struct cpumask *mask)
+{
+       struct task_struct *p, *t;
+
+       read_lock(&tasklist_lock);
+       for_each_process_thread(p, t) {
+               if (!from || t->closid == from->closid) {
+                       t->closid = to->closid;
+#ifdef CONFIG_SMP
+                       /*
+                        * This is safe on x86 w/o barriers as the ordering
+                        * of writing to task_cpu() and t->on_cpu is
+                        * reverse to the reading here. The detection is
+                        * inaccurate as tasks might move or schedule
+                        * before the smp function call takes place. In
+                        * such a case the function call is pointless, but
+                        * there is no other side effect.
+                        */
+                       if (mask && t->on_cpu)
+                               cpumask_set_cpu(task_cpu(t), mask);
+#endif
+               }
+       }
+       read_unlock(&tasklist_lock);
+}
+
+/*
+ * Forcibly remove all of subdirectories under root.
+ */
+static void rmdir_all_sub(void)
+{
+       struct rdtgroup *rdtgrp, *tmp;
+
+       /* Move all tasks to the default resource group */
+       rdt_move_group_tasks(NULL, &rdtgroup_default, NULL);
+
+       list_for_each_entry_safe(rdtgrp, tmp, &rdt_all_groups, rdtgroup_list) {
+               /* Remove each rdtgroup other than root */
+               if (rdtgrp == &rdtgroup_default)
+                       continue;
+
+               /*
+                * Give any CPUs back to the default group. We cannot copy
+                * cpu_online_mask because a CPU might have executed the
+                * offline callback already, but is still marked online.
+                */
+               cpumask_or(&rdtgroup_default.cpu_mask,
+                          &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
+
+               kernfs_remove(rdtgrp->kn);
+               list_del(&rdtgrp->rdtgroup_list);
+               kfree(rdtgrp);
+       }
+       /* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */
+       get_online_cpus();
+       rdt_update_closid(cpu_online_mask, &rdtgroup_default.closid);
+       put_online_cpus();
+
+       kernfs_remove(kn_info);
+}
+
+static void rdt_kill_sb(struct super_block *sb)
+{
+       struct rdt_resource *r;
+
+       mutex_lock(&rdtgroup_mutex);
+
+       /*Put everything back to default values. */
+       for_each_enabled_rdt_resource(r)
+               reset_all_cbms(r);
+       cdp_disable();
+       rmdir_all_sub();
+       static_branch_disable(&rdt_enable_key);
+       kernfs_kill_sb(sb);
+       mutex_unlock(&rdtgroup_mutex);
+}
+
+static struct file_system_type rdt_fs_type = {
+       .name    = "resctrl",
+       .mount   = rdt_mount,
+       .kill_sb = rdt_kill_sb,
+};
+
+static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
+                         umode_t mode)
+{
+       struct rdtgroup *parent, *rdtgrp;
+       struct kernfs_node *kn;
+       int ret, closid;
+
+       /* Only allow mkdir in the root directory */
+       if (parent_kn != rdtgroup_default.kn)
+               return -EPERM;
+
+       /* Do not accept '\n' to avoid unparsable situation. */
+       if (strchr(name, '\n'))
+               return -EINVAL;
+
+       parent = rdtgroup_kn_lock_live(parent_kn);
+       if (!parent) {
+               ret = -ENODEV;
+               goto out_unlock;
+       }
+
+       ret = closid_alloc();
+       if (ret < 0)
+               goto out_unlock;
+       closid = ret;
+
+       /* allocate the rdtgroup. */
+       rdtgrp = kzalloc(sizeof(*rdtgrp), GFP_KERNEL);
+       if (!rdtgrp) {
+               ret = -ENOSPC;
+               goto out_closid_free;
+       }
+       rdtgrp->closid = closid;
+       list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
+
+       /* kernfs creates the directory for rdtgrp */
+       kn = kernfs_create_dir(parent->kn, name, mode, rdtgrp);
+       if (IS_ERR(kn)) {
+               ret = PTR_ERR(kn);
+               goto out_cancel_ref;
+       }
+       rdtgrp->kn = kn;
+
+       /*
+        * kernfs_remove() will drop the reference count on "kn" which
+        * will free it. But we still need it to stick around for the
+        * rdtgroup_kn_unlock(kn} call below. Take one extra reference
+        * here, which will be dropped inside rdtgroup_kn_unlock().
+        */
+       kernfs_get(kn);
+
+       ret = rdtgroup_kn_set_ugid(kn);
+       if (ret)
+               goto out_destroy;
+
+       ret = rdtgroup_add_files(kn, rdtgroup_base_files,
+                                ARRAY_SIZE(rdtgroup_base_files));
+       if (ret)
+               goto out_destroy;
+
+       kernfs_activate(kn);
+
+       ret = 0;
+       goto out_unlock;
+
+out_destroy:
+       kernfs_remove(rdtgrp->kn);
+out_cancel_ref:
+       list_del(&rdtgrp->rdtgroup_list);
+       kfree(rdtgrp);
+out_closid_free:
+       closid_free(closid);
+out_unlock:
+       rdtgroup_kn_unlock(parent_kn);
+       return ret;
+}
+
+static int rdtgroup_rmdir(struct kernfs_node *kn)
+{
+       int ret, cpu, closid = rdtgroup_default.closid;
+       struct rdtgroup *rdtgrp;
+       cpumask_var_t tmpmask;
+
+       if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
+               return -ENOMEM;
+
+       rdtgrp = rdtgroup_kn_lock_live(kn);
+       if (!rdtgrp) {
+               ret = -EPERM;
+               goto out;
+       }
+
+       /* Give any tasks back to the default group */
+       rdt_move_group_tasks(rdtgrp, &rdtgroup_default, tmpmask);
+
+       /* Give any CPUs back to the default group */
+       cpumask_or(&rdtgroup_default.cpu_mask,
+                  &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
+
+       /* Update per cpu closid of the moved CPUs first */
+       for_each_cpu(cpu, &rdtgrp->cpu_mask)
+               per_cpu(cpu_closid, cpu) = closid;
+       /*
+        * Update the MSR on moved CPUs and CPUs which have moved
+        * task running on them.
+        */
+       cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
+       rdt_update_closid(tmpmask, NULL);
+
+       rdtgrp->flags = RDT_DELETED;
+       closid_free(rdtgrp->closid);
+       list_del(&rdtgrp->rdtgroup_list);
+
+       /*
+        * one extra hold on this, will drop when we kfree(rdtgrp)
+        * in rdtgroup_kn_unlock()
+        */
+       kernfs_get(kn);
+       kernfs_remove(rdtgrp->kn);
+       ret = 0;
+out:
+       rdtgroup_kn_unlock(kn);
+       free_cpumask_var(tmpmask);
+       return ret;
+}
+
+static int rdtgroup_show_options(struct seq_file *seq, struct kernfs_root *kf)
+{
+       if (rdt_resources_all[RDT_RESOURCE_L3DATA].enabled)
+               seq_puts(seq, ",cdp");
+       return 0;
+}
+
+static struct kernfs_syscall_ops rdtgroup_kf_syscall_ops = {
+       .mkdir          = rdtgroup_mkdir,
+       .rmdir          = rdtgroup_rmdir,
+       .show_options   = rdtgroup_show_options,
+};
+
+static int __init rdtgroup_setup_root(void)
+{
+       int ret;
+
+       rdt_root = kernfs_create_root(&rdtgroup_kf_syscall_ops,
+                                     KERNFS_ROOT_CREATE_DEACTIVATED,
+                                     &rdtgroup_default);
+       if (IS_ERR(rdt_root))
+               return PTR_ERR(rdt_root);
+
+       mutex_lock(&rdtgroup_mutex);
+
+       rdtgroup_default.closid = 0;
+       list_add(&rdtgroup_default.rdtgroup_list, &rdt_all_groups);
+
+       ret = rdtgroup_add_files(rdt_root->kn, rdtgroup_base_files,
+                                ARRAY_SIZE(rdtgroup_base_files));
+       if (ret) {
+               kernfs_destroy_root(rdt_root);
+               goto out;
+       }
+
+       rdtgroup_default.kn = rdt_root->kn;
+       kernfs_activate(rdtgroup_default.kn);
+
+out:
+       mutex_unlock(&rdtgroup_mutex);
+
+       return ret;
+}
+
+/*
+ * rdtgroup_init - rdtgroup initialization
+ *
+ * Setup resctrl file system including set up root, create mount point,
+ * register rdtgroup filesystem, and initialize files under root directory.
+ *
+ * Return: 0 on success or -errno
+ */
+int __init rdtgroup_init(void)
+{
+       int ret = 0;
+
+       ret = rdtgroup_setup_root();
+       if (ret)
+               return ret;
+
+       ret = sysfs_create_mount_point(fs_kobj, "resctrl");
+       if (ret)
+               goto cleanup_root;
+
+       ret = register_filesystem(&rdt_fs_type);
+       if (ret)
+               goto cleanup_mountpoint;
+
+       return 0;
+
+cleanup_mountpoint:
+       sysfs_remove_mount_point(fs_kobj, "resctrl");
+cleanup_root:
+       kernfs_destroy_root(rdt_root);
+
+       return ret;
+}
diff --git a/arch/x86/kernel/cpu/intel_rdt_schemata.c b/arch/x86/kernel/cpu/intel_rdt_schemata.c
new file mode 100644 (file)
index 0000000..f369cb8
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Resource Director Technology(RDT)
+ * - Cache Allocation code.
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Authors:
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ *    Tony Luck <tony.luck@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * More information about RDT be found in the Intel (R) x86 Architecture
+ * Software Developer Manual June 2016, volume 3, section 17.17.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/kernfs.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <asm/intel_rdt.h>
+
+/*
+ * Check whether a cache bit mask is valid. The SDM says:
+ *     Please note that all (and only) contiguous '1' combinations
+ *     are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
+ * Additionally Haswell requires at least two bits set.
+ */
+static bool cbm_validate(unsigned long var, struct rdt_resource *r)
+{
+       unsigned long first_bit, zero_bit;
+
+       if (var == 0 || var > r->max_cbm)
+               return false;
+
+       first_bit = find_first_bit(&var, r->cbm_len);
+       zero_bit = find_next_zero_bit(&var, r->cbm_len, first_bit);
+
+       if (find_next_bit(&var, r->cbm_len, zero_bit) < r->cbm_len)
+               return false;
+
+       if ((zero_bit - first_bit) < r->min_cbm_bits)
+               return false;
+       return true;
+}
+
+/*
+ * Read one cache bit mask (hex). Check that it is valid for the current
+ * resource type.
+ */
+static int parse_cbm(char *buf, struct rdt_resource *r)
+{
+       unsigned long data;
+       int ret;
+
+       ret = kstrtoul(buf, 16, &data);
+       if (ret)
+               return ret;
+       if (!cbm_validate(data, r))
+               return -EINVAL;
+       r->tmp_cbms[r->num_tmp_cbms++] = data;
+
+       return 0;
+}
+
+/*
+ * For each domain in this resource we expect to find a series of:
+ *     id=mask
+ * separated by ";". The "id" is in decimal, and must appear in the
+ * right order.
+ */
+static int parse_line(char *line, struct rdt_resource *r)
+{
+       char *dom = NULL, *id;
+       struct rdt_domain *d;
+       unsigned long dom_id;
+
+       list_for_each_entry(d, &r->domains, list) {
+               dom = strsep(&line, ";");
+               if (!dom)
+                       return -EINVAL;
+               id = strsep(&dom, "=");
+               if (kstrtoul(id, 10, &dom_id) || dom_id != d->id)
+                       return -EINVAL;
+               if (parse_cbm(dom, r))
+                       return -EINVAL;
+       }
+
+       /* Any garbage at the end of the line? */
+       if (line && line[0])
+               return -EINVAL;
+       return 0;
+}
+
+static int update_domains(struct rdt_resource *r, int closid)
+{
+       struct msr_param msr_param;
+       cpumask_var_t cpu_mask;
+       struct rdt_domain *d;
+       int cpu, idx = 0;
+
+       if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       msr_param.low = closid;
+       msr_param.high = msr_param.low + 1;
+       msr_param.res = r;
+
+       list_for_each_entry(d, &r->domains, list) {
+               cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
+               d->cbm[msr_param.low] = r->tmp_cbms[idx++];
+       }
+       cpu = get_cpu();
+       /* Update CBM on this cpu if it's in cpu_mask. */
+       if (cpumask_test_cpu(cpu, cpu_mask))
+               rdt_cbm_update(&msr_param);
+       /* Update CBM on other cpus. */
+       smp_call_function_many(cpu_mask, rdt_cbm_update, &msr_param, 1);
+       put_cpu();
+
+       free_cpumask_var(cpu_mask);
+
+       return 0;
+}
+
+ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
+                               char *buf, size_t nbytes, loff_t off)
+{
+       struct rdtgroup *rdtgrp;
+       struct rdt_resource *r;
+       char *tok, *resname;
+       int closid, ret = 0;
+       u32 *l3_cbms = NULL;
+
+       /* Valid input requires a trailing newline */
+       if (nbytes == 0 || buf[nbytes - 1] != '\n')
+               return -EINVAL;
+       buf[nbytes - 1] = '\0';
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       if (!rdtgrp) {
+               rdtgroup_kn_unlock(of->kn);
+               return -ENOENT;
+       }
+
+       closid = rdtgrp->closid;
+
+       /* get scratch space to save all the masks while we validate input */
+       for_each_enabled_rdt_resource(r) {
+               r->tmp_cbms = kcalloc(r->num_domains, sizeof(*l3_cbms),
+                                     GFP_KERNEL);
+               if (!r->tmp_cbms) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               r->num_tmp_cbms = 0;
+       }
+
+       while ((tok = strsep(&buf, "\n")) != NULL) {
+               resname = strsep(&tok, ":");
+               if (!tok) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               for_each_enabled_rdt_resource(r) {
+                       if (!strcmp(resname, r->name) &&
+                           closid < r->num_closid) {
+                               ret = parse_line(tok, r);
+                               if (ret)
+                                       goto out;
+                               break;
+                       }
+               }
+               if (!r->name) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       /* Did the parser find all the masks we need? */
+       for_each_enabled_rdt_resource(r) {
+               if (r->num_tmp_cbms != r->num_domains) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       for_each_enabled_rdt_resource(r) {
+               ret = update_domains(r, closid);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       rdtgroup_kn_unlock(of->kn);
+       for_each_enabled_rdt_resource(r) {
+               kfree(r->tmp_cbms);
+               r->tmp_cbms = NULL;
+       }
+       return ret ?: nbytes;
+}
+
+static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
+{
+       struct rdt_domain *dom;
+       bool sep = false;
+
+       seq_printf(s, "%s:", r->name);
+       list_for_each_entry(dom, &r->domains, list) {
+               if (sep)
+                       seq_puts(s, ";");
+               seq_printf(s, "%d=%x", dom->id, dom->cbm[closid]);
+               sep = true;
+       }
+       seq_puts(s, "\n");
+}
+
+int rdtgroup_schemata_show(struct kernfs_open_file *of,
+                          struct seq_file *s, void *v)
+{
+       struct rdtgroup *rdtgrp;
+       struct rdt_resource *r;
+       int closid, ret = 0;
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       if (rdtgrp) {
+               closid = rdtgrp->closid;
+               for_each_enabled_rdt_resource(r) {
+                       if (closid < r->num_closid)
+                               show_doms(s, r, closid);
+               }
+       } else {
+               ret = -ENOENT;
+       }
+       rdtgroup_kn_unlock(of->kn);
+       return ret;
+}
index d1316f9c8329846b0d3f7dede754fa0eef256bd3..d9794060fe225f72f34e78cdc74959aa1bf38934 100644 (file)
@@ -20,12 +20,15 @@ struct cpuid_bit {
 /* Please keep the leaf sorted by cpuid_bit.level for faster search. */
 static const struct cpuid_bit cpuid_bits[] = {
        { X86_FEATURE_APERFMPERF,       CPUID_ECX,  0, 0x00000006, 0 },
-       { X86_FEATURE_EPB,              CPUID_ECX,  3, 0x00000006, 0 },
-       { X86_FEATURE_INTEL_PT,         CPUID_EBX, 25, 0x00000007, 0 },
+       { X86_FEATURE_EPB,              CPUID_ECX,  3, 0x00000006, 0 },
+       { X86_FEATURE_INTEL_PT,         CPUID_EBX, 25, 0x00000007, 0 },
        { X86_FEATURE_AVX512_4VNNIW,    CPUID_EDX,  2, 0x00000007, 0 },
        { X86_FEATURE_AVX512_4FMAPS,    CPUID_EDX,  3, 0x00000007, 0 },
-       { X86_FEATURE_HW_PSTATE,        CPUID_EDX,  7, 0x80000007, 0 },
-       { X86_FEATURE_CPB,              CPUID_EDX,  9, 0x80000007, 0 },
+       { X86_FEATURE_CAT_L3,           CPUID_EBX,  1, 0x00000010, 0 },
+       { X86_FEATURE_CAT_L2,           CPUID_EBX,  2, 0x00000010, 0 },
+       { X86_FEATURE_CDP_L3,           CPUID_ECX,  2, 0x00000010, 1 },
+       { X86_FEATURE_HW_PSTATE,        CPUID_EDX,  7, 0x80000007, 0 },
+       { X86_FEATURE_CPB,              CPUID_EDX,  9, 0x80000007, 0 },
        { X86_FEATURE_PROC_FEEDBACK,    CPUID_EDX, 11, 0x80000007, 0 },
        { 0, 0, 0, 0, 0 }
 };
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 d0d7441085942fc5efe3fda3dd0c0c8fe9fdef69..a0ac3e81518ad8f633c4a3c16e17cabea38950e5 100644 (file)
@@ -53,6 +53,7 @@
 #include <asm/debugreg.h>
 #include <asm/switch_to.h>
 #include <asm/vm86.h>
+#include <asm/intel_rdt.h>
 
 void __show_regs(struct pt_regs *regs, int all)
 {
@@ -296,5 +297,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 
        this_cpu_write(current_task, next_p);
 
+       /* Load the Intel cache allocation PQR MSR. */
+       intel_rdt_sched_in();
+
        return prev_p;
 }
index a76b65e3e615e8d511f213b2ea2a4511aff516f4..a61e141b6891ed4a08437fee3413fedfbc65e429 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/switch_to.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/vdso.h>
+#include <asm/intel_rdt.h>
 
 __visible DEFINE_PER_CPU(unsigned long, rsp_scratch);
 
@@ -476,6 +477,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
                        loadsegment(ss, __KERNEL_DS);
        }
 
+       /* Load the Intel cache allocation PQR MSR. */
+       intel_rdt_sched_in();
+
        return prev_p;
 }
 
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 7dd527f8ca1d24b10915c865dc3f24e4a8e34b92..94be8a8e6c082cbe5b808b049187db0657ad5cb0 100644 (file)
@@ -166,6 +166,12 @@ acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc,
 
 acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address);
 
+acpi_status
+acpi_tb_get_table(struct acpi_table_desc *table_desc,
+                 struct acpi_table_header **out_table);
+
+void acpi_tb_put_table(struct acpi_table_desc *table_desc);
+
 /*
  * tbxfload
  */
index 5fb838e592dc430c49b657ce6fba3dce1572676f..81473a4880ce219febb9024515cc92759362d426 100644 (file)
@@ -311,6 +311,8 @@ void acpi_tb_parse_fadt(void)
 {
        u32 length;
        struct acpi_table_header *table;
+       struct acpi_table_desc *fadt_desc;
+       acpi_status status;
 
        /*
         * The FADT has multiple versions with different lengths,
@@ -319,14 +321,12 @@ void acpi_tb_parse_fadt(void)
         * Get a local copy of the FADT and convert it to a common format
         * Map entire FADT, assumed to be smaller than one page.
         */
-       length = acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index].length;
-
-       table =
-           acpi_os_map_memory(acpi_gbl_root_table_list.
-                              tables[acpi_gbl_fadt_index].address, length);
-       if (!table) {
+       fadt_desc = &acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index];
+       status = acpi_tb_get_table(fadt_desc, &table);
+       if (ACPI_FAILURE(status)) {
                return;
        }
+       length = fadt_desc->length;
 
        /*
         * Validate the FADT checksum before we copy the table. Ignore
@@ -340,7 +340,7 @@ void acpi_tb_parse_fadt(void)
 
        /* All done with the real FADT, unmap it */
 
-       acpi_os_unmap_memory(table, length);
+       acpi_tb_put_table(fadt_desc);
 
        /* Obtain the DSDT and FACS tables via their addresses within the FADT */
 
index 51eb07cf989844842b6dce634a589d1e7440e154..86854e84680056e164c6adad591ad772e85a3e79 100644 (file)
@@ -381,3 +381,88 @@ next_table:
        acpi_os_unmap_memory(table, length);
        return_ACPI_STATUS(AE_OK);
 }
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_get_table
+ *
+ * PARAMETERS:  table_desc          - Table descriptor
+ *              out_table           - Where the pointer to the table is returned
+ *
+ * RETURN:      Status and pointer to the requested table
+ *
+ * DESCRIPTION: Increase a reference to a table descriptor and return the
+ *              validated table pointer.
+ *              If the table descriptor is an entry of the root table list,
+ *              this API must be invoked with ACPI_MTX_TABLES acquired.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_table(struct acpi_table_desc *table_desc,
+                 struct acpi_table_header **out_table)
+{
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(acpi_tb_get_table);
+
+       if (table_desc->validation_count == 0) {
+
+               /* Table need to be "VALIDATED" */
+
+               status = acpi_tb_validate_table(table_desc);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
+       }
+
+       table_desc->validation_count++;
+       if (table_desc->validation_count == 0) {
+               ACPI_ERROR((AE_INFO,
+                           "Table %p, Validation count is zero after increment\n",
+                           table_desc));
+               table_desc->validation_count--;
+               return_ACPI_STATUS(AE_LIMIT);
+       }
+
+       *out_table = table_desc->pointer;
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_put_table
+ *
+ * PARAMETERS:  table_desc          - Table descriptor
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Decrease a reference to a table descriptor and release the
+ *              validated table pointer if no references.
+ *              If the table descriptor is an entry of the root table list,
+ *              this API must be invoked with ACPI_MTX_TABLES acquired.
+ *
+ ******************************************************************************/
+
+void acpi_tb_put_table(struct acpi_table_desc *table_desc)
+{
+
+       ACPI_FUNCTION_TRACE(acpi_tb_put_table);
+
+       if (table_desc->validation_count == 0) {
+               ACPI_WARNING((AE_INFO,
+                             "Table %p, Validation count is zero before decrement\n",
+                             table_desc));
+               return_VOID;
+       }
+       table_desc->validation_count--;
+
+       if (table_desc->validation_count == 0) {
+
+               /* Table need to be "INVALIDATED" */
+
+               acpi_tb_invalidate_table(table_desc);
+       }
+
+       return_VOID;
+}
index d5adb7ac468430c82c4c1d7a1d7c75be6be40c5e..7684707b254b93cf7b7c9aa90ef3346d50609ee7 100644 (file)
@@ -282,7 +282,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_get_table_with_size
+ * FUNCTION:    acpi_get_table
  *
  * PARAMETERS:  signature           - ACPI signature of needed table
  *              instance            - Which instance (for SSDTs)
@@ -292,16 +292,21 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header)
  *
  * DESCRIPTION: Finds and verifies an ACPI table. Table must be in the
  *              RSDT/XSDT.
+ *              Note that an early stage acpi_get_table() call must be paired
+ *              with an early stage acpi_put_table() call. otherwise the table
+ *              pointer mapped by the early stage mapping implementation may be
+ *              erroneously unmapped by the late stage unmapping implementation
+ *              in an acpi_put_table() invoked during the late stage.
  *
  ******************************************************************************/
 acpi_status
-acpi_get_table_with_size(char *signature,
-              u32 instance, struct acpi_table_header **out_table,
-              acpi_size *tbl_size)
+acpi_get_table(char *signature,
+              u32 instance, struct acpi_table_header ** out_table)
 {
        u32 i;
        u32 j;
-       acpi_status status;
+       acpi_status status = AE_NOT_FOUND;
+       struct acpi_table_desc *table_desc;
 
        /* Parameter validation */
 
@@ -309,13 +314,22 @@ acpi_get_table_with_size(char *signature,
                return (AE_BAD_PARAMETER);
        }
 
+       /*
+        * Note that the following line is required by some OSPMs, they only
+        * check if the returned table is NULL instead of the returned status
+        * to determined if this function is succeeded.
+        */
+       *out_table = NULL;
+
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
        /* Walk the root table list */
 
        for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
             i++) {
-               if (!ACPI_COMPARE_NAME
-                   (&(acpi_gbl_root_table_list.tables[i].signature),
-                    signature)) {
+               table_desc = &acpi_gbl_root_table_list.tables[i];
+
+               if (!ACPI_COMPARE_NAME(&table_desc->signature, signature)) {
                        continue;
                }
 
@@ -323,43 +337,65 @@ acpi_get_table_with_size(char *signature,
                        continue;
                }
 
-               status =
-                   acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
-               if (ACPI_SUCCESS(status)) {
-                       *out_table = acpi_gbl_root_table_list.tables[i].pointer;
-                       *tbl_size = acpi_gbl_root_table_list.tables[i].length;
-               }
-
-               if (!acpi_gbl_permanent_mmap) {
-                       acpi_gbl_root_table_list.tables[i].pointer = NULL;
-               }
-
-               return (status);
+               status = acpi_tb_get_table(table_desc, out_table);
+               break;
        }
 
-       return (AE_NOT_FOUND);
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return (status);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_get_table_with_size)
+ACPI_EXPORT_SYMBOL(acpi_get_table)
 
-acpi_status
-acpi_get_table(char *signature,
-              u32 instance, struct acpi_table_header **out_table)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_put_table
+ *
+ * PARAMETERS:  table               - The pointer to the table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Release a table returned by acpi_get_table() and its clones.
+ *              Note that it is not safe if this function was invoked after an
+ *              uninstallation happened to the original table descriptor.
+ *              Currently there is no OSPMs' requirement to handle such
+ *              situations.
+ *
+ ******************************************************************************/
+void acpi_put_table(struct acpi_table_header *table)
 {
-       acpi_size tbl_size;
+       u32 i;
+       struct acpi_table_desc *table_desc;
+
+       ACPI_FUNCTION_TRACE(acpi_put_table);
+
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+       /* Walk the root table list */
+
+       for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
+               table_desc = &acpi_gbl_root_table_list.tables[i];
 
-       return acpi_get_table_with_size(signature,
-                      instance, out_table, &tbl_size);
+               if (table_desc->pointer != table) {
+                       continue;
+               }
+
+               acpi_tb_put_table(table_desc);
+               break;
+       }
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_VOID;
 }
 
-ACPI_EXPORT_SYMBOL(acpi_get_table)
+ACPI_EXPORT_SYMBOL(acpi_put_table)
 
 /*******************************************************************************
  *
  * FUNCTION:    acpi_get_table_by_index
  *
  * PARAMETERS:  table_index         - Table index
- *              table               - Where the pointer to the table is returned
+ *              out_table           - Where the pointer to the table is returned
  *
  * RETURN:      Status and pointer to the requested table
  *
@@ -368,7 +404,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table)
  *
  ******************************************************************************/
 acpi_status
-acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
+acpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table)
 {
        acpi_status status;
 
@@ -376,35 +412,33 @@ acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
 
        /* Parameter validation */
 
-       if (!table) {
+       if (!out_table) {
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
+       /*
+        * Note that the following line is required by some OSPMs, they only
+        * check if the returned table is NULL instead of the returned status
+        * to determined if this function is succeeded.
+        */
+       *out_table = NULL;
+
        (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
 
        /* Validate index */
 
        if (table_index >= acpi_gbl_root_table_list.current_table_count) {
-               (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+               status = AE_BAD_PARAMETER;
+               goto unlock_and_exit;
        }
 
-       if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
-
-               /* Table is not mapped, map it */
+       status =
+           acpi_tb_get_table(&acpi_gbl_root_table_list.tables[table_index],
+                             out_table);
 
-               status =
-                   acpi_tb_validate_table(&acpi_gbl_root_table_list.
-                                          tables[table_index]);
-               if (ACPI_FAILURE(status)) {
-                       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-                       return_ACPI_STATUS(status);
-               }
-       }
-
-       *table = acpi_gbl_root_table_list.tables[table_index].pointer;
+unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-       return_ACPI_STATUS(AE_OK);
+       return_ACPI_STATUS(status);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
index 5cbefd7621f01174ff1c3ba3012d9c193dbc1e49..95855cb9d6fb772634e2dd6f683c62a1de819ffd 100644 (file)
@@ -974,7 +974,7 @@ void __init acpi_early_init(void)
        if (!acpi_strict)
                acpi_gbl_enable_interpreter_slack = TRUE;
 
-       acpi_gbl_permanent_mmap = 1;
+       acpi_permanent_mmap = true;
 
        /*
         * If the machine falls into the DMI check table,
index 312c4b4dc363fdbc4847d3db55c0cfbfbb80f5f4..2f82b8eba360e7f369338b7d7a340060d6519f4f 100644 (file)
@@ -2806,12 +2806,13 @@ static int acpi_nfit_add(struct acpi_device *adev)
        acpi_size sz;
        int rc = 0;
 
-       status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz);
+       status = acpi_get_table(ACPI_SIG_NFIT, 0, &tbl);
        if (ACPI_FAILURE(status)) {
                /* This is ok, we could have an nvdimm hotplugged later */
                dev_dbg(dev, "failed to find NFIT at startup\n");
                return 0;
        }
+       sz = tbl->length;
 
        acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
        if (!acpi_desc)
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 9a4c6abee63e0e86a6941d19665a409d3931b301..a404ff4d71511d0a9d56ce10a238682e9ffc6073 100644 (file)
@@ -76,6 +76,7 @@ static struct workqueue_struct *kacpi_notify_wq;
 static struct workqueue_struct *kacpi_hotplug_wq;
 static bool acpi_os_initialized;
 unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
+bool acpi_permanent_mmap = false;
 
 /*
  * This list of permanent mappings is for memory that may be accessed from
@@ -306,7 +307,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
  * virtual address).  If not found, map it, add it to that list and return a
  * pointer to it.
  *
- * During early init (when acpi_gbl_permanent_mmap has not been set yet) this
+ * During early init (when acpi_permanent_mmap has not been set yet) this
  * routine simply calls __acpi_map_table() to get the job done.
  */
 void __iomem *__ref
@@ -322,7 +323,7 @@ acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
                return NULL;
        }
 
-       if (!acpi_gbl_permanent_mmap)
+       if (!acpi_permanent_mmap)
                return __acpi_map_table((unsigned long)phys, size);
 
        mutex_lock(&acpi_ioremap_lock);
@@ -392,7 +393,7 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map)
  * mappings, drop a reference to it and unmap it if there are no more active
  * references to it.
  *
- * During early init (when acpi_gbl_permanent_mmap has not been set yet) this
+ * During early init (when acpi_permanent_mmap has not been set yet) this
  * routine simply calls __acpi_unmap_table() to get the job done.  Since
  * __acpi_unmap_table() is an __init function, the __ref annotation is needed
  * here.
@@ -401,7 +402,7 @@ void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
 {
        struct acpi_ioremap *map;
 
-       if (!acpi_gbl_permanent_mmap) {
+       if (!acpi_permanent_mmap) {
                __acpi_unmap_table(virt, size);
                return;
        }
@@ -426,12 +427,6 @@ void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
-void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
-{
-       if (!acpi_gbl_permanent_mmap)
-               __acpi_unmap_table(virt, size);
-}
-
 int acpi_os_map_generic_address(struct acpi_generic_address *gas)
 {
        u64 addr;
index 5c78ee1860b0ad390671e8f1b1c624339f7414ed..611a5585a9024a728c71e60ada951b3a73936708 100644 (file)
@@ -154,18 +154,16 @@ static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
 phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
 {
        struct acpi_table_madt *madt = NULL;
-       acpi_size tbl_size;
        phys_cpuid_t rv;
 
-       acpi_get_table_with_size(ACPI_SIG_MADT, 0,
-                                (struct acpi_table_header **)&madt,
-                                &tbl_size);
+       acpi_get_table(ACPI_SIG_MADT, 0,
+                      (struct acpi_table_header **)&madt);
        if (!madt)
                return PHYS_CPUID_INVALID;
 
        rv = map_madt_entry(madt, 1, acpi_id, true);
 
-       early_acpi_os_unmap_memory(madt, tbl_size);
+       acpi_put_table((struct acpi_table_header *)madt);
 
        return rv;
 }
index 93b00cf4eb3922d541a43d200ce73d5d414f6c3f..45dec874ea55b820281457a3ae5de2fe1f12403c 100644 (file)
@@ -1120,9 +1120,6 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
                                  "support\n"));
                *cap |= ACPI_VIDEO_BACKLIGHT;
-               if (!acpi_has_method(handle, "_BQC"))
-                       printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
-                               "cannot determine initial brightness\n");
                /* We have backlight support, no need to scan further */
                return AE_CTRL_TERMINATE;
        }
index e8d7bc7d4da89b1d0ff8f86bbf5ebbb258a411e4..b8019c4c1d38908895b21a92a094074ca2bd5bd8 100644 (file)
@@ -33,7 +33,6 @@ int __init parse_spcr(bool earlycon)
 {
        static char opts[64];
        struct acpi_table_spcr *table;
-       acpi_size table_size;
        acpi_status status;
        char *uart;
        char *iotype;
@@ -43,9 +42,8 @@ int __init parse_spcr(bool earlycon)
        if (acpi_disabled)
                return -ENODEV;
 
-       status = acpi_get_table_with_size(ACPI_SIG_SPCR, 0,
-                                         (struct acpi_table_header **)&table,
-                                         &table_size);
+       status = acpi_get_table(ACPI_SIG_SPCR, 0,
+                               (struct acpi_table_header **)&table);
 
        if (ACPI_FAILURE(status))
                return -ENOENT;
@@ -106,6 +104,6 @@ int __init parse_spcr(bool earlycon)
        err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
 
 done:
-       early_acpi_os_unmap_memory((void __iomem *)table, table_size);
+       acpi_put_table((struct acpi_table_header *)table);
        return err;
 }
index cdd56c4657e05ff38ed8e11da59d0c37a91326d6..2604189d6cd156e5449c7dd071d63120ea000a0e 100644 (file)
@@ -333,7 +333,6 @@ acpi_table_parse_entries_array(char *id,
                         unsigned int max_entries)
 {
        struct acpi_table_header *table_header = NULL;
-       acpi_size tbl_size;
        int count;
        u32 instance = 0;
 
@@ -346,7 +345,7 @@ acpi_table_parse_entries_array(char *id,
        if (!strncmp(id, ACPI_SIG_MADT, 4))
                instance = acpi_apic_instance;
 
-       acpi_get_table_with_size(id, instance, &table_header, &tbl_size);
+       acpi_get_table(id, instance, &table_header);
        if (!table_header) {
                pr_warn("%4.4s not present\n", id);
                return -ENODEV;
@@ -355,7 +354,7 @@ acpi_table_parse_entries_array(char *id,
        count = acpi_parse_entries_array(id, table_size, table_header,
                        proc, proc_num, max_entries);
 
-       early_acpi_os_unmap_memory((char *)table_header, tbl_size);
+       acpi_put_table(table_header);
        return count;
 }
 
@@ -397,7 +396,6 @@ acpi_table_parse_madt(enum acpi_madt_type id,
 int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
 {
        struct acpi_table_header *table = NULL;
-       acpi_size tbl_size;
 
        if (acpi_disabled)
                return -ENODEV;
@@ -406,13 +404,13 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
                return -EINVAL;
 
        if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
-               acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size);
+               acpi_get_table(id, acpi_apic_instance, &table);
        else
-               acpi_get_table_with_size(id, 0, &table, &tbl_size);
+               acpi_get_table(id, 0, &table);
 
        if (table) {
                handler(table);
-               early_acpi_os_unmap_memory(table, tbl_size);
+               acpi_put_table(table);
                return 0;
        } else
                return -ENODEV;
@@ -426,16 +424,15 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
 static void __init check_multiple_madt(void)
 {
        struct acpi_table_header *table = NULL;
-       acpi_size tbl_size;
 
-       acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size);
+       acpi_get_table(ACPI_SIG_MADT, 2, &table);
        if (table) {
                pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n",
                        acpi_apic_instance);
                pr_warn("If \"acpi_apic_instance=%d\" works better, "
                        "notify linux-acpi@vger.kernel.org\n",
                        acpi_apic_instance ? 0 : 2);
-               early_acpi_os_unmap_memory(table, tbl_size);
+               acpi_put_table(table);
 
        } else
                acpi_apic_instance = 0;
index 1e3903d0d99441897cae42cd032dfff319b1115f..eb3af2739537a8def39259206e2345a2adc72c71 100644 (file)
@@ -363,6 +363,7 @@ static ssize_t file_name##_show(struct device *dev,         \
        return sprintf(buf, "%u\n", this_leaf->object);         \
 }
 
+show_one(id, id);
 show_one(level, level);
 show_one(coherency_line_size, coherency_line_size);
 show_one(number_of_sets, number_of_sets);
@@ -444,6 +445,7 @@ static ssize_t write_policy_show(struct device *dev,
        return n;
 }
 
+static DEVICE_ATTR_RO(id);
 static DEVICE_ATTR_RO(level);
 static DEVICE_ATTR_RO(type);
 static DEVICE_ATTR_RO(coherency_line_size);
@@ -457,6 +459,7 @@ static DEVICE_ATTR_RO(shared_cpu_list);
 static DEVICE_ATTR_RO(physical_line_partition);
 
 static struct attribute *cache_default_attrs[] = {
+       &dev_attr_id.attr,
        &dev_attr_type.attr,
        &dev_attr_level.attr,
        &dev_attr_shared_cpu_map.attr,
@@ -480,6 +483,8 @@ cache_default_attrs_is_visible(struct kobject *kobj,
        const struct cpumask *mask = &this_leaf->shared_cpu_map;
        umode_t mode = attr->mode;
 
+       if ((attr == &dev_attr_id.attr) && (this_leaf->attributes & CACHE_ID))
+               return mode;
        if ((attr == &dev_attr_type.attr) && this_leaf->type)
                return mode;
        if ((attr == &dev_attr_level.attr) && this_leaf->level)
index 3a98702b7445f747d9a710f16753d29e312b17a6..3a2ca0f79daf281c5940222f6b9da179b35f64f3 100644 (file)
@@ -930,7 +930,7 @@ static void __init acpi_cpufreq_boost_init(void)
 
 static void acpi_cpufreq_boost_exit(void)
 {
-       if (acpi_cpufreq_online >= 0)
+       if (acpi_cpufreq_online > 0)
                cpuhp_remove_state_nocalls(acpi_cpufreq_online);
 }
 
index 176e84cc3991994871d6eee9a1b8927a3bdf95fa..0cb9040eca49c3c84fb852f674f649f213bfd3e7 100644 (file)
@@ -107,7 +107,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
 }
 
 #ifdef CONFIG_REGULATOR
-static void __init s3c64xx_cpufreq_config_regulator(void)
+static void s3c64xx_cpufreq_config_regulator(void)
 {
        int count, v, i, found;
        struct cpufreq_frequency_table *freq;
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 4f973a9c7b8714d55229b6f712522f50fcfb1fdf..8ec1967a850b86361b18535955fd161a0808f6d4 100644 (file)
@@ -305,8 +305,9 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
        GOP_VBIOS_CONTENT *vbios;
        VFCT_IMAGE_HEADER *vhdr;
 
-       if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size)))
+       if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
                return false;
+       tbl_size = hdr->length;
        if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
                DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
                goto out_unmap;
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 21b6732425c50d4b368d6b0fb016ea507a8aa6a1..c829cfb02fc4c994a1167e9daa7b4c1010a97ab0 100644 (file)
@@ -603,8 +603,9 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
        GOP_VBIOS_CONTENT *vbios;
        VFCT_IMAGE_HEADER *vhdr;
 
-       if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size)))
+       if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
                return false;
+       tbl_size = hdr->length;
        if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
                DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
                goto out_unmap;
index 08153ea4d848097ef5659f40c6bb71964cbc99e2..6ce4313231257f8251b62e02f5aaa390a4619edf 100644 (file)
@@ -150,6 +150,29 @@ static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
        return 0;
 }
 
+static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id)
+{
+       u32 param, tx_fifo_depth, rx_fifo_depth;
+
+       /*
+        * Try to detect the FIFO depth if not set by interface driver,
+        * the depth could be from 2 to 256 from HW spec.
+        */
+       param = i2c_dw_read_comp_param(dev);
+       tx_fifo_depth = ((param >> 16) & 0xff) + 1;
+       rx_fifo_depth = ((param >> 8)  & 0xff) + 1;
+       if (!dev->tx_fifo_depth) {
+               dev->tx_fifo_depth = tx_fifo_depth;
+               dev->rx_fifo_depth = rx_fifo_depth;
+               dev->adapter.nr = id;
+       } else if (tx_fifo_depth >= 2) {
+               dev->tx_fifo_depth = min_t(u32, dev->tx_fifo_depth,
+                               tx_fifo_depth);
+               dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
+                               rx_fifo_depth);
+       }
+}
+
 static int dw_i2c_plat_probe(struct platform_device *pdev)
 {
        struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -245,13 +268,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
                                1000000);
        }
 
-       if (!dev->tx_fifo_depth) {
-               u32 param1 = i2c_dw_read_comp_param(dev);
-
-               dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
-               dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
-               dev->adapter.nr = pdev->id;
-       }
+       dw_i2c_set_fifo_size(dev, pdev->id);
 
        adap = &dev->adapter;
        adap->owner = THIS_MODULE;
index 3d10f1a802be4b8df5488535fda6e32f5d2b2fca..1d87757990568c40b9cebe4df7dda54fe21918f7 100644 (file)
@@ -342,7 +342,9 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
                if (result)
                        return result;
 
-               data[i] = octeon_i2c_data_read(i2c);
+               data[i] = octeon_i2c_data_read(i2c, &result);
+               if (result)
+                       return result;
                if (recv_len && i == 0) {
                        if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
                                return -EPROTO;
index 87151ea74acd475a37726fd43fa927f486ddc76e..e160f838c25461f111f89871eac87beebca61a09 100644 (file)
@@ -141,11 +141,14 @@ static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
  */
 static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
 {
+       int tries = 1000;
        u64 tmp;
 
        __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c));
        do {
                tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+               if (--tries < 0)
+                       return;
        } while ((tmp & SW_TWSI_V) != 0);
 }
 
@@ -163,24 +166,32 @@ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static inline u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg)
+static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
+                                     int *error)
 {
+       int tries = 1000;
        u64 tmp;
 
        __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c));
        do {
                tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+               if (--tries < 0) {
+                       /* signal that the returned data is invalid */
+                       if (error)
+                               *error = -EIO;
+                       return 0;
+               }
        } while ((tmp & SW_TWSI_V) != 0);
 
        return tmp & 0xFF;
 }
 
 #define octeon_i2c_ctl_read(i2c)                                       \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL)
-#define octeon_i2c_data_read(i2c)                                      \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA)
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL)
+#define octeon_i2c_data_read(i2c, error)                               \
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error)
 #define octeon_i2c_stat_read(i2c)                                      \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT)
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL)
 
 /**
  * octeon_i2c_read_int - read the TWSI_INT register
index 05cf192ef1acae340397d9ff67f942bca6d08d3e..0ab1e55558bcd7a520afd8dcf07ae3d8cb77e1c0 100644 (file)
@@ -415,6 +415,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
        adapter->algo = &xgene_slimpro_i2c_algorithm;
        adapter->class = I2C_CLASS_HWMON;
        adapter->dev.parent = &pdev->dev;
+       adapter->dev.of_node = pdev->dev.of_node;
        i2c_set_adapdata(adapter, ctx);
        rc = i2c_add_adapter(adapter);
        if (rc) {
index 3ab654bbfab56f4fe299800e2372fbee86b1385d..b7ca249ec9c38b884ed48fbb8387dcc6729f1cc6 100644 (file)
@@ -95,6 +95,7 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
                                 struct i2c_client *client, u8 val)
 {
        struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
+       int ret = -ENODEV;
 
        if (adap->algo->master_xfer) {
                struct i2c_msg msg;
@@ -104,17 +105,21 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
                msg.flags = 0;
                msg.len = 2;
                msg.buf = msgbuf;
-               return __i2c_transfer(adap, &msg, 1);
+               ret = __i2c_transfer(adap, &msg, 1);
+
+               if (ret >= 0 && ret != 1)
+                       ret = -EREMOTEIO;
        } else if (adap->algo->smbus_xfer) {
                union i2c_smbus_data data;
 
                data.byte = val;
-               return adap->algo->smbus_xfer(adap, client->addr,
-                                             client->flags, I2C_SMBUS_WRITE,
-                                             pdata->sel_reg_addr,
-                                             I2C_SMBUS_BYTE_DATA, &data);
-       } else
-               return -ENODEV;
+               ret = adap->algo->smbus_xfer(adap, client->addr,
+                                            client->flags, I2C_SMBUS_WRITE,
+                                            pdata->sel_reg_addr,
+                                            I2C_SMBUS_BYTE_DATA, &data);
+       }
+
+       return ret;
 }
 
 static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
@@ -127,10 +132,7 @@ static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
        /* Only select the channel if its different from the last channel */
        if (data->last_chan != regval) {
                err = mlxcpld_mux_reg_write(muxc->parent, client, regval);
-               if (err)
-                       data->last_chan = 0;
-               else
-                       data->last_chan = regval;
+               data->last_chan = err < 0 ? 0 : regval;
        }
 
        return err;
index 9a348ee4dc14deb9eb1686fd1a20dc672b73a5df..dd18b9ccb1f40b4f6ddf5904e1f6d529931801df 100644 (file)
@@ -167,6 +167,9 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
                buf[0] = val;
                msg.buf = buf;
                ret = __i2c_transfer(adap, &msg, 1);
+
+               if (ret >= 0 && ret != 1)
+                       ret = -EREMOTEIO;
        } else {
                union i2c_smbus_data data;
                ret = adap->algo->smbus_xfer(adap, client->addr,
@@ -195,7 +198,7 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
        /* Only select the channel if its different from the last channel */
        if (data->last_chan != regval) {
                ret = pca954x_reg_write(muxc->parent, client, regval);
-               data->last_chan = ret ? 0 : regval;
+               data->last_chan = ret < 0 ? 0 : regval;
        }
 
        return ret;
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 971154cbbb03eb36efc7fb60608afe23d48f38a2..6799cf9713f77f460f990e6bc0f38b31422c0745 100644 (file)
@@ -2209,14 +2209,13 @@ static void __init free_dma_resources(void)
 static int __init early_amd_iommu_init(void)
 {
        struct acpi_table_header *ivrs_base;
-       acpi_size ivrs_size;
        acpi_status status;
        int i, remap_cache_sz, ret = 0;
 
        if (!amd_iommu_detected)
                return -ENODEV;
 
-       status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size);
+       status = acpi_get_table("IVRS", 0, &ivrs_base);
        if (status == AE_NOT_FOUND)
                return -ENODEV;
        else if (ACPI_FAILURE(status)) {
@@ -2338,7 +2337,7 @@ static int __init early_amd_iommu_init(void)
 
 out:
        /* Don't leak any ACPI memory */
-       early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
+       acpi_put_table(ivrs_base);
        ivrs_base = NULL;
 
        return ret;
@@ -2362,10 +2361,9 @@ out:
 static bool detect_ivrs(void)
 {
        struct acpi_table_header *ivrs_base;
-       acpi_size ivrs_size;
        acpi_status status;
 
-       status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size);
+       status = acpi_get_table("IVRS", 0, &ivrs_base);
        if (status == AE_NOT_FOUND)
                return false;
        else if (ACPI_FAILURE(status)) {
@@ -2374,7 +2372,7 @@ static bool detect_ivrs(void)
                return false;
        }
 
-       early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
+       acpi_put_table(ivrs_base);
 
        /* Make sure ACS will be enabled during PCI probe */
        pci_request_acs();
index 8c53748a769d447fac83622725c305a3ee6bc92f..a88576d50740b2dbdbe6e65b2bfe1985f01c81ca 100644 (file)
@@ -68,7 +68,6 @@ DECLARE_RWSEM(dmar_global_lock);
 LIST_HEAD(dmar_drhd_units);
 
 struct acpi_table_header * __initdata dmar_tbl;
-static acpi_size dmar_tbl_size;
 static int dmar_dev_scope_status = 1;
 static unsigned long dmar_seq_ids[BITS_TO_LONGS(DMAR_UNITS_SUPPORTED)];
 
@@ -543,9 +542,7 @@ static int __init dmar_table_detect(void)
        acpi_status status = AE_OK;
 
        /* if we could find DMAR table, then there are DMAR devices */
-       status = acpi_get_table_with_size(ACPI_SIG_DMAR, 0,
-                               (struct acpi_table_header **)&dmar_tbl,
-                               &dmar_tbl_size);
+       status = acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_tbl);
 
        if (ACPI_SUCCESS(status) && !dmar_tbl) {
                pr_warn("Unable to map DMAR\n");
@@ -906,7 +903,7 @@ int __init detect_intel_iommu(void)
                x86_init.iommu.iommu_init = intel_iommu_init;
 #endif
 
-       early_acpi_os_unmap_memory((void __iomem *)dmar_tbl, dmar_tbl_size);
+       acpi_put_table(dmar_tbl);
        dmar_tbl = NULL;
        up_write(&dmar_global_lock);
 
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 c19dd820ea9b4baafb1b2d15ebb5031f464af9d0..2aeb034d5fb9cd4d0ce14e5c26a10fb6abf62538 100644 (file)
 #define RING_ENTRY_SIZE   sizeof(struct dma64dd)
 
 /* # entries in PDC dma ring */
-#define PDC_RING_ENTRIES  128
+#define PDC_RING_ENTRIES  512
+/*
+ * Minimum number of ring descriptor entries that must be free to tell mailbox
+ * framework that it can submit another request
+ */
+#define PDC_RING_SPACE_MIN  15
+
 #define PDC_RING_SIZE    (PDC_RING_ENTRIES * RING_ENTRY_SIZE)
 /* Rings are 8k aligned */
 #define RING_ALIGN_ORDER  13
  * Interrupt mask and status definitions. Enable interrupts for tx and rx on
  * ring 0
  */
-#define PDC_XMTINT_0         (24 + PDC_RINGSET)
 #define PDC_RCVINT_0         (16 + PDC_RINGSET)
-#define PDC_XMTINTEN_0       BIT(PDC_XMTINT_0)
 #define PDC_RCVINTEN_0       BIT(PDC_RCVINT_0)
-#define PDC_INTMASK  (PDC_XMTINTEN_0 | PDC_RCVINTEN_0)
+#define PDC_INTMASK         (PDC_RCVINTEN_0)
 #define PDC_LAZY_FRAMECOUNT  1
 #define PDC_LAZY_TIMEOUT     10000
 #define PDC_LAZY_INT  (PDC_LAZY_TIMEOUT | (PDC_LAZY_FRAMECOUNT << 24))
 
 /*
  * Sets the following bits for write to transmit control reg:
- *  0    - XmtEn - enable activity on the tx channel
  * 11    - PtyChkDisable - parity check is disabled
  * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
  */
-#define PDC_TX_CTL              0x000C0801
+#define PDC_TX_CTL             0x000C0800
+
+/* Bit in tx control reg to enable tx channel */
+#define PDC_TX_ENABLE          0x1
 
 /*
  * Sets the following bits for write to receive control reg:
- * 0     - RcvEn - enable activity on the rx channel
  * 7:1   - RcvOffset - size in bytes of status region at start of rx frame buf
  * 9     - SepRxHdrDescEn - place start of new frames only in descriptors
  *                          that have StartOfFrame set
  * 11    - PtyChkDisable - parity check is disabled
  * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
  */
-#define PDC_RX_CTL              0x000C0E01
+#define PDC_RX_CTL             0x000C0E00
+
+/* Bit in rx control reg to enable rx channel */
+#define PDC_RX_ENABLE          0x1
 
 #define CRYPTO_D64_RS0_CD_MASK   ((PDC_RING_ENTRIES * RING_ENTRY_SIZE) - 1)
 
@@ -252,11 +260,29 @@ struct pdc_ring_alloc {
        u32         size;    /* ring allocation size in bytes */
 };
 
+/*
+ * context associated with a receive descriptor.
+ * @rxp_ctx: opaque context associated with frame that starts at each
+ *           rx ring index.
+ * @dst_sg:  Scatterlist used to form reply frames beginning at a given ring
+ *           index. Retained in order to unmap each sg after reply is processed.
+ * @rxin_numd: Number of rx descriptors associated with the message that starts
+ *             at a descriptor index. Not set for every index. For example,
+ *             if descriptor index i points to a scatterlist with 4 entries,
+ *             then the next three descriptor indexes don't have a value set.
+ * @resp_hdr: Virtual address of buffer used to catch DMA rx status
+ * @resp_hdr_daddr: physical address of DMA rx status buffer
+ */
+struct pdc_rx_ctx {
+       void *rxp_ctx;
+       struct scatterlist *dst_sg;
+       u32  rxin_numd;
+       void *resp_hdr;
+       dma_addr_t resp_hdr_daddr;
+};
+
 /* PDC state structure */
 struct pdc_state {
-       /* synchronize access to this PDC state structure */
-       spinlock_t pdc_lock;
-
        /* Index of the PDC whose state is in this structure instance */
        u8 pdc_idx;
 
@@ -272,13 +298,8 @@ struct pdc_state {
 
        unsigned int pdc_irq;
 
-       /*
-        * Last interrupt status read from PDC device. Saved in interrupt
-        * handler so the handler can clear the interrupt in the device,
-        * and the interrupt thread called later can know which interrupt
-        * bits are active.
-        */
-       unsigned long intstatus;
+       /* tasklet for deferred processing after DMA rx interrupt */
+       struct tasklet_struct rx_tasklet;
 
        /* Number of bytes of receive status prior to each rx frame */
        u32 rx_status_len;
@@ -369,11 +390,7 @@ struct pdc_state {
        /* Index of next rx descriptor to post. */
        u32  rxout;
 
-       /*
-        * opaque context associated with frame that starts at each
-        * rx ring index.
-        */
-       void *rxp_ctx[PDC_RING_ENTRIES];
+       struct pdc_rx_ctx rx_ctx[PDC_RING_ENTRIES];
 
        /*
         * Scatterlists used to form request and reply frames beginning at a
@@ -381,27 +398,18 @@ struct pdc_state {
         * is processed
         */
        struct scatterlist *src_sg[PDC_RING_ENTRIES];
-       struct scatterlist *dst_sg[PDC_RING_ENTRIES];
-
-       /*
-        * Number of rx descriptors associated with the message that starts
-        * at this descriptor index. Not set for every index. For example,
-        * if descriptor index i points to a scatterlist with 4 entries, then
-        * the next three descriptor indexes don't have a value set.
-        */
-       u32  rxin_numd[PDC_RING_ENTRIES];
-
-       void *resp_hdr[PDC_RING_ENTRIES];
-       dma_addr_t resp_hdr_daddr[PDC_RING_ENTRIES];
 
        struct dentry *debugfs_stats;  /* debug FS stats file for this PDC */
 
        /* counters */
-       u32  pdc_requests;    /* number of request messages submitted */
-       u32  pdc_replies;     /* number of reply messages received */
-       u32  txnobuf;         /* count of tx ring full */
-       u32  rxnobuf;         /* count of rx ring full */
-       u32  rx_oflow;        /* count of rx overflows */
+       u32  pdc_requests;     /* number of request messages submitted */
+       u32  pdc_replies;      /* number of reply messages received */
+       u32  last_tx_not_done; /* too few tx descriptors to indicate done */
+       u32  tx_ring_full;     /* unable to accept msg because tx ring full */
+       u32  rx_ring_full;     /* unable to accept msg because rx ring full */
+       u32  txnobuf;          /* unable to create tx descriptor */
+       u32  rxnobuf;          /* unable to create rx descriptor */
+       u32  rx_oflow;         /* count of rx overflows */
 };
 
 /* Global variables */
@@ -434,20 +442,33 @@ static ssize_t pdc_debugfs_read(struct file *filp, char __user *ubuf,
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "SPU %u stats:\n", pdcs->pdc_idx);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "PDC requests............%u\n",
+                              "PDC requests....................%u\n",
                               pdcs->pdc_requests);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "PDC responses...........%u\n",
+                              "PDC responses...................%u\n",
                               pdcs->pdc_replies);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "Tx err ring full........%u\n",
+                              "Tx not done.....................%u\n",
+                              pdcs->last_tx_not_done);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "Tx ring full....................%u\n",
+                              pdcs->tx_ring_full);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "Rx ring full....................%u\n",
+                              pdcs->rx_ring_full);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "Tx desc write fail. Ring full...%u\n",
                               pdcs->txnobuf);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "Rx err ring full........%u\n",
+                              "Rx desc write fail. Ring full...%u\n",
                               pdcs->rxnobuf);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "Receive overflow........%u\n",
+                              "Receive overflow................%u\n",
                               pdcs->rx_oflow);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "Num frags in rx ring............%u\n",
+                              NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr,
+                                         pdcs->nrxpost));
 
        if (out_offset > out_count)
                out_offset = out_count;
@@ -480,17 +501,16 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs)
        if (!debugfs_dir)
                debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
 
-       pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, S_IRUSR,
+       /* S_IRUSR == 0400 */
+       pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400,
                                                  debugfs_dir, pdcs,
                                                  &pdc_debugfs_stats);
 }
 
 static void pdc_free_debugfs(void)
 {
-       if (debugfs_dir && simple_empty(debugfs_dir)) {
-               debugfs_remove_recursive(debugfs_dir);
-               debugfs_dir = NULL;
-       }
+       debugfs_remove_recursive(debugfs_dir);
+       debugfs_dir = NULL;
 }
 
 /**
@@ -505,17 +525,17 @@ pdc_build_rxd(struct pdc_state *pdcs, dma_addr_t dma_addr,
              u32 buf_len, u32 flags)
 {
        struct device *dev = &pdcs->pdev->dev;
+       struct dma64dd *rxd = &pdcs->rxd_64[pdcs->rxout];
 
        dev_dbg(dev,
                "Writing rx descriptor for PDC %u at index %u with length %u. flags %#x\n",
                pdcs->pdc_idx, pdcs->rxout, buf_len, flags);
 
-       iowrite32(lower_32_bits(dma_addr),
-                 (void *)&pdcs->rxd_64[pdcs->rxout].addrlow);
-       iowrite32(upper_32_bits(dma_addr),
-                 (void *)&pdcs->rxd_64[pdcs->rxout].addrhigh);
-       iowrite32(flags, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl1);
-       iowrite32(buf_len, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl2);
+       rxd->addrlow = cpu_to_le32(lower_32_bits(dma_addr));
+       rxd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr));
+       rxd->ctrl1 = cpu_to_le32(flags);
+       rxd->ctrl2 = cpu_to_le32(buf_len);
+
        /* bump ring index and return */
        pdcs->rxout = NEXTRXD(pdcs->rxout, pdcs->nrxpost);
 }
@@ -533,53 +553,50 @@ pdc_build_txd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len,
              u32 flags)
 {
        struct device *dev = &pdcs->pdev->dev;
+       struct dma64dd *txd = &pdcs->txd_64[pdcs->txout];
 
        dev_dbg(dev,
                "Writing tx descriptor for PDC %u at index %u with length %u, flags %#x\n",
                pdcs->pdc_idx, pdcs->txout, buf_len, flags);
 
-       iowrite32(lower_32_bits(dma_addr),
-                 (void *)&pdcs->txd_64[pdcs->txout].addrlow);
-       iowrite32(upper_32_bits(dma_addr),
-                 (void *)&pdcs->txd_64[pdcs->txout].addrhigh);
-       iowrite32(flags, (void *)&pdcs->txd_64[pdcs->txout].ctrl1);
-       iowrite32(buf_len, (void *)&pdcs->txd_64[pdcs->txout].ctrl2);
+       txd->addrlow = cpu_to_le32(lower_32_bits(dma_addr));
+       txd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr));
+       txd->ctrl1 = cpu_to_le32(flags);
+       txd->ctrl2 = cpu_to_le32(buf_len);
 
        /* bump ring index and return */
        pdcs->txout = NEXTTXD(pdcs->txout, pdcs->ntxpost);
 }
 
 /**
- * pdc_receive() - Receive a response message from a given SPU.
+ * pdc_receive_one() - Receive a response message from a given SPU.
  * @pdcs:    PDC state for the SPU to receive from
- * @mssg:    mailbox message to be returned to client
  *
  * When the return code indicates success, the response message is available in
  * the receive buffers provided prior to submission of the request.
  *
- * Input:
- *   pdcs - PDC state structure for the SPU to be polled
- *   mssg - mailbox message to be returned to client. This function sets the
- *         context pointer on the message to help the client associate the
- *         response with a request.
- *
  * Return:  PDC_SUCCESS if one or more receive descriptors was processed
  *          -EAGAIN indicates that no response message is available
  *          -EIO an error occurred
  */
 static int
-pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
+pdc_receive_one(struct pdc_state *pdcs)
 {
        struct device *dev = &pdcs->pdev->dev;
+       struct mbox_controller *mbc;
+       struct mbox_chan *chan;
+       struct brcm_message mssg;
        u32 len, rx_status;
        u32 num_frags;
-       int i;
        u8 *resp_hdr;    /* virtual addr of start of resp message DMA header */
        u32 frags_rdy;   /* number of fragments ready to read */
        u32 rx_idx;      /* ring index of start of receive frame */
        dma_addr_t resp_hdr_daddr;
+       struct pdc_rx_ctx *rx_ctx;
 
-       spin_lock(&pdcs->pdc_lock);
+       mbc = &pdcs->mbc;
+       chan = &mbc->chans[0];
+       mssg.type = BRCM_MESSAGE_SPU;
 
        /*
         * return if a complete response message is not yet ready.
@@ -587,47 +604,34 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
         * to read.
         */
        frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost);
-       if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) {
-               /* See if the hw has written more fragments than we know */
-               pdcs->last_rx_curr =
-                   (ioread32((void *)&pdcs->rxregs_64->status0) &
-                    CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE;
-               frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr,
-                                      pdcs->nrxpost);
-               if ((frags_rdy == 0) ||
-                   (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) {
-                       /* No response ready */
-                       spin_unlock(&pdcs->pdc_lock);
-                       return -EAGAIN;
-               }
-               /* can't read descriptors/data until write index is read */
-               rmb();
-       }
+       if ((frags_rdy == 0) ||
+           (frags_rdy < pdcs->rx_ctx[pdcs->rxin].rxin_numd))
+               /* No response ready */
+               return -EAGAIN;
 
        num_frags = pdcs->txin_numd[pdcs->txin];
+       WARN_ON(num_frags == 0);
+
        dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin],
                     sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE);
 
-       for (i = 0; i < num_frags; i++)
-               pdcs->txin = NEXTTXD(pdcs->txin, pdcs->ntxpost);
+       pdcs->txin = (pdcs->txin + num_frags) & pdcs->ntxpost;
 
        dev_dbg(dev, "PDC %u reclaimed %d tx descriptors",
                pdcs->pdc_idx, num_frags);
 
        rx_idx = pdcs->rxin;
-       num_frags = pdcs->rxin_numd[rx_idx];
+       rx_ctx = &pdcs->rx_ctx[rx_idx];
+       num_frags = rx_ctx->rxin_numd;
        /* Return opaque context with result */
-       mssg->ctx = pdcs->rxp_ctx[rx_idx];
-       pdcs->rxp_ctx[rx_idx] = NULL;
-       resp_hdr = pdcs->resp_hdr[rx_idx];
-       resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx];
-       dma_unmap_sg(dev, pdcs->dst_sg[rx_idx],
-                    sg_nents(pdcs->dst_sg[rx_idx]), DMA_FROM_DEVICE);
-
-       for (i = 0; i < num_frags; i++)
-               pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost);
+       mssg.ctx = rx_ctx->rxp_ctx;
+       rx_ctx->rxp_ctx = NULL;
+       resp_hdr = rx_ctx->resp_hdr;
+       resp_hdr_daddr = rx_ctx->resp_hdr_daddr;
+       dma_unmap_sg(dev, rx_ctx->dst_sg, sg_nents(rx_ctx->dst_sg),
+                    DMA_FROM_DEVICE);
 
-       spin_unlock(&pdcs->pdc_lock);
+       pdcs->rxin = (pdcs->rxin + num_frags) & pdcs->nrxpost;
 
        dev_dbg(dev, "PDC %u reclaimed %d rx descriptors",
                pdcs->pdc_idx, num_frags);
@@ -659,12 +663,35 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
 
        dma_pool_free(pdcs->rx_buf_pool, resp_hdr, resp_hdr_daddr);
 
+       mbox_chan_received_data(chan, &mssg);
+
        pdcs->pdc_replies++;
-       /* if we read one or more rx descriptors, claim success */
-       if (num_frags > 0)
-               return PDC_SUCCESS;
-       else
-               return -EIO;
+       return PDC_SUCCESS;
+}
+
+/**
+ * pdc_receive() - Process as many responses as are available in the rx ring.
+ * @pdcs:  PDC state
+ *
+ * Called within the hard IRQ.
+ * Return:
+ */
+static int
+pdc_receive(struct pdc_state *pdcs)
+{
+       int rx_status;
+
+       /* read last_rx_curr from register once */
+       pdcs->last_rx_curr =
+           (ioread32(&pdcs->rxregs_64->status0) &
+            CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE;
+
+       do {
+               /* Could be many frames ready */
+               rx_status = pdc_receive_one(pdcs);
+       } while (rx_status == PDC_SUCCESS);
+
+       return 0;
 }
 
 /**
@@ -766,8 +793,8 @@ static int pdc_tx_list_final(struct pdc_state *pdcs)
         * before chip starts to process new request
         */
        wmb();
-       iowrite32(pdcs->rxout << 4, (void *)&pdcs->rxregs_64->ptr);
-       iowrite32(pdcs->txout << 4, (void *)&pdcs->txregs_64->ptr);
+       iowrite32(pdcs->rxout << 4, &pdcs->rxregs_64->ptr);
+       iowrite32(pdcs->txout << 4, &pdcs->txregs_64->ptr);
        pdcs->pdc_requests++;
 
        return PDC_SUCCESS;
@@ -796,6 +823,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
        u32 rx_pkt_cnt = 1;     /* Adding a single rx buffer */
        dma_addr_t daddr;
        void *vaddr;
+       struct pdc_rx_ctx *rx_ctx;
 
        rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
                                              pdcs->nrxpost);
@@ -806,7 +834,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
 
        /* allocate a buffer for the dma rx status */
        vaddr = dma_pool_zalloc(pdcs->rx_buf_pool, GFP_ATOMIC, &daddr);
-       if (!vaddr)
+       if (unlikely(!vaddr))
                return -ENOMEM;
 
        /*
@@ -819,15 +847,16 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
 
        /* This is always the first descriptor in the receive sequence */
        flags = D64_CTRL1_SOF;
-       pdcs->rxin_numd[pdcs->rx_msg_start] = 1;
+       pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd = 1;
 
        if (unlikely(pdcs->rxout == (pdcs->nrxd - 1)))
                flags |= D64_CTRL1_EOT;
 
-       pdcs->rxp_ctx[pdcs->rxout] = ctx;
-       pdcs->dst_sg[pdcs->rxout] = dst_sg;
-       pdcs->resp_hdr[pdcs->rxout] = vaddr;
-       pdcs->resp_hdr_daddr[pdcs->rxout] = daddr;
+       rx_ctx = &pdcs->rx_ctx[pdcs->rxout];
+       rx_ctx->rxp_ctx = ctx;
+       rx_ctx->dst_sg = dst_sg;
+       rx_ctx->resp_hdr = vaddr;
+       rx_ctx->resp_hdr_daddr = daddr;
        pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags);
        return PDC_SUCCESS;
 }
@@ -895,7 +924,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
                desc_w++;
                sg = sg_next(sg);
        }
-       pdcs->rxin_numd[pdcs->rx_msg_start] += desc_w;
+       pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd += desc_w;
 
        return PDC_SUCCESS;
 }
@@ -903,7 +932,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
 /**
  * pdc_irq_handler() - Interrupt handler called in interrupt context.
  * @irq:      Interrupt number that has fired
- * @cookie:   PDC state for DMA engine that generated the interrupt
+ * @data:     device struct for DMA engine that generated the interrupt
  *
  * We have to clear the device interrupt status flags here. So cache the
  * status for later use in the thread function. Other than that, just return
@@ -912,88 +941,39 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
  * Return: IRQ_WAKE_THREAD if interrupt is ours
  *         IRQ_NONE otherwise
  */
-static irqreturn_t pdc_irq_handler(int irq, void *cookie)
+static irqreturn_t pdc_irq_handler(int irq, void *data)
 {
-       struct pdc_state *pdcs = cookie;
+       struct device *dev = (struct device *)data;
+       struct pdc_state *pdcs = dev_get_drvdata(dev);
        u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
 
-       if (intstatus & PDC_XMTINTEN_0)
-               set_bit(PDC_XMTINT_0, &pdcs->intstatus);
-       if (intstatus & PDC_RCVINTEN_0)
-               set_bit(PDC_RCVINT_0, &pdcs->intstatus);
+       if (unlikely(intstatus == 0))
+               return IRQ_NONE;
+
+       /* Disable interrupts until soft handler runs */
+       iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
 
        /* Clear interrupt flags in device */
        iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
 
        /* Wakeup IRQ thread */
-       if (pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))
-               return IRQ_WAKE_THREAD;
-
-       return IRQ_NONE;
+       tasklet_schedule(&pdcs->rx_tasklet);
+       return IRQ_HANDLED;
 }
 
 /**
- * pdc_irq_thread() - Function invoked on deferred thread when a DMA tx has
- * completed or data is available to receive.
- * @irq:    Interrupt number
- * @cookie: PDC state for PDC that generated the interrupt
- *
- * On DMA tx complete, notify the mailbox client. On DMA rx complete, process
- * as many SPU response messages as are available and send each to the mailbox
- * client.
- *
- * Return: IRQ_HANDLED if we recognized and handled the interrupt
- *         IRQ_NONE otherwise
+ * pdc_tasklet_cb() - Tasklet callback that runs the deferred processing after
+ * a DMA receive interrupt. Reenables the receive interrupt.
+ * @data: PDC state structure
  */
-static irqreturn_t pdc_irq_thread(int irq, void *cookie)
+static void pdc_tasklet_cb(unsigned long data)
 {
-       struct pdc_state *pdcs = cookie;
-       struct mbox_controller *mbc;
-       struct mbox_chan *chan;
-       bool tx_int;
-       bool rx_int;
-       int rx_status;
-       struct brcm_message mssg;
+       struct pdc_state *pdcs = (struct pdc_state *)data;
 
-       tx_int = test_and_clear_bit(PDC_XMTINT_0, &pdcs->intstatus);
-       rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus);
+       pdc_receive(pdcs);
 
-       if (pdcs && (tx_int || rx_int)) {
-               dev_dbg(&pdcs->pdev->dev,
-                       "%s() got irq %d with tx_int %s, rx_int %s",
-                       __func__, irq,
-                       tx_int ? "set" : "clear", rx_int ? "set" : "clear");
-
-               mbc = &pdcs->mbc;
-               chan = &mbc->chans[0];
-
-               if (tx_int) {
-                       dev_dbg(&pdcs->pdev->dev, "%s(): tx done", __func__);
-                       /* only one frame in flight at a time */
-                       mbox_chan_txdone(chan, PDC_SUCCESS);
-               }
-               if (rx_int) {
-                       while (1) {
-                               /* Could be many frames ready */
-                               memset(&mssg, 0, sizeof(mssg));
-                               mssg.type = BRCM_MESSAGE_SPU;
-                               rx_status = pdc_receive(pdcs, &mssg);
-                               if (rx_status >= 0) {
-                                       dev_dbg(&pdcs->pdev->dev,
-                                               "%s(): invoking client rx cb",
-                                               __func__);
-                                       mbox_chan_received_data(chan, &mssg);
-                               } else {
-                                       dev_dbg(&pdcs->pdev->dev,
-                                               "%s(): no SPU response available",
-                                               __func__);
-                                       break;
-                               }
-                       }
-               }
-               return IRQ_HANDLED;
-       }
-       return IRQ_NONE;
+       /* reenable interrupts */
+       iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
 }
 
 /**
@@ -1016,14 +996,14 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
 
        /* Allocate tx ring */
        tx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &tx.dmabase);
-       if (!tx.vbase) {
+       if (unlikely(!tx.vbase)) {
                err = -ENOMEM;
                goto done;
        }
 
        /* Allocate rx ring */
        rx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &rx.dmabase);
-       if (!rx.vbase) {
+       if (unlikely(!rx.vbase)) {
                err = -ENOMEM;
                goto fail_dealloc;
        }
@@ -1033,9 +1013,6 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
        dev_dbg(dev, " - base DMA addr of rx ring      %pad", &rx.dmabase);
        dev_dbg(dev, " - base virtual addr of rx ring  %p", rx.vbase);
 
-       /* lock after ring allocation to avoid scheduling while atomic */
-       spin_lock(&pdcs->pdc_lock);
-
        memcpy(&pdcs->tx_ring_alloc, &tx, sizeof(tx));
        memcpy(&pdcs->rx_ring_alloc, &rx, sizeof(rx));
 
@@ -1053,40 +1030,52 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
 
        /* Tell device the base DMA address of each ring */
        dma_reg = &pdcs->regs->dmaregs[ringset];
+
+       /* But first disable DMA and set curptr to 0 for both TX & RX */
+       iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
+       iowrite32((PDC_RX_CTL + (pdcs->rx_status_len << 1)),
+                 &dma_reg->dmarcv.control);
+       iowrite32(0, &dma_reg->dmaxmt.ptr);
+       iowrite32(0, &dma_reg->dmarcv.ptr);
+
+       /* Set base DMA addresses */
        iowrite32(lower_32_bits(pdcs->tx_ring_alloc.dmabase),
-                 (void *)&dma_reg->dmaxmt.addrlow);
+                 &dma_reg->dmaxmt.addrlow);
        iowrite32(upper_32_bits(pdcs->tx_ring_alloc.dmabase),
-                 (void *)&dma_reg->dmaxmt.addrhigh);
+                 &dma_reg->dmaxmt.addrhigh);
 
        iowrite32(lower_32_bits(pdcs->rx_ring_alloc.dmabase),
-                 (void *)&dma_reg->dmarcv.addrlow);
+                 &dma_reg->dmarcv.addrlow);
        iowrite32(upper_32_bits(pdcs->rx_ring_alloc.dmabase),
-                 (void *)&dma_reg->dmarcv.addrhigh);
+                 &dma_reg->dmarcv.addrhigh);
+
+       /* Re-enable DMA */
+       iowrite32(PDC_TX_CTL | PDC_TX_ENABLE, &dma_reg->dmaxmt.control);
+       iowrite32((PDC_RX_CTL | PDC_RX_ENABLE | (pdcs->rx_status_len << 1)),
+                 &dma_reg->dmarcv.control);
 
        /* Initialize descriptors */
        for (i = 0; i < PDC_RING_ENTRIES; i++) {
                /* Every tx descriptor can be used for start of frame. */
                if (i != pdcs->ntxpost) {
                        iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF,
-                                 (void *)&pdcs->txd_64[i].ctrl1);
+                                 &pdcs->txd_64[i].ctrl1);
                } else {
                        /* Last descriptor in ringset. Set End of Table. */
                        iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF |
-                                 D64_CTRL1_EOT,
-                                 (void *)&pdcs->txd_64[i].ctrl1);
+                                 D64_CTRL1_EOT, &pdcs->txd_64[i].ctrl1);
                }
 
                /* Every rx descriptor can be used for start of frame */
                if (i != pdcs->nrxpost) {
                        iowrite32(D64_CTRL1_SOF,
-                                 (void *)&pdcs->rxd_64[i].ctrl1);
+                                 &pdcs->rxd_64[i].ctrl1);
                } else {
                        /* Last descriptor in ringset. Set End of Table. */
                        iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOT,
-                                 (void *)&pdcs->rxd_64[i].ctrl1);
+                                 &pdcs->rxd_64[i].ctrl1);
                }
        }
-       spin_unlock(&pdcs->pdc_lock);
        return PDC_SUCCESS;
 
 fail_dealloc:
@@ -1110,6 +1099,80 @@ static void pdc_ring_free(struct pdc_state *pdcs)
        }
 }
 
+/**
+ * pdc_desc_count() - Count the number of DMA descriptors that will be required
+ * for a given scatterlist. Account for the max length of a DMA buffer.
+ * @sg:    Scatterlist to be DMA'd
+ * Return: Number of descriptors required
+ */
+static u32 pdc_desc_count(struct scatterlist *sg)
+{
+       u32 cnt = 0;
+
+       while (sg) {
+               cnt += ((sg->length / PDC_DMA_BUF_MAX) + 1);
+               sg = sg_next(sg);
+       }
+       return cnt;
+}
+
+/**
+ * pdc_rings_full() - Check whether the tx ring has room for tx_cnt descriptors
+ * and the rx ring has room for rx_cnt descriptors.
+ * @pdcs:  PDC state
+ * @tx_cnt: The number of descriptors required in the tx ring
+ * @rx_cnt: The number of descriptors required i the rx ring
+ *
+ * Return: true if one of the rings does not have enough space
+ *         false if sufficient space is available in both rings
+ */
+static bool pdc_rings_full(struct pdc_state *pdcs, int tx_cnt, int rx_cnt)
+{
+       u32 rx_avail;
+       u32 tx_avail;
+       bool full = false;
+
+       /* Check if the tx and rx rings are likely to have enough space */
+       rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
+                                             pdcs->nrxpost);
+       if (unlikely(rx_cnt > rx_avail)) {
+               pdcs->rx_ring_full++;
+               full = true;
+       }
+
+       if (likely(!full)) {
+               tx_avail = pdcs->ntxpost - NTXDACTIVE(pdcs->txin, pdcs->txout,
+                                                     pdcs->ntxpost);
+               if (unlikely(tx_cnt > tx_avail)) {
+                       pdcs->tx_ring_full++;
+                       full = true;
+               }
+       }
+       return full;
+}
+
+/**
+ * pdc_last_tx_done() - If both the tx and rx rings have at least
+ * PDC_RING_SPACE_MIN descriptors available, then indicate that the mailbox
+ * framework can submit another message.
+ * @chan:  mailbox channel to check
+ * Return: true if PDC can accept another message on this channel
+ */
+static bool pdc_last_tx_done(struct mbox_chan *chan)
+{
+       struct pdc_state *pdcs = chan->con_priv;
+       bool ret;
+
+       if (unlikely(pdc_rings_full(pdcs, PDC_RING_SPACE_MIN,
+                                   PDC_RING_SPACE_MIN))) {
+               pdcs->last_tx_not_done++;
+               ret = false;
+       } else {
+               ret = true;
+       }
+       return ret;
+}
+
 /**
  * pdc_send_data() - mailbox send_data function
  * @chan:      The mailbox channel on which the data is sent. The channel
@@ -1141,29 +1204,43 @@ static int pdc_send_data(struct mbox_chan *chan, void *data)
        int src_nent;
        int dst_nent;
        int nent;
+       u32 tx_desc_req;
+       u32 rx_desc_req;
 
-       if (mssg->type != BRCM_MESSAGE_SPU)
+       if (unlikely(mssg->type != BRCM_MESSAGE_SPU))
                return -ENOTSUPP;
 
        src_nent = sg_nents(mssg->spu.src);
-       if (src_nent) {
+       if (likely(src_nent)) {
                nent = dma_map_sg(dev, mssg->spu.src, src_nent, DMA_TO_DEVICE);
-               if (nent == 0)
+               if (unlikely(nent == 0))
                        return -EIO;
        }
 
        dst_nent = sg_nents(mssg->spu.dst);
-       if (dst_nent) {
+       if (likely(dst_nent)) {
                nent = dma_map_sg(dev, mssg->spu.dst, dst_nent,
                                  DMA_FROM_DEVICE);
-               if (nent == 0) {
+               if (unlikely(nent == 0)) {
                        dma_unmap_sg(dev, mssg->spu.src, src_nent,
                                     DMA_TO_DEVICE);
                        return -EIO;
                }
        }
 
-       spin_lock(&pdcs->pdc_lock);
+       /*
+        * Check if the tx and rx rings have enough space. Do this prior to
+        * writing any tx or rx descriptors. Need to ensure that we do not write
+        * a partial set of descriptors, or write just rx descriptors but
+        * corresponding tx descriptors don't fit. Note that we want this check
+        * and the entire sequence of descriptor to happen without another
+        * thread getting in. The channel spin lock in the mailbox framework
+        * ensures this.
+        */
+       tx_desc_req = pdc_desc_count(mssg->spu.src);
+       rx_desc_req = pdc_desc_count(mssg->spu.dst);
+       if (unlikely(pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1)))
+               return -ENOSPC;
 
        /* Create rx descriptors to SPU catch response */
        err = pdc_rx_list_init(pdcs, mssg->spu.dst, mssg->ctx);
@@ -1173,9 +1250,7 @@ static int pdc_send_data(struct mbox_chan *chan, void *data)
        err |= pdc_tx_list_sg_add(pdcs, mssg->spu.src);
        err |= pdc_tx_list_final(pdcs); /* initiate transfer */
 
-       spin_unlock(&pdcs->pdc_lock);
-
-       if (err)
+       if (unlikely(err))
                dev_err(&pdcs->pdev->dev,
                        "%s failed with error %d", __func__, err);
 
@@ -1224,32 +1299,50 @@ void pdc_hw_init(struct pdc_state *pdcs)
        /* initialize data structures */
        pdcs->regs = (struct pdc_regs *)pdcs->pdc_reg_vbase;
        pdcs->txregs_64 = (struct dma64_regs *)
-           (void *)(((u8 *)pdcs->pdc_reg_vbase) +
+           (((u8 *)pdcs->pdc_reg_vbase) +
                     PDC_TXREGS_OFFSET + (sizeof(struct dma64) * ringset));
        pdcs->rxregs_64 = (struct dma64_regs *)
-           (void *)(((u8 *)pdcs->pdc_reg_vbase) +
+           (((u8 *)pdcs->pdc_reg_vbase) +
                     PDC_RXREGS_OFFSET + (sizeof(struct dma64) * ringset));
 
        pdcs->ntxd = PDC_RING_ENTRIES;
        pdcs->nrxd = PDC_RING_ENTRIES;
        pdcs->ntxpost = PDC_RING_ENTRIES - 1;
        pdcs->nrxpost = PDC_RING_ENTRIES - 1;
-       pdcs->regs->intmask = 0;
+       iowrite32(0, &pdcs->regs->intmask);
 
        dma_reg = &pdcs->regs->dmaregs[ringset];
-       iowrite32(0, (void *)&dma_reg->dmaxmt.ptr);
-       iowrite32(0, (void *)&dma_reg->dmarcv.ptr);
 
-       iowrite32(PDC_TX_CTL, (void *)&dma_reg->dmaxmt.control);
+       /* Configure DMA but will enable later in pdc_ring_init() */
+       iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
 
        iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1),
-                 (void *)&dma_reg->dmarcv.control);
+                 &dma_reg->dmarcv.control);
+
+       /* Reset current index pointers after making sure DMA is disabled */
+       iowrite32(0, &dma_reg->dmaxmt.ptr);
+       iowrite32(0, &dma_reg->dmarcv.ptr);
 
        if (pdcs->pdc_resp_hdr_len == PDC_SPU2_RESP_HDR_LEN)
                iowrite32(PDC_CKSUM_CTRL,
                          pdcs->pdc_reg_vbase + PDC_CKSUM_CTRL_OFFSET);
 }
 
+/**
+ * pdc_hw_disable() - Disable the tx and rx control in the hw.
+ * @pdcs: PDC state structure
+ *
+ */
+static void pdc_hw_disable(struct pdc_state *pdcs)
+{
+       struct dma64 *dma_reg;
+
+       dma_reg = &pdcs->regs->dmaregs[PDC_RINGSET];
+       iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
+       iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1),
+                 &dma_reg->dmarcv.control);
+}
+
 /**
  * pdc_rx_buf_pool_create() - Pool of receive buffers used to catch the metadata
  * header returned with each response message.
@@ -1301,8 +1394,6 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
        struct device_node *dn = pdev->dev.of_node;
        int err;
 
-       pdcs->intstatus = 0;
-
        /* interrupt configuration */
        iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
        iowrite32(PDC_LAZY_INT, pdcs->pdc_reg_vbase + PDC_RCVLAZY0_OFFSET);
@@ -1311,11 +1402,11 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
        pdcs->pdc_irq = irq_of_parse_and_map(dn, 0);
        dev_dbg(dev, "pdc device %s irq %u for pdcs %p",
                dev_name(dev), pdcs->pdc_irq, pdcs);
-       err = devm_request_threaded_irq(dev, pdcs->pdc_irq,
-                                       pdc_irq_handler,
-                                       pdc_irq_thread, 0, dev_name(dev), pdcs);
+
+       err = devm_request_irq(dev, pdcs->pdc_irq, pdc_irq_handler, 0,
+                              dev_name(dev), dev);
        if (err) {
-               dev_err(dev, "threaded tx IRQ %u request failed with err %d\n",
+               dev_err(dev, "IRQ %u request failed with err %d\n",
                        pdcs->pdc_irq, err);
                return err;
        }
@@ -1324,6 +1415,7 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
 
 static const struct mbox_chan_ops pdc_mbox_chan_ops = {
        .send_data = pdc_send_data,
+       .last_tx_done = pdc_last_tx_done,
        .startup = pdc_startup,
        .shutdown = pdc_shutdown
 };
@@ -1356,8 +1448,9 @@ static int pdc_mb_init(struct pdc_state *pdcs)
        if (!mbc->chans)
                return -ENOMEM;
 
-       mbc->txdone_irq = true;
-       mbc->txdone_poll = false;
+       mbc->txdone_irq = false;
+       mbc->txdone_poll = true;
+       mbc->txpoll_period = 1;
        for (chan_index = 0; chan_index < mbc->num_chans; chan_index++)
                mbc->chans[chan_index].con_priv = pdcs;
 
@@ -1427,7 +1520,6 @@ static int pdc_probe(struct platform_device *pdev)
                goto cleanup;
        }
 
-       spin_lock_init(&pdcs->pdc_lock);
        pdcs->pdev = pdev;
        platform_set_drvdata(pdev, pdcs);
        pdcs->pdc_idx = pdcg.num_spu;
@@ -1473,6 +1565,9 @@ static int pdc_probe(struct platform_device *pdev)
 
        pdc_hw_init(pdcs);
 
+       /* Init tasklet for deferred DMA rx processing */
+       tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long)pdcs);
+
        err = pdc_interrupts_init(pdcs);
        if (err)
                goto cleanup_buf_pool;
@@ -1489,6 +1584,7 @@ static int pdc_probe(struct platform_device *pdev)
        return PDC_SUCCESS;
 
 cleanup_buf_pool:
+       tasklet_kill(&pdcs->rx_tasklet);
        dma_pool_destroy(pdcs->rx_buf_pool);
 
 cleanup_ring_pool:
@@ -1504,6 +1600,10 @@ static int pdc_remove(struct platform_device *pdev)
 
        pdc_free_debugfs();
 
+       tasklet_kill(&pdcs->rx_tasklet);
+
+       pdc_hw_disable(pdcs);
+
        mbox_controller_unregister(&pdcs->mbc);
 
        dma_pool_destroy(pdcs->rx_buf_pool);
index a334db5c9f1c126939873555671302b97ebecae9..41bcd339b68a1987eb1a62c1a6653c711341e350 100644 (file)
@@ -403,6 +403,7 @@ static const struct of_device_id sti_mailbox_match[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(of, sti_mailbox_match);
 
 static int sti_mbox_probe(struct platform_device *pdev)
 {
index 9ca96e9db6bfb137863250f8b27b2232fc1c449d..9c79f8019d2a5f2f08df00ea6762f4398013c482 100644 (file)
 
 #include <linux/debugfs.h>
 #include <linux/err.h>
+#include <linux/fs.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/mailbox_client.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 
@@ -39,6 +41,8 @@ struct mbox_test_device {
        char                    *signal;
        char                    *message;
        spinlock_t              lock;
+       wait_queue_head_t       waitq;
+       struct fasync_struct    *async_queue;
 };
 
 static ssize_t mbox_test_signal_write(struct file *filp,
@@ -81,6 +85,13 @@ static const struct file_operations mbox_test_signal_ops = {
        .llseek = generic_file_llseek,
 };
 
+static int mbox_test_message_fasync(int fd, struct file *filp, int on)
+{
+       struct mbox_test_device *tdev = filp->private_data;
+
+       return fasync_helper(fd, filp, on, &tdev->async_queue);
+}
+
 static ssize_t mbox_test_message_write(struct file *filp,
                                       const char __user *userbuf,
                                       size_t count, loff_t *ppos)
@@ -138,6 +149,20 @@ out:
        return ret < 0 ? ret : count;
 }
 
+static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
+{
+       unsigned char data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tdev->lock, flags);
+       data = tdev->rx_buffer[0];
+       spin_unlock_irqrestore(&tdev->lock, flags);
+
+       if (data != '\0')
+               return true;
+       return false;
+}
+
 static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
                                      size_t count, loff_t *ppos)
 {
@@ -147,6 +172,8 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
        int l = 0;
        int ret;
 
+       DECLARE_WAITQUEUE(wait, current);
+
        touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
        if (!touser)
                return -ENOMEM;
@@ -155,15 +182,29 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
                ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
                ret = simple_read_from_buffer(userbuf, count, ppos,
                                              touser, ret);
-               goto out;
+               goto kfree_err;
        }
 
-       if (tdev->rx_buffer[0] == '\0') {
-               ret = snprintf(touser, 9, "<EMPTY>\n");
-               ret = simple_read_from_buffer(userbuf, count, ppos,
-                                             touser, ret);
-               goto out;
-       }
+       add_wait_queue(&tdev->waitq, &wait);
+
+       do {
+               __set_current_state(TASK_INTERRUPTIBLE);
+
+               if (mbox_test_message_data_ready(tdev))
+                       break;
+
+               if (filp->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       goto waitq_err;
+               }
+
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       goto waitq_err;
+               }
+               schedule();
+
+       } while (1);
 
        spin_lock_irqsave(&tdev->lock, flags);
 
@@ -185,14 +226,31 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
        spin_unlock_irqrestore(&tdev->lock, flags);
 
        ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN);
-out:
+waitq_err:
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tdev->waitq, &wait);
+kfree_err:
        kfree(touser);
        return ret;
 }
 
+static unsigned int
+mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
+{
+       struct mbox_test_device *tdev = filp->private_data;
+
+       poll_wait(filp, &tdev->waitq, wait);
+
+       if (mbox_test_message_data_ready(tdev))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
 static const struct file_operations mbox_test_message_ops = {
        .write  = mbox_test_message_write,
        .read   = mbox_test_message_read,
+       .fasync = mbox_test_message_fasync,
+       .poll   = mbox_test_message_poll,
        .open   = simple_open,
        .llseek = generic_file_llseek,
 };
@@ -234,6 +292,10 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message)
                memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
        }
        spin_unlock_irqrestore(&tdev->lock, flags);
+
+       wake_up_interruptible(&tdev->waitq);
+
+       kill_fasync(&tdev->async_queue, SIGIO, POLL_IN);
 }
 
 static void mbox_test_prepare_message(struct mbox_client *client, void *message)
@@ -290,6 +352,7 @@ static int mbox_test_probe(struct platform_device *pdev)
 {
        struct mbox_test_device *tdev;
        struct resource *res;
+       resource_size_t size;
        int ret;
 
        tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
@@ -298,14 +361,21 @@ static int mbox_test_probe(struct platform_device *pdev)
 
        /* It's okay for MMIO to be NULL */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       size = resource_size(res);
        tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(tdev->tx_mmio))
+       if (PTR_ERR(tdev->tx_mmio) == -EBUSY)
+               /* if reserved area in SRAM, try just ioremap */
+               tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
+       else if (IS_ERR(tdev->tx_mmio))
                tdev->tx_mmio = NULL;
 
        /* If specified, second reg entry is Rx MMIO */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       size = resource_size(res);
        tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(tdev->rx_mmio))
+       if (PTR_ERR(tdev->rx_mmio) == -EBUSY)
+               tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
+       else if (IS_ERR(tdev->rx_mmio))
                tdev->rx_mmio = tdev->tx_mmio;
 
        tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
@@ -334,6 +404,7 @@ static int mbox_test_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       init_waitqueue_head(&tdev->waitq);
        dev_info(&pdev->dev, "Successfully registered\n");
 
        return 0;
@@ -357,6 +428,7 @@ static const struct of_device_id mbox_test_match[] = {
        { .compatible = "mailbox-test" },
        {},
 };
+MODULE_DEVICE_TABLE(of, mbox_test_match);
 
 static struct platform_driver mbox_test_driver = {
        .driver = {
index 1f32688c312d717639ecfe7de3ca94b35d31a637..dd9ecd354a3e001a1b4037f0e1ca2c92c5672957 100644 (file)
@@ -447,7 +447,6 @@ static int pcc_parse_subspace_irq(int id,
  */
 static int __init acpi_pcc_probe(void)
 {
-       acpi_size pcct_tbl_header_size;
        struct acpi_table_header *pcct_tbl;
        struct acpi_subtable_header *pcct_entry;
        struct acpi_table_pcct *acpi_pcct_tbl;
@@ -456,9 +455,7 @@ static int __init acpi_pcc_probe(void)
        acpi_status status = AE_OK;
 
        /* Search for PCCT */
-       status = acpi_get_table_with_size(ACPI_SIG_PCCT, 0,
-                       &pcct_tbl,
-                       &pcct_tbl_header_size);
+       status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl);
 
        if (ACPI_FAILURE(status) || !pcct_tbl) {
                pr_warn("PCCT header not found.\n");
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 543eadd230e55c8918c45c3ef3b6428cbb73ed97..1076b9d89df38e26bfb088fae3586a6c577fd70e 100644 (file)
@@ -496,8 +496,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
  * Returns enum mmc_blk_status after checking errors.
  */
 static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
-                                     struct mmc_request *mrq,
-                                     struct mmc_async_req *next_req)
+                                                     struct mmc_request *mrq)
 {
        struct mmc_command *cmd;
        struct mmc_context_info *context_info = &host->context_info;
@@ -507,7 +506,7 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
                wait_event_interruptible(context_info->wait,
                                (context_info->is_done_rcv ||
                                 context_info->is_new_req));
-               context_info->is_waiting_last_req = false;
+
                if (context_info->is_done_rcv) {
                        context_info->is_done_rcv = false;
                        cmd = mrq->cmd;
@@ -527,10 +526,9 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
                                __mmc_start_request(host, mrq);
                                continue; /* wait for done/new event again */
                        }
-               } else if (context_info->is_new_req) {
-                       if (!next_req)
-                               return MMC_BLK_NEW_REQUEST;
                }
+
+               return MMC_BLK_NEW_REQUEST;
        }
        mmc_retune_release(host);
        return status;
@@ -660,7 +658,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
                mmc_pre_req(host, areq->mrq);
 
        if (host->areq) {
-               status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
+               status = mmc_wait_for_data_req_done(host, host->areq->mrq);
                if (status == MMC_BLK_NEW_REQUEST) {
                        if (ret_stat)
                                *ret_stat = status;
index deb90c2ff6b423e63352283c8dfdbb935bfb4e27..a614f37faf27e05e52d851353024384e5cbc3f41 100644 (file)
@@ -223,6 +223,7 @@ static int mmc_decode_scr(struct mmc_card *card)
 static int mmc_read_ssr(struct mmc_card *card)
 {
        unsigned int au, es, et, eo;
+       u32 *raw_ssr;
        int i;
 
        if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
@@ -231,14 +232,21 @@ static int mmc_read_ssr(struct mmc_card *card)
                return 0;
        }
 
-       if (mmc_app_sd_status(card, card->raw_ssr)) {
+       raw_ssr = kmalloc(sizeof(card->raw_ssr), GFP_KERNEL);
+       if (!raw_ssr)
+               return -ENOMEM;
+
+       if (mmc_app_sd_status(card, raw_ssr)) {
                pr_warn("%s: problem reading SD Status register\n",
                        mmc_hostname(card->host));
+               kfree(raw_ssr);
                return 0;
        }
 
        for (i = 0; i < 16; i++)
-               card->raw_ssr[i] = be32_to_cpu(card->raw_ssr[i]);
+               card->raw_ssr[i] = be32_to_cpu(raw_ssr[i]);
+
+       kfree(raw_ssr);
 
        /*
         * UNSTUFF_BITS only works with four u32s so we have to offset the
index 1501cfdac4734246aa6746ed5ee8d2678122d964..4b0ecb981842248b1cc4ea8edaf35dc4bac753e1 100644 (file)
@@ -262,6 +262,7 @@ disable_clk:
 }
 
 static const struct of_device_id sdhci_cdns_match[] = {
+       { .compatible = "socionext,uniphier-sd4hc" },
        { .compatible = "cdns,sd4hc" },
        { /* sentinel */ }
 };
index 111991e5b9a0e7ecf587eaf402a5ecd0d2906f55..23909804ffb840d3187f21f67180a634a769425e 100644 (file)
@@ -1576,6 +1576,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        unsigned long flags;
        u8 ctrl;
 
+       if (ios->power_mode == MMC_POWER_UNDEFINED)
+               return;
+
        spin_lock_irqsave(&host->lock, flags);
 
        if (host->flags & SDHCI_DEVICE_DEAD) {
@@ -2938,22 +2941,24 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
 
        sdhci_init(host, 0);
 
-       /* Force clock and power re-program */
-       host->pwr = 0;
-       host->clock = 0;
-       mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
-       mmc->ops->set_ios(mmc, &mmc->ios);
+       if (mmc->ios.power_mode != MMC_POWER_UNDEFINED) {
+               /* Force clock and power re-program */
+               host->pwr = 0;
+               host->clock = 0;
+               mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
+               mmc->ops->set_ios(mmc, &mmc->ios);
 
-       if ((host_flags & SDHCI_PV_ENABLED) &&
-               !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
-               spin_lock_irqsave(&host->lock, flags);
-               sdhci_enable_preset_value(host, true);
-               spin_unlock_irqrestore(&host->lock, flags);
-       }
+               if ((host_flags & SDHCI_PV_ENABLED) &&
+                   !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
+                       spin_lock_irqsave(&host->lock, flags);
+                       sdhci_enable_preset_value(host, true);
+                       spin_unlock_irqrestore(&host->lock, flags);
+               }
 
-       if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
-           mmc->ops->hs400_enhanced_strobe)
-               mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
+               if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
+                   mmc->ops->hs400_enhanced_strobe)
+                       mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
+       }
 
        spin_lock_irqsave(&host->lock, flags);
 
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 6e16e441f85e09596a437f78f5c7891f2c91988f..e4c28fed61d50866c5a7955d8de6ee458eae7834 100644 (file)
@@ -166,7 +166,6 @@ source "drivers/net/ethernet/seeq/Kconfig"
 source "drivers/net/ethernet/silan/Kconfig"
 source "drivers/net/ethernet/sis/Kconfig"
 source "drivers/net/ethernet/sfc/Kconfig"
-source "drivers/net/ethernet/sfc/falcon/Kconfig"
 source "drivers/net/ethernet/sgi/Kconfig"
 source "drivers/net/ethernet/smsc/Kconfig"
 source "drivers/net/ethernet/stmicro/Kconfig"
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 16e12c45904be6d4a24b858d5f4265a78adbc3d9..21f80f5744ba2f048b4d7e0a8a8862e45977a339 100644 (file)
@@ -1469,6 +1469,12 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
        p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size);
        p->agl_prt_ctl = (u64)devm_ioremap(&pdev->dev, p->agl_prt_ctl_phys,
                                           p->agl_prt_ctl_size);
+       if (!p->mix || !p->agl || !p->agl_prt_ctl) {
+               dev_err(&pdev->dev, "failed to map I/O memory\n");
+               result = -ENOMEM;
+               goto err;
+       }
+
        spin_lock_init(&p->lock);
 
        skb_queue_head_init(&p->tx_list);
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 79b7c84b7869939425f93a2175ef8254a2d6bb03..dc0850b3b517b9b02e3cd9a42cf98425a55d0df3 100644 (file)
@@ -1,6 +1,6 @@
 config FSL_FMAN
        tristate "FMan support"
-       depends on FSL_SOC || COMPILE_TEST
+       depends on FSL_SOC || ARCH_LAYERSCAPE || COMPILE_TEST
        select GENERIC_ALLOCATOR
        select PHYLIB
        default n
index dafd9e1baba2cb420ea70826408d0474488ca246..f60845f0c6cad060b193fecdf00dd3a93127fb9c 100644 (file)
@@ -1890,6 +1890,7 @@ static int fman_reset(struct fman *fman)
 
                goto _return;
        } else {
+#ifdef CONFIG_PPC
                struct device_node *guts_node;
                struct ccsr_guts __iomem *guts_regs;
                u32 devdisr2, reg;
@@ -1921,6 +1922,7 @@ static int fman_reset(struct fman *fman)
 
                /* Enable all MACs */
                iowrite32be(reg, &guts_regs->devdisr2);
+#endif
 
                /* Perform FMan reset */
                iowrite32be(FPM_RSTC_FM_RESET, &fman->fpm_regs->fm_rstc);
@@ -1932,25 +1934,31 @@ static int fman_reset(struct fman *fman)
                } while (((ioread32be(&fman->fpm_regs->fm_rstc)) &
                         FPM_RSTC_FM_RESET) && --count);
                if (count == 0) {
+#ifdef CONFIG_PPC
                        iounmap(guts_regs);
                        of_node_put(guts_node);
+#endif
                        err = -EBUSY;
                        goto _return;
                }
+#ifdef CONFIG_PPC
 
                /* Restore devdisr2 value */
                iowrite32be(devdisr2, &guts_regs->devdisr2);
 
                iounmap(guts_regs);
                of_node_put(guts_node);
+#endif
 
                goto _return;
 
+#ifdef CONFIG_PPC
 guts_regs:
                of_node_put(guts_node);
 guts_node:
                dev_dbg(fman->dev, "%s: Didn't perform FManV3 reset due to Errata A007273!\n",
                        __func__);
+#endif
        }
 _return:
        return err;
@@ -2868,6 +2876,13 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
 
        fman->dev = &of_dev->dev;
 
+       err = of_platform_populate(fm_node, NULL, NULL, &of_dev->dev);
+       if (err) {
+               dev_err(&of_dev->dev, "%s: of_platform_populate() failed\n",
+                       __func__);
+               goto fman_free;
+       }
+
        return fman;
 
 fman_node_put:
index 69ca42ce5dd5034803c557df92c7a8911aedd35e..0b31f8502adae2e86c292fb99437ee943c0794bf 100644 (file)
@@ -594,6 +594,7 @@ static const u16 phy2speed[] = {
        [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000,
        [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
        [PHY_INTERFACE_MODE_RTBI]               = SPEED_1000,
+       [PHY_INTERFACE_MODE_QSGMII]             = SPEED_1000,
        [PHY_INTERFACE_MODE_XGMII]              = SPEED_10000
 };
 
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 ee7e9ce2f5b34b9bd6e4f5434e56a2a8bf7899f9..418ca1f3774aabbd1575c934243ac938124b54ad 100644 (file)
@@ -1316,10 +1316,11 @@ static int hix5hd2_dev_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id hix5hd2_of_match[] = {
-       { .compatible = "hisilicon,hisi-gemac-v1", .data = (void *)GEMAC_V1 },
-       { .compatible = "hisilicon,hisi-gemac-v2", .data = (void *)GEMAC_V2 },
-       { .compatible = "hisilicon,hix5hd2-gemac", .data = (void *)GEMAC_V1 },
-       { .compatible = "hisilicon,hi3798cv200-gemac", .data = (void *)GEMAC_V2 },
+       { .compatible = "hisilicon,hisi-gmac-v1", .data = (void *)GEMAC_V1 },
+       { .compatible = "hisilicon,hisi-gmac-v2", .data = (void *)GEMAC_V2 },
+       { .compatible = "hisilicon,hix5hd2-gmac", .data = (void *)GEMAC_V1 },
+       { .compatible = "hisilicon,hi3798cv200-gmac", .data = (void *)GEMAC_V2 },
+       { .compatible = "hisilicon,hi3516a-gmac", .data = (void *)GEMAC_V2 },
        {},
 };
 
@@ -1327,7 +1328,7 @@ MODULE_DEVICE_TABLE(of, hix5hd2_of_match);
 
 static struct platform_driver hix5hd2_dev_driver = {
        .driver = {
-               .name = "hisi-gemac",
+               .name = "hisi-gmac",
                .of_match_table = hix5hd2_of_match,
        },
        .probe = hix5hd2_dev_probe,
@@ -1338,4 +1339,4 @@ module_platform_driver(hix5hd2_dev_driver);
 
 MODULE_DESCRIPTION("HISILICON Gigabit Ethernet MAC driver");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:hisi-gemac");
+MODULE_ALIAS("platform:hisi-gmac");
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 3b026c151cf24f370137b4655b417d6e024d6dec..7431f633de3135f5ccee6a9f506892d5f13dff35 100644 (file)
@@ -75,7 +75,7 @@ static void mlx5_fc_stats_insert(struct rb_root *root, struct mlx5_fc *counter)
        struct rb_node *parent = NULL;
 
        while (*new) {
-               struct mlx5_fc *this = container_of(*new, struct mlx5_fc, node);
+               struct mlx5_fc *this = rb_entry(*new, struct mlx5_fc, node);
                int result = counter->id - this->id;
 
                parent = *new;
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 46f7be85f5a387ce96be02c66af18b21750b7210..2c032629c36929f20fe3a53866a045f202e487e5 100644 (file)
@@ -1,3 +1,20 @@
+#
+# Solarflare device configuration
+#
+
+config NET_VENDOR_SOLARFLARE
+       bool "Solarflare devices"
+       default y
+       ---help---
+         If you have a network (Ethernet) card belonging to this class, say Y.
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about Solarflare devices. If you say Y, you will be asked
+         for your specific card in the following questions.
+
+if NET_VENDOR_SOLARFLARE
+
 config SFC
        tristate "Solarflare SFC9000/SFC9100-family support"
        depends on PCI
@@ -44,3 +61,7 @@ config SFC_MCDI_LOGGING
          Driver-Interface) commands and responses, allowing debugging of
          driver/firmware interaction.  The tracing is actually enabled by
          a sysfs file 'mcdi_logging' under the PCI device.
+
+source "drivers/net/ethernet/sfc/falcon/Kconfig"
+
+endif # NET_VENDOR_SOLARFLARE
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 a340fc8bd0debf305ff2cb2d6b72b1925ec8b86e..8816515e1bbbc5c4a1fd5a443a478f2061d27c50 100644 (file)
@@ -334,7 +334,7 @@ static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
                 * descriptors for the same frame has to be set before, to
                 * avoid race condition.
                 */
-               wmb();
+               dma_wmb();
 
        p->des3 = cpu_to_le32(tdes3);
 }
@@ -377,7 +377,7 @@ static void dwmac4_rd_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
                 * descriptors for the same frame has to be set before, to
                 * avoid race condition.
                 */
-               wmb();
+               dma_wmb();
 
        p->des3 = cpu_to_le32(tdes3);
 }
index ce97e522566a8910e05707870d5c3f511a20ee3b..f0d86321dfe22b0d4455436326c93a8af513764a 100644 (file)
@@ -350,7 +350,7 @@ static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
                 * descriptors for the same frame has to be set before, to
                 * avoid race condition.
                 */
-               wmb();
+               dma_wmb();
 
        p->des0 = cpu_to_le32(tdes0);
 }
index 3e405785b81c84e551e499af4fe85cf0c0983f40..bb40382e205deffd9a3312099723b72f84da18a5 100644 (file)
@@ -2125,7 +2125,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
         * descriptor and then barrier is needed to make sure that
         * all is coherent before granting the DMA engine.
         */
-       smp_wmb();
+       dma_wmb();
 
        if (netif_msg_pktdata(priv)) {
                pr_info("%s: curr=%d dirty=%d f=%d, e=%d, f_p=%p, nfrags %d\n",
@@ -2338,7 +2338,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                 * descriptor and then barrier is needed to make sure that
                 * all is coherent before granting the DMA engine.
                 */
-               smp_wmb();
+               dma_wmb();
        }
 
        netdev_sent_queue(dev, skb->len);
@@ -2443,14 +2443,14 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
                        netif_dbg(priv, rx_status, priv->dev,
                                  "refill entry #%d\n", entry);
                }
-               wmb();
+               dma_wmb();
 
                if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))
                        priv->hw->desc->init_rx_desc(p, priv->use_riwt, 0, 0);
                else
                        priv->hw->desc->set_rx_owner(p);
 
-               wmb();
+               dma_wmb();
 
                entry = STMMAC_GET_ENTRY(entry, DMA_RX_SIZE);
        }
index c7e547e4f2b1f4e233134b4e1a540ba1924d6f08..7d9e36f66735cfd7da35f5df0f17c4d003dc4e0c 100644 (file)
@@ -94,6 +94,7 @@
 
 /* offset relative to base of XGBE_SS_REG_INDEX */
 #define XGBE10_SGMII_MODULE_OFFSET     0x100
+#define IS_SS_ID_XGBE(d)               ((d)->ss_version == XGBE_SS_VERSION_10)
 /* offset relative to base of XGBE_SM_REG_INDEX */
 #define XGBE10_HOST_PORT_OFFSET                0x34
 #define XGBE10_SLAVE_PORT_OFFSET       0x64
@@ -1746,6 +1747,17 @@ static void keystone_set_msglevel(struct net_device *ndev, u32 value)
        netcp->msg_enable = value;
 }
 
+static struct gbe_intf *keystone_get_intf_data(struct netcp_intf *netcp)
+{
+       struct gbe_intf *gbe_intf;
+
+       gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+       if (!gbe_intf)
+               gbe_intf = netcp_module_get_intf_data(&xgbe_module, netcp);
+
+       return gbe_intf;
+}
+
 static void keystone_get_stat_strings(struct net_device *ndev,
                                      uint32_t stringset, uint8_t *data)
 {
@@ -1754,7 +1766,7 @@ static void keystone_get_stat_strings(struct net_device *ndev,
        struct gbe_priv *gbe_dev;
        int i;
 
-       gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+       gbe_intf = keystone_get_intf_data(netcp);
        if (!gbe_intf)
                return;
        gbe_dev = gbe_intf->gbe_dev;
@@ -1778,7 +1790,7 @@ static int keystone_get_sset_count(struct net_device *ndev, int stringset)
        struct gbe_intf *gbe_intf;
        struct gbe_priv *gbe_dev;
 
-       gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+       gbe_intf = keystone_get_intf_data(netcp);
        if (!gbe_intf)
                return -EINVAL;
        gbe_dev = gbe_intf->gbe_dev;
@@ -1896,7 +1908,7 @@ static void keystone_get_ethtool_stats(struct net_device *ndev,
        struct gbe_intf *gbe_intf;
        struct gbe_priv *gbe_dev;
 
-       gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+       gbe_intf = keystone_get_intf_data(netcp);
        if (!gbe_intf)
                return;
 
@@ -1920,7 +1932,7 @@ static int keystone_get_link_ksettings(struct net_device *ndev,
        if (!phy)
                return -EINVAL;
 
-       gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+       gbe_intf = keystone_get_intf_data(netcp);
        if (!gbe_intf)
                return -EINVAL;
 
@@ -1953,7 +1965,7 @@ static int keystone_set_link_ksettings(struct net_device *ndev,
        if (!phy)
                return -EINVAL;
 
-       gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+       gbe_intf = keystone_get_intf_data(netcp);
        if (!gbe_intf)
                return -EINVAL;
 
@@ -2311,7 +2323,7 @@ static void gbe_init_host_port(struct gbe_priv *priv)
        int bypass_en = 1;
 
        /* Host Tx Pri */
-       if (IS_SS_ID_NU(priv))
+       if (IS_SS_ID_NU(priv) || IS_SS_ID_XGBE(priv))
                writel(HOST_TX_PRI_MAP_DEFAULT,
                       GBE_REG_ADDR(priv, host_port_regs, tx_pri_map));
 
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 9c06f8028f0c349629365cbdc82f63f63b55c098..92b08383cafa8b88e8d5b79ea3a5c0da9998770f 100644 (file)
@@ -1187,8 +1187,8 @@ static int genphy_config_advert(struct phy_device *phydev)
  */
 static int genphy_config_eee_advert(struct phy_device *phydev)
 {
-       u32 broken = phydev->eee_broken_modes;
-       u32 old_adv, adv;
+       int broken = phydev->eee_broken_modes;
+       int old_adv, adv;
 
        /* Nothing to disable */
        if (!broken)
@@ -1665,7 +1665,7 @@ static void of_set_phy_supported(struct phy_device *phydev)
 static void of_set_phy_eee_broken(struct phy_device *phydev)
 {
        struct device_node *node = phydev->mdio.dev.of_node;
-       u32 broken;
+       u32 broken = 0;
 
        if (!IS_ENABLED(CONFIG_OF_MDIO))
                return;
@@ -1673,8 +1673,20 @@ static void of_set_phy_eee_broken(struct phy_device *phydev)
        if (!node)
                return;
 
-       if (!of_property_read_u32(node, "eee-broken-modes", &broken))
-               phydev->eee_broken_modes = broken;
+       if (of_property_read_bool(node, "eee-broken-100tx"))
+               broken |= MDIO_EEE_100TX;
+       if (of_property_read_bool(node, "eee-broken-1000t"))
+               broken |= MDIO_EEE_1000T;
+       if (of_property_read_bool(node, "eee-broken-10gt"))
+               broken |= MDIO_EEE_10GT;
+       if (of_property_read_bool(node, "eee-broken-1000kx"))
+               broken |= MDIO_EEE_1000KX;
+       if (of_property_read_bool(node, "eee-broken-10gkx4"))
+               broken |= MDIO_EEE_10GKX4;
+       if (of_property_read_bool(node, "eee-broken-10gkr"))
+               broken |= MDIO_EEE_10GKR;
+
+       phydev->eee_broken_modes = broken;
 }
 
 /**
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 c9fa3565c671e9f1b0f4e16e847c713cd6165078..2583e8b50b21c2cfa6ec3d10e624adb8141d5c9d 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/string.h>
+#include <linux/delay.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
index 98b0ca79a5c5e2e04c526ca741c504377c75ca9e..65c6189885ab08f24212bce5f008c1973539a0f7 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef __H_IBMVSCSI_TGT
 #define __H_IBMVSCSI_TGT
 
+#include <linux/interrupt.h>
 #include "libsrp.h"
 
 #define SYS_ID_NAME_LEN                64
index 19f18485a854ff1dbe8a4db1105fca4b75009931..d8efddf6f312e9df82c81d2edeefa731a7c4cac8 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/t10-pi.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_bsg_fc.h>
 #include <scsi/scsi_eh.h>
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 d02bf58aea6d85bfdfa0473b95ca94794135becc..8bcb9b71f764325d585f659fb1430b393b54214c 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
 #include <asm/unaligned.h>
+#include <net/tcp.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
 #include "cxgbit.h"
index b7d747e92c7abf589e35154b25482a9dedb57118..da2c73a255dec194bba90826f6b3e95e9a264e32 100644 (file)
@@ -23,7 +23,9 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/idr.h>
+#include <linux/delay.h>
 #include <asm/unaligned.h>
+#include <net/ipv6.h>
 #include <scsi/scsi_proto.h>
 #include <scsi/iscsi_proto.h>
 #include <scsi/scsi_tcq.h>
index 4cf2c0f2ba2f981699499cce77726d20aeee9dc9..e0db2ceb0f87cb170a2ff1b12fcb5a8e7a407cb2 100644 (file)
@@ -1,6 +1,18 @@
 #ifndef ISCSI_TARGET_H
 #define ISCSI_TARGET_H
 
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_np;
+struct iscsi_portal_group;
+struct iscsi_session;
+struct iscsi_tpg_np;
+struct kref;
+struct sockaddr_storage;
+
 extern struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *);
 extern struct iscsi_tiqn *iscsit_get_tiqn(unsigned char *, int);
 extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *);
index e116f0e845c08c4f7c91bd9d91c891c1fb9683b7..903b667f8e0136d1e1d919c1bc51d2a3c99bd7c3 100644 (file)
@@ -20,8 +20,8 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/err.h>
+#include <linux/random.h>
 #include <linux/scatterlist.h>
-
 #include <target/iscsi/iscsi_target_core.h>
 #include "iscsi_target_nego.h"
 #include "iscsi_target_auth.h"
index d22f7b96a06ca98aa3bd83f669d92eb686cfcec9..1b91c13cc9657e5661c6ea254e799a068eedc4b7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ISCSI_CHAP_H_
 #define _ISCSI_CHAP_H_
 
+#include <linux/types.h>
+
 #define CHAP_DIGEST_UNKNOWN    0
 #define CHAP_DIGEST_MD5                5
 #define CHAP_DIGEST_SHA                6
@@ -18,6 +20,9 @@
 #define CHAP_STAGE_CLIENT_NRIC 4
 #define CHAP_STAGE_SERVER_NR   5
 
+struct iscsi_node_auth;
+struct iscsi_conn;
+
 extern u32 chap_main_loop(struct iscsi_conn *, struct iscsi_node_auth *, char *, char *,
                                int *, int *);
 
index 923c032f0b95f1efe2d1e12e90cb9086f3fd9346..bf40f03755ddc50697652ccde864d40df840fa0b 100644 (file)
 #include <linux/ctype.h>
 #include <linux/export.h>
 #include <linux/inet.h>
+#include <linux/module.h>
+#include <net/ipv6.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
 #include <target/iscsi/iscsi_transport.h>
-
 #include <target/iscsi/iscsi_target_core.h>
 #include "iscsi_target_parameters.h"
 #include "iscsi_target_device.h"
@@ -100,8 +101,10 @@ static ssize_t lio_target_np_driver_store(struct config_item *item,
 
                tpg_np_new = iscsit_tpg_add_network_portal(tpg,
                                        &np->np_sockaddr, tpg_np, type);
-               if (IS_ERR(tpg_np_new))
+               if (IS_ERR(tpg_np_new)) {
+                       rc = PTR_ERR(tpg_np_new);
                        goto out;
+               }
        } else {
                tpg_np_new = iscsit_tpg_locate_child_np(tpg_np, type);
                if (tpg_np_new) {
index 647d4a5dca5281838b904ba67fd03d8a0ea80642..173ddd93c75726937dabfb33a11e85479437a207 100644 (file)
@@ -16,8 +16,8 @@
  * GNU General Public License for more details.
  ******************************************************************************/
 
+#include <linux/slab.h>
 #include <scsi/iscsi_proto.h>
-
 #include <target/iscsi/iscsi_target_core.h>
 #include "iscsi_target_seq_pdu_list.h"
 #include "iscsi_target_erl1.h"
index 646429ac5a02bf3055f87204e7591d09c530062e..16edeeeb7777b447cd93a4222e4e2cf54a10cfa1 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef ISCSI_TARGET_DATAIN_VALUES_H
 #define ISCSI_TARGET_DATAIN_VALUES_H
 
+struct iscsi_cmd;
+struct iscsi_datain;
+
 extern struct iscsi_datain_req *iscsit_allocate_datain_req(void);
 extern void iscsit_attach_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *);
 extern void iscsit_free_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *);
index a0e2df9e809032034d80da9b398252365b626b92..06dbff5cd52069af9539d24305d0a2960bf5402f 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef ISCSI_TARGET_DEVICE_H
 #define ISCSI_TARGET_DEVICE_H
 
+struct iscsi_cmd;
+struct iscsi_session;
+
 extern void iscsit_determine_maxcmdsn(struct iscsi_session *);
 extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
 
index a9e2f9497fb22a1734ae27393e63fa351533f2d8..60e69e2af6eda981efb74e4ac313fb0d031093bd 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef ISCSI_TARGET_ERL0_H
 #define ISCSI_TARGET_ERL0_H
 
+#include <linux/types.h>
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_session;
+
 extern void iscsit_set_dataout_sequence_values(struct iscsi_cmd *);
 extern int iscsit_check_pre_dataout(struct iscsi_cmd *, unsigned char *);
 extern int iscsit_check_post_dataout(struct iscsi_cmd *, unsigned char *, u8);
index 9214c9dafa2be56082b792eaccd31ca87420b59e..fe9b7f1e44aca5c8bcda8677310351f03e507095 100644 (file)
@@ -17,6 +17,7 @@
  ******************************************************************************/
 
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
index 2a3ebf118a342fb33200810237afef1694c78536..54d36bd25beacdf4da8856b0b97ab5e237d4b2aa 100644 (file)
@@ -1,6 +1,16 @@
 #ifndef ISCSI_TARGET_ERL1_H
 #define ISCSI_TARGET_ERL1_H
 
+#include <linux/types.h>
+#include <scsi/iscsi_proto.h> /* itt_t */
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_datain_req;
+struct iscsi_ooo_cmdsn;
+struct iscsi_pdu;
+struct iscsi_session;
+
 extern int iscsit_dump_data_payload(struct iscsi_conn *, u32, int);
 extern int iscsit_create_recovery_datain_values_datasequenceinorder_yes(
                        struct iscsi_cmd *, struct iscsi_datain_req *);
index e24f1c7c5862d4af2f0ae53efb3e981f153080db..faf9ae014b30443583555c1a49f089a3ad7d32c0 100644 (file)
@@ -17,6 +17,7 @@
  * GNU General Public License for more details.
  ******************************************************************************/
 
+#include <linux/slab.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
index 63f2501f3fe08344ea000d3ae83e414fe4e361de..7965f1e865061ef0ec40ef63fe89d33a5e189379 100644 (file)
@@ -1,6 +1,13 @@
 #ifndef ISCSI_TARGET_ERL2_H
 #define ISCSI_TARGET_ERL2_H
 
+#include <linux/types.h>
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_conn_recovery;
+struct iscsi_session;
+
 extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, __be32);
 extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *);
 extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
index 15f79a2ca34ab6e17fd5fda6f68425b9af1809eb..450f51deb2a2ae18137ede36d4a3e8c188fd7352 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/string.h>
 #include <linux/kthread.h>
 #include <linux/idr.h>
+#include <linux/tcp.h>        /* TCP_NODELAY */
+#include <net/ipv6.h>         /* ipv6_addr_v4mapped() */
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
index b597aa2c61a1c60d2794610796ac156c220e43fe..0e1fd6cedd54cb83ffc576654d5428d47e75efa9 100644 (file)
@@ -1,6 +1,13 @@
 #ifndef ISCSI_TARGET_LOGIN_H
 #define ISCSI_TARGET_LOGIN_H
 
+#include <linux/types.h>
+
+struct iscsi_conn;
+struct iscsi_login;
+struct iscsi_np;
+struct sockaddr_storage;
+
 extern int iscsi_login_setup_crypto(struct iscsi_conn *);
 extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
 extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
index 89d34bd6d87f94519c26168741b74bcb6478061a..46388c9e08dad3e5de751d3280f8fc829683154d 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <linux/ctype.h>
 #include <linux/kthread.h>
+#include <linux/slab.h>
+#include <net/sock.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
index f021cbd330e51e0c61d85fc4f909e502073f09e5..53438bfca4c66bee15a05ca56ae4d89686d6a05d 100644 (file)
@@ -4,6 +4,10 @@
 #define DECIMAL         0
 #define HEX             1
 
+struct iscsi_conn;
+struct iscsi_login;
+struct iscsi_np;
+
 extern void convert_null_to_semi(char *, int);
 extern int extract_param(const char *, const char *, unsigned int, char *,
                unsigned char *);
index 0c69a46a62ec7f9b082679e7a24f24fb0ffe321e..79cdf06ade48bf8d63336877b40af572778f574a 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef ISCSI_TARGET_NODEATTRIB_H
 #define ISCSI_TARGET_NODEATTRIB_H
 
+#include <linux/types.h>
+
+struct iscsi_node_acl;
+struct iscsi_portal_group;
+
 extern void iscsit_set_default_node_attribues(struct iscsi_node_acl *,
                                              struct iscsi_portal_group *);
 extern int iscsit_na_dataout_timeout(struct iscsi_node_acl *, u32);
index 0efa80bb89628602598346c0647a958536acdf3b..e65bf78ceef3740fc1923c1b3ed446aa2996b82d 100644 (file)
@@ -17,7 +17,7 @@
  ******************************************************************************/
 
 #include <linux/slab.h>
-
+#include <linux/uio.h> /* struct kvec */
 #include <target/iscsi/iscsi_target_core.h>
 #include "iscsi_target_util.h"
 #include "iscsi_target_parameters.h"
index a0751e3f0813429bd5c87c2ecab16780cfbfa1c7..9962ccf0ccd7d923d074923661a48e4b058e5400 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef ISCSI_PARAMETERS_H
 #define ISCSI_PARAMETERS_H
 
+#include <linux/types.h>
 #include <scsi/iscsi_proto.h>
 
 struct iscsi_extra_response {
@@ -23,6 +24,11 @@ struct iscsi_param {
        struct list_head p_list;
 } ____cacheline_aligned;
 
+struct iscsi_conn;
+struct iscsi_conn_ops;
+struct iscsi_param_list;
+struct iscsi_sess_ops;
+
 extern int iscsi_login_rx_data(struct iscsi_conn *, char *, int);
 extern int iscsi_login_tx_data(struct iscsi_conn *, char *, char *, int);
 extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *);
index d5b153751a8d223c9edb21a01490748911a4756d..be1234362271b0b3f672c33a83b26f0407b630c8 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef ISCSI_SEQ_AND_PDU_LIST_H
 #define ISCSI_SEQ_AND_PDU_LIST_H
 
+#include <linux/types.h>
+#include <linux/cache.h>
+
 /* struct iscsi_pdu->status */
 #define DATAOUT_PDU_SENT                       1
 
@@ -78,6 +81,8 @@ struct iscsi_seq {
        u32             xfer_len;
 } ____cacheline_aligned;
 
+struct iscsi_cmd;
+
 extern int iscsit_build_pdu_and_seq_lists(struct iscsi_cmd *, u32);
 extern struct iscsi_pdu *iscsit_get_pdu_holder(struct iscsi_cmd *, u32, u32);
 extern struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(struct iscsi_cmd *, struct iscsi_seq *);
index 142e992cb097a63cb9a8efbd41c0a725ba719592..64cc5c07e47c2d301cfc66c14082a6a76458542f 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef ISCSI_TARGET_TMR_H
 #define ISCSI_TARGET_TMR_H
 
+#include <linux/types.h>
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_tmr_req;
+
 extern u8 iscsit_tmr_abort_task(struct iscsi_cmd *, unsigned char *);
 extern int iscsit_tmr_task_warm_reset(struct iscsi_conn *, struct iscsi_tmr_req *,
                        unsigned char *);
index 0814e5894a9616ffcc79fb0d0f086f718a971fd7..2e7e08dbda4807ed51c6e886b3399bc95199f3d5 100644 (file)
@@ -16,9 +16,9 @@
  * GNU General Public License for more details.
  ******************************************************************************/
 
+#include <linux/slab.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
-
 #include <target/iscsi/iscsi_target_core.h>
 #include "iscsi_target_erl0.h"
 #include "iscsi_target_login.h"
@@ -260,7 +260,6 @@ err_out:
                iscsi_release_param_list(tpg->param_list);
                tpg->param_list = NULL;
        }
-       kfree(tpg);
        return -ENOMEM;
 }
 
index 2da211920c186215e740d1aaa47f781999d1fb71..ceba298511677a5cf5ca49d784258f6c111da7dd 100644 (file)
@@ -1,6 +1,15 @@
 #ifndef ISCSI_TARGET_TPG_H
 #define ISCSI_TARGET_TPG_H
 
+#include <linux/types.h>
+
+struct iscsi_np;
+struct iscsi_session;
+struct iscsi_tiqn;
+struct iscsi_tpg_np;
+struct se_node_acl;
+struct sockaddr_storage;
+
 extern struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *, u16);
 extern int iscsit_load_discovery_tpg(void);
 extern void iscsit_release_discovery_tpg(void);
index 08217d62fb0d6860e40bcb9fa4b2947e710b3bd4..c4eb141c6435983ea3493159f48cf6c3919a9f7c 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/module.h>
 #include <target/iscsi/iscsi_transport.h>
 
 static LIST_HEAD(g_transport_list);
index 1f38177207e0806b18641766fdd6849ae1555a9b..b5a1b4ccba124d4dbf60fd528ec05d3a7d0dbf32 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/list.h>
 #include <linux/percpu_ida.h>
+#include <net/ipv6.h>         /* ipv6_addr_equal() */
 #include <scsi/scsi_tcq.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
index 995f1cb29d0e08268acf9f3547494d23498dc87b..8ff08856516aba68394fc07661ec71b635c8b6a2 100644 (file)
@@ -1,8 +1,16 @@
 #ifndef ISCSI_TARGET_UTIL_H
 #define ISCSI_TARGET_UTIL_H
 
+#include <linux/types.h>
+#include <scsi/iscsi_proto.h>        /* itt_t */
+
 #define MARKER_SIZE    8
 
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_conn_recovery;
+struct iscsi_session;
+
 extern int iscsit_add_r2t_to_list(struct iscsi_cmd *, u32, u32, int, u32);
 extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32);
 extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
index 4346462094a1af4e4ce778abd41a0f1da1d0a559..a8a230b4e6b532866becda3b04d70d2fee7c93c2 100644 (file)
@@ -1,3 +1,7 @@
+#include <linux/types.h>
+#include <linux/device.h>
+#include <target/target_core_base.h> /* struct se_cmd */
+
 #define TCM_LOOP_VERSION               "v2.1-rc2"
 #define TL_WWN_ADDR_LEN                        256
 #define TL_TPGS_PER_HBA                        32
index 58bb6ed181853b49370d9fda31f73e7bd24c7fda..e5c3e5f827d0b8f163bbe9f1e78c2da7cfc2bae5 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/string.h>
 #include <linux/configfs.h>
 #include <linux/ctype.h>
+#include <linux/delay.h>
 #include <linux/firewire.h>
 #include <linux/firewire-constants.h>
 #include <scsi/scsi_proto.h>
@@ -928,7 +929,7 @@ static struct sbp_target_request *sbp_mgt_get_req(struct sbp_session *sess,
        struct sbp_target_request *req;
        int tag;
 
-       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
        if (tag < 0)
                return ERR_PTR(-ENOMEM);
 
index 4c82bbe19003d083979fac3139ab91e3a15a01a0..f5e330099bfca713f4cb12bd2dc77826fdad1b3b 100644 (file)
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/configfs.h>
+#include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/fcntl.h>
 #include <linux/file.h>
+#include <linux/fs.h>
 #include <scsi/scsi_proto.h>
 #include <asm/unaligned.h>
 
index 9b250f9b33bfb830ff194e3b0bf028f9e0ff02fb..c69c11baf07f03ab6dae23a52bace4e956b613a2 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef TARGET_CORE_ALUA_H
 #define TARGET_CORE_ALUA_H
 
+#include <target/target_core_base.h>
+
 /*
  * INQUIRY response data, TPGS Field
  *
index a35a347ec357ad48626cc4083eca16588c29eb8b..54b36c9835be3ae2127cb1f447321eba73b824ac 100644 (file)
@@ -144,12 +144,12 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
                return -EINVAL;
        }
        if (!S_ISDIR(file_inode(fp)->i_mode)) {
-               filp_close(fp, 0);
+               filp_close(fp, NULL);
                mutex_unlock(&g_tf_lock);
                pr_err("db_root: not a directory: %s\n", db_root_stage);
                return -EINVAL;
        }
-       filp_close(fp, 0);
+       filp_close(fp, NULL);
 
        strncpy(db_root, db_root_stage, read_bytes);
 
index 6b423485c5d6b4f6e8e54a332f1dd62eda0325d9..1ebd13ef7bd333c5cbc488f7543eda58e29a2123 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/kthread.h>
 #include <linux/in.h>
 #include <linux/export.h>
+#include <linux/t10-pi.h>
 #include <asm/unaligned.h>
 #include <net/sock.h>
 #include <net/tcp.h>
index d545993df18be9ede3253861e24c25726d9a8e27..87aa376a1a1ae9f9119369725199d7bd5ba22a1e 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/falloc.h>
+#include <linux/uio.h>
 #include <scsi/scsi_proto.h>
 #include <asm/unaligned.h>
 
index 068966fce3089527fb7f14dd7bd3aa0fafdd1041..526595a072de899c618487b4edc909ad0fd64d91 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef TARGET_CORE_FILE_H
 #define TARGET_CORE_FILE_H
 
+#include <target/target_core_base.h>
+
 #define FD_VERSION             "4.0"
 
 #define FD_MAX_DEV_NAME                256
index 01c2afd815008d6cfa9d6b6d5490e1c39394db89..718d3fcd3e7cd8d8cacd7057ff85119a836725ca 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef TARGET_CORE_IBLOCK_H
 #define TARGET_CORE_IBLOCK_H
 
+#include <linux/atomic.h>
+#include <target/target_core_base.h>
+
 #define IBLOCK_VERSION         "4.0"
 
 #define IBLOCK_MAX_CDBS                16
index e2c970a9d61c32c7a95d034f889992a7560fdb64..9ab7090f7c839c6900cb30ddf7db1b8be4bc78cf 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef TARGET_CORE_INTERNAL_H
 #define TARGET_CORE_INTERNAL_H
 
+#include <linux/configfs.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
 #define TARGET_CORE_NAME_MAX_LEN       64
 #define TARGET_FABRIC_NAME_SIZE                32
 
index 47463c99c3181ed8e133b2d39ba9362d0196541a..d761025144f9dc178cc43d4803b4c79b0147815b 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
 #include <scsi/scsi_proto.h>
 #include <asm/unaligned.h>
 
@@ -253,8 +255,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd)
 
        if ((cmd->t_task_cdb[1] & 0x01) &&
            (cmd->t_task_cdb[1] & 0x02)) {
-               pr_err("LongIO and Obselete Bits set, returning"
-                               " ILLEGAL_REQUEST\n");
+               pr_err("LongIO and Obsolete Bits set, returning ILLEGAL_REQUEST\n");
                return TCM_UNSUPPORTED_SCSI_OPCODE;
        }
        /*
index e3d26e9126a01fa860693d4ecb6852b0c7de3d36..847bd470339c7ab1e1d498a6ddf37be37c526d57 100644 (file)
@@ -1,5 +1,9 @@
 #ifndef TARGET_CORE_PR_H
 #define TARGET_CORE_PR_H
+
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
 /*
  * PERSISTENT_RESERVE_OUT service action codes
  *
index 6d2007e35df65919f1687341499b26076ba25ed1..8a02fa47c7e8e907952f740b490f145f083e8459 100644 (file)
 #define PS_TIMEOUT_DISK                (15*HZ)
 #define PS_TIMEOUT_OTHER       (500*HZ)
 
-#include <linux/device.h>
-#include <linux/kref.h>
-#include <linux/kobject.h>
+#include <linux/cache.h>             /* ___cacheline_aligned */
+#include <target/target_core_base.h> /* struct se_device */
 
+struct block_device;
 struct scsi_device;
+struct Scsi_Host;
 
 struct pscsi_plugin_task {
        unsigned char pscsi_sense[TRANSPORT_SENSE_BUFFER];
index 24b36fd785f19a03d4dcd4507890d4ef850f023f..ddc216c9f1f63dcdea780b5be5edbf34d9cc93d4 100644 (file)
@@ -26,7 +26,9 @@
 
 #include <linux/string.h>
 #include <linux/parser.h>
+#include <linux/highmem.h>
 #include <linux/timer.h>
+#include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <scsi/scsi_proto.h>
index cc46a6a89b38e863a3d7b4c2f13207d251539fd2..91fc1a34791d909a1d68d265321caeaa833657db 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef TARGET_CORE_RD_H
 #define TARGET_CORE_RD_H
 
+#include <linux/module.h>
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
 #define RD_HBA_VERSION         "v4.0"
 #define RD_MCP_VERSION         "4.0"
 
index 04f616b3ba0a848a80d4a70c084c1b45d406c168..4879e70e2eefb68ddc229effbe4a9822f369ce3f 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/ratelimit.h>
 #include <linux/crc-t10dif.h>
+#include <linux/t10-pi.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi_proto.h>
 #include <scsi/scsi_tcq.h>
index bd6e78ba153d68bd37b784ba7ebd52290932906c..97402856a8f0e3be40ae8eee5b0f74e74fdb2f9d 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef TARGET_CORE_UA_H
 #define TARGET_CORE_UA_H
 
+#include <target/target_core_base.h>
+
 /*
  * From spc4r17, Table D.1: ASC and ASCQ Assignement
  */
index 2b3c8564ace8154548349c6a71872f0b1aceeadb..8041710b697298ec7073c4e5910849bd1a154703 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/uio_driver.h>
 #include <linux/stringify.h>
 #include <linux/bitops.h>
+#include <linux/highmem.h>
 #include <net/genetlink.h>
 #include <scsi/scsi_common.h>
 #include <scsi/scsi_proto.h>
@@ -537,7 +538,7 @@ tcmu_queue_cmd(struct se_cmd *se_cmd)
        struct se_device *se_dev = se_cmd->se_dev;
        struct tcmu_dev *udev = TCMU_DEV(se_dev);
        struct tcmu_cmd *tcmu_cmd;
-       int ret;
+       sense_reason_t ret;
 
        tcmu_cmd = tcmu_alloc_cmd(se_cmd);
        if (!tcmu_cmd)
@@ -685,8 +686,6 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data)
        target_complete_cmd(cmd->se_cmd, SAM_STAT_CHECK_CONDITION);
        cmd->se_cmd = NULL;
 
-       kmem_cache_free(tcmu_cmd_cache, cmd);
-
        return 0;
 }
 
index 094a1440eacb3dccdd9c35a678a2940c3e03216d..37d5caebffa6b593025a28b703a54a71e7d940d3 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/configfs.h>
+#include <linux/ratelimit.h>
 #include <scsi/scsi_proto.h>
 #include <asm/unaligned.h>
 
index 700a981c7b415264c40d70058cc3fc6c497b32ed..4d3d4dd060f28366ebd069abb603472ae0275d5b 100644 (file)
@@ -1,3 +1,5 @@
+#include <target/target_core_base.h>
+
 #define XCOPY_TARGET_DESC_LEN          32
 #define XCOPY_SEGMENT_DESC_LEN         28
 #define XCOPY_NAA_IEEE_REGEX_LEN       16
index e28209b99b59804de51663afe0a677c91745a827..11d27b93b41392aee08a4034c1e828927521defc 100644 (file)
@@ -17,6 +17,9 @@
 #ifndef __TCM_FC_H__
 #define __TCM_FC_H__
 
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
 #define FT_VERSION "0.4"
 
 #define FT_NAMELEN 32          /* length of ASCII WWPNs including pad */
index 197f73386fac9ab45473de09db462ab5e4640d90..d2351139342f6200209078e769e04f5ea1eb2d1f 100644 (file)
@@ -1073,7 +1073,7 @@ static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu,
        struct usbg_cmd *cmd;
        int tag;
 
-       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
        if (tag < 0)
                return ERR_PTR(-ENOMEM);
 
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 cb22a9f9ae7e3694db1532a683ae34d4d313e787..fad81041f5ab6a60e23e53f45ae429bbde7a9470 100644 (file)
@@ -1273,8 +1273,8 @@ out_error:
  */
 static int nfs_weak_revalidate(struct dentry *dentry, unsigned int flags)
 {
-       int error;
        struct inode *inode = d_inode(dentry);
+       int error = 0;
 
        /*
         * I believe we can only get a negative dentry here in the case of a
@@ -1293,7 +1293,8 @@ static int nfs_weak_revalidate(struct dentry *dentry, unsigned int flags)
                return 0;
        }
 
-       error = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+       if (nfs_mapping_need_revalidate_inode(inode))
+               error = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
        dfprintk(LOOKUPCACHE, "NFS: %s: inode %lu is %s\n",
                        __func__, inode->i_ino, error ? "invalid" : "valid");
        return !error;
@@ -2285,8 +2286,7 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
                if (cache == NULL)
                        goto out;
                /* Found an entry, is our attribute cache valid? */
-               if (!nfs_attribute_cache_expired(inode) &&
-                   !(nfsi->cache_validity & NFS_INO_INVALID_ATTR))
+               if (!nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS))
                        break;
                err = -ECHILD;
                if (!may_block)
@@ -2334,12 +2334,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred,
                cache = NULL;
        if (cache == NULL)
                goto out;
-       err = nfs_revalidate_inode_rcu(NFS_SERVER(inode), inode);
-       if (err)
+       if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS))
                goto out;
        res->jiffies = cache->jiffies;
        res->cred = cache->cred;
        res->mask = cache->mask;
+       err = 0;
 out:
        rcu_read_unlock();
        return err;
@@ -2491,12 +2491,13 @@ EXPORT_SYMBOL_GPL(nfs_may_open);
 static int nfs_execute_ok(struct inode *inode, int mask)
 {
        struct nfs_server *server = NFS_SERVER(inode);
-       int ret;
+       int ret = 0;
 
-       if (mask & MAY_NOT_BLOCK)
-               ret = nfs_revalidate_inode_rcu(server, inode);
-       else
-               ret = nfs_revalidate_inode(server, inode);
+       if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS)) {
+               if (mask & MAY_NOT_BLOCK)
+                       return -ECHILD;
+               ret = __nfs_revalidate_inode(server, inode);
+       }
        if (ret == 0 && !execute_ok(inode))
                ret = -EACCES;
        return ret;
index 64c11f399b3d4edfb0b9416550e5391277cf5a3e..157cb43ce9dbef4bd1c190ae54da4a3ec07e780e 100644 (file)
@@ -101,21 +101,11 @@ EXPORT_SYMBOL_GPL(nfs_file_release);
 static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
 {
        struct nfs_server *server = NFS_SERVER(inode);
-       struct nfs_inode *nfsi = NFS_I(inode);
-       const unsigned long force_reval = NFS_INO_REVAL_PAGECACHE|NFS_INO_REVAL_FORCED;
-       unsigned long cache_validity = nfsi->cache_validity;
-
-       if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) &&
-           (cache_validity & force_reval) != force_reval)
-               goto out_noreval;
 
        if (filp->f_flags & O_DIRECT)
                goto force_reval;
-       if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
-               goto force_reval;
-       if (nfs_attribute_timeout(inode))
+       if (nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE))
                goto force_reval;
-out_noreval:
        return 0;
 force_reval:
        return __nfs_revalidate_inode(server, inode);
@@ -377,7 +367,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 a5589b791439af1c6f426cb95e2a0670edd2a30b..f956ca20a8a3595e36e6cae0e913dc90a47b1e22 100644 (file)
@@ -282,7 +282,8 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
                             s->nfs_client->cl_minorversion);
 
 out_test_devid:
-       if (filelayout_test_devid_unavailable(devid))
+       if (ret->ds_clp == NULL ||
+           filelayout_test_devid_unavailable(devid))
                ret = NULL;
 out:
        return ret;
index 9e111d07f66747b200051955d9c21997187d4002..45962fe5098c6ff9e87a1a23158409841ad02033 100644 (file)
@@ -1126,7 +1126,8 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
        case -EPIPE:
                dprintk("%s DS connection error %d\n", __func__,
                        task->tk_status);
-               nfs4_mark_deviceid_unavailable(devid);
+               nfs4_delete_deviceid(devid->ld, devid->nfs_client,
+                               &devid->deviceid);
                rpc_wake_up(&tbl->slot_tbl_waitq);
                /* fall through */
        default:
@@ -1175,7 +1176,8 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
        default:
                dprintk("%s DS connection error %d\n", __func__,
                        task->tk_status);
-               nfs4_mark_deviceid_unavailable(devid);
+               nfs4_delete_deviceid(devid->ld, devid->nfs_client,
+                               &devid->deviceid);
        }
        /* FIXME: Need to prevent infinite looping here. */
        return -NFS4ERR_RESET_TO_PNFS;
index 3cc39d1c1206512b4b58b189f7bd39be20a4611a..e5a6f248697b369003e89ed526608d7cd2a296eb 100644 (file)
@@ -177,7 +177,7 @@ out_err:
 static void ff_layout_mark_devid_invalid(struct pnfs_layout_segment *lseg,
                struct nfs4_deviceid_node *devid)
 {
-       nfs4_mark_deviceid_unavailable(devid);
+       nfs4_delete_deviceid(devid->ld, devid->nfs_client, &devid->deviceid);
        if (!ff_layout_has_available_ds(lseg))
                pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode,
                                lseg);
index 5864146e05e6ad36d616593b10aeddeb8398eece..011e4f8c1e015d72f6ec7b485f27555200168457 100644 (file)
@@ -160,6 +160,43 @@ int nfs_sync_mapping(struct address_space *mapping)
        return ret;
 }
 
+static int nfs_attribute_timeout(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
+}
+
+static bool nfs_check_cache_invalid_delegated(struct inode *inode, unsigned long flags)
+{
+       unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
+
+       /* Special case for the pagecache or access cache */
+       if (flags == NFS_INO_REVAL_PAGECACHE &&
+           !(cache_validity & NFS_INO_REVAL_FORCED))
+               return false;
+       return (cache_validity & flags) != 0;
+}
+
+static bool nfs_check_cache_invalid_not_delegated(struct inode *inode, unsigned long flags)
+{
+       unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
+
+       if ((cache_validity & flags) != 0)
+               return true;
+       if (nfs_attribute_timeout(inode))
+               return true;
+       return false;
+}
+
+bool nfs_check_cache_invalid(struct inode *inode, unsigned long flags)
+{
+       if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
+               return nfs_check_cache_invalid_delegated(inode, flags);
+
+       return nfs_check_cache_invalid_not_delegated(inode, flags);
+}
+
 static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -795,6 +832,8 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
        if (!is_sync)
                return;
        inode = d_inode(ctx->dentry);
+       if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
+               return;
        nfsi = NFS_I(inode);
        if (inode->i_mapping->nrpages == 0)
                return;
@@ -1044,13 +1083,6 @@ out:
        return status;
 }
 
-int nfs_attribute_timeout(struct inode *inode)
-{
-       struct nfs_inode *nfsi = NFS_I(inode);
-
-       return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
-}
-
 int nfs_attribute_cache_expired(struct inode *inode)
 {
        if (nfs_have_delegated_attributes(inode))
@@ -1073,15 +1105,6 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 }
 EXPORT_SYMBOL_GPL(nfs_revalidate_inode);
 
-int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode)
-{
-       if (!(NFS_I(inode)->cache_validity &
-                       (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
-                       && !nfs_attribute_cache_expired(inode))
-               return NFS_STALE(inode) ? -ESTALE : 0;
-       return -ECHILD;
-}
-
 static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -1114,17 +1137,8 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
 
 bool nfs_mapping_need_revalidate_inode(struct inode *inode)
 {
-       unsigned long cache_validity = NFS_I(inode)->cache_validity;
-
-       if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) {
-               const unsigned long force_reval =
-                       NFS_INO_REVAL_PAGECACHE|NFS_INO_REVAL_FORCED;
-               return (cache_validity & force_reval) == force_reval;
-       }
-
-       return (cache_validity & NFS_INO_REVAL_PAGECACHE)
-               || nfs_attribute_timeout(inode)
-               || NFS_STALE(inode);
+       return nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE) ||
+               NFS_STALE(inode);
 }
 
 int nfs_revalidate_mapping_rcu(struct inode *inode)
@@ -1536,13 +1550,6 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
 {
        unsigned long invalid = NFS_INO_INVALID_ATTR;
 
-       /*
-        * Don't revalidate the pagecache if we hold a delegation, but do
-        * force an attribute update
-        */
-       if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
-               invalid = NFS_INO_INVALID_ATTR|NFS_INO_REVAL_FORCED;
-
        if (S_ISDIR(inode->i_mode))
                invalid |= NFS_INO_INVALID_DATA;
        nfs_set_cache_invalid(inode, invalid);
index 6b79c2ca9b9a5eed783117d43b12006f6260f107..09ca5095c04e427c881785170aefe7fdf58e7621 100644 (file)
@@ -381,6 +381,7 @@ extern int nfs_drop_inode(struct inode *);
 extern void nfs_clear_inode(struct inode *);
 extern void nfs_evict_inode(struct inode *);
 void nfs_zap_acl_cache(struct inode *inode);
+extern bool nfs_check_cache_invalid(struct inode *, unsigned long);
 extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
 extern int nfs_wait_atomic_killable(atomic_t *p);
 
index d33242c8d95d58a5366a4a57283005702852c29b..6dcbc5defb7a8dd670b63995eb553c379e47a0d4 100644 (file)
@@ -1089,8 +1089,15 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
 
        spin_lock(&dir->i_lock);
        nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
-       if (!cinfo->atomic || cinfo->before != dir->i_version)
+       if (cinfo->atomic && cinfo->before == dir->i_version) {
+               nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
+               nfsi->attrtimeo_timestamp = jiffies;
+       } else {
                nfs_force_lookup_revalidate(dir);
+               if (cinfo->before != dir->i_version)
+                       nfsi->cache_validity |= NFS_INO_INVALID_ACCESS |
+                               NFS_INO_INVALID_ACL;
+       }
        dir->i_version = cinfo->after;
        nfsi->attr_gencount = nfs_inc_attr_generation_counter();
        nfs_fscache_invalidate(dir);
@@ -3115,6 +3122,16 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                        res_stateid = &calldata->res.stateid;
                        renew_lease(server, calldata->timestamp);
                        break;
+               case -NFS4ERR_ACCESS:
+                       if (calldata->arg.bitmask != NULL) {
+                               calldata->arg.bitmask = NULL;
+                               calldata->res.fattr = NULL;
+                               task->tk_status = 0;
+                               rpc_restart_call_prepare(task);
+                               goto out_release;
+
+                       }
+                       break;
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_EXPIRED:
@@ -3140,7 +3157,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                        res_stateid, calldata->arg.fmode);
 out_release:
        nfs_release_seqid(calldata->arg.seqid);
-       nfs_refresh_inode(calldata->inode, calldata->res.fattr);
+       nfs_refresh_inode(calldata->inode, &calldata->fattr);
        dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
 }
 
@@ -3193,9 +3210,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                goto out_wait;
        }
 
-       if (calldata->arg.fmode == 0) {
+       if (calldata->arg.fmode == 0)
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
 
+       if (calldata->arg.fmode == 0 || calldata->arg.fmode == FMODE_READ) {
                /* Close-to-open cache consistency revalidation */
                if (!nfs4_have_delegation(inode, FMODE_READ))
                        calldata->arg.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
@@ -3207,7 +3225,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                nfs4_map_atomic_open_share(NFS_SERVER(inode),
                                calldata->arg.fmode, 0);
 
-       nfs_fattr_init(calldata->res.fattr);
+       if (calldata->res.fattr == NULL)
+               calldata->arg.bitmask = NULL;
+       else if (calldata->arg.bitmask == NULL)
+               calldata->res.fattr = NULL;
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence(NFS_SERVER(inode),
                                &calldata->arg.seq_args,
@@ -3274,6 +3295,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
        calldata->arg.seqid = alloc_seqid(&state->owner->so_seqid, gfp_mask);
        if (IS_ERR(calldata->arg.seqid))
                goto out_free_calldata;
+       nfs_fattr_init(&calldata->fattr);
        calldata->arg.fmode = 0;
        calldata->lr.arg.ld_private = &calldata->lr.ld_private;
        calldata->res.fattr = &calldata->fattr;
@@ -5673,6 +5695,14 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
        case -NFS4ERR_STALE_STATEID:
                task->tk_status = 0;
                break;
+       case -NFS4ERR_ACCESS:
+               if (data->args.bitmask) {
+                       data->args.bitmask = NULL;
+                       data->res.fattr = NULL;
+                       task->tk_status = 0;
+                       rpc_restart_call_prepare(task);
+                       return;
+               }
        default:
                if (nfs4_async_handle_error(task, data->res.server,
                                            NULL, NULL) == -EAGAIN) {
@@ -5692,6 +5722,7 @@ static void nfs4_delegreturn_release(void *calldata)
                if (data->lr.roc)
                        pnfs_roc_release(&data->lr.arg, &data->lr.res,
                                        data->res.lr_ret);
+               nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
                nfs_iput_and_deactive(inode);
        }
        kfree(calldata);
@@ -5780,10 +5811,6 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        if (status != 0)
                goto out;
        status = data->rpc_status;
-       if (status == 0)
-               nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
-       else
-               nfs_refresh_inode(inode, &data->fattr);
 out:
        rpc_put_task(task);
        return status;
index 95baf7d340f04117ef4a123ac3da5972b07693a1..1d152f4470cd6f6b0bcc6f73fd572e331b18778b 100644 (file)
@@ -494,21 +494,18 @@ nfs4_alloc_state_owner(struct nfs_server *server,
 }
 
 static void
-nfs4_drop_state_owner(struct nfs4_state_owner *sp)
-{
-       struct rb_node *rb_node = &sp->so_server_node;
-
-       if (!RB_EMPTY_NODE(rb_node)) {
-               struct nfs_server *server = sp->so_server;
-               struct nfs_client *clp = server->nfs_client;
-
-               spin_lock(&clp->cl_lock);
-               if (!RB_EMPTY_NODE(rb_node)) {
-                       rb_erase(rb_node, &server->state_owners);
-                       RB_CLEAR_NODE(rb_node);
-               }
-               spin_unlock(&clp->cl_lock);
-       }
+nfs4_reset_state_owner(struct nfs4_state_owner *sp)
+{
+       /* This state_owner is no longer usable, but must
+        * remain in place so that state recovery can find it
+        * and the opens associated with it.
+        * It may also be used for new 'open' request to
+        * return a delegation to the server.
+        * So update the 'create_time' so that it looks like
+        * a new state_owner.  This will cause the server to
+        * request an OPEN_CONFIRM to start a new sequence.
+        */
+       sp->so_seqid.create_time = ktime_get();
 }
 
 static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
@@ -797,21 +794,33 @@ void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
 
 /*
  * Search the state->lock_states for an existing lock_owner
- * that is compatible with current->files
+ * that is compatible with either of the given owners.
+ * If the second is non-zero, then the first refers to a Posix-lock
+ * owner (current->files) and the second refers to a flock/OFD
+ * owner (struct file*).  In that case, prefer a match for the first
+ * owner.
+ * If both sorts of locks are held on the one file we cannot know
+ * which stateid was intended to be used, so a "correct" choice cannot
+ * be made.  Failing that, a "consistent" choice is preferable.  The
+ * consistent choice we make is to prefer the first owner, that of a
+ * Posix lock.
  */
 static struct nfs4_lock_state *
 __nfs4_find_lock_state(struct nfs4_state *state,
                       fl_owner_t fl_owner, fl_owner_t fl_owner2)
 {
-       struct nfs4_lock_state *pos;
+       struct nfs4_lock_state *pos, *ret = NULL;
        list_for_each_entry(pos, &state->lock_states, ls_locks) {
-               if (pos->ls_owner != fl_owner &&
-                   pos->ls_owner != fl_owner2)
-                       continue;
-               atomic_inc(&pos->ls_count);
-               return pos;
+               if (pos->ls_owner == fl_owner) {
+                       ret = pos;
+                       break;
+               }
+               if (pos->ls_owner == fl_owner2)
+                       ret = pos;
        }
-       return NULL;
+       if (ret)
+               atomic_inc(&ret->ls_count);
+       return ret;
 }
 
 /*
@@ -1101,7 +1110,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
 
        sp = container_of(seqid->sequence, struct nfs4_state_owner, so_seqid);
        if (status == -NFS4ERR_BAD_SEQID)
-               nfs4_drop_state_owner(sp);
+               nfs4_reset_state_owner(sp);
        if (!nfs4_has_session(sp->so_server->nfs_client))
                nfs_increment_seqid(status, seqid);
 }
index 1af6268a7d8c4c71779d3b64f7ce087b431df723..e9255cb453e664c385c9a94969f69bc3514024b1 100644 (file)
@@ -502,11 +502,13 @@ static int nfs4_stat_to_errno(int);
                                (compound_encode_hdr_maxsz + \
                                 encode_sequence_maxsz + \
                                 encode_putfh_maxsz + \
+                                encode_layoutreturn_maxsz + \
                                 encode_open_downgrade_maxsz)
 #define NFS4_dec_open_downgrade_sz \
                                (compound_decode_hdr_maxsz + \
                                 decode_sequence_maxsz + \
                                 decode_putfh_maxsz + \
+                                decode_layoutreturn_maxsz + \
                                 decode_open_downgrade_maxsz)
 #define NFS4_enc_close_sz      (compound_encode_hdr_maxsz + \
                                 encode_sequence_maxsz + \
@@ -2277,9 +2279,9 @@ static void nfs4_xdr_enc_close(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_putfh(xdr, args->fh, &hdr);
        if (args->lr_args)
                encode_layoutreturn(xdr, args->lr_args, &hdr);
-       encode_close(xdr, args, &hdr);
        if (args->bitmask != NULL)
                encode_getfattr(xdr, args->bitmask, &hdr);
+       encode_close(xdr, args, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2356,6 +2358,8 @@ static void nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req,
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
+       if (args->lr_args)
+               encode_layoutreturn(xdr, args->lr_args, &hdr);
        encode_open_downgrade(xdr, args, &hdr);
        encode_nops(&hdr);
 }
@@ -2701,7 +2705,8 @@ static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
        encode_putfh(xdr, args->fhandle, &hdr);
        if (args->lr_args)
                encode_layoutreturn(xdr, args->lr_args, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
+       if (args->bitmask)
+               encode_getfattr(xdr, args->bitmask, &hdr);
        encode_delegreturn(xdr, args->stateid, &hdr);
        encode_nops(&hdr);
 }
@@ -6151,6 +6156,12 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
        status = decode_putfh(xdr);
        if (status)
                goto out;
+       if (res->lr_res) {
+               status = decode_layoutreturn(xdr, res->lr_res);
+               res->lr_ret = status;
+               if (status)
+                       goto out;
+       }
        status = decode_open_downgrade(xdr, res);
 out:
        return status;
@@ -6484,16 +6495,12 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
                if (status)
                        goto out;
        }
+       if (res->fattr != NULL) {
+               status = decode_getfattr(xdr, res->fattr, res->server);
+               if (status != 0)
+                       goto out;
+       }
        status = decode_close(xdr, res);
-       if (status != 0)
-               goto out;
-       /*
-        * Note: Server may do delete on close for this file
-        *      in which case the getattr call will fail with
-        *      an ESTALE error. Shouldn't be a problem,
-        *      though, since fattr->valid will remain unset.
-        */
-       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6966,9 +6973,11 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
                if (status)
                        goto out;
        }
-       status = decode_getfattr(xdr, res->fattr, res->server);
-       if (status != 0)
-               goto out;
+       if (res->fattr) {
+               status = decode_getfattr(xdr, res->fattr, res->server);
+               if (status != 0)
+                       goto out;
+       }
        status = decode_delegreturn(xdr);
 out:
        return status;
index 896df7bdf85f6c5a92b1c206cb799afea454c1e9..59554f3adf2948a10dd945b5f8441c236f53e9f2 100644 (file)
@@ -1251,6 +1251,7 @@ bool pnfs_roc(struct inode *ino,
        nfs4_stateid stateid;
        enum pnfs_iomode iomode = 0;
        bool layoutreturn = false, roc = false;
+       bool skip_read = false;
 
        if (!nfs_have_layout(ino))
                return false;
@@ -1270,18 +1271,27 @@ retry:
        }
 
        /* no roc if we hold a delegation */
-       if (nfs4_check_delegation(ino, FMODE_READ))
-               goto out_noroc;
+       if (nfs4_check_delegation(ino, FMODE_READ)) {
+               if (nfs4_check_delegation(ino, FMODE_WRITE))
+                       goto out_noroc;
+               skip_read = true;
+       }
 
        list_for_each_entry(ctx, &nfsi->open_files, list) {
                state = ctx->state;
+               if (state == NULL)
+                       continue;
                /* Don't return layout if there is open file state */
-               if (state != NULL && state->state != 0)
+               if (state->state & FMODE_WRITE)
                        goto out_noroc;
+               if (state->state & FMODE_READ)
+                       skip_read = true;
        }
 
 
        list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) {
+               if (skip_read && lseg->pls_range.iomode == IOMODE_READ)
+                       continue;
                /* If we are sending layoutreturn, invalidate all valid lsegs */
                if (!test_and_clear_bit(NFS_LSEG_ROC, &lseg->pls_flags))
                        continue;
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 8ed7c9d8c0fbaf7ec81de0afa9ac3edafe8932aa..873d83104e79aed14a24c417f211e38ae4038122 100644 (file)
@@ -1087,7 +1087,13 @@ EXPORT_SYMBOL(do_splice_direct);
 
 static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
 {
-       while (pipe->nrbufs == pipe->buffers) {
+       for (;;) {
+               if (unlikely(!pipe->readers)) {
+                       send_sig(SIGPIPE, current, 0);
+                       return -EPIPE;
+               }
+               if (pipe->nrbufs != pipe->buffers)
+                       return 0;
                if (flags & SPLICE_F_NONBLOCK)
                        return -EAGAIN;
                if (signal_pending(current))
@@ -1096,7 +1102,6 @@ static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
                pipe_wait(pipe);
                pipe->waiting_writers--;
        }
-       return 0;
 }
 
 static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
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
index d7d0f495a34e975d7c045efab5dd029d5f393687..303315b9693fc999022b192f91b4681505f3c571 100644 (file)
@@ -13,6 +13,8 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
 }
 #endif
 
+extern bool acpi_permanent_mmap;
+
 void __iomem *__ref
 acpi_os_map_iomem(acpi_physical_address phys, acpi_size size);
 void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size);
index 5c7356adc10b5f96f0fc39f430ae4741fbda8ea1..f5e10dd8e86b712a4c0e97a206d36ff88fabe02f 100644 (file)
@@ -513,10 +513,12 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                             acpi_get_table(acpi_string signature, u32 instance,
                                            struct acpi_table_header
                                            **out_table))
+ACPI_EXTERNAL_RETURN_VOID(void acpi_put_table(struct acpi_table_header *table))
+
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
-                            acpi_get_table_by_index(u32 table_index,
-                                                    struct acpi_table_header
-                                                    **out_table))
+                           acpi_get_table_by_index(u32 table_index,
+                                                   struct acpi_table_header
+                                                   **out_table))
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                             acpi_install_table_handler(acpi_table_handler
                                                        handler, void *context))
@@ -965,15 +967,6 @@ void acpi_terminate_debugger(void);
 /*
  * Divergences
  */
-ACPI_GLOBAL(u8, acpi_gbl_permanent_mmap);
-
-ACPI_EXTERNAL_RETURN_STATUS(acpi_status
-                           acpi_get_table_with_size(acpi_string signature,
-                                                    u32 instance,
-                                                    struct acpi_table_header
-                                                    **out_table,
-                                                    acpi_size *tbl_size))
-
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                            acpi_get_data_full(acpi_handle object,
                                               acpi_object_handler handler,
index c19700e2a2fe25d169a64180593438d9815c3f77..da5708caf8a12493de0e52376c27b7c0bffd1378 100644 (file)
@@ -371,6 +371,7 @@ struct acpi_table_desc {
        union acpi_name_union signature;
        acpi_owner_id owner_id;
        u8 flags;
+       u16 validation_count;
 };
 
 /* Masks for Flags field above */
index a5509d87230a4778de5566f8cfe7b705a1dd89f1..7dbb1141f546077ceec4c9fe39b077ae8e1ba379 100644 (file)
@@ -142,7 +142,6 @@ static inline void acpi_os_terminate_command_signals(void)
 /*
  * OSL interfaces added by Linux
  */
-void early_acpi_os_unmap_memory(void __iomem * virt, acpi_size size);
 
 #endif                         /* __KERNEL__ */
 
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)
  */
diff --git a/include/dt-bindings/net/mdio.h b/include/dt-bindings/net/mdio.h
deleted file mode 100644 (file)
index 99c6d90..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * This header provides generic constants for ethernet MDIO bindings
- */
-
-#ifndef _DT_BINDINGS_NET_MDIO_H
-#define _DT_BINDINGS_NET_MDIO_H
-
-/*
- * EEE capability Advertisement
- */
-
-#define MDIO_EEE_100TX         0x0002  /* 100TX EEE cap */
-#define MDIO_EEE_1000T         0x0004  /* 1000T EEE cap */
-#define MDIO_EEE_10GT          0x0008  /* 10GT EEE cap */
-#define MDIO_EEE_1000KX                0x0010  /* 1000KX EEE cap */
-#define MDIO_EEE_10GKX4                0x0020  /* 10G KX4 EEE cap */
-#define MDIO_EEE_10GKR         0x0040  /* 10G KR EEE cap */
-
-#endif
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 a951fd10aaaad07cf7ab897615a4e3d84caf6a42..6a524bf6a06d112613075547c5b17a069da00077 100644 (file)
@@ -18,6 +18,7 @@ enum cache_type {
 
 /**
  * struct cacheinfo - represent a cache leaf node
+ * @id: This cache's id. It is unique among caches with the same (type, level).
  * @type: type of the cache - data, inst or unified
  * @level: represents the hierarchy in the multi-level cache
  * @coherency_line_size: size of each cache line usually representing
@@ -44,6 +45,7 @@ enum cache_type {
  * keeping, the remaining members form the core properties of the cache
  */
 struct cacheinfo {
+       unsigned int id;
        enum cache_type type;
        unsigned int level;
        unsigned int coherency_line_size;
@@ -61,6 +63,7 @@ struct cacheinfo {
 #define CACHE_WRITE_ALLOCATE   BIT(3)
 #define CACHE_ALLOCATE_POLICY_MASK     \
        (CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE)
+#define CACHE_ID               BIT(4)
 
        struct device_node *of_node;
        bool disable_sysfs;
index 9a30b921f7401487cb6238b9bcb6e9f096e9a39f..2319b8c108e87b9e87c11cc4c9aa314d24eb0364 100644 (file)
 #ifndef _CONFIGFS_H_
 #define _CONFIGFS_H_
 
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/kref.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-
-#include <linux/atomic.h>
+#include <linux/stat.h>   /* S_IRUGO */
+#include <linux/types.h>  /* ssize_t */
+#include <linux/list.h>   /* struct list_head */
+#include <linux/kref.h>   /* struct kref */
+#include <linux/mutex.h>  /* struct mutex */
 
 #define CONFIGFS_ITEM_NAME_LEN 20
 
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 0eb7c2e7f0d633b577169fe46dca6767a0c9c415..7f6952f8d6aad7281f5403364bcfc13bdd30d36d 100644 (file)
@@ -11,6 +11,7 @@
 #define _LINUX_IMA_H
 
 #include <linux/fs.h>
+#include <linux/kexec.h>
 struct linux_binprm;
 
 #ifdef CONFIG_IMA
@@ -23,6 +24,10 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
                              enum kernel_read_file_id id);
 extern void ima_post_path_mknod(struct dentry *dentry);
 
+#ifdef CONFIG_IMA_KEXEC
+extern void ima_add_kexec_buffer(struct kimage *image);
+#endif
+
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
 {
@@ -62,6 +67,13 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
 
 #endif /* CONFIG_IMA */
 
+#ifndef CONFIG_IMA_KEXEC
+struct kimage;
+
+static inline void ima_add_kexec_buffer(struct kimage *image)
+{}
+#endif
+
 #ifdef CONFIG_IMA_APPRAISE
 extern void ima_inode_post_setattr(struct dentry *dentry);
 extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
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;
index cb631973839a7ff7dd10a8426de10d3a30393e9a..f1da8c8dd473869897c3363f9e299bd28086c8d5 100644 (file)
@@ -340,10 +340,8 @@ extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
 extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
 extern int nfs_permission(struct inode *, int);
 extern int nfs_open(struct inode *, struct file *);
-extern int nfs_attribute_timeout(struct inode *inode);
 extern int nfs_attribute_cache_expired(struct inode *inode);
 extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
-extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern bool nfs_mapping_need_revalidate_inode(struct inode *inode);
 extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
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 57c9e0622a38dbd8a742015cd9742bcd52abf226..56375edf2ed22c7f32dd1d92c6b4fe59f3b42229 100644 (file)
@@ -77,8 +77,11 @@ extern int ___ratelimit(struct ratelimit_state *rs, const char *func);
 
 #ifdef CONFIG_PRINTK
 
-#define WARN_ON_RATELIMIT(condition, state)                    \
-               WARN_ON((condition) && __ratelimit(state))
+#define WARN_ON_RATELIMIT(condition, state)    ({              \
+       bool __rtn_cond = !!(condition);                        \
+       WARN_ON(__rtn_cond && __ratelimit(state));              \
+       __rtn_cond;                                             \
+})
 
 #define WARN_RATELIMIT(condition, format, ...)                 \
 ({                                                             \
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 a440cf178191ee8b84c01068201abb5c846af031..4d1905245c7aa50df56acf0f77c77f3347c28c04 100644 (file)
@@ -1821,6 +1821,9 @@ struct task_struct {
        /* cg_list protected by css_set_lock and tsk->alloc_lock */
        struct list_head cg_list;
 #endif
+#ifdef CONFIG_INTEL_RDT_A
+       int closid;
+#endif
 #ifdef CONFIG_FUTEX
        struct robust_list_head __user *robust_list;
 #ifdef CONFIG_COMPAT
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 4ac24f5a3308a8c8bcec7c973433f1f714cda9b2..275581d483ddd90d97c550ee8bf44d705833ecf8 100644 (file)
@@ -1,12 +1,14 @@
 #ifndef ISCSI_TARGET_CORE_H
 #define ISCSI_TARGET_CORE_H
 
-#include <linux/in.h>
-#include <linux/configfs.h>
-#include <net/sock.h>
-#include <net/tcp.h>
-#include <scsi/iscsi_proto.h>
-#include <target/target_core_base.h>
+#include <linux/dma-direction.h>     /* enum dma_data_direction */
+#include <linux/list.h>              /* struct list_head */
+#include <linux/socket.h>            /* struct sockaddr_storage */
+#include <linux/types.h>             /* u8 */
+#include <scsi/iscsi_proto.h>        /* itt_t */
+#include <target/target_core_base.h> /* struct se_cmd */
+
+struct sock;
 
 #define ISCSIT_VERSION                 "v4.1.0"
 #define ISCSI_MAX_DATASN_MISSING_COUNT 16
index e615bb485d0b3a79ea43e7494db956db17805ac0..c27dd471656dc2da4745516d47253b5d06285cf3 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef ISCSI_TARGET_STAT_H
 #define ISCSI_TARGET_STAT_H
 
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+
 /*
  * For struct iscsi_tiqn->tiqn_wwn default groups
  */
index 40ac7cd801505db68a979a4fc4a22a6eb71019be..1277e9ba031818e22cd8720a4125f1c9ebf0cb12 100644 (file)
@@ -1,6 +1,6 @@
-#include <linux/module.h>
-#include <linux/list.h>
-#include "iscsi_target_core.h"
+#include "iscsi_target_core.h" /* struct iscsi_cmd */
+
+struct sockaddr_storage;
 
 struct iscsit_transport {
 #define ISCSIT_TRANSPORT_NAME  16
index f6f3bc52c1ac2e21611ba7be2a274c7cb442166d..b54b98dc2d4a77681dd3ecf883d75e062589ee8c 100644 (file)
@@ -1,8 +1,14 @@
 #ifndef TARGET_CORE_BACKEND_H
 #define TARGET_CORE_BACKEND_H
 
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
 #define TRANSPORT_FLAG_PASSTHROUGH             1
 
+struct request_queue;
+struct scatterlist;
+
 struct target_backend_ops {
        char name[16];
        char inquiry_prod[16];
index 00558287936d9a0bcc2e386e8fa0b2bcb9af4f97..29e6858bb1648b636dcce48072f9fe43e5a8a884 100644 (file)
@@ -1,14 +1,10 @@
 #ifndef TARGET_CORE_BASE_H
 #define TARGET_CORE_BASE_H
 
-#include <linux/in.h>
-#include <linux/configfs.h>
-#include <linux/dma-mapping.h>
-#include <linux/blkdev.h>
-#include <linux/percpu_ida.h>
-#include <linux/t10-pi.h>
-#include <net/sock.h>
-#include <net/tcp.h>
+#include <linux/configfs.h>      /* struct config_group */
+#include <linux/dma-direction.h> /* enum dma_data_direction */
+#include <linux/percpu_ida.h>    /* struct percpu_ida */
+#include <linux/semaphore.h>     /* struct semaphore */
 
 #define TARGET_CORE_VERSION            "v5.0"
 
index 5cd6faa6e0d166ed07444cf5e3735e2626483205..358041bad1da0350b776d7ff174ab682b0bb82ef 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef TARGET_CORE_FABRIC_H
 #define TARGET_CORE_FABRIC_H
 
+#include <linux/configfs.h>
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
 struct target_core_fabric_ops {
        struct module *module;
        const char *name;
index 9bd559472c9280a6317e336f3a62471fd0aafa49..e230af2e68558fa8ed1778b2c154686f8b1e2481 100644 (file)
@@ -57,6 +57,7 @@
 #define CGROUP_SUPER_MAGIC     0x27e0eb
 #define CGROUP2_SUPER_MAGIC    0x63677270
 
+#define RDTGROUP_SUPER_MAGIC   0x7655821
 
 #define STACK_END_MAGIC                0x57AC6E9D
 
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 cc2fa35ca480367fe96430ef23ec7b869974c0e7..85e5546cd791cc31261cd6deb8aea933bb41c008 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/kcov.h>
+#include <asm/setup.h>
 
 /*
  * kcov descriptor (one per opened debugfs file).
@@ -73,6 +74,11 @@ void notrace __sanitizer_cov_trace_pc(void)
        if (mode == KCOV_MODE_TRACE) {
                unsigned long *area;
                unsigned long pos;
+               unsigned long ip = _RET_IP_;
+
+#ifdef CONFIG_RANDOMIZE_BASE
+               ip -= kaslr_offset();
+#endif
 
                /*
                 * There is some code that runs in interrupts but for which
@@ -86,7 +92,7 @@ void notrace __sanitizer_cov_trace_pc(void)
                /* The first word is number of subsequent PCs. */
                pos = READ_ONCE(area[0]) + 1;
                if (likely(pos < t->kcov_size)) {
-                       area[pos] = _RET_IP_;
+                       area[pos] = ip;
                        WRITE_ONCE(area[0], pos);
                }
        }
index 0c2df7f737925b6d0bd5bf624ceb12e8a6d53d86..b56a558e406db6375bea4b07e5873a4c6f0b401e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/fs.h>
+#include <linux/ima.h>
 #include <crypto/hash.h>
 #include <crypto/sha.h>
 #include <linux/syscalls.h>
@@ -132,6 +133,9 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
                return ret;
        image->kernel_buf_len = size;
 
+       /* IMA needs to pass the measurement list to the next kernel. */
+       ima_add_kexec_buffer(image);
+
        /* Call arch image probe handlers */
        ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,
                                            image->kernel_buf_len);
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 7446097f72bd8b590ea192b9fb6c2955461c1338..cb66a46488401b6a99091b489df029c3035a79dd 100644 (file)
@@ -26,7 +26,7 @@ config CONSOLE_LOGLEVEL_DEFAULT
          the kernel bootargs. loglevel=<x> continues to override whatever
          value is specified here as well.
 
-         Note: This does not affect the log level of un-prefixed prink()
+         Note: This does not affect the log level of un-prefixed printk()
          usage in the kernel. That is controlled by the MESSAGE_LOGLEVEL_DEFAULT
          option.
 
index 6c707bfe02fde002feae9ea2fab3fc9647c3baa0..a430131125815803ba25a7014917c6118087dd5c 100644 (file)
@@ -139,7 +139,20 @@ SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)
                }
 
                if (end_index >= start_index) {
-                       unsigned long count = invalidate_mapping_pages(mapping,
+                       unsigned long count;
+
+                       /*
+                        * It's common to FADV_DONTNEED right after
+                        * the read or write that instantiates the
+                        * pages, in which case there will be some
+                        * sitting on the local LRU cache. Try to
+                        * avoid the expensive remote drain and the
+                        * second cache tree walk below by flushing
+                        * them out right away.
+                        */
+                       lru_add_drain();
+
+                       count = invalidate_mapping_pages(mapping,
                                                start_index, end_index);
 
                        /*
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 6c9615c90f37a8bf53a423b489d1e67c8dbf66c4..618ab5079816edf2d449cf7d17c7a954185bc6ad 100644 (file)
@@ -958,7 +958,7 @@ static int __ip_append_data(struct sock *sk,
                csummode = CHECKSUM_PARTIAL;
 
        cork->length += length;
-       if (((length > mtu) || (skb && skb_is_gso(skb))) &&
+       if ((((length + fragheaderlen) > mtu) || (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
            (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
            (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx) {
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 d19044f2b1f4d1216ec7a4f25eaabecbf99c6214..c87d359b9b37a07711c65e61a1cb882148f76ee0 100644 (file)
@@ -2195,6 +2195,7 @@ static int validate_set(const struct nlattr *a,
        case OVS_KEY_ATTR_ETHERNET:
                if (mac_proto != MAC_PROTO_ETHERNET)
                        return -EINVAL;
+               break;
 
        case OVS_KEY_ATTR_TUNNEL:
                if (masked)
index 4c93badeabf2236d3d90c933e6169174b3ba68d1..ea961144084fadb3ee98abd708ce5cd31eba42a5 100644 (file)
@@ -135,7 +135,7 @@ void rds_rdma_drop_keys(struct rds_sock *rs)
        /* Release any MRs associated with this socket */
        spin_lock_irqsave(&rs->rs_rdma_lock, flags);
        while ((node = rb_first(&rs->rs_rdma_keys))) {
-               mr = container_of(node, struct rds_mr, r_rb_node);
+               mr = rb_entry(node, struct rds_mr, r_rb_node);
                if (mr->r_trans == rs->rs_transport)
                        mr->r_invalidate = 0;
                rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
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 86309a3156a580d2be0a1cffbc93b62a4e1b10bf..a4f738ac77283b19927aef0a0e6c9fc8dafcdd42 100644 (file)
@@ -136,7 +136,7 @@ static void fq_flow_set_throttled(struct fq_sched_data *q, struct fq_flow *f)
                struct fq_flow *aux;
 
                parent = *p;
-               aux = container_of(parent, struct fq_flow, rate_node);
+               aux = rb_entry(parent, struct fq_flow, rate_node);
                if (f->time_next_packet >= aux->time_next_packet)
                        p = &parent->rb_right;
                else
@@ -188,7 +188,7 @@ static void fq_gc(struct fq_sched_data *q,
        while (*p) {
                parent = *p;
 
-               f = container_of(parent, struct fq_flow, fq_node);
+               f = rb_entry(parent, struct fq_flow, fq_node);
                if (f->sk == sk)
                        break;
 
@@ -256,7 +256,7 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
        while (*p) {
                parent = *p;
 
-               f = container_of(parent, struct fq_flow, fq_node);
+               f = rb_entry(parent, struct fq_flow, fq_node);
                if (f->sk == sk) {
                        /* socket might have been reallocated, so check
                         * if its sk_hash is the same.
@@ -424,7 +424,7 @@ static void fq_check_throttled(struct fq_sched_data *q, u64 now)
 
        q->time_next_delayed_flow = ~0ULL;
        while ((p = rb_first(&q->delayed)) != NULL) {
-               struct fq_flow *f = container_of(p, struct fq_flow, rate_node);
+               struct fq_flow *f = rb_entry(p, struct fq_flow, rate_node);
 
                if (f->time_next_packet > now) {
                        q->time_next_delayed_flow = f->time_next_packet;
@@ -563,7 +563,7 @@ static void fq_reset(struct Qdisc *sch)
        for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
                root = &q->fq_root[idx];
                while ((p = rb_first(root)) != NULL) {
-                       f = container_of(p, struct fq_flow, fq_node);
+                       f = rb_entry(p, struct fq_flow, fq_node);
                        rb_erase(p, root);
 
                        fq_flow_purge(f);
@@ -593,7 +593,7 @@ static void fq_rehash(struct fq_sched_data *q,
                oroot = &old_array[idx];
                while ((op = rb_first(oroot)) != NULL) {
                        rb_erase(op, oroot);
-                       of = container_of(op, struct fq_flow, fq_node);
+                       of = rb_entry(op, struct fq_flow, fq_node);
                        if (fq_gc_candidate(of)) {
                                fcnt++;
                                kmem_cache_free(fq_flow_cachep, of);
@@ -606,7 +606,7 @@ static void fq_rehash(struct fq_sched_data *q,
                        while (*np) {
                                parent = *np;
 
-                               nf = container_of(parent, struct fq_flow, fq_node);
+                               nf = rb_entry(parent, struct fq_flow, fq_node);
                                BUG_ON(nf->sk == of->sk);
 
                                if (nf->sk > of->sk)
index 9f7b380cf0a3836aca117b6d9bde05e0fecea32b..b7e4097bfdab22dc0f43b314aadf3c001cc3b24f 100644 (file)
@@ -152,7 +152,7 @@ struct netem_skb_cb {
 
 static struct sk_buff *netem_rb_to_skb(struct rb_node *rb)
 {
-       return container_of(rb, struct sk_buff, rbnode);
+       return rb_entry(rb, struct sk_buff, rbnode);
 }
 
 static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
index 401c60750b206c00f9fb14f6b635d15a4342ae0f..1ebc184a0e2355e348c6c6f575e0b20a1daf5dd9 100644 (file)
@@ -292,6 +292,8 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
                }
 
                af->from_addr_param(&addr, rawaddr, htons(port), 0);
+               if (sctp_bind_addr_state(bp, &addr) != -1)
+                       goto next;
                retval = sctp_add_bind_addr(bp, &addr, sizeof(addr),
                                            SCTP_ADDR_SRC, gfp);
                if (retval) {
@@ -300,6 +302,7 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
                        break;
                }
 
+next:
                len = ntohs(param->length);
                addrs_len -= len;
                raw_addr_list += len;
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 7b523e3f551f1761d891b606f293b2b721a87ca8..616a9428e0c4f3ba2b2cf910f339074f79488e62 100644 (file)
@@ -205,26 +205,30 @@ int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
        list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) {
                if (!addr->valid)
                        continue;
-               if (sctp_in_scope(net, &addr->a, scope)) {
-                       /* Now that the address is in scope, check to see if
-                        * the address type is really supported by the local
-                        * sock as well as the remote peer.
-                        */
-                       if ((((AF_INET == addr->a.sa.sa_family) &&
-                             (copy_flags & SCTP_ADDR4_PEERSUPP))) ||
-                           (((AF_INET6 == addr->a.sa.sa_family) &&
-                             (copy_flags & SCTP_ADDR6_ALLOWED) &&
-                             (copy_flags & SCTP_ADDR6_PEERSUPP)))) {
-                               error = sctp_add_bind_addr(bp, &addr->a,
-                                                   sizeof(addr->a),
-                                                   SCTP_ADDR_SRC, GFP_ATOMIC);
-                               if (error)
-                                       goto end_copy;
-                       }
-               }
+               if (!sctp_in_scope(net, &addr->a, scope))
+                       continue;
+
+               /* Now that the address is in scope, check to see if
+                * the address type is really supported by the local
+                * sock as well as the remote peer.
+                */
+               if (addr->a.sa.sa_family == AF_INET &&
+                   !(copy_flags & SCTP_ADDR4_PEERSUPP))
+                       continue;
+               if (addr->a.sa.sa_family == AF_INET6 &&
+                   (!(copy_flags & SCTP_ADDR6_ALLOWED) ||
+                    !(copy_flags & SCTP_ADDR6_PEERSUPP)))
+                       continue;
+
+               if (sctp_bind_addr_state(bp, &addr->a) != -1)
+                       continue;
+
+               error = sctp_add_bind_addr(bp, &addr->a, sizeof(addr->a),
+                                          SCTP_ADDR_SRC, GFP_ATOMIC);
+               if (error)
+                       break;
        }
 
-end_copy:
        rcu_read_unlock();
        return error;
 }
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 1d1ac51359e3abe9ff1e32ebaba24de04f2909e9..6fc2b8789a0bf677f2ca874dab6eaec96ef4ca3b 100644 (file)
@@ -1,4 +1,6 @@
 hostprogs-y    := genheaders
-HOST_EXTRACFLAGS += -Isecurity/selinux/include
+HOST_EXTRACFLAGS += \
+       -I$(srctree)/include/uapi -I$(srctree)/include \
+       -I$(srctree)/security/selinux/include
 
 always         := $(hostprogs-y)
index 539855ff31f977f32a1afbc16b35c9bfc2df6387..f4dd41f900d5ce8a672479139938feb8b96105f9 100644 (file)
@@ -1,3 +1,7 @@
+
+/* NOTE: we really do want to use the kernel headers here */
+#define __EXPORTED_HEADERS__
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
index dba7eff69a00962e99ca2e34ff4a4f47da59f58b..d6a83cafe59f46d35df53048005be42a1fca6c90 100644 (file)
@@ -1,5 +1,7 @@
 hostprogs-y    := mdp
-HOST_EXTRACFLAGS += -Isecurity/selinux/include
+HOST_EXTRACFLAGS += \
+       -I$(srctree)/include/uapi -I$(srctree)/include \
+       -I$(srctree)/security/selinux/include
 
 always         := $(hostprogs-y)
 clean-files    := policy.* file_contexts
index e10beb11b696e4f6d289e3c74a7dddf970b1b66b..c29fa4a6228d6f59f9346721d4569cb15002b3c6 100644 (file)
  * Authors: Serge E. Hallyn <serue@us.ibm.com>
  */
 
+
+/* NOTE: we really do want to use the kernel headers here */
+#define __EXPORTED_HEADERS__
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
index 5487827fa86c7f1b236521dca9d36c1805bfc1f8..370eb2f4dd379f7cf0708f17306f5a98c721443b 100644 (file)
@@ -27,6 +27,18 @@ config IMA
          to learn more about IMA.
          If unsure, say N.
 
+config IMA_KEXEC
+       bool "Enable carrying the IMA measurement list across a soft boot"
+       depends on IMA && TCG_TPM && HAVE_IMA_KEXEC
+       default n
+       help
+          TPM PCRs are only reset on a hard reboot.  In order to validate
+          a TPM's quote after a soft boot, the IMA measurement list of the
+          running kernel must be saved and restored on boot.
+
+          Depending on the IMA policy, the measurement list can grow to
+          be very large.
+
 config IMA_MEASURE_PCR_IDX
        int
        depends on IMA
index 9aeaedad1e2b9f69e89fa19750490b9ad5cdcc0b..29f198bde02b9ff12fb38b18dfda191b9c3c1e91 100644 (file)
@@ -8,4 +8,5 @@ obj-$(CONFIG_IMA) += ima.o
 ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
         ima_policy.o ima_template.o ima_template_lib.o
 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
+ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
 obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
index db25f54a04fe5bd28cdd90dbb82d794bca5e9262..5e6180a4da7d2a9d583d4b81bbcfb76a1d9e558a 100644 (file)
 
 #include "../integrity.h"
 
+#ifdef CONFIG_HAVE_IMA_KEXEC
+#include <asm/ima.h>
+#endif
+
 enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN,
                     IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII };
 enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
@@ -81,6 +85,7 @@ struct ima_template_field {
 
 /* IMA template descriptor definition */
 struct ima_template_desc {
+       struct list_head list;
        char *name;
        char *fmt;
        int num_fields;
@@ -102,6 +107,27 @@ struct ima_queue_entry {
 };
 extern struct list_head ima_measurements;      /* list of all measurements */
 
+/* Some details preceding the binary serialized measurement list */
+struct ima_kexec_hdr {
+       u16 version;
+       u16 _reserved0;
+       u32 _reserved1;
+       u64 buffer_size;
+       u64 count;
+};
+
+#ifdef CONFIG_HAVE_IMA_KEXEC
+void ima_load_kexec_buffer(void);
+#else
+static inline void ima_load_kexec_buffer(void) {}
+#endif /* CONFIG_HAVE_IMA_KEXEC */
+
+/*
+ * The default binary_runtime_measurements list format is defined as the
+ * platform native format.  The canonical format is defined as little-endian.
+ */
+extern bool ima_canonical_fmt;
+
 /* Internal IMA function definitions */
 int ima_init(void);
 int ima_fs_init(void);
@@ -122,7 +148,12 @@ int ima_init_crypto(void);
 void ima_putc(struct seq_file *m, void *data, int datalen);
 void ima_print_digest(struct seq_file *m, u8 *digest, u32 size);
 struct ima_template_desc *ima_template_desc_current(void);
+int ima_restore_measurement_entry(struct ima_template_entry *entry);
+int ima_restore_measurement_list(loff_t bufsize, void *buf);
+int ima_measurements_show(struct seq_file *m, void *v);
+unsigned long ima_get_binary_runtime_size(void);
 int ima_init_template(void);
+void ima_init_template_list(void);
 
 /*
  * used to protect h_table and sha_table
index 38f2ed830dd6fb23c216b014e39405318705d8ee..802d5d20f36fe46ecb787163f4dafd532741c78b 100644 (file)
@@ -477,11 +477,13 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
                u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 };
                u8 *data_to_hash = field_data[i].data;
                u32 datalen = field_data[i].len;
+               u32 datalen_to_hash =
+                   !ima_canonical_fmt ? datalen : cpu_to_le32(datalen);
 
                if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) {
                        rc = crypto_shash_update(shash,
-                                               (const u8 *) &field_data[i].len,
-                                               sizeof(field_data[i].len));
+                                               (const u8 *) &datalen_to_hash,
+                                               sizeof(datalen_to_hash));
                        if (rc)
                                break;
                } else if (strcmp(td->fields[i]->field_id, "n") == 0) {
index 3df46906492dec72a6381aa2a6aa67500e6d7883..ca303e5d2b9403d858c9df8f5512c80040b0f3f7 100644 (file)
 
 static DEFINE_MUTEX(ima_write_mutex);
 
+bool ima_canonical_fmt;
+static int __init default_canonical_fmt_setup(char *str)
+{
+#ifdef __BIG_ENDIAN
+       ima_canonical_fmt = 1;
+#endif
+       return 1;
+}
+__setup("ima_canonical_fmt", default_canonical_fmt_setup);
+
 static int valid_policy = 1;
 #define TMPBUFLEN 12
 static ssize_t ima_show_htable_value(char __user *buf, size_t count,
@@ -116,13 +126,13 @@ void ima_putc(struct seq_file *m, void *data, int datalen)
  *       [eventdata length]
  *       eventdata[n]=template specific data
  */
-static int ima_measurements_show(struct seq_file *m, void *v)
+int ima_measurements_show(struct seq_file *m, void *v)
 {
        /* the list never shrinks, so we don't need a lock here */
        struct ima_queue_entry *qe = v;
        struct ima_template_entry *e;
        char *template_name;
-       int namelen;
+       u32 pcr, namelen, template_data_len; /* temporary fields */
        bool is_ima_template = false;
        int i;
 
@@ -139,25 +149,29 @@ static int ima_measurements_show(struct seq_file *m, void *v)
         * PCR used defaults to the same (config option) in
         * little-endian format, unless set in policy
         */
-       ima_putc(m, &e->pcr, sizeof(e->pcr));
+       pcr = !ima_canonical_fmt ? e->pcr : cpu_to_le32(e->pcr);
+       ima_putc(m, &pcr, sizeof(e->pcr));
 
        /* 2nd: template digest */
        ima_putc(m, e->digest, TPM_DIGEST_SIZE);
 
        /* 3rd: template name size */
-       namelen = strlen(template_name);
+       namelen = !ima_canonical_fmt ? strlen(template_name) :
+               cpu_to_le32(strlen(template_name));
        ima_putc(m, &namelen, sizeof(namelen));
 
        /* 4th:  template name */
-       ima_putc(m, template_name, namelen);
+       ima_putc(m, template_name, strlen(template_name));
 
        /* 5th:  template length (except for 'ima' template) */
        if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0)
                is_ima_template = true;
 
-       if (!is_ima_template)
-               ima_putc(m, &e->template_data_len,
-                        sizeof(e->template_data_len));
+       if (!is_ima_template) {
+               template_data_len = !ima_canonical_fmt ? e->template_data_len :
+                       cpu_to_le32(e->template_data_len);
+               ima_putc(m, &template_data_len, sizeof(e->template_data_len));
+       }
 
        /* 6th:  template specific data */
        for (i = 0; i < e->template_desc->num_fields; i++) {
index 2ac1f41db5c05677007d09aac73c1fa1aa19ff03..2967d497a665c9f627af9ecf77f1554a97f5addc 100644 (file)
@@ -129,6 +129,8 @@ int __init ima_init(void)
        if (rc != 0)
                return rc;
 
+       ima_load_kexec_buffer();
+
        rc = ima_add_boot_aggregate();  /* boot aggregate must be first entry */
        if (rc != 0)
                return rc;
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
new file mode 100644 (file)
index 0000000..e473eee
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 IBM Corporation
+ *
+ * Authors:
+ * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
+ * Mimi Zohar <zohar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+#include <linux/kexec.h>
+#include "ima.h"
+
+#ifdef CONFIG_IMA_KEXEC
+static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
+                                    unsigned long segment_size)
+{
+       struct ima_queue_entry *qe;
+       struct seq_file file;
+       struct ima_kexec_hdr khdr;
+       int ret = 0;
+
+       /* segment size can't change between kexec load and execute */
+       file.buf = vmalloc(segment_size);
+       if (!file.buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       file.size = segment_size;
+       file.read_pos = 0;
+       file.count = sizeof(khdr);      /* reserved space */
+
+       memset(&khdr, 0, sizeof(khdr));
+       khdr.version = 1;
+       list_for_each_entry_rcu(qe, &ima_measurements, later) {
+               if (file.count < file.size) {
+                       khdr.count++;
+                       ima_measurements_show(&file, qe);
+               } else {
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       if (ret < 0)
+               goto out;
+
+       /*
+        * fill in reserved space with some buffer details
+        * (eg. version, buffer size, number of measurements)
+        */
+       khdr.buffer_size = file.count;
+       if (ima_canonical_fmt) {
+               khdr.version = cpu_to_le16(khdr.version);
+               khdr.count = cpu_to_le64(khdr.count);
+               khdr.buffer_size = cpu_to_le64(khdr.buffer_size);
+       }
+       memcpy(file.buf, &khdr, sizeof(khdr));
+
+       print_hex_dump(KERN_DEBUG, "ima dump: ", DUMP_PREFIX_NONE,
+                       16, 1, file.buf,
+                       file.count < 100 ? file.count : 100, true);
+
+       *buffer_size = file.count;
+       *buffer = file.buf;
+out:
+       if (ret == -EINVAL)
+               vfree(file.buf);
+       return ret;
+}
+
+/*
+ * Called during kexec_file_load so that IMA can add a segment to the kexec
+ * image for the measurement list for the next kernel.
+ *
+ * This function assumes that kexec_mutex is held.
+ */
+void ima_add_kexec_buffer(struct kimage *image)
+{
+       struct kexec_buf kbuf = { .image = image, .buf_align = PAGE_SIZE,
+                                 .buf_min = 0, .buf_max = ULONG_MAX,
+                                 .top_down = true };
+       unsigned long binary_runtime_size;
+
+       /* use more understandable variable names than defined in kbuf */
+       void *kexec_buffer = NULL;
+       size_t kexec_buffer_size;
+       size_t kexec_segment_size;
+       int ret;
+
+       /*
+        * Reserve an extra half page of memory for additional measurements
+        * added during the kexec load.
+        */
+       binary_runtime_size = ima_get_binary_runtime_size();
+       if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
+               kexec_segment_size = ULONG_MAX;
+       else
+               kexec_segment_size = ALIGN(ima_get_binary_runtime_size() +
+                                          PAGE_SIZE / 2, PAGE_SIZE);
+       if ((kexec_segment_size == ULONG_MAX) ||
+           ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages / 2)) {
+               pr_err("Binary measurement list too large.\n");
+               return;
+       }
+
+       ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
+                                 kexec_segment_size);
+       if (!kexec_buffer) {
+               pr_err("Not enough memory for the kexec measurement buffer.\n");
+               return;
+       }
+
+       kbuf.buffer = kexec_buffer;
+       kbuf.bufsz = kexec_buffer_size;
+       kbuf.memsz = kexec_segment_size;
+       ret = kexec_add_buffer(&kbuf);
+       if (ret) {
+               pr_err("Error passing over kexec measurement buffer.\n");
+               return;
+       }
+
+       ret = arch_ima_add_kexec_buffer(image, kbuf.mem, kexec_segment_size);
+       if (ret) {
+               pr_err("Error passing over kexec measurement buffer.\n");
+               return;
+       }
+
+       pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
+                kbuf.mem);
+}
+#endif /* IMA_KEXEC */
+
+/*
+ * Restore the measurement list from the previous kernel.
+ */
+void ima_load_kexec_buffer(void)
+{
+       void *kexec_buffer = NULL;
+       size_t kexec_buffer_size = 0;
+       int rc;
+
+       rc = ima_get_kexec_buffer(&kexec_buffer, &kexec_buffer_size);
+       switch (rc) {
+       case 0:
+               rc = ima_restore_measurement_list(kexec_buffer_size,
+                                                 kexec_buffer);
+               if (rc != 0)
+                       pr_err("Failed to restore the measurement list: %d\n",
+                               rc);
+
+               ima_free_kexec_buffer();
+               break;
+       case -ENOTSUPP:
+               pr_debug("Restoring the measurement list not supported\n");
+               break;
+       case -ENOENT:
+               pr_debug("No measurement list to restore\n");
+               break;
+       default:
+               pr_debug("Error restoring the measurement list: %d\n", rc);
+       }
+}
index 423d111b3b9475ef43092b77a744ed6fe65599ab..50818c60538b8e0e764de72c842cfb608abb305a 100644 (file)
@@ -418,6 +418,7 @@ static int __init init_ima(void)
 {
        int error;
 
+       ima_init_template_list();
        hash_setup(CONFIG_IMA_DEFAULT_HASH);
        error = ima_init();
        if (!error) {
index 32f6ac0f96dfb0ed3c8d296c817e97946834c28e..d9aa5ab712044a4d7e0a3a11ecfb86547198e3af 100644 (file)
 #define AUDIT_CAUSE_LEN_MAX 32
 
 LIST_HEAD(ima_measurements);   /* list of all measurements */
+#ifdef CONFIG_IMA_KEXEC
+static unsigned long binary_runtime_size;
+#else
+static unsigned long binary_runtime_size = ULONG_MAX;
+#endif
 
 /* key: inode (before secure-hashing a file) */
 struct ima_h_table ima_htable = {
@@ -64,12 +69,32 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
        return ret;
 }
 
+/*
+ * Calculate the memory required for serializing a single
+ * binary_runtime_measurement list entry, which contains a
+ * couple of variable length fields (e.g template name and data).
+ */
+static int get_binary_runtime_size(struct ima_template_entry *entry)
+{
+       int size = 0;
+
+       size += sizeof(u32);    /* pcr */
+       size += sizeof(entry->digest);
+       size += sizeof(int);    /* template name size field */
+       size += strlen(entry->template_desc->name) + 1;
+       size += sizeof(entry->template_data_len);
+       size += entry->template_data_len;
+       return size;
+}
+
 /* ima_add_template_entry helper function:
- * - Add template entry to measurement list and hash table.
+ * - Add template entry to the measurement list and hash table, for
+ *   all entries except those carried across kexec.
  *
  * (Called with ima_extend_list_mutex held.)
  */
-static int ima_add_digest_entry(struct ima_template_entry *entry)
+static int ima_add_digest_entry(struct ima_template_entry *entry,
+                               bool update_htable)
 {
        struct ima_queue_entry *qe;
        unsigned int key;
@@ -85,11 +110,34 @@ static int ima_add_digest_entry(struct ima_template_entry *entry)
        list_add_tail_rcu(&qe->later, &ima_measurements);
 
        atomic_long_inc(&ima_htable.len);
-       key = ima_hash_key(entry->digest);
-       hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+       if (update_htable) {
+               key = ima_hash_key(entry->digest);
+               hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+       }
+
+       if (binary_runtime_size != ULONG_MAX) {
+               int size;
+
+               size = get_binary_runtime_size(entry);
+               binary_runtime_size = (binary_runtime_size < ULONG_MAX - size) ?
+                    binary_runtime_size + size : ULONG_MAX;
+       }
        return 0;
 }
 
+/*
+ * Return the amount of memory required for serializing the
+ * entire binary_runtime_measurement list, including the ima_kexec_hdr
+ * structure.
+ */
+unsigned long ima_get_binary_runtime_size(void)
+{
+       if (binary_runtime_size >= (ULONG_MAX - sizeof(struct ima_kexec_hdr)))
+               return ULONG_MAX;
+       else
+               return binary_runtime_size + sizeof(struct ima_kexec_hdr);
+};
+
 static int ima_pcr_extend(const u8 *hash, int pcr)
 {
        int result = 0;
@@ -103,8 +151,13 @@ static int ima_pcr_extend(const u8 *hash, int pcr)
        return result;
 }
 
-/* Add template entry to the measurement list and hash table,
- * and extend the pcr.
+/*
+ * Add template entry to the measurement list and hash table, and
+ * extend the pcr.
+ *
+ * On systems which support carrying the IMA measurement list across
+ * kexec, maintain the total memory size required for serializing the
+ * binary_runtime_measurements.
  */
 int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                           const char *op, struct inode *inode,
@@ -126,7 +179,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                }
        }
 
-       result = ima_add_digest_entry(entry);
+       result = ima_add_digest_entry(entry, 1);
        if (result < 0) {
                audit_cause = "ENOMEM";
                audit_info = 0;
@@ -149,3 +202,13 @@ out:
                            op, audit_cause, result, audit_info);
        return result;
 }
+
+int ima_restore_measurement_entry(struct ima_template_entry *entry)
+{
+       int result = 0;
+
+       mutex_lock(&ima_extend_list_mutex);
+       result = ima_add_digest_entry(entry, 0);
+       mutex_unlock(&ima_extend_list_mutex);
+       return result;
+}
index febd12ed9b55ab4d6009176c355655c646272437..cebb37c63629fc89465cd020f2efbd550442cfc7 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/rculist.h>
 #include "ima.h"
 #include "ima_template_lib.h"
 
-static struct ima_template_desc defined_templates[] = {
+static struct ima_template_desc builtin_templates[] = {
        {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
        {.name = "ima-ng", .fmt = "d-ng|n-ng"},
        {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
        {.name = "", .fmt = ""},        /* placeholder for a custom format */
 };
 
+static LIST_HEAD(defined_templates);
+static DEFINE_SPINLOCK(template_list);
+
 static struct ima_template_field supported_fields[] = {
        {.field_id = "d", .field_init = ima_eventdigest_init,
         .field_show = ima_show_template_digest},
@@ -37,6 +41,7 @@ static struct ima_template_field supported_fields[] = {
        {.field_id = "sig", .field_init = ima_eventsig_init,
         .field_show = ima_show_template_sig},
 };
+#define MAX_TEMPLATE_NAME_LEN 15
 
 static struct ima_template_desc *ima_template;
 static struct ima_template_desc *lookup_template_desc(const char *name);
@@ -52,6 +57,8 @@ static int __init ima_template_setup(char *str)
        if (ima_template)
                return 1;
 
+       ima_init_template_list();
+
        /*
         * Verify that a template with the supplied name exists.
         * If not, use CONFIG_IMA_DEFAULT_TEMPLATE.
@@ -80,7 +87,7 @@ __setup("ima_template=", ima_template_setup);
 
 static int __init ima_template_fmt_setup(char *str)
 {
-       int num_templates = ARRAY_SIZE(defined_templates);
+       int num_templates = ARRAY_SIZE(builtin_templates);
 
        if (ima_template)
                return 1;
@@ -91,22 +98,28 @@ static int __init ima_template_fmt_setup(char *str)
                return 1;
        }
 
-       defined_templates[num_templates - 1].fmt = str;
-       ima_template = defined_templates + num_templates - 1;
+       builtin_templates[num_templates - 1].fmt = str;
+       ima_template = builtin_templates + num_templates - 1;
+
        return 1;
 }
 __setup("ima_template_fmt=", ima_template_fmt_setup);
 
 static struct ima_template_desc *lookup_template_desc(const char *name)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(defined_templates); i++) {
-               if (strcmp(defined_templates[i].name, name) == 0)
-                       return defined_templates + i;
+       struct ima_template_desc *template_desc;
+       int found = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(template_desc, &defined_templates, list) {
+               if ((strcmp(template_desc->name, name) == 0) ||
+                   (strcmp(template_desc->fmt, name) == 0)) {
+                       found = 1;
+                       break;
+               }
        }
-
-       return NULL;
+       rcu_read_unlock();
+       return found ? template_desc : NULL;
 }
 
 static struct ima_template_field *lookup_template_field(const char *field_id)
@@ -142,9 +155,14 @@ static int template_desc_init_fields(const char *template_fmt,
 {
        const char *template_fmt_ptr;
        struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX];
-       int template_num_fields = template_fmt_size(template_fmt);
+       int template_num_fields;
        int i, len;
 
+       if (num_fields && *num_fields > 0) /* already initialized? */
+               return 0;
+
+       template_num_fields = template_fmt_size(template_fmt);
+
        if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) {
                pr_err("format string '%s' contains too many fields\n",
                       template_fmt);
@@ -182,11 +200,28 @@ static int template_desc_init_fields(const char *template_fmt,
        return 0;
 }
 
+void ima_init_template_list(void)
+{
+       int i;
+
+       if (!list_empty(&defined_templates))
+               return;
+
+       spin_lock(&template_list);
+       for (i = 0; i < ARRAY_SIZE(builtin_templates); i++) {
+               list_add_tail_rcu(&builtin_templates[i].list,
+                                 &defined_templates);
+       }
+       spin_unlock(&template_list);
+}
+
 struct ima_template_desc *ima_template_desc_current(void)
 {
-       if (!ima_template)
+       if (!ima_template) {
+               ima_init_template_list();
                ima_template =
                    lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE);
+       }
        return ima_template;
 }
 
@@ -205,3 +240,239 @@ int __init ima_init_template(void)
 
        return result;
 }
+
+static struct ima_template_desc *restore_template_fmt(char *template_name)
+{
+       struct ima_template_desc *template_desc = NULL;
+       int ret;
+
+       ret = template_desc_init_fields(template_name, NULL, NULL);
+       if (ret < 0) {
+               pr_err("attempting to initialize the template \"%s\" failed\n",
+                       template_name);
+               goto out;
+       }
+
+       template_desc = kzalloc(sizeof(*template_desc), GFP_KERNEL);
+       if (!template_desc)
+               goto out;
+
+       template_desc->name = "";
+       template_desc->fmt = kstrdup(template_name, GFP_KERNEL);
+       if (!template_desc->fmt)
+               goto out;
+
+       spin_lock(&template_list);
+       list_add_tail_rcu(&template_desc->list, &defined_templates);
+       spin_unlock(&template_list);
+out:
+       return template_desc;
+}
+
+static int ima_restore_template_data(struct ima_template_desc *template_desc,
+                                    void *template_data,
+                                    int template_data_size,
+                                    struct ima_template_entry **entry)
+{
+       struct binary_field_data {
+               u32 len;
+               u8 data[0];
+       } __packed;
+
+       struct binary_field_data *field_data;
+       int offset = 0;
+       int ret = 0;
+       int i;
+
+       *entry = kzalloc(sizeof(**entry) +
+                   template_desc->num_fields * sizeof(struct ima_field_data),
+                   GFP_NOFS);
+       if (!*entry)
+               return -ENOMEM;
+
+       (*entry)->template_desc = template_desc;
+       for (i = 0; i < template_desc->num_fields; i++) {
+               field_data = template_data + offset;
+
+               /* Each field of the template data is prefixed with a length. */
+               if (offset > (template_data_size - sizeof(*field_data))) {
+                       pr_err("Restoring the template field failed\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               offset += sizeof(*field_data);
+
+               if (ima_canonical_fmt)
+                       field_data->len = le32_to_cpu(field_data->len);
+
+               if (offset > (template_data_size - field_data->len)) {
+                       pr_err("Restoring the template field data failed\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               offset += field_data->len;
+
+               (*entry)->template_data[i].len = field_data->len;
+               (*entry)->template_data_len += sizeof(field_data->len);
+
+               (*entry)->template_data[i].data =
+                       kzalloc(field_data->len + 1, GFP_KERNEL);
+               if (!(*entry)->template_data[i].data) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               memcpy((*entry)->template_data[i].data, field_data->data,
+                       field_data->len);
+               (*entry)->template_data_len += field_data->len;
+       }
+
+       if (ret < 0) {
+               ima_free_template_entry(*entry);
+               *entry = NULL;
+       }
+
+       return ret;
+}
+
+/* Restore the serialized binary measurement list without extending PCRs. */
+int ima_restore_measurement_list(loff_t size, void *buf)
+{
+       struct binary_hdr_v1 {
+               u32 pcr;
+               u8 digest[TPM_DIGEST_SIZE];
+               u32 template_name_len;
+               char template_name[0];
+       } __packed;
+       char template_name[MAX_TEMPLATE_NAME_LEN];
+
+       struct binary_data_v1 {
+               u32 template_data_size;
+               char template_data[0];
+       } __packed;
+
+       struct ima_kexec_hdr *khdr = buf;
+       struct binary_hdr_v1 *hdr_v1;
+       struct binary_data_v1 *data_v1;
+
+       void *bufp = buf + sizeof(*khdr);
+       void *bufendp;
+       struct ima_template_entry *entry;
+       struct ima_template_desc *template_desc;
+       unsigned long count = 0;
+       int ret = 0;
+
+       if (!buf || size < sizeof(*khdr))
+               return 0;
+
+       if (ima_canonical_fmt) {
+               khdr->version = le16_to_cpu(khdr->version);
+               khdr->count = le64_to_cpu(khdr->count);
+               khdr->buffer_size = le64_to_cpu(khdr->buffer_size);
+       }
+
+       if (khdr->version != 1) {
+               pr_err("attempting to restore a incompatible measurement list");
+               return -EINVAL;
+       }
+
+       if (khdr->count > ULONG_MAX - 1) {
+               pr_err("attempting to restore too many measurements");
+               return -EINVAL;
+       }
+
+       /*
+        * ima kexec buffer prefix: version, buffer size, count
+        * v1 format: pcr, digest, template-name-len, template-name,
+        *            template-data-size, template-data
+        */
+       bufendp = buf + khdr->buffer_size;
+       while ((bufp < bufendp) && (count++ < khdr->count)) {
+               hdr_v1 = bufp;
+               if (bufp > (bufendp - sizeof(*hdr_v1))) {
+                       pr_err("attempting to restore partial measurement\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               bufp += sizeof(*hdr_v1);
+
+               if (ima_canonical_fmt)
+                       hdr_v1->template_name_len =
+                           le32_to_cpu(hdr_v1->template_name_len);
+
+               if ((hdr_v1->template_name_len >= MAX_TEMPLATE_NAME_LEN) ||
+                   (bufp > (bufendp - hdr_v1->template_name_len))) {
+                       pr_err("attempting to restore a template name \
+                               that is too long\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               data_v1 = bufp += (u_int8_t)hdr_v1->template_name_len;
+
+               /* template name is not null terminated */
+               memcpy(template_name, hdr_v1->template_name,
+                      hdr_v1->template_name_len);
+               template_name[hdr_v1->template_name_len] = 0;
+
+               if (strcmp(template_name, "ima") == 0) {
+                       pr_err("attempting to restore an unsupported \
+                               template \"%s\" failed\n", template_name);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               template_desc = lookup_template_desc(template_name);
+               if (!template_desc) {
+                       template_desc = restore_template_fmt(template_name);
+                       if (!template_desc)
+                               break;
+               }
+
+               /*
+                * Only the running system's template format is initialized
+                * on boot.  As needed, initialize the other template formats.
+                */
+               ret = template_desc_init_fields(template_desc->fmt,
+                                               &(template_desc->fields),
+                                               &(template_desc->num_fields));
+               if (ret < 0) {
+                       pr_err("attempting to restore the template fmt \"%s\" \
+                               failed\n", template_desc->fmt);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (bufp > (bufendp - sizeof(data_v1->template_data_size))) {
+                       pr_err("restoring the template data size failed\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               bufp += (u_int8_t) sizeof(data_v1->template_data_size);
+
+               if (ima_canonical_fmt)
+                       data_v1->template_data_size =
+                           le32_to_cpu(data_v1->template_data_size);
+
+               if (bufp > (bufendp - data_v1->template_data_size)) {
+                       pr_err("restoring the template data failed\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               bufp += data_v1->template_data_size;
+
+               ret = ima_restore_template_data(template_desc,
+                                               data_v1->template_data,
+                                               data_v1->template_data_size,
+                                               &entry);
+               if (ret < 0)
+                       break;
+
+               memcpy(entry->digest, hdr_v1->digest, TPM_DIGEST_SIZE);
+               entry->pcr =
+                   !ima_canonical_fmt ? hdr_v1->pcr : le32_to_cpu(hdr_v1->pcr);
+               ret = ima_restore_measurement_entry(entry);
+               if (ret < 0)
+                       break;
+
+       }
+       return ret;
+}
index f9bae04ba1762cd3e91728e4506719739b541e7d..f9ba37b3928dce36bb940e7aa4620848aca1f15b 100644 (file)
@@ -103,8 +103,11 @@ static void ima_show_template_data_binary(struct seq_file *m,
        u32 len = (show == IMA_SHOW_BINARY_OLD_STRING_FMT) ?
            strlen(field_data->data) : field_data->len;
 
-       if (show != IMA_SHOW_BINARY_NO_FIELD_LEN)
-               ima_putc(m, &len, sizeof(len));
+       if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) {
+               u32 field_len = !ima_canonical_fmt ? len : cpu_to_le32(len);
+
+               ima_putc(m, &field_len, sizeof(field_len));
+       }
 
        if (!len)
                return;
index e2d4ad3a4b4c5e01a063747a4286e1b51c05f697..13ae49b0baa091f3ca9202fd51e3a20e46d9b6f4 100644 (file)
@@ -1,3 +1,5 @@
+#include <linux/capability.h>
+
 #define COMMON_FILE_SOCK_PERMS "ioctl", "read", "write", "create", \
     "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
 
index a2cdf3370afe75f5f5029f5fd78a4a32fa9cc1f7..15d1d5c63c3c40faa5f62316370ea9d8e711fa75 100644 (file)
@@ -384,9 +384,6 @@ static void snd_complete_urb(struct urb *urb)
        if (unlikely(atomic_read(&ep->chip->shutdown)))
                goto exit_clear;
 
-       if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
-               goto exit_clear;
-
        if (usb_pipeout(ep->pipe)) {
                retire_outbound_urb(ep, ctx);
                /* can be stopped during retire callback */
@@ -537,11 +534,6 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
                        alive, ep->ep_num);
        clear_bit(EP_FLAG_STOPPING, &ep->flags);
 
-       ep->data_subs = NULL;
-       ep->sync_slave = NULL;
-       ep->retire_data_urb = NULL;
-       ep->prepare_data_urb = NULL;
-
        return 0;
 }
 
@@ -1028,6 +1020,10 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
 
        if (--ep->use_count == 0) {
                deactivate_urbs(ep, false);
+               ep->data_subs = NULL;
+               ep->sync_slave = NULL;
+               ep->retire_data_urb = NULL;
+               ep->prepare_data_urb = NULL;
                set_bit(EP_FLAG_STOPPING, &ep->flags);
        }
 }
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 = {